/* ==========================================================================
   Collsta website — Hero + Hero→next cinematic transition

   Scroll model
   ------------
   `.hero-stage` is a runway taller than the viewport, and something inside it
   sticks for that whole runway so the board scene stays composed on screen
   while the page scrolls underneath. site.js writes ONE custom property,
   `--p` (0 → 1), onto `.hero-stage`; every transform below derives from it
   in CSS. Nothing is scroll-hijacked — this is ordinary document scroll.

   Which element sticks depends on the breakpoint:
     desktop … `.hero-pin`  — copy and board are framed together
     mobile  … `.scene`     — the copy has already had a screen of its own

   `--pe` is the *effective* progress the animation actually reads. On desktop
   it is `--p` directly. On mobile it is delayed, so the board gets a beat of
   full-screen clarity after it sticks and before it starts receding.

   pe = 0.00 … hero at rest
   pe → 0.45 … copy lifts away, board begins to recede
   pe → 1.00 … board sits back and blurs, the source cards separate from it
               and step forward — the visual set-up for "Save anything"
   ========================================================================== */

.hero-stage{
  --p:0;                       /* raw scroll progress, written by site.js */
  --pe:var(--p);               /* effective progress the motion reads */
  --recede-at:.45;             /* raw --p at which the focus swap fires; site.js reads this */

  /* Brand moment over the stretch the receding board leaves empty. Arrival
     only — there is deliberately no fall term. It used to be a bell whose
     second half returned to zero by pe 1.00, which took the logo off screen
     while the hero was still the thing being looked at. The hand-off is the
     pin releasing and Save Anything scrolling over it, not a fade to nothing. */
  --brand:clamp(0,calc((var(--pe) - .44) / .14),1);
  --mx:0;                      /* pointer parallax, -1 … 1 */
  --my:0;
  --hero-runway:118vh;

  position:relative;
  height:calc(100vh + var(--hero-runway));
  height:calc(100svh + var(--hero-runway));
}

.hero-pin{
  position:sticky;
  top:0;
  height:100vh;
  height:100svh;
  min-height:600px;
  /* `clip` rather than `hidden`: hidden makes this a scroll container, which
     silently kills `position: sticky` on the board scene at mobile widths.
     Both clip the blobs and the off-canvas satellites identically. */
  overflow:hidden;
  display:flex;
  align-items:center;
  /* The stack is centred in the pin's content box on its own; the old large
     bottom padding was there to lift a two-column group and now only steals
     room from the scene. The stage stays 100svh and the runway is measured
     from the stage and the pin's OUTER height, so timing is untouched. */
  /* Top-aligned with an explicit clearance rather than centred: centring gave
     the same small margin above and below, which put the headline right up
     against the nav. */
  align-items:flex-start;
  padding-top:calc(var(--nav-h) + clamp(24px,calc(4.5vh + 4px),80px));
  padding-bottom:clamp(6px,0.8vh,14px);
  isolation:isolate;
}
@supports (overflow:clip){
  .hero-pin{overflow:clip}
}

/* ---- Background: soft blobs + a dot field, per DS "Backgrounds" ---- */
.hero-bg{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden}
/* No `will-change` here on purpose: these are the largest surfaces on the
   page and already blurred, so promoting them permanently costs a lot of
   layer memory for movement that only happens on pointer parallax. */
.hero-bg__blob{
  filter:blur(30px);
  transform:translate3d(calc(var(--mx) * var(--d,14px)),calc(var(--my) * var(--d,14px)),0);
}
.hero-bg__blob--a{width:min(52vw,660px);aspect-ratio:1;top:-22%;left:-12%;opacity:.5;--d:18px}
.hero-bg__blob--b{width:min(46vw,580px);aspect-ratio:1;bottom:-26%;right:-10%;opacity:.55;--d:24px}
.hero-bg__dots{
  position:absolute;
  top:12%;right:6%;
  width:210px;height:170px;
  opacity:.35;
  -webkit-mask-image:radial-gradient(ellipse at center,#000 25%,transparent 72%);
  mask-image:radial-gradient(ellipse at center,#000 25%,transparent 72%);
}

/* ---- Layout ---- */
/* Stacked and centred at every width: message on top, the product scene
   directly under it. The two-column version left the frame half empty and
   fell apart as the board receded mid-scroll. */
.hero-grid{
  position:relative;
  z-index:2;
  width:100%;
  display:grid;
  grid-template-columns:minmax(0,1fr);
  justify-items:center;
  align-content:center;
  /* The breathing room between the message and the product scene. Deliberately
     large: at the previous ~20px the note line sat right on the board's top
     edge and the two halves of the hero read as one crowded block. */
  gap:clamp(46px,9.35vh,120px);
}

/* ==========================================================================
   Copy column
   ========================================================================== */
.hero-copy{
  /* Wide enough that "Everything for what you're doing." sits on one line —
     that alone takes the headline from four rendered lines to two. */
  max-width:min(100%,68rem);
  margin-inline:auto;
  text-align:center;
  /* Recedes instead of leaving. It used to fade to nothing by pe .42, which
     emptied the top half of the frame for the rest of the sequence; now it
     softens to .55 and drifts a little, so the message stays with the scene. */
  transform:translate3d(0,calc(var(--pe) * -16px),0);
  opacity:clamp(.55,calc(1 - var(--pe) * .45),1);
  will-change:transform,opacity;
}

.hero-copy__eyebrow{
  /* Block-level flex rather than the global .eyebrow's inline-flex: as an
     inline box it sat in a line box governed by the copy's own line-height,
     which laid ~8px of leading above it — dead space at the very top of the
     composition, paid for by the board. No visual change; the lockup has no
     box of its own and centres the same way. */
  display:flex;
  justify-content:center;
  margin-bottom:clamp(10px,1.1vw,13px);
}

.hero-title{
  font-family:var(--font-display);
  font-weight:var(--fw-extrabold);
  font-size:var(--fs-h1);
  line-height:var(--lh-tight);
  letter-spacing:var(--ls-tight);
  color:var(--navy);
  text-wrap:balance;
}
.hero-title__line{display:block}
/* "One board." is the payoff line — it carries the brand gradient. */
.hero-title__accent{
  background:var(--grad-text);
  -webkit-background-clip:text;
  background-clip:text;
  color:transparent;
}

.hero-sub{
  margin:clamp(12px,1.4vw,17px) auto 0;
  max-width:44rem;
  font-size:var(--fs-body-lg);
  line-height:var(--lh-body);
  color:var(--text-body);
  text-wrap:pretty;
}
.hero-sub b{
  font-weight:var(--fw-semibold);
  color:var(--navy);
}

.hero-actions{
  margin-top:clamp(14px,1.6vw,20px);
  display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:14px;
}
.hero-note{
  margin-top:10px;
  font-size:var(--fs-small);
  color:var(--text-meta);
}

/* ==========================================================================
   Scene — the board is the protagonist
   ========================================================================== */
/* Collapses to nothing on desktop — the hero pin is the sticky frame there. */
.scene-track{position:relative;width:100%}
.scene-runway{height:0}

/* The scene box is capped to the board's own width and centred, so the
   satellite offsets (which are percentages of it) keep flanking the board
   instead of flying off into the full-width column. */
.scene{
  position:relative;
  display:flex;
  justify-content:center;
  width:min(100%,var(--scene-w,764px));
  margin-inline:auto;
  /* Nothing to re-centre any more — the composition starts centred. */
  --scene-drift:0%;
  transform:translate3d(calc(var(--pe) * var(--scene-drift)),0,0);
}
/* `width:100%` is load-bearing: as a bare flex item the figure sizes to
   content, which made `.scene__board`'s own `width:100%` circular and left
   the board ~11% narrower than the column it sits in. */
.scene__figure{margin:0;width:100%}

.scene__board{
  position:relative;
  z-index:3;
  width:100%;
}
.board-layer{
  position:relative;
  perspective:1600px;
  transform:
    translate3d(calc(var(--mx) * -9px),
                calc(var(--pe) * -44px + var(--my) * -7px),0)
    scale(calc(1 - var(--pe) * .17));
  opacity:clamp(.2,calc(1 - var(--pe) * .78),1);
  will-change:transform,opacity;
  transition:filter var(--dur-slow) var(--ease-out);
}
/* Blur is toggled once by class, never animated per frame — a large blurred
   surface is the one effect here that is not cheap to interpolate. */
.hero-stage.is-receding .board-layer{filter:blur(7px)}

/* ==========================================================================
   Board
   ========================================================================== */
.board{
  --pad:clamp(8px,0.63vw,9px);
  border-radius:var(--radius-lg);
  background:var(--surface);
  border:1px solid var(--border);
  box-shadow:var(--shadow-lg);
  overflow:hidden;
  transform:rotateY(-3.4deg) rotateX(1.6deg);
  transform-origin:60% 50%;
  transition:transform var(--dur-slow) var(--ease-out);
}
.scene:hover .board{transform:rotateY(calc(-3.4deg + var(--mx) * 2.2deg)) rotateX(calc(1.6deg + var(--my) * -1.4deg))}

/* ---- Board header ---- */
.board__head{
  display:flex;align-items:center;gap:14px;
  padding:calc(var(--pad) - 2px) var(--pad);
  border-bottom:1px solid var(--border);
  background:var(--grad-lavender);
}
.board__cover{
  position:relative;flex:none;
  width:clamp(46px,4.8vw,60px);aspect-ratio:1;
  border-radius:18px;
  border:3px solid #fff;
  box-shadow:var(--shadow-md);
  background:linear-gradient(150deg,#FFE7E9,#FF9AA3 46%,#B8ABF2);
  display:grid;place-items:center;
  font-size:clamp(22px,2.6vw,29px);
  line-height:1;
}
.board__meta{flex:1;min-width:0}
.board__people{display:flex;align-items:center;gap:8px}
.board__avatars{display:flex}
.board__avatar{
  width:21px;height:21px;border-radius:50%;
  border:2px solid #fff;
  display:grid;place-items:center;
  font-family:var(--font-display);font-weight:var(--fw-extrabold);
  font-size:8.5px;color:#fff;
}
.board__avatar + .board__avatar{margin-left:-7px}
.board__avatar--a{background:linear-gradient(160deg,#FFB3B9,#FF7A85)}
.board__avatar--b{background:linear-gradient(160deg,#C9BEF7,#735CFF)}
.board__avatar--c{background:linear-gradient(160deg,#B8ABF2,#0D0F3C)}
.board__people-text{font-size:12px;color:var(--text-meta);line-height:1.3}
.board__title{
  margin-top:6px;
  font-family:var(--font-display);
  font-weight:var(--fw-extrabold);
  font-size:clamp(18px,2.1vw,24px);
  letter-spacing:var(--ls-tight);
  line-height:1.15;
  color:var(--navy);
}
.board__desc{
  margin-top:4px;
  font-size:clamp(12px,1.15vw,13.5px);
  line-height:1.45;
  color:var(--text-meta);
}
.board__count{
  flex:none;align-self:flex-start;
  display:inline-flex;align-items:center;gap:6px;
  padding:6px 12px;border-radius:var(--radius-pill);
  background:rgba(255,255,255,.82);
  border:1px solid var(--border);
  font-family:var(--font-display);font-weight:var(--fw-bold);
  font-size:11.5px;color:var(--text-meta);white-space:nowrap;
}

/* ---- Board grid — same areas at every size, only the scale changes ---- */
.board__grid{
  display:grid;
  grid-template-columns:1fr 1fr;
  grid-template-areas:
    "vid  stay"
    "map  map"
    "reel site";
  gap:clamp(5px,.45vw,6px);
  padding:var(--pad);
}
.card--vid{grid-area:vid}
.card--stay{grid-area:stay}
.card--map{grid-area:map}
.card--reel{grid-area:reel}
.card--site{grid-area:site}

/* ==========================================================================
   Saved cards — one component, two layouts
   `.card` is a media card; `.card--row` is the compact horizontal variant.
   Every card carries a source badge, which is the whole point of the scene.
   ========================================================================== */
.card{
  display:flex;flex-direction:column;
  border-radius:var(--radius-md);
  background:var(--surface);
  border:1px solid var(--border);
  box-shadow:var(--shadow-sm);
  overflow:hidden;
  transition:transform var(--dur-mid) var(--ease-out),box-shadow var(--dur-mid) var(--ease-out);
}
.card:hover{transform:translateY(-3px);box-shadow:var(--shadow-md)}

.card--row{flex-direction:row;align-items:stretch}

.card__media{
  position:relative;
  flex:none;
  height:clamp(36px,4.45vh,62px);
  overflow:hidden;
}
.card--map .card__media{width:clamp(92px,11vw,124px);height:auto;min-height:52px}
.card--reel .card__media,
.card--site .card__media{width:clamp(46px,5.2vw,60px);height:auto}

.card__body{
  flex:1;min-width:0;
  display:flex;flex-direction:column;justify-content:center;
  padding:clamp(6px,.75vw,10px) clamp(9px,1vw,13px);
}
.card__title{
  font-family:var(--font-display);
  font-weight:var(--fw-bold);
  font-size:clamp(12.5px,1.25vw,15.5px);
  line-height:1.25;
  color:var(--navy);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.card__meta{
  margin-top:3px;
  font-size:clamp(10.5px,1.02vw,12.5px);
  line-height:1.3;
  color:var(--text-meta);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* ---- Source badge — translucent navy chip + monogram.
   Third-party marks are deliberately not recreated (DS: Iconography). ---- */
.badge{
  position:absolute;top:8px;left:8px;
  display:inline-flex;align-items:center;gap:5px;
  padding:4px 9px 4px 5px;
  border-radius:var(--radius-pill);
  background:rgba(13,15,60,.72);
  -webkit-backdrop-filter:blur(4px);
  backdrop-filter:blur(4px);
  font-family:var(--font-display);font-weight:var(--fw-bold);
  font-size:10px;letter-spacing:.01em;color:#fff;white-space:nowrap;
}
.badge__mark{
  width:15px;height:15px;border-radius:50%;
  background:#fff;
  display:grid;place-items:center;
  font-weight:var(--fw-extrabold);font-size:8px;
}
.badge__mark--tiktok{color:#0D0F3C}
.badge__mark--booking{color:#003580}
.badge__mark--maps{color:#34A853}
.badge__mark--ig{color:#E1306C;font-size:7px}

/* The map card's media is only ~100px wide — the badge shrinks to match. */
.badge--compact{
  top:6px;left:6px;
  padding:3px 7px 3px 4px;
  gap:4px;
  font-size:9px;
}
.badge--compact .badge__mark{width:13px;height:13px;font-size:7px}

/* Compact cards carry their source as a tinted square instead of a chip. */
.src-tile{
  width:100%;height:100%;
  display:grid;place-items:center;
  font-family:var(--font-display);font-weight:var(--fw-extrabold);
  font-size:12px;color:var(--navy);
}
.src-tile--site{background:linear-gradient(160deg,#F5F3FA,#B8ABF2)}
.src-tile--reel{background:linear-gradient(160deg,#FFE7E9,#FF7A85)}

/* ---- Media fills ---- */
.fill--vid{background:linear-gradient(160deg,#EDE8FF,#735CFF)}
.fill--stay{background:linear-gradient(155deg,#E4ECFF,#B8ABF2)}

/* ---- Overlays ---- */
.play{
  position:absolute;inset:0;
  display:grid;place-items:center;
}
.play__btn{
  width:clamp(32px,3.4vw,42px);aspect-ratio:1;
  border-radius:50%;
  background:rgba(255,255,255,.94);
  display:grid;place-items:center;
  box-shadow:var(--shadow-md);
}
.price{
  position:absolute;bottom:8px;left:8px;
  padding:4px 10px;border-radius:var(--radius-pill);
  background:rgba(255,255,255,.94);
  font-family:var(--font-display);font-weight:var(--fw-extrabold);
  font-size:11px;color:var(--navy);
}
/* Absolute so it fills the row card's stretched media box regardless of
   how the flex row resolves its height. */
.map-svg{position:absolute;inset:0;width:100%;height:100%;display:block}
.map-pin{
  position:absolute;left:54%;top:58%;
  width:22px;height:22px;
  transform:translate(-50%,-100%) rotate(-45deg);
  border-radius:50% 50% 50% 4px;
  background:var(--purple-bright);
  box-shadow:var(--glow-purple);
  display:grid;place-items:center;
}
.map-pin__dot{width:7px;height:7px;border-radius:50%;background:#fff;transform:rotate(45deg)}

/* ---- Sticker — a single user-placed accent, not a UI element ---- */
.sticker{
  position:absolute;
  /* Left corner, above the board cover: the top-right belongs to the article
     satellite, and the two collide there in every mode (the back plane's
     blur only made it look intentional). */
  top:-14px;left:26px;
  z-index:4;
  padding:7px 14px;
  border-radius:var(--radius-pill);
  background:#FFE7E9;
  color:var(--coral);
  border:2px solid #fff;
  box-shadow:var(--shadow-md);
  font-family:var(--font-display);font-weight:var(--fw-extrabold);
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  transform:rotate(-7deg);
}

/* ==========================================================================
   Brand moment
   The punctuation at the end of the hero's sentence: the sources have spread
   out, the board has receded, and what is left in the middle is where they
   all go. Sits at the centre of the scene — the board's own position — so the
   constellation reads as surrounding it.
   ========================================================================== */
.hero-brand{
  position:absolute;
  left:50%;top:50%;
  z-index:3;
  display:flex;flex-direction:column;align-items:center;
  gap:clamp(12px,1.5vw,18px);
  text-align:center;
  pointer-events:none;
  /* Settles a little toward the middle of the frame as it arrives. The scene
     column sits right of centre and the copy is long gone by now, so without
     this the moment lands in the right third and leaves the left empty — the
     very gap it exists to fill. The shift rides the fade-in, so it reads as
     one arrival rather than a separate move. */
  transform:
    translate3d(calc(-50% + var(--brand) * var(--brand-pull,0px)),-50%,0)
    scale(calc(.94 + var(--brand) * .06));
  /* Full strength once it has arrived, and it stays there. No settle, no
     partial fade: the moment is released by the pin scrolling away under
     Save Anything, never by losing opacity in place. */
  opacity:var(--brand);
  /* Comes out of soft focus rather than simply appearing. */
  filter:blur(calc((1 - var(--brand)) * 6px));
}
/* Minimal glow response — a wash, not a spotlight. */
.hero-brand::before{
  content:"";
  position:absolute;
  left:50%;top:34%;
  width:min(56vw,400px);aspect-ratio:1;
  transform:translate3d(-50%,-50%,0);
  border-radius:50%;
  background:radial-gradient(circle at center,rgba(184,171,242,.4) 0%,rgba(184,171,242,0) 66%);
  z-index:-1;
}
.hero-brand__lockup{display:inline-flex;align-items:center;gap:clamp(8px,1vw,12px)}
.hero-brand__mark{width:clamp(40px,4.4vw,58px);height:auto;flex:none}
.hero-brand__word{
  font-family:var(--font-display);
  font-weight:var(--fw-extrabold);
  font-size:clamp(26px,3vw,40px);
  letter-spacing:var(--ls-tight);
  line-height:1;
  color:var(--navy);
}
.hero-brand__line{
  font-size:clamp(14px,1.4vw,17px);
  line-height:1.4;
  color:var(--text-body);
  max-width:22ch;
}

/* ---- "not shipped yet" disclosure — discreet, once ---- */
.scene__note{
  position:absolute;
  left:50%;bottom:-34px;
  transform:translateX(-50%);
  z-index:3;
  display:inline-flex;align-items:center;gap:8px;
  font-family:var(--font-display);font-weight:var(--fw-bold);
  font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--text-meta);
  white-space:nowrap;
  opacity:clamp(0,calc(1 - var(--pe) * 3),1);
}
.scene__note > span{display:inline-flex;align-items:center;gap:8px}
.scene__note .collsta-sparkle{width:12px;height:12px}

/* ==========================================================================
   Satellites — links floating in from everywhere.
   Three nested elements on purpose, so three independent transforms never
   fight each other:
     .sat        → scroll separation + pointer parallax
     .sat__in    → entry reveal
     .sat__float → slow idle drift
   ========================================================================== */
.sat{
  position:absolute;
  z-index:2;
  width:clamp(158px,16vw,206px);
  transform:
    translate3d(calc(var(--tx,0px) * var(--pe) + var(--mx) * var(--depth,14px)),
                calc(var(--ty,0px) * var(--pe) + var(--my) * var(--depth,14px)),0)
    scale(calc(1 + var(--ts,.16) * var(--pe)));
  opacity:calc(var(--o,.9) + (1 - var(--o,.9)) * var(--pe));
  will-change:transform,opacity;
  transition:filter var(--dur-slow) var(--ease-out);
}
/* Two depth planes. `--back` sits behind the board and is slightly out of
   focus; `--front` lies on top of it and casts a shadow onto it. Both are
   readable — a card whose icon is hidden behind the board just looks broken. */
.sat--back{filter:blur(2.5px)}
.sat--front{z-index:4}
.sat--front .sat__card{box-shadow:var(--shadow-lg)}
/* As the board recedes, the sources sharpen — the focus swap that sets up
   the next section. */
.hero-stage.is-receding .sat--back{filter:blur(0)}

.sat__float{
  animation:co-drift var(--drift,12s) var(--ease-inout) infinite;
  animation-delay:var(--drift-delay,0s);
}
@keyframes co-drift{
  0%,100%{transform:translate3d(0,0,0)}
  50%{transform:translate3d(0,-9px,0)}
}

.sat__card{
  display:flex;align-items:center;gap:10px;
  padding:10px 12px;
  border-radius:var(--radius-md);
  background:var(--surface);
  border:1px solid var(--border);
  box-shadow:var(--shadow-md);
  transform:rotate(var(--r0,0deg));
}
.sat__icon{
  flex:none;width:34px;height:34px;
  border-radius:11px;
  display:grid;place-items:center;
  font-family:var(--font-display);font-weight:var(--fw-extrabold);
  font-size:11px;color:#fff;
}
.sat__text{min-width:0}
.sat__src{
  display:block;
  font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;
  font-family:var(--font-display);font-weight:var(--fw-bold);
  color:var(--text-meta);
}
.sat__title{
  display:block;margin-top:3px;
  font-family:var(--font-display);font-weight:var(--fw-bold);
  font-size:12.5px;line-height:1.2;color:var(--navy);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* Placement + separation targets. `--tx/--ty` are where each card travels as
   p goes 0 → 1. The movement is mostly lateral: the cards step apart and
   toward the viewer, and deliberately do NOT sink into the hand-off veil at
   the bottom of the frame. */
.sat--1{                       /* TikTok — back plane, left */
  top:2%;left:-22%;
  --r0:-7deg;--tx:-72px;--ty:10px;--ts:.14;--o:.62;--depth:9px;
  --drift:13s;--drift-delay:-2s;
}
.sat--2{                       /* Webshop — front plane, lower left */
  bottom:9%;left:-19%;
  --r0:4deg;--tx:-66px;--ty:26px;--ts:.2;--o:.9;--depth:20px;
  --drift:11s;--drift-delay:-5s;
}
.sat--3{                       /* Article — back plane, above the top-right corner */
  top:-10%;right:-2%;
  --r0:5deg;--tx:72px;--ty:-22px;--ts:.16;--o:.72;--depth:12px;
  --drift:14s;--drift-delay:-8s;
}
.sat--4{                       /* Flight — front plane, over the bottom-right corner */
  /* Overhang is a percentage of the scene, so the taller board pushed this
     card's absolute drop past the pin's bottom edge. Trimmed to keep the same
     tuck over the corner without hanging out of the frame at rest. */
  bottom:1%;right:-9%;
  --r0:-4deg;--tx:66px;--ty:18px;--ts:.22;--o:.95;--depth:23px;
  --drift:10s;--drift-delay:-3.5s;
}

.icon--tiktok{background:linear-gradient(160deg,#0D0F3C,#3A3D5C)}
.icon--shop{background:linear-gradient(160deg,#FF9AA3,#E16D7B)}
.icon--article{background:linear-gradient(160deg,#B8ABF2,#665EE6)}
.icon--flight{background:linear-gradient(160deg,#8FA8FF,#735CFF)}

/* ==========================================================================
   Scroll cue + handoff veil
   ========================================================================== */
.hero-cue{
  position:absolute;
  left:50%;bottom:22px;
  transform:translateX(-50%);
  z-index:3;
  display:flex;flex-direction:column;align-items:center;gap:9px;
  opacity:clamp(0,calc(1 - var(--pe) * 4),1);
  pointer-events:none;
}
.hero-cue__label{
  font-family:var(--font-display);font-weight:var(--fw-bold);
  font-size:10px;letter-spacing:var(--ls-overline);text-transform:uppercase;
  color:var(--text-meta);
}
.hero-cue__rail{
  position:relative;
  width:1.5px;height:38px;border-radius:2px;
  background:linear-gradient(to bottom,var(--border),transparent);
  overflow:hidden;
}
.hero-cue__dot{
  position:absolute;left:0;right:0;top:0;
  height:12px;border-radius:2px;
  background:var(--purple-bright);
  animation:co-cue 2.4s var(--ease-inout) infinite;
}
@keyframes co-cue{
  0%{transform:translateY(-14px);opacity:0}
  35%{opacity:1}
  100%{transform:translateY(38px);opacity:0}
}

/* The clean hand-off into whatever section mounts next. */
/* NOTE — there is deliberately no veil over the pin's bottom edge.

   A near-white wash used to sit there to soften the hero's tail. It was the
   cause of the visible horizontal break at the hero → Save anything boundary:
   its bottom edge lands exactly on that boundary, and it painted on top of the
   `.cine__seam` glow — the one layer kept unclipped precisely so it can run
   through the junction. The glow came out dimmed above the line and full
   strength below it, which reads as a section break.

   If a softer hand-off is ever wanted again, do it on the seam (which spans
   both sides) or on the board itself — not with a layer whose edge coincides
   with the junction. */


/* ==========================================================================
   Breakpoints — the mobile hero is composed, not squeezed
   ========================================================================== */

/* Tablet, still two columns. The scene column loses ~130px here, which is
   exactly the room the left-hand satellites need: pushed out they collide
   with the copy, pulled in they cover the board's own cards. So the left
   pair drops and the remaining two work the right edge, where they can bleed
   off-canvas instead of onto something. */
@media (max-width:1080px) and (min-width:901px){
  .hero-grid{gap:clamp(24px,3vw,44px)}
  .sat--1,.sat--2{display:none}
  .sat{width:clamp(138px,16vw,164px)}
  .sat--3{top:-9%;right:-6%;--tx:44px;--ty:-18px}
  .sat--4{bottom:-9%;right:-6%;--tx:40px;--ty:26px}
  /* Centred, the note runs under the flight card; anchored left it does not. */
  .scene__note{left:0;transform:none}
}

/* ---- Mobile: a different composition, not a compressed desktop one --------
   A phone cannot hold the copy block and a desirable board inside one
   viewport without shrinking the board into a thumbnail, so the two get a
   screen each. The copy fills the first screen (its bottom edge deliberately
   short of the fold, so the top of the board peeks in and earns the scroll),
   then the BOARD is what sticks — it gets the whole viewport to itself and
   plays the same separation transition. The pin moves from the section to
   the scene; site.js measures whichever element is sticky, so no JS changes
   are needed for this swap.
   -------------------------------------------------------------------------- */
@media (max-width:900px){
  .hero-stage{
    --hero-runway:88vh;
    /* Hold the board still and sharp for the first third of its runway —
       it has only just become full-screen, and receding immediately would
       mean the product is never actually seen on a phone. */
    --pe:clamp(0,calc((var(--p) - .34) / .66),1);
    /* Raw --p, so it lands at the same effective moment as desktop's .45. */
    --recede-at:.64;
    height:auto;
  }
  .hero-pin{
    position:static;
    display:block;
    height:auto;
    min-height:0;
    /* The desktop lift is a centring trick inside a viewport-sized frame.
       Here the pin is a tall static block, so the same padding would just be
       dead space under the board. */
    padding-top:0;
    padding-bottom:0;
  }
  /* Keep the blobs in the hero's own airspace now that the pin is tall. */
  .hero-bg{height:118svh}

  .hero-grid{
    grid-template-columns:minmax(0,1fr);
    gap:0;
  }
  .scene-runway{height:var(--hero-runway)}

  .hero-copy{
    display:flex;flex-direction:column;justify-content:center;
    min-height:72svh;
    padding-top:calc(var(--nav-h) + 24px);
    padding-bottom:clamp(20px,4vh,36px);
    max-width:34rem;
    /* It scrolls away under its own steam here; --p belongs to the board. */
    transform:none;
    opacity:1;
  }

  .scene{
    position:sticky;
    /* Leaves headroom above the board for the satellite that hangs off its
       top corner, so it never tucks under the header. */
    top:calc(var(--nav-h) + clamp(26px,4.5vh,40px));
  }
  .hero-title{font-size:clamp(34px,9vw,46px)}
  .hero-sub{font-size:17px;max-width:38ch}
  .hero-actions{margin-top:22px}
  .hero-note{margin-top:12px;font-size:13px}

  /* Stacked layout is already centred — nothing to drift back toward. */
  .scene{--scene-drift:0%}
  .scene__board{max-width:min(100%,520px);margin-inline:auto}
  /* No perspective tilt on touch — there is no pointer to justify it and it
     costs text crispness on low-DPI phones. */
  .board{transform:none}
  .scene:hover .board{transform:none}
  .board-layer{
    transform:translate3d(0,calc(var(--pe) * -26px),0) scale(calc(1 - var(--pe) * .13));
  }
  .card__media{height:clamp(88px,11vh,116px)}

  /* At this width a single ellipsised line loses the source's name, which is
     the one thing each card exists to show. Row cards get two lines. */
  .card--reel .card__title,
  .card--site .card__title,
  .card--map .card__title{white-space:normal;overflow:visible;text-overflow:clip}

  /* Shorter and tighter on a phone: the window closes sooner and the
     lockup is sized so it never crowds the scene it sits in. */
  /* Mobile --pe is delayed, so the same window would leave the moment on
     screen for only a few vh. Opened earlier and closed later to give it a
     readable hold without lengthening the runway. */
  .hero-stage{
    --brand:min(
      clamp(0,calc((var(--pe) - .40) / .14),1),
      clamp(0,calc((1 - var(--pe)) / .14),1)
    );
  }
  .hero-brand{gap:10px;--brand-pull:0px}
  .hero-brand__mark{width:34px}
  .hero-brand__word{font-size:clamp(22px,6.4vw,30px)}
  .hero-brand__line{font-size:13.5px;max-width:19ch}
  .hero-brand::before{width:min(72vw,320px)}

  .hero-bg__dots{display:none}
  .hero-cue{display:none}
  .scene__note{bottom:-54px;font-size:9.5px}

  .sticker{left:18px;top:-13px}

  /* Two satellites only — enough to say "from anywhere", few enough to
     stay legible at 375px. They hug the board's opposite corners. */
  .sat--1,.sat--2{display:none}
  /* There is no room for a back plane at this width — a card tucked behind
     the board would have its title swallowed. Both sit in front. */
  .sat{width:clamp(132px,40vw,158px);z-index:4}
  .sat__card{box-shadow:var(--shadow-lg)}
  .sat--3{top:-24px;right:-14px;--tx:26px;--ty:-14px;--ts:.1;--o:.95}
  /* Clears the board's bottom edge rather than sitting on top of a card —
     overlapping a cover is depth, covering a source's name is just a bug. */
  .sat--4{bottom:-30px;left:-12px;right:auto;--tx:-22px;--ty:26px;--ts:.12;--o:1}
  .sat--back{filter:none}
  .sat__card{padding:8px 10px}
  .sat__icon{width:30px;height:30px;border-radius:10px}
}

/* Small phones: trim the header row and tighten the board. */
@media (max-width:420px){
  .hero-stage{--hero-runway:70vh}
  .board{--pad:12px}
  .board__count{display:none}
  .board__head{gap:11px}
  .card__media{height:clamp(80px,10.5vh,100px)}
  .sticker{top:-11px;left:14px;padding:6px 11px;font-size:10px}
  .hero-actions .btn{flex:1 1 auto;justify-content:center}
}

/* The lift is only affordable when the frame has slack to give. On shorter
   desktop viewports the copy column wraps taller than the space 14vh would
   leave, and a centred group that no longer fits overflows upward — under
   the header. Trade most of the lift back rather than clip the hero. */
@media (max-height:820px) and (min-width:901px){
  .hero-pin{padding-bottom:clamp(24px,6vh,64px)}
}

/* Short landscape viewports: never let the scene overflow the pin. */
@media (max-height:680px) and (min-width:901px){
  /* Too little height here to spend 14vh on lifting the group — the board
     would run out of the frame before it gained anything. */
  .hero-pin{min-height:0;padding-bottom:clamp(20px,5vh,48px)}
  .card__media{height:clamp(88px,11vh,112px)}
  .board__cover{width:52px}
}

/* ==========================================================================
   Reduced motion
   The runway collapses so there is no dead scroll, the pin releases, and the
   scene renders in its resting composition. The page still reads as a
   deliberate cinematic layout — it just does not move.
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  .hero-stage{--hero-runway:0px;height:auto}
  .hero-pin{
    position:relative;
    height:auto;
    min-height:100svh;
    padding-block:calc(var(--nav-h) + 32px) 64px;
  }
  .hero-copy,.board-layer,.sat,.hero-bg__blob,.scene{transform:none;opacity:1}
  .scene__note{opacity:1}
  .board{transform:none}
  .sat--back{filter:none}
  .sat__float{animation:none}
  .hero-cue__dot{animation:none;opacity:.9}
  .hero-stage.is-receding .board-layer{filter:none}
  /* No scroll progress here, so the bell never rises. The moment becomes a
     static closing line under the scene instead — same words, same lockup,
     still the hand-off from the hero into Save anything. */
  .hero-brand{
    position:static;
    transform:none;
    opacity:1;
    filter:none;
    margin-top:clamp(56px,7vw,84px);
  }
  .hero-brand::before{display:none}
  /* The note is absolutely pinned to the scene's floor; with the brand now in
     flow beneath the board the two would land on each other. Both flow. */
  .scene__note{
    position:static;
    transform:none;
    margin-top:clamp(16px,2.2vw,26px);
    opacity:1;
  }
}
