/* MindSpring — landing graphics layer.

   Canvas placement, film grain, and the bracketed stat frames. The canvases
   themselves are drawn by graphics.js; everything here is the surround. */

/* ---------------------------------------------------------------------------
   Canvas slots
   ------------------------------------------------------------------------ */
.gfx{display:block;width:100%;height:100%;}

/* The hero canvas is deliberately larger than its box and centred, so the
   outer rings bleed past the edges instead of sitting politely inside a
   rectangle — the reference objects all overflow their container. */
.gfx-hero{
  position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:min(1100px,124vw);height:min(1100px,124vw);
}

/* ---------------------------------------------------------------------------
   Film grain.

   Present in both references and doing more work than it looks: a black page
   made of flat #000 fills reads as dead, and on OLED it also shows banding
   wherever a gradient falls off. A ~3% noise layer breaks up the banding and
   gives the whole page the texture of a printed photograph.

   Generated with feTurbulence as a data URI — no image request. `stitchTiles`
   makes the pattern tile seamlessly.
   ------------------------------------------------------------------------ */
.grain{
  position:fixed;inset:-50%;
  z-index:1;
  pointer-events:none;
  opacity:.038;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  will-change:transform;
  animation:grain-shift 7s steps(6) infinite;
}
/* Nudging the layer between a handful of fixed offsets makes the grain look
   alive — like film running — rather than a static texture pasted on top.
   steps() keeps it snapping between frames instead of sliding smoothly. */
@keyframes grain-shift{
  0%,100%{transform:translate(0,0);}
  16%{transform:translate(-3%,2%);}
  33%{transform:translate(2%,-3%);}
  50%{transform:translate(-2%,-2%);}
  66%{transform:translate(3%,1%);}
  83%{transform:translate(1%,3%);}
}

/* ---------------------------------------------------------------------------
   Bracketed stat frames — lifted in spirit from the reference's stat row,
   where each figure sits inside four dashed corner marks rather than a full
   border. The corners imply a frame without drawing a box, which keeps a
   dense row of numbers from turning into a grid of cells.
   ------------------------------------------------------------------------ */
.stat-band{
  display:grid;grid-template-columns:1fr;gap:14px;
  padding:clamp(56px,9vw,88px) 0 0;
}
@media(min-width:640px){.stat-band{grid-template-columns:repeat(3,1fr);gap:20px;}}

.stat{position:relative;padding:30px 26px;}
.stat::before,.stat::after,
.stat > .br::before,.stat > .br::after{
  content:"";position:absolute;width:12px;height:12px;
  border-color:hsl(var(--muted-foreground) / .5);border-style:solid;border-width:0;
}
.stat::before{top:0;left:0;border-top-width:1px;border-left-width:1px;}
.stat::after{top:0;right:0;border-top-width:1px;border-right-width:1px;}
.stat > .br::before{bottom:0;left:0;border-bottom-width:1px;border-left-width:1px;}
.stat > .br::after{bottom:0;right:0;border-bottom-width:1px;border-right-width:1px;}

.stat .num{
  font-size:clamp(1.75rem,3.4vw,2.5rem);font-weight:500;letter-spacing:-1px;
  color:hsl(var(--foreground));line-height:1.1;
}
.stat .cap{margin-top:8px;font-size:13px;color:hsl(var(--muted-foreground));line-height:1.5;}
.stat .idx{
  position:absolute;top:12px;right:16px;
  font-size:10px;letter-spacing:.14em;color:hsl(var(--muted-foreground) / .6);
}

/* ---------------------------------------------------------------------------
   Blur-in headline, from the first reference — words resolve out of a soft
   blur rather than just fading. Costs one extra property on the same
   transition, and gives the entrance real depth.
   ------------------------------------------------------------------------ */
.blur-in{
  opacity:0;filter:blur(14px);transform:translateY(14px);
  transition:opacity .9s cubic-bezier(.16,1,.3,1),
             filter  .9s cubic-bezier(.16,1,.3,1),
             transform .9s cubic-bezier(.16,1,.3,1);
  transition-delay:var(--delay,0s);
}
.blur-in.in{opacity:1;filter:blur(0);transform:none;}

/* ---------------------------------------------------------------------------
   LIQUID GLASS BUTTONS — coloured

   Built from the UI-kit reference. Five things make those pills read as a
   moulded, lit piece of glass rather than a rounded rectangle:

     1. A two-stop HUE gradient across the body. The reference pills are never
        one flat colour — the pink one runs to orange, the blue one to cyan.
        That shift across the surface is what implies a curved, refracting
        body rather than a painted one.
     2. A bright specular SWEEP over the top third only, with a hard lower
        edge. The hard cutoff is the whole trick; a soft even sheen reads as
        a gradient, not glass.
     3. Rim lights — a bright inset line along the top, a fainter one along
        the bottom where light wraps around the far side.
     4. A saturated cast GLOW pooling underneath, which is what makes the pill
        look lit from within and lifts it off the page.
     5. A cursor-tracked highlight (--mx/--my, written by motion.js). Real
        glass moves its highlight as you move relative to it; this is the
        single cheapest thing that makes the surface feel physical.

   Every variant is the same structure with two custom properties swapped:
   --lg-a / --lg-b are the body hue stops, --lg-glow the cast light.
   ------------------------------------------------------------------------ */
.lg-btn{
  --lg-a:250,250,252;
  --lg-b:205,205,215;
  --lg-glow:255,255,255;
  --shine:0;

  position:relative;isolation:isolate;
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  padding:16px 34px;border:none;cursor:pointer;text-decoration:none;
  border-radius:100px;
  font-family:'Inter',sans-serif;font-size:15px;font-weight:500;
  color:hsl(var(--foreground));
  background:
    /* 5 — cursor highlight, invisible until hover raises --shine */
    radial-gradient(120px circle at var(--mx,50%) var(--my,50%),
      rgba(255,255,255,calc(.34 * var(--shine))), transparent 62%),
    /* 2 — top specular */
    linear-gradient(180deg,
      rgba(255,255,255,.34) 0%,
      rgba(255,255,255,.10) 26%,
      rgba(255,255,255,0) 42%,
      rgba(0,0,0,.26) 100%),
    /* 1 — body hue shift */
    linear-gradient(155deg, rgba(var(--lg-a),.95), rgba(var(--lg-b),.95)),
    #0a0a0c;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.55),
    inset 0 -1px 0 rgba(255,255,255,.14),
    inset 0 12px 22px -14px rgba(255,255,255,.45),
    0 10px 26px -10px rgba(0,0,0,.9),
    0 22px 50px -20px rgba(var(--lg-glow),.60);
  transition:transform .24s cubic-bezier(.2,.8,.3,1),
             box-shadow .24s ease, --shine .2s ease;
}
/* Chromatic rim picking up the body hue. */
.lg-btn::after{
  content:'';position:absolute;z-index:-1;inset:0;border-radius:inherit;padding:1px;
  background:linear-gradient(180deg,
    rgba(255,255,255,.75), rgba(var(--lg-glow),.35) 50%, rgba(255,255,255,.45));
  -webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
  -webkit-mask-composite:xor;
          mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);
          mask-composite:exclude;
  pointer-events:none;
}
.lg-btn:hover{
  --shine:1;
  transform:translateY(-3px) scale(1.02);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.7),
    inset 0 -1px 0 rgba(255,255,255,.2),
    inset 0 12px 22px -14px rgba(255,255,255,.6),
    0 16px 34px -10px rgba(0,0,0,.9),
    0 34px 74px -20px rgba(var(--lg-glow),.95);
}
.lg-btn:active{transform:translateY(-1px) scale(.985);}

/* --- Variants, matched to the reference kit ------------------------------ */
/* Dark primary with a violet under-light — the "Start project" pill. */
.lg-dark{
  --lg-a:26,26,38; --lg-b:10,10,16; --lg-glow:120,110,255;
  color:#fff;
}
/* Magenta running to orange — the "Secondary" pill. */
.lg-pink{
  --lg-a:236,72,153; --lg-b:251,146,60; --lg-glow:244,94,160;
  color:#fff;
}
/* Cyan to deep blue — the "Icon button". */
.lg-blue{
  --lg-a:56,189,248; --lg-b:37,99,235; --lg-glow:56,160,248;
  color:#fff;
}
/* Green to yellow — the "Select" pill. */
.lg-green{
  --lg-a:74,222,128; --lg-b:250,204,21; --lg-glow:110,225,140;
  color:#08240f;
}
/* Silver — the "Text field". Dark label, since the body is near-white. */
.lg-silver{
  --lg-a:255,255,255; --lg-b:200,202,212; --lg-glow:190,200,225;
  color:hsl(var(--primary-foreground));
}
.lg-silver::after{background:linear-gradient(180deg,rgba(255,255,255,.95),rgba(255,255,255,.25));}

/* Registering --shine lets it animate; without this the cursor highlight
   would pop on and off instead of fading. Ignored by browsers that don't
   support @property, which simply get the instant version. */
@supports (background: paint(x)) or (color: color-mix(in srgb, red, blue)){
  @property --shine{syntax:'<number>';inherits:false;initial-value:0;}
}

/* ---------------------------------------------------------------------------
   COLLAGE STICKERS

   Halftone paper cut-outs. The source art already carries its torn white
   border, so all that is added here is the physical bit: a drop shadow, so it
   sits ON the page like something stuck down, and a slight rotation, because
   nothing hand-placed is ever perfectly square.
   ------------------------------------------------------------------------ */
.sticker{
  position:absolute;pointer-events:none;z-index:2;
  filter:drop-shadow(0 14px 22px rgba(0,0,0,.65));
  opacity:.92;
}
.sticker img{width:100%;height:auto;display:block;}

.sticker-inline{
  position:relative;display:block;margin:0 auto;
  filter:drop-shadow(0 14px 22px rgba(0,0,0,.6));
}
.sticker-inline img{width:100%;height:auto;display:block;}

/* ---------------------------------------------------------------------------
   CONVERGING HANDS

   The supplied pointing-hand cut-outs enter from opposite edges, then crossfade
   into the supplied robot/human handshake at contact. --converge controls the
   approach and --grip adds one damped, scroll-owned settling motion.
   ------------------------------------------------------------------------ */
.converge{
  position:relative;
  min-height:clamp(520px,78svh,700px);
  display:flex;align-items:center;justify-content:center;
  overflow:hidden;
}
.converge-message{
  position:absolute;left:50%;top:50%;z-index:4;width:min(88vw,620px);
  margin:0;text-align:center;pointer-events:none;
  transform:translate(-50%,calc(-50% - var(--converge,0) * 170px));
  color:hsl(var(--foreground));
  filter:drop-shadow(0 2px 16px rgba(0,0,0,.9));
  text-shadow:
    0 2px 2px rgba(0,0,0,.98),
    0 8px 22px rgba(0,0,0,.94),
    0 18px 42px rgba(0,0,0,.82);
}
.converge-message span{
  display:block;font-size:clamp(13px,1.4vw,16px);font-weight:500;
  letter-spacing:.14em;text-transform:uppercase;color:hsl(var(--muted-foreground));
}
.converge-message strong{
  display:block;margin-top:5px;
  font-family:'Instrument Serif',Georgia,serif;font-size:clamp(34px,5.5vw,68px);
  font-style:italic;font-weight:400;line-height:.95;letter-spacing:-.035em;
}
.converge-hand{
  position:absolute;top:50%;
  filter:drop-shadow(0 18px 30px rgba(0,0,0,.7));
  opacity:clamp(0,calc((.86 - var(--converge,0)) * 6.25),1);
  will-change:transform,opacity;
}
.converge-hand img,.converge-result img{width:100%;height:auto;display:block;}
.converge-result img{transform:scaleX(-1);}

/* The two source images have different silhouettes and aspect ratios, so each
   gets its own calibrated box. Their fingertips meet at the centre before the
   final handshake replaces them. */
.converge-hand.left{
  width:clamp(230px,38vw,460px);right:calc(50% + 3px);
  transform:
    translate(calc((100% + 50vw) * (var(--approach,0) - 1)),-50%)
    rotate(calc(-8deg + var(--approach,0) * 8deg))
    scale(calc(.93 + var(--approach,0) * .07));
}
.converge-hand.right{
  width:clamp(205px,33vw,390px);left:calc(50% + 3px);
  transform:
    translate(calc((100% + 50vw) * (1 - var(--approach,0))),-50%)
    rotate(calc(7deg - var(--approach,0) * 7deg))
    scale(calc(.93 + var(--approach,0) * .07));
}
.converge-result{
  position:absolute;top:50%;left:50%;
  width:clamp(300px,56vw,660px);
  opacity:clamp(0,calc((var(--converge,0) - .70) * 6.25),1);
  transform:
    translate(-50%,calc(-50% + var(--grip,0) * 7px))
    rotate(calc(var(--grip,0) * 1.8deg))
    scale(calc(.86 + var(--converge,0) * .14 + var(--grip,0) * .018));
  filter:drop-shadow(0 22px 34px rgba(0,0,0,.76));
  will-change:transform,opacity;
  pointer-events:none;
}

@media(prefers-reduced-motion:reduce){
  .grain{animation:none;}
  .blur-in{opacity:1;filter:none;transform:none;transition:none;}
  /* Show the completed handshake, not an unfinished approach. */
  .converge{--converge:1 !important;--approach:1 !important;--grip:0 !important;}
  .converge-hand{display:none;}
  .converge-result{opacity:1;transform:translate(-50%,-50%);}
}

@media(max-width:600px){
  .converge-message{transform:translate(-50%,calc(-50% - var(--converge,0) * 156px));}
}

/* ---------------------------------------------------------------------------
   REACTIVE BACKGROUND

   Three fixed layers under everything, in order of subtlety:

     .bg-field   a fine dot lattice, so the black is a surface rather than a void
     .bg-aura    two very low-alpha colour fields that drift with scroll, tying
                 the page to the coloured glass without becoming blob soup
     .bg-spot    a highlight that follows the cursor

   Every alpha here is deliberately tiny. The point is that you should not be
   able to name what is happening — only notice the page feels lit rather than
   printed. Anything stronger and this becomes the exact glowing-gradient
   cliche the rest of the design avoids.
   ------------------------------------------------------------------------ */
/* z-index MUST be negative, not 0. In CSS paint order a positioned element
   with z-index:0 paints ABOVE the inline content of non-positioned ancestors —
   so at z-index:0 these layers rendered on top of the body copy in every
   section that isn't position:relative. -1 puts them behind all content while
   still keeping them above the page background. */
.bg-layer{position:fixed;inset:0;z-index:-1;pointer-events:none;}

.bg-field{
  background-image:radial-gradient(rgba(255,255,255,.16) 1px, transparent 1px);
  background-size:26px 26px;
  opacity:.16;
  -webkit-mask-image:radial-gradient(ellipse 90% 70% at 50% 30%,#000 20%,transparent 78%);
          mask-image:radial-gradient(ellipse 90% 70% at 50% 30%,#000 20%,transparent 78%);
}

/* --scrollp (0..1 down the page) is written by motion.js. The aura shifts
   position with it, so the light appears to travel as you read. */
.bg-aura{
  background:
    radial-gradient(46vw 46vw at calc(12% + var(--scrollp,0) * 26%) calc(8% + var(--scrollp,0) * 30%),
      rgba(120,110,255,.075), transparent 62%),
    radial-gradient(40vw 40vw at calc(88% - var(--scrollp,0) * 24%) calc(84% - var(--scrollp,0) * 26%),
      rgba(236,72,153,.055), transparent 60%);
}

.bg-spot{
  background:radial-gradient(420px circle at var(--px,50%) var(--py,20%),
    rgba(255,255,255,.055), transparent 70%);
  transition:opacity .4s ease;
}

/* ---------------------------------------------------------------------------
   HOVER REACTIVITY
   ------------------------------------------------------------------------ */
/* Nav links get a hairline that wipes in from the left. */
.nav-links a::before{content:none;}
.nav-links a{--u:0;}
.nav-links a:hover{--u:1;}

/* Chips lift and pick up a rim. */
.hero-chips a{transition:transform .2s cubic-bezier(.2,.8,.3,1),border-color .2s ease,color .2s ease,box-shadow .2s ease;}
.hero-chips a:hover{
  transform:translateY(-3px);
  box-shadow:0 8px 22px -10px rgba(255,255,255,.5);
}

/* Stat frames: corners brighten and push outward, so the bracket "opens". */
.stat{transition:transform .25s cubic-bezier(.2,.8,.3,1);}
.stat::before,.stat::after,.stat > .br::before,.stat > .br::after{
  transition:border-color .25s ease,width .25s ease,height .25s ease;
}
.stat:hover{transform:translateY(-3px);}
.stat:hover::before,.stat:hover::after,
.stat:hover > .br::before,.stat:hover > .br::after{
  border-color:hsl(var(--foreground));width:20px;height:20px;
}

/* Stickers respond to the card being hovered, not to themselves — they are
   pointer-events:none so they never block the card. */
.prob-card{transition:transform .3s cubic-bezier(.2,.8,.3,1);}
.prob-card .sticker-inline{transition:transform .45s cubic-bezier(.2,.8,.3,1),filter .3s ease;}
.prob-card:hover{transform:translateY(-4px);}
.prob-card:hover .sticker-inline{
  transform:scale(1.06) rotate(-2deg);
  filter:drop-shadow(0 20px 30px rgba(0,0,0,.75));
}

/* ---------------------------------------------------------------------------
   FEATURE SCROLLER — the study loop, walked through by scrolling.

   The section is deliberately tall; the inner panel is sticky, so it holds
   still in the viewport while the page scrolls past it. That scroll distance
   is what advances the feature index — the user "scrolls through" the product
   without the page appearing to move. --sp (0..1) and data-active are written
   by motion.js.
   ------------------------------------------------------------------------ */
.scroller{position:relative;}
.scroller-inner{
  position:sticky;top:0;min-height:100svh;
  display:flex;flex-direction:column;justify-content:center;
  padding:96px 0 56px;overflow:hidden;
}

/* Progress rail */
.scroller-rail{
  position:absolute;left:24px;top:50%;transform:translateY(-50%);
  display:none;flex-direction:column;gap:14px;z-index:4;
}
@media(min-width:1024px){.scroller-rail{display:flex;left:clamp(32px,7vw,112px);}}
.scroller-rail button{
  display:flex;align-items:center;gap:12px;
  background:none;border:none;cursor:pointer;padding:4px 0;
  font-family:'Inter',sans-serif;font-size:13px;
  color:hsl(var(--muted-foreground) / .55);
  transition:color .3s ease;
}
.scroller-rail button i{
  display:block;width:26px;height:2px;border-radius:2px;
  background:hsl(var(--muted-foreground) / .3);
  transition:width .35s cubic-bezier(.2,.8,.3,1),background .3s ease;
}
.scroller-rail button:hover{color:hsl(var(--foreground) / .8);}
.scroller-rail button[aria-current="true"]{color:hsl(var(--foreground));}
.scroller-rail button[aria-current="true"] i{width:52px;background:hsl(var(--foreground));}

/* Panels are stacked; only the active one is visible. */
.scroller-stage{position:relative;min-height:min(56vh,460px);}
.panel{
  position:absolute;inset:0;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;gap:18px;
  opacity:0;transform:translateY(28px) scale(.97);
  transition:opacity .5s ease,transform .6s cubic-bezier(.2,.8,.3,1);
  pointer-events:none;
}
.panel[data-on="1"]{opacity:1;transform:none;pointer-events:auto;}
.panel .p-idx{
  font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.22em;
  color:hsl(var(--muted-foreground));
}
.panel h3{font-size:clamp(1.9rem,4.6vw,3.4rem);letter-spacing:-1.5px;}
.panel p{max-width:40rem;color:hsl(var(--hero-subtitle));font-size:clamp(15px,1.7vw,18px);line-height:1.6;}
.panel .p-art{
  width:clamp(110px,15vw,190px);height:clamp(110px,15vw,190px);
  display:grid;place-items:center;
  filter:drop-shadow(0 18px 28px rgba(0,0,0,.7));
}
.panel .p-art img{max-width:100%;max-height:100%;width:auto;height:auto;display:block;}

/* Scrub bar showing progress through the whole sequence. */
.scroller-bar{
  position:relative;height:2px;margin:36px auto 0;width:min(520px,72vw);
  background:hsl(var(--border));border-radius:2px;overflow:hidden;
}
.scroller-bar i{
  position:absolute;inset:0 auto 0 0;display:block;
  width:calc(var(--sp,0) * 100%);
  background:hsl(var(--foreground));
  border-radius:2px;
}

@media(prefers-reduced-motion:reduce){
  /* No pinning: the section becomes a plain stacked list that scrolls
     normally, and every panel is simply visible. */
  .scroller-inner{position:static;min-height:0;}
  .scroller-stage{min-height:0;display:grid;gap:56px;}
  .panel{position:static;opacity:1;transform:none;pointer-events:auto;}
  .bg-aura,.bg-spot{display:none;}
}
