/* ==========================================================================
   Collsta website — Section 3: Board customize / Make it yours

   Same scroll contract as the hero and Save anything: site.js writes ONE
   custom property, `--bcp` (0 → 1), onto `.bc`; every transform derives from it
   in CSS. Ordinary document scroll, sticky frame, no hijacking.

   One board is rebuilt in front of the reader, beat by beat:

     p 0.00 → 0.08   DEFAULT    plain board, grey cover, neutral accent
     p 0.08 → 0.22   COVER      the cover photo reveals behind the header
     p 0.22 → 0.34   ACCENT     the accent colour washes through the board
     p 0.34 → 0.44   EMOJI      🌴 lands in the title
     p 0.44 → 0.54   STICKER    the sticker drops onto the cover
     p 0.54 → 0.88   LAYOUT     the SAME six cards re-arrange:
                                grid → moodboard → list → moodboard
     p 0.88 → 1.00   FEATURED   one save is promoted; the board settles

   The layout beat blends four position sets additively — each stage finishes
   before the next begins, so the sums never overlap and the cards genuinely
   travel between layouts instead of cross-fading.

   Card visuals (.badge, .badge__mark--*, .fill--*) are REUSED from hero.css,
   like Save anything does. This file must load after it.
   ========================================================================== */

/* --------------------------------------------------------------------------
   The clock

   --bcp is the whole section's timeline: every beat below is a window on it.
   It used to be written by a requestAnimationFrame loop in site.js, and that
   is what made this block feel scroll-driven long after the last piece of
   scroll code had been taken out of it. rAF is only called when the browser
   produces a frame; when frame production is suppressed on a page that is
   still nominally visible, the loop stops being called, and scrolling is then
   the thing that forces frames. The animation advanced while the user
   scrolled and stalled when they stopped.

   A declarative animation does not have that failure mode: the browser
   derives its progress from the document timeline, so the value is a function
   of elapsed time rather than of how often a callback ran. This is also the
   mechanism every other auto-playing section here already uses (2, 5-8) —
   a keyframe sequence parked at `animation-play-state: paused`, released by
   `is-live` from the shared observer in site.js.

   `@property` is what makes it possible: an unregistered custom property is
   not interpolatable, so --bcp would jump between keyframes instead of sweeping
   through them. Registered as a <number> it animates smoothly, and every
   `calc()` below picks the animated value up unchanged.

   The cycle is 11.2s in four phases, forward-only:

     hold 0     0 → 6.25%     0.7s   the board before any customizing
     play 0→1  6.25 → 70.54%  7.2s   the part meant to be watched
     hold 1  70.54 → 93.75%   2.6s   the finished FEATURED board
     reset 1→0 93.75 → 100%   0.7s   a rewind, not a reverse scrub

   The return leg is deliberately ~10x faster than the forward leg. A
   symmetric 0→1→0 triangle — which this ran before — replays the whole
   choreography backwards at watching speed, and that is visually
   indistinguishable from someone dragging a scrubbed timeline back.
   -------------------------------------------------------------------------- */
@property --bcp{
  syntax:'<number>';
  inherits:true;
  initial-value:0;
}

@keyframes bc-showcase{
  0%      {--bcp:0; animation-timing-function:linear}
  /* smoothstep-shaped, matching the ease the old clock applied in JS */
  6.25%   {--bcp:0; animation-timing-function:cubic-bezier(.42,0,.58,1)}
  70.54%  {--bcp:1; animation-timing-function:linear}
  93.75%  {--bcp:1; animation-timing-function:cubic-bezier(.4,0,.85,1)}
  100%    {--bcp:0}
}

.bc{
  /* Parked until the shared observer says the section is on screen, the tab is
     visible and motion is not reduced — identical contract to sections 2, 5-8.
     Nothing in JavaScript writes --bcp any more. */
  animation:bc-showcase 11.2s linear infinite;
  animation-play-state:paused;
}
.bc.is-live{animation-play-state:running}

.bc{
  --bcp:0;

  /* ---- beats ---- */
  --cover:clamp(0,calc((var(--bcp) - .08) / .14),1);
  --accent:clamp(0,calc((var(--bcp) - .22) / .12),1);
  --emoji:clamp(0,calc((var(--bcp) - .34) / .10),1);
  --sticker:clamp(0,calc((var(--bcp) - .44) / .10),1);

  /* layout hops — strictly sequential, never overlapping */
  --l1:clamp(0,calc((var(--bcp) - .54) / .12),1);   /* grid      → moodboard */
  --l2:clamp(0,calc((var(--bcp) - .68) / .10),1);   /* moodboard → list      */
  --l3:clamp(0,calc((var(--bcp) - .80) / .08),1);   /* list      → moodboard */

  --feat:clamp(0,calc((var(--bcp) - .88) / .12),1);

  position:relative;

  /* Transparent on purpose — `.cine__floor` paints this section's surface
     colour from a layer beneath the shared glow. An opaque background here
     would cut the atmosphere off at the section boundary. */
  background:transparent;

  /* No pull-up any more. It existed to reclaim the dead tail of a pinned,
     three-viewport scene; with the section in normal flow there is no tail to
     reclaim and a negative margin would simply collide it with Save anything.
     The gap between the two blocks is now each one's own padding, which is
     how every other junction on the page already works. */
}

/* Was a sticky, viewport-sized frame holding the scene still while 200vh of
   runway scrolled past underneath. Now an ordinary block: the class name is
   kept so the rest of this file and the markup stay untouched — the same
   conversion `.sa__pin` already went through.

   `overflow` stays: the background blobs are still sized to bleed past the
   edges and this is what keeps them inside the block. The old `padding-top:
   var(--nav-h)` is gone with the pin — that cleared the fixed header while
   stuck at top:0, and in normal flow the header never overlaps this. What
   replaces it is ordinary section padding, matching sections 2 and 5-8. */
.bc__pin{
  position:relative;
  overflow:hidden;
  display:flex;
  flex-direction:column;
  padding-block:clamp(44px,6vw,84px) clamp(48px,6.5vw,92px);
  isolation:isolate;
}
@supports (overflow:clip){
  .bc__pin{overflow:clip}
}

.bc__bg{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.bc__blob{filter:blur(30px)}
/* Sideways bleed is fine — that edge sits at the viewport boundary. Vertical
   bleed is not: this pin clips its own overflow, so a blob hanging past the
   top or bottom gets sliced along an edge that travels through the viewport
   as the section scrolls in and out. Both are kept fully inside. */
.bc__blob--a{width:min(40vw,520px);aspect-ratio:1;top:5%;left:-10%;opacity:.34}
.bc__blob--b{width:min(34vw,440px);aspect-ratio:1;bottom:4%;right:-8%;opacity:.36}

/* ==========================================================================
   Copy
   ========================================================================== */
.bc__copy{
  position:relative;
  z-index:3;
  text-align:center;
  padding-top:clamp(14px,3svh,40px);
}
.bc__eyebrow-row{
  display:flex;align-items:center;justify-content:center;
  gap:12px;flex-wrap:wrap;
  margin-bottom:clamp(12px,1.6vw,18px);
}
/* The one status flag for this section — the customize system is still being
   built, and it is said once rather than stamped on every control. */
.bc__status{
  display:inline-flex;align-items:center;gap:7px;
  padding:5px 12px;
  border-radius:var(--radius-pill);
  background:var(--lavender-pale);
  color:var(--navy);
  font-family:var(--font-display);font-weight:var(--fw-bold);
  font-size:10px;letter-spacing:.16em;text-transform:uppercase;
}
.bc__status::before{
  content:"";width:6px;height:6px;border-radius:50%;
  background:var(--purple-bright);
}

.bc__title{
  font-family:var(--font-display);
  font-weight:var(--fw-extrabold);
  font-size:var(--fs-h2);
  line-height:var(--lh-tight);
  letter-spacing:var(--ls-tight);
  color:var(--navy);
  text-wrap:balance;
}
.bc__title-accent{
  background:var(--grad-text);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
.bc__sub{
  margin:clamp(10px,1.4vw,16px) auto 0;
  max-width:44rem;
  font-size:var(--fs-body-lg);
  line-height:var(--lh-body);
  color:var(--text-body);
  text-wrap:pretty;
}
.bc__sub b{font-weight:var(--fw-semibold);color:var(--navy)}

/* ==========================================================================
   Stage — option rails flanking the board
   ========================================================================== */
.bc__stage{
  position:relative;
  z-index:2;
  /* `flex:1` here filled the pin's fixed 100svh; with the parent auto-height
     the row simply takes the height of the board it contains. */
  display:grid;
  grid-template-columns:clamp(120px,12vw,158px) minmax(0,1fr) clamp(120px,12vw,158px);
  align-items:center;
  /* `align-content:start` is what makes the beat above measurable. The row is
     auto-height, and back when this pin was a fixed 100svh frame the row
     stretched to fill it and the group floated in the middle — the distance
     under the copy was whatever slack happened to be left over. The frame is
     gone, but packing to the top is still what makes the padding below the
     gap, exactly, rather than something the row's own height can absorb.
     `align-items:center` is untouched, so the rails still centre on the board
     and the scene's own composition is unchanged. */
  align-content:start;
  gap:clamp(14px,2.2vw,34px);
  padding-block:var(--section-copy-gap) clamp(40px,7svh,72px);
}

.bc-rail{display:flex;flex-direction:column;gap:clamp(12px,2svh,22px)}
.bc-rail--right{align-items:flex-end}

.bc-opt__label{
  display:block;
  margin-bottom:8px;
  font-family:var(--font-display);font-weight:var(--fw-bold);
  font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--text-meta);
}
.bc-rail--right .bc-opt__label{text-align:right}

/* ---- Cover presets ---- */
.bc-covers{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}
.bc-cover-chip{
  aspect-ratio:1;
  border-radius:9px;
  overflow:hidden;
  border:1.5px solid var(--border);
  background:var(--bg-soft);
  position:relative;
}
.bc-cover-chip img{width:100%;height:100%;object-fit:cover;display:block}
/* The chip that the scene actually applies, ringed as the cover beat lands. */
.bc-cover-chip--on::after{
  content:"";position:absolute;inset:-1.5px;border-radius:9px;
  border:2px solid var(--purple-bright);
  box-shadow:var(--glow-purple);
  opacity:var(--cover);
}

/* ---- Accent swatches ---- */
.bc-accents{display:grid;grid-template-columns:repeat(4,1fr);gap:7px}
.bc-accent-chip{
  aspect-ratio:1;border-radius:50%;
  border:1.5px solid rgba(13,15,60,.08);
  position:relative;
}
.bc-accent-chip--on::after{
  content:"";position:absolute;inset:-4px;border-radius:50%;
  border:2px solid var(--purple-bright);
  opacity:var(--accent);
}

/* ---- Emoji + sticker picks ---- */
.bc-picks{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}
.bc-pick{
  width:clamp(30px,3.2vw,38px);aspect-ratio:1;
  border-radius:11px;
  display:grid;place-items:center;
  background:var(--surface);
  border:1px solid var(--border);
  box-shadow:var(--shadow-sm);
  font-size:clamp(15px,1.7vw,19px);
  line-height:1;
  position:relative;
}
.bc-pick img{width:78%;height:78%;object-fit:contain;display:block}
.bc-pick--on::after{
  content:"";position:absolute;inset:-3px;border-radius:13px;
  border:2px solid var(--purple-bright);
}
.bc-pick--emoji-on::after{opacity:var(--emoji)}
.bc-pick--sticker-on::after{opacity:var(--sticker)}

/* ---- Layout picker ---- */
.bc-layouts{display:flex;gap:7px;justify-content:flex-end}
.bc-layout-chip{
  width:clamp(34px,3.6vw,42px);aspect-ratio:1;
  border-radius:10px;
  background:var(--surface);
  border:1px solid var(--border);
  box-shadow:var(--shadow-sm);
  display:grid;place-items:center;
  position:relative;
}
.bc-layout-chip svg{width:60%;height:60%}
.bc-layout-chip::after{
  content:"";position:absolute;inset:-3px;border-radius:12px;
  border:2px solid var(--purple-bright);
  opacity:0;
}
/* Each chip is lit only while its own layout is the one on screen. */
.bc-layout-chip--grid::after{opacity:calc(1 - var(--l1))}
.bc-layout-chip--mood::after{opacity:calc(var(--l1) - var(--l2) + var(--l3))}
.bc-layout-chip--list::after{opacity:calc(var(--l2) - var(--l3))}

/* ==========================================================================
   The board
   ========================================================================== */
.bc-board-col{display:flex;justify-content:center;min-width:0}

.bc-board{
  --accent-neutral:#9AA3B8;
  --accent-pick:var(--purple-bright);
  --bc-accent:var(--accent-neutral);

  position:relative;
  width:100%;
  max-width:clamp(420px,52vw,600px);
  border-radius:var(--radius-lg);
  background:var(--surface);
  border:1px solid var(--border);
  box-shadow:var(--shadow-lg);
  overflow:hidden;
  transform:scale(calc(.985 + var(--feat) * .015));
}
/* The accent is one interpolated colour rather than a stack of cross-faded
   copies, so a single property drives every accented part of the board. */
/* A deeper cut of the same accent, used wherever the accent carries white
   text: the accent at full strength measures 4.5:1 against white, which small
   bold labels do not clear. Same hue family, legible. */
.bc-board{--bc-accent-ink:#5A4FA8}
@supports (color:color-mix(in oklab,red,blue)){
  .bc-board{
    --bc-accent:color-mix(in oklab,
      var(--accent-pick) calc(var(--accent) * 100%),
      var(--accent-neutral));
    --bc-accent-ink:color-mix(in oklab,var(--bc-accent) 72%,var(--navy));
  }
}

/* ---- Cover ---- */
.bc-board__cover{
  position:relative;
  height:clamp(78px,11svh,108px);
  background:linear-gradient(160deg,#E9E7F2,#D9D7E6);
  overflow:hidden;
}
.bc-board__cover img{
  width:100%;height:100%;object-fit:cover;display:block;
  opacity:var(--cover);
  transform:scale(calc(1.06 - var(--cover) * .06));
}

/* ---- Sticker ---- */
.bc-sticker{
  position:absolute;
  right:clamp(14px,3vw,30px);
  top:clamp(30px,5svh,54px);
  z-index:4;
  width:clamp(52px,6.4vw,74px);
  transform:
    translate3d(0,calc((1 - var(--sticker)) * -22px),0)
    rotate(calc(-12deg + var(--sticker) * 6deg))
    scale(calc(.7 + var(--sticker) * .3));
  opacity:var(--sticker);
  filter:drop-shadow(0 10px 18px rgba(13,15,60,.24));
  pointer-events:none;
}
.bc-sticker img{width:100%;height:auto;display:block}

/* ---- Header ---- */
.bc-board__head{
  position:relative;
  display:flex;align-items:flex-start;gap:12px;
  padding:12px clamp(14px,1.6vw,20px) 10px;
  border-bottom:1px solid var(--border);
}
.bc-board__emoji{
  position:relative;
  flex:none;
  width:clamp(42px,4.6vw,56px);aspect-ratio:1;
  margin-top:-26px;
  border-radius:16px;
  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(19px,2.2vw,25px);
  line-height:1;
}
.bc-board__emoji span{
  opacity:var(--emoji);
  transform:scale(calc(.4 + var(--emoji) * .6));
}
.bc-board__meta{flex:1;min-width:0}
.bc-board__title{
  display:flex;align-items:center;gap:7px;
  font-family:var(--font-display);font-weight:var(--fw-extrabold);
  font-size:clamp(15px,1.6vw,19px);
  letter-spacing:var(--ls-tight);
  color:var(--navy);
}
.bc-board__title-emoji{
  opacity:var(--emoji);
  transform:scale(calc(.3 + var(--emoji) * .7));
  display:inline-block;
}
.bc-board__desc{
  margin-top:3px;
  font-size:11.5px;line-height:1.35;color:var(--text-meta);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* Members sit here already so the Together section can grow straight out of
   this board — no collaboration behaviour is implemented yet. */
.bc-board__people{display:flex;align-items:center;gap:7px;margin-top:7px}
.bc-board__avatars{display:flex}
.bc-board__avatar{
  width:19px;height:19px;border-radius:50%;
  border:2px solid #fff;
  display:grid;place-items:center;
  font-family:var(--font-display);font-weight:var(--fw-extrabold);
  font-size:8px;color:#fff;
}
.bc-board__avatar + .bc-board__avatar{margin-left:-6px}
.bc-board__avatar--a{background:linear-gradient(160deg,#FFB3B9,#FF7A85)}
.bc-board__avatar--b{background:linear-gradient(160deg,#C9BEF7,#735CFF)}
.bc-board__avatar--c{background:linear-gradient(160deg,#B8ABF2,#0D0F3C)}
.bc-board__avatar--add{
  background:var(--bg-soft);color:var(--text-meta);
  border-style:dashed;border-color:var(--border);
  font-size:11px;
}
.bc-board__people-text{font-size:10.5px;color:var(--text-meta)}
.bc-board__count{
  flex:none;align-self:flex-start;
  padding:4px 10px;border-radius:var(--radius-pill);
  background:var(--bc-accent-ink);
  color:#fff;
  font-family:var(--font-display);font-weight:var(--fw-bold);
  font-size:10px;white-space:nowrap;
}

/* ==========================================================================
   Card canvas — one set of cards, four arrangements
   ========================================================================== */
.bc-canvas{
  position:relative;
  height:clamp(268px,34svh,340px);
  padding:0;
}

.bc-card{
  position:absolute;
  left:50%;top:50%;
  width:152px;
  /* Tile height and the caption's offset are one value — the caption is
     absolutely positioned, so if they drift apart the grid rows silently run
     past the bottom of the board. */
  --tile-h:106px;
  /* Additive blend across the four layout states. Each hop is finished before
     the next starts, so the terms never fight. */
  --x:calc(var(--gx) + (var(--mx) - var(--gx)) * var(--l1)
                     + (var(--lx) - var(--mx)) * var(--l2)
                     + (var(--mx) - var(--lx)) * var(--l3));
  --y:calc(var(--gy) + (var(--my) - var(--gy)) * var(--l1)
                     + (var(--ly) - var(--my)) * var(--l2)
                     + (var(--my) - var(--ly)) * var(--l3));
  --s:calc(1 + (var(--ms) - 1) * var(--l1)
             + (var(--ls) - var(--ms)) * var(--l2)
             + (var(--ms) - var(--ls)) * var(--l3));
  --r:calc(0deg + var(--mr) * var(--l1)
                - var(--mr) * var(--l2)
                + var(--mr) * var(--l3));
  transform:translate3d(calc(-50% + var(--x)),calc(-50% + var(--y)),0) rotate(var(--r)) scale(var(--s));
  will-change:transform;
}

.bc-card__tile{
  position:relative;
  height:var(--tile-h);
  border-radius:var(--radius-md);
  overflow:hidden;
  border:1px solid var(--border);
  box-shadow:var(--shadow-sm);
}
/* Meta rides under the tile in grid, disappears in moodboard, and swings out
   to the right in list. */
.bc-card__meta{
  position:absolute;
  left:0;top:var(--tile-h);
  width:152px;
  padding-top:7px;
  text-align:left;
  --mtx:calc(0px + (var(--lmx) - 0px) * var(--l2) + (0px - var(--lmx)) * var(--l3));
  --mty:calc(0px + (var(--lmy) - 0px) * var(--l2) + (0px - var(--lmy)) * var(--l3));
  transform:translate3d(var(--mtx),var(--mty),0) scale(calc(1 + var(--l2) * 1.5 - var(--l3) * 1.5));
  transform-origin:0 50%;
  opacity:calc(1 - var(--l1) + var(--l2) - var(--l3));
}
.bc-card__title{
  font-family:var(--font-display);font-weight:var(--fw-bold);
  font-size:11.5px;line-height:1.25;color:var(--navy);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.bc-card__sub{
  margin-top:2px;
  font-size:10px;color:var(--text-meta);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* Tile fills. `.fill--vid` / `.fill--stay` come from hero.css; these are the
   three this section adds, in the same gradient language. */
.bc-fill--place{background:#F1EFF9}
.bc-fill--reel{background:linear-gradient(155deg,#FFE7E9,#FF9AA3 62%,#E16D7B)}
.bc-fill--shop{background:linear-gradient(150deg,#E4ECFF,#B8ABF2 58%,#8E7CE8)}
.bc-fill--read{background:linear-gradient(160deg,#F5F3FA,#C9BEF7)}
.bc-tile-glyph{
  position:absolute;inset:0;display:grid;place-items:center;
  font-size:26px;line-height:1;opacity:.9;
}

/* Featured promotion at the end of the story. */
.bc-card--feature .bc-card__tile{
  box-shadow:calc(var(--feat) * 0px) calc(var(--feat) * 14px) calc(var(--feat) * 34px) rgba(13,15,60,.2),var(--shadow-sm);
  border-color:color-mix(in oklab,var(--bc-accent) calc(var(--feat) * 100%),var(--border));
}
.bc-feature-flag{
  position:absolute;top:7px;left:7px;
  z-index:3;
  display:inline-flex;align-items:center;gap:4px;
  padding:3px 8px;border-radius:var(--radius-pill);
  background:var(--bc-accent-ink);
  color:#fff;
  font-family:var(--font-display);font-weight:var(--fw-bold);
  font-size:8.5px;letter-spacing:.06em;
  opacity:var(--feat);
  transform:translate3d(0,calc((1 - var(--feat)) * -6px),0);
}

/* ---- Layout coordinate sets -------------------------------------------
   grid  : 3 × 2, uniform
   mood  : staggered, varied scale, slight rotation, meta hidden
   list  : one column at 0.4 scale, meta swung out to the right
   ---------------------------------------------------------------------- */
/* List-mode caption offset, in the card's LOCAL units — the card itself is at
   0.4 scale there, so an on-screen gap of g needs g / 0.4 here. The caption's
   own 2.5 counter-scale is what brings the text back to normal size. */
.bc-card{--lmx:187px;--lmy:-72px}

/* Grid rows are asymmetric on purpose: the card box is only as tall as its
   tile (the caption is absolute), so centring on the tile alone would hang
   the bottom row's captions past the board. These offsets centre the block
   INCLUDING both captions.
   Moodboard y values also account for each card's own scale, so no tile
   reaches up into the board header. */
.bc-card--1{--gx:-166px;--gy:-97px; --mx:-172px;--my:-84px;--ms:1.02;--mr:-2deg; --lx:-86px;--ly:-125px;--ls:.4}
.bc-card--2{--gx:0px;   --gy:-97px; --mx:-6px;  --my:-98px;--ms:.8; --mr:1.5deg; --lx:-86px;--ly:-75px; --ls:.4}
.bc-card--3{--gx:166px; --gy:-97px; --mx:158px; --my:-78px;--ms:.94;--mr:-1deg;  --lx:-86px;--ly:-25px; --ls:.4}
.bc-card--4{--gx:-166px;--gy:53px;  --mx:-160px;--my:74px; --ms:.88;--mr:2deg;   --lx:-86px;--ly:25px;  --ls:.4}
.bc-card--5{--gx:0px;   --gy:53px;  --mx:4px;   --my:58px; --ms:1.1;--mr:-1.5deg;--lx:-86px;--ly:75px;  --ls:.4}
.bc-card--6{--gx:166px; --gy:53px;  --mx:166px; --my:92px; --ms:.78;--mr:1deg;   --lx:-86px;--ly:125px; --ls:.4}

/* ==========================================================================
   Board character row — same system, five different vibes
   ========================================================================== */
.bc-chars{
  position:relative;
  /* Pulled up into the pin's exit travel and given a shorter top pad: this is
     the payoff of the customize scene, not a new section starting far below
     it. The overlap stops short of the finished board so it is never covered
     while still on screen. */
  /* The room this can borrow is the slack under the board inside the pin. That
     slack is not a fixed number and it is not proportional to the viewport
     either: the pin grows with the frame while the board is a fixed height, so
     it is (roughly) 0.65 x viewport minus the fixed stack above it — measured
     94px at 900 tall and 211px at 1080. The old tiered pull could not track
     that, so the finished board and this heading drifted apart on exactly the
     tall screens where the section already had the most air: the heading sat
     97px under the board at 900 and 153px at 1080.

     Following the slack instead keeps that distance constant. The -511 leaves
     a ~20px ledge so this section's own surface never rides up over the
     finished board, and the clamp stops the calc going negative on short
     frames or unbounded on very tall ones. */
  /* The pull-up is gone with the pin. It used to follow the slack underneath
     the board *inside* the pinned frame; in normal flow there is no slack to
     follow and any negative margin here would ride up over the finished
     board. The character row now simply follows the block. */
  --bc-chars-pull:0px;
  /* Was clamp(40px,5vw,72px): 72px of inset directly under a gap this section
     exists to close. */
  padding-block:clamp(24px,2.2vw,32px) clamp(40px,5.4vw,76px);
  background:var(--surface-soft);
}
.bc-chars__head{text-align:center;margin-bottom:clamp(22px,3vw,36px)}
.bc-chars__title{
  font-family:var(--font-display);font-weight:var(--fw-extrabold);
  font-size:var(--fs-h3);letter-spacing:var(--ls-tight);color:var(--navy);
}
.bc-chars__sub{
  margin-top:8px;font-size:var(--fs-small);color:var(--text-meta);
}
.bc-chars__grid{
  display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(14px,1.8vw,24px);
}

.bc-char{
  border-radius:var(--radius-lg);
  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);
}
.bc-char:hover{transform:translateY(-4px);box-shadow:var(--shadow-md)}
.bc-char__cover{height:clamp(78px,9vw,104px);position:relative;overflow:hidden}
.bc-char__cover img{width:100%;height:100%;object-fit:cover;display:block}
.bc-char__body{padding:0 14px 14px;position:relative}
.bc-char__emoji{
  width:38px;aspect-ratio:1;margin-top:-19px;
  border-radius:12px;border:3px solid #fff;
  box-shadow:var(--shadow-sm);
  display:grid;place-items:center;font-size:17px;line-height:1;
}
.bc-char__title{
  margin-top:8px;
  font-family:var(--font-display);font-weight:var(--fw-extrabold);
  font-size:14.5px;letter-spacing:var(--ls-tight);color:var(--navy);
}
.bc-char__desc{margin-top:3px;font-size:11.5px;color:var(--text-meta)}
.bc-char__sources{display:flex;gap:5px;margin-top:10px;flex-wrap:wrap}
.bc-char__src{
  padding:3px 8px;border-radius:var(--radius-pill);
  background:var(--bg-soft);border:1px solid var(--border);
  font-family:var(--font-display);font-weight:var(--fw-bold);
  font-size:9px;color:var(--text-meta);white-space:nowrap;
}

/* ==========================================================================
   Breakpoints
   ========================================================================== */

/* Taller frames leave more unused space under the pinned board, so they can
   afford to pull the character row further up into it. */

@media (max-width:1100px){
  .bc__stage{grid-template-columns:clamp(104px,11vw,132px) minmax(0,1fr) clamp(104px,11vw,132px)}
  .bc-covers{grid-template-columns:repeat(4,1fr);gap:5px}
  .bc-chars__grid{grid-template-columns:repeat(2,minmax(0,1fr))}
}

/* ---- Mobile: the rails become one strip that names the beat ---------------
   Five option groups flanking a board does not survive 375px, and stacking
   them would bury the board. Instead the board takes the full width and a
   single strip underneath shows only the control the story is touching right
   now — the same beats, told one at a time.
   -------------------------------------------------------------------------- */
@media (max-width:820px){
  /* The shared copy → visual beat costs ~23px more here than the old local
     value did. That is taken back out of the copy's own top inset and the
     stage's bottom inset, which kept the section's height unchanged back when
     the pin was a fixed frame that clipped; in normal flow it simply keeps
     this block as compact on a phone as it was. */
  .bc__copy{padding-top:clamp(4px,0.9svh,14px)}
  .bc__title{font-size:clamp(26px,7vw,38px)}
  .bc__sub{font-size:15.5px;max-width:32rem}

  .bc__stage{
    grid-template-columns:minmax(0,1fr);
    gap:clamp(6px,1.15svh,12px);
    padding-block:var(--section-copy-gap) clamp(2px,0.5svh,8px);
  }
  .bc-board{max-width:100%}
  .bc-canvas{height:clamp(232px,30svh,286px)}
  .bc-card{width:clamp(104px,29vw,126px);--tile-h:78px}
  .bc-card__meta{width:clamp(104px,29vw,126px)}

  /* Tighter coordinate sets for the narrower canvas. Grid columns are pulled
     in so the outer tiles clear the board's own padding, and the rows are
     offset the same asymmetric way as on desktop. */
  .bc-card{--lmx:139px;--lmy:-57px}
  .bc-card--1{--gx:-106px;--gy:-76px;--mx:-104px;--my:-66px;--lx:-61px;--ly:-96px}
  .bc-card--2{--gx:0px;   --gy:-76px;--mx:-4px;  --my:-82px;--lx:-61px;--ly:-58px}
  .bc-card--3{--gx:106px; --gy:-76px;--mx:104px; --my:-58px;--lx:-61px;--ly:-20px}
  .bc-card--4{--gx:-106px;--gy:38px; --mx:-104px;--my:52px; --lx:-61px;--ly:18px}
  .bc-card--5{--gx:0px;   --gy:38px; --mx:2px;   --my:40px; --lx:-61px;--ly:56px}
  .bc-card--6{--gx:106px; --gy:38px; --mx:106px; --my:66px; --lx:-61px;--ly:94px}

  /* One strip, and only the group whose beat is running is shown. */
  .bc-rail{
    flex-direction:row;
    align-items:center;
    justify-content:center;
    gap:0;
    position:relative;
    min-height:64px;
  }
  .bc-rail--right{align-items:center}
  .bc-opt{
    position:absolute;
    left:50%;top:50%;
    transform:translate3d(-50%,-50%,0);
    display:flex;flex-direction:column;align-items:center;gap:7px;
  }
  .bc-opt__label,.bc-rail--right .bc-opt__label{text-align:center;margin-bottom:0}
  .bc-covers{grid-template-columns:repeat(8,1fr);gap:5px;width:min(300px,86vw)}
  .bc-accents{grid-template-columns:repeat(8,1fr);gap:6px;width:min(258px,76vw)}
  .bc-picks{flex-wrap:nowrap;justify-content:center}
  .bc-pick{width:34px}

  /* Each group is on screen only for its own beat. Cover starts visible so
     the strip is never empty while the board is still in its default state. */
  .bc-opt--cover  {opacity:calc(1 - var(--accent))}
  .bc-opt--accent {opacity:calc(var(--accent) - var(--emoji))}
  .bc-opt--emoji  {opacity:calc(var(--emoji) - var(--sticker))}
  .bc-opt--sticker{opacity:calc(var(--sticker) - var(--l1))}
  .bc-opt--layout {opacity:var(--l1)}

  .bc-chars__grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .bc-char__cover{height:82px}
}

@media (max-width:480px){
  .bc-chars__grid{grid-template-columns:minmax(0,1fr);max-width:340px;margin-inline:auto}
}

/* Short desktop frames: the board has to lose height before the canvas does. */
@media (max-height:820px) and (min-width:821px){
  .bc-canvas{height:clamp(244px,30svh,286px)}
  .bc-card__tile{height:100px}
  .bc-card__meta{top:100px}
}

/* ==========================================================================
   Reduced motion
   The runway collapses, the pin releases, and the board renders FINISHED —
   cover, accent, emoji, sticker, featured item, moodboard layout. The default
   state is shown beside it as a small static "before", so the difference the
   section is about is still legible without any movement.
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  .bc{
    /* No loop at all — the settled state below is the whole story here. */
    animation:none;
    --cover:1;--accent:1;--emoji:1;--sticker:1;
    --l1:1;--l2:0;--l3:0;--feat:1;
    /* No animated tail to reclaim here — pulling up would just collide the
       two sections. */
    --cine-overlap:0px;
  }
  .bc-chars{--bc-chars-pull:0px}
  .bc__stage{
    grid-template-columns:minmax(0,1fr);
    padding-block:clamp(24px,4svh,44px);
  }
  .bc-canvas{height:320px}
  .bc-rail{flex-direction:row;flex-wrap:wrap;justify-content:center;gap:22px}
  .bc-rail--right{align-items:flex-start}
  .bc-opt{position:static;transform:none;opacity:1}
  .bc-opt__label,.bc-rail--right .bc-opt__label{text-align:left}
  .bc-covers,.bc-accents{width:auto}
  .bc-card,.bc-card__meta,.bc-sticker,.bc-board{transition:none}
  .bc-before{display:block}
}

/* The static "before" board, only ever shown under reduced motion. */
.bc-before{display:none;margin-top:clamp(28px,4vw,44px);text-align:center}
.bc-before__label{
  display:block;margin-bottom:12px;
  font-family:var(--font-display);font-weight:var(--fw-bold);
  font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--text-meta);
}
.bc-before__card{
  display:inline-block;width:min(300px,80vw);
  border-radius:var(--radius-lg);
  background:var(--surface);border:1px solid var(--border);
  box-shadow:var(--shadow-sm);overflow:hidden;text-align:left;
}
.bc-before__cover{height:58px;background:linear-gradient(160deg,#E9E7F2,#D9D7E6)}
.bc-before__body{padding:12px 14px}
.bc-before__title{
  font-family:var(--font-display);font-weight:var(--fw-extrabold);
  font-size:14px;color:var(--navy);
}
.bc-before__desc{margin-top:3px;font-size:11px;color:var(--text-meta)}
.bc-before__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-top:10px}
.bc-before__cell{aspect-ratio:4/3;border-radius:8px;background:var(--bg-soft);border:1px solid var(--border)}
