/* ===================================================================
   drex.style — app.css
   M0 split: extracted VERBATIM from index.html <style> (pixel-identical).
   Feature CSS is layered on in later milestones, keyed off body[data-motion].
   =================================================================== */
/* =================================================================
   Drex — drex.style — handmade ZINE / SCRAPBOOK landing
   Built on backend-gstack/DESIGN.md (the web-app neo-skeuomorphic
   "whimsymaxx" system): cut-paper cards w/ torn edges + ink borders
   + HARD SOLID OFFSET registration shadows (never blurred, never a
   gradient), washi tape, .splay tilts (littered, not a grid),
   highlighter h1, wobbly marker underlines, rubber-stamp press-down
   buttons, .scrawl (Patrick Hand) annotations, notebook+dot+grain
   ground. Palette §4 only. The LOGO stays clean: upright, one solid
   colour, no filter / shadow / tilt (brand §3.3).
   ================================================================= */
:root{
  --grass:#1CAB5B; --oats:#FEF6E4; --sambas:#414D57; --colorado:#F75458;
  --lazuli:#2496C9; --schoolbus:#ECAF21; --happy:#F1DD01;
  --grass-deep:#0C6E39;      /* AA-safe grass: oats text clears 4.5:1 — for the primary button fill + footer band */
  --coral-ink:#C9343A;       /* sanctioned deepened Colorado (matches letters) */
  --lazuli-deep:#1C6F94;     /* sanctioned deepened Lazuli (matches letters) */
  --ink:#414D57;
  /* Text ink has exactly three levels and NONE go below .80 — under that it fails AA on Oats
     (.75 = 4.22:1). Body is solid. Bitter Light at full ink reads sharper, not heavier: it stops
     competing with the paper grain. Do not invent a fourth level. */
  --ink-soft:rgba(65,77,87,.85);   /* 5.42:1 — captions, secondary */
  --ink-faint:rgba(65,77,87,.80);  /* 4.77:1 — the floor. Nothing on text is quieter than this. */
  --paper:#FEF6E4;            /* Oats — palette-pure; cards lift off the textured ground via torn ink border + hard shadow */

  /* ---- The four brand faces (brand book §06). One job each; never trade. ----
     Pitch      → DISPLAY, "moments where we need maximum impact" = the h1, and nothing else.
     Pitch Sans → "Headings and Subheadings" — an upright SANS. Was wrongly substituted with
                  DM Mono (a monospace), which collapsed it into Pitch and killed the hierarchy.
     Bitter     → body. Birdie → margin annotations ONLY (never a heading, never body). */
  --f-display:"Courier Prime",ui-monospace,monospace;   /* Pitch — h1 only */
  --f-slab:"Courier Prime",ui-monospace,monospace;      /* Pitch — display accents (pull-quotes, dropcap) */
  --f-head:"Space Grotesk",system-ui,sans-serif;        /* Pitch Sans — h2, h3 */
  --f-mono:"Space Grotesk",system-ui,sans-serif;        /* Pitch Sans — tracked uppercase labels */
  --f-body:"Bitter",Georgia,serif;
  --f-hand:"Patrick Hand",cursive;                      /* Birdie (scrawl) */

  /* ---- Type scale: fluid, two-ratio (1.2 @375 → 1.333 @1440), base 17→19px. ----
     THE RULE: no font-size literal anywhere outside this block. The page previously carried 108
     font-size declarations / 58 distinct clamps for ~5 real ranks, which is why size stopped
     meaning rank. One deliberately off-scale size exists (--fs-display). Do not add a second. */
  /* --fs-display is capped at 72px because that is the hard ceiling of the hero's LAYOUT, not a
     taste call: the hero card's inner width is 561px, and 13 characters of Courier Prime (a mono,
     ~0.6em advance) at anything above 72px overflows it. Going bigger means going full-bleed and
     dropping the polaroid below the headline. Measured, not guessed. */
  --fs-display:clamp(2.375rem, 1.28rem + 4.60vw, 4.5rem);    /*  38 →  72px  hero h1 — off-scale, on purpose */
  --fs-1:clamp(1.75rem, 1.35rem + 1.69vw, 2.75rem);          /*  28 →  44px  h2, TIER A */
  --fs-2:clamp(1.5rem, 1.29rem + 0.94vw, 2.125rem);          /*  24 →  34px  h2, TIER B */
  --fs-3:clamp(1.25rem, 1.13rem + 0.56vw, 1.625rem);         /*  20 →  26px  h3 / card heads */
  --fs-lede:clamp(1.1875rem, 1.08rem + 0.47vw, 1.5rem);      /*  19 →  24px  hero lede, sub-decks */
  --fs-body:clamp(1.0625rem, 1.02rem + 0.19vw, 1.1875rem);   /*  17 →  19px  body */
  --fs-small:clamp(0.875rem, 0.84rem + 0.14vw, 0.97rem);     /*  14 → 15.5px captions, marginalia — FLOOR */
  --fs-label:clamp(0.78rem, 0.76rem + 0.09vw, 0.84rem);      /* 12.5 → 13.5px tracked uppercase labels */
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;overflow-x:clip}
body{
  margin:0;color:var(--ink);font-family:var(--f-body);font-weight:300;line-height:1.6;
  font-size:clamp(1rem,.97rem + .25vw,1.13rem);overflow-x:clip;-webkit-font-smoothing:antialiased;
  /* the table: dot grid + faint notebook rules + paper grain over Oats */
  background-color:var(--oats);
  background-image:
    radial-gradient(rgba(65,77,87,.10) 1.1px, transparent 1.2px),
    repeating-linear-gradient(0deg, transparent 0 33px, rgba(36,150,201,.09) 33px 34px),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)' opacity='0.45'/%3E%3C/svg%3E");
  background-size:23px 23px, auto, 220px 220px;
  background-blend-mode:normal, normal, multiply;
}
a{color:inherit}
.wrap{max-width:1150px;margin:0 auto;padding-inline:clamp(1rem,4.5vw,3.5rem)}

/* ---------- the cut-paper sheet (base material) ---------- */
.paper{position:relative;isolation:isolate}
.paper>.sheet{
  content:"";position:absolute;inset:0;z-index:0;
  background:var(--paper);
  border:2.6px solid var(--ink);border-radius:6px;
  filter:url(#torn);                                /* torn / hand-cut edge */
  box-shadow:8px 8px 0 0 var(--ink);                /* hard SOLID registration shadow — one light, equal offset */
}
.paper>.sheet.ruled{
  background:var(--paper) repeating-linear-gradient(0deg, transparent 0 27px, rgba(65,77,87,.07) 27px 28px);
}
.paper>.inner{position:relative;z-index:2;padding:clamp(1.5rem,4vw,3rem)}

/* ---------- washi / scotch tape ---------- */
.tape{position:absolute;z-index:3;width:118px;height:32px;
  background:linear-gradient(94deg,rgba(241,221,1,.52),rgba(241,221,1,.32) 55%,rgba(241,221,1,.48)); /* Happy washi, opacity varies along the strip */
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.22);
  filter:url(#roughsm);
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 8px,#000 calc(100% - 8px),transparent 100%); /* feathered adhesive ends */
  mask-image:linear-gradient(90deg,transparent 0,#000 8px,#000 calc(100% - 8px),transparent 100%);
  transform:rotate(-5deg);}
.tape.b{background:linear-gradient(94deg,rgba(36,150,201,.44),rgba(36,150,201,.26) 55%,rgba(36,150,201,.4))}   /* lazuli washi */
.tape.c{background:linear-gradient(94deg,rgba(247,84,88,.44),rgba(247,84,88,.26) 55%,rgba(247,84,88,.4))}      /* colorado washi */
.tape::after{content:"";position:absolute;inset:0;background:repeating-linear-gradient(90deg,transparent 0 11px,rgba(255,255,255,.10) 11px 12px)}

/* ---------- type ---------- */
.scrawl{font-family:var(--f-hand);font-weight:400;line-height:1.15}
.eyebrow{font-family:var(--f-hand);font-size:clamp(1.15rem,2.4vw,1.6rem);color:var(--colorado);transform:rotate(-1.2deg);display:inline-block}
.label{font-family:var(--f-mono);font-weight:500;text-transform:uppercase;letter-spacing:.14em;font-size:.74rem}
.dot{color:var(--grass-deep);font-weight:700}
.slab{font-family:var(--f-slab);font-style:italic;font-weight:700;line-height:.98;letter-spacing:-.02em}
/* #resources — reuses the shared corkboard/.pinit/.pu-* styles; just the section chrome + polaroid pins */
.resources{padding:clamp(1.8rem,4.5vw,3rem) 0}
.resources .head{margin-bottom:clamp(1.6rem,3.6vw,2.4rem);text-align:center}
.resources .head h2{font-size:clamp(1.8rem,5.4vw,2.9rem);margin:.3rem 0 0;color:var(--ink)}
.resources .head h2 .stop{color:var(--grass-deep)}
.res-sub{font-family:var(--f-body);font-style:italic;font-size:clamp(1rem,1.6vw,1.2rem);line-height:1.5;color:rgba(65,77,87,.85);max-width:52ch;margin:.85rem auto 0}
.res-sub b{font-style:normal;color:var(--ink)}
/* polaroid pins: a square app screenshot where the line-icon would be */
.pinpola{width:clamp(132px,15vw,172px)}
.pinpola .pinshot{display:block;width:100%;aspect-ratio:1;margin:.15rem auto .4rem;border:2px solid var(--ink);border-radius:2px;background-color:var(--paper);background-size:cover;background-position:top center}

/* highlighter band behind the hero line — hand-swiped, tipped */
.hl{position:relative;display:inline;z-index:0}
.hl::before{content:"";position:absolute;left:-.19em;right:-.24em;top:.08em;bottom:-.04em;z-index:-1;
  background:var(--happy);mix-blend-mode:multiply;opacity:.95;transform:rotate(-.9deg) skewX(-5deg);filter:url(#rough);border-radius:2px}
.hl.g::before{background:var(--grass);opacity:.9}

/* wobbly marker underline — INK (grass is reserved as the "people are here" signal) */
.ul{position:relative;display:inline}
.ul::after{content:"";position:absolute;left:-.04em;right:-.07em;bottom:-.05em;height:.16em;
  background:var(--ink);filter:url(#rough);border-radius:3px}

/* ---------- rubber-stamp press-down button ---------- */
.btn{
  --bg:var(--grass-deep);--fg:var(--oats);   /* deep grass clears AA (oats label 5.9:1); bright grass was 2.78:1 */
  font-family:var(--f-mono);font-weight:500;font-size:.86rem;letter-spacing:.12em;text-transform:uppercase;
  display:inline-flex;align-items:center;gap:.5rem;text-decoration:none;cursor:pointer;
  background:var(--bg);color:var(--fg);border:2.6px solid var(--ink);border-radius:6px;
  padding:.85em 1.35em;min-height:46px;
  box-shadow:5px 5px 0 0 var(--ink);transform:rotate(-1.4deg);
  transition:transform .09s ease, box-shadow .09s ease;}
.btn:hover{transform:rotate(0)}
.btn:active{transform:translate(5px,5px) rotate(0);box-shadow:0 0 0 0 var(--ink)}  /* press INTO the shadow */
.btn:focus-visible{outline:3px solid var(--lazuli);outline-offset:3px}
.btn.ink{--bg:var(--paper);--fg:var(--ink)}
.btn .arr{font-family:var(--f-mono)}

/* ---------- masthead = printed broadsheet w/ torn bottom ---------- */
/* z-index:60 lifts the whole masthead (incl. the burger pull-down tray) above the
   hero/reel (root z 3–5) so the dragged nav never hides behind the reel polaroid.
   Stays UNDER the full-screen takeover overlays by design: .vol-layer(70),
   .tape-fall(90), #finale-*(80–95) still cover the menu during the eruption/finale. */
.mast{position:relative;z-index:60;background:var(--oats);border-bottom:0}
.mast::after{content:"";position:absolute;left:0;right:0;bottom:-15px;height:30px;background:var(--oats);filter:url(#tornbig);z-index:1}
.mast .wrap{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding-block:1rem;position:relative;z-index:2}
.mast .brand{display:flex;align-items:center;gap:0}   /* brand rule: exactly one 'x' of space between mark + word.
   The SVG art carries ~18px of internal whitespace (mark's right + word's left) at this size, which equals
   the wordmark's 'x' (~17px), so gap:0 lands the visible space at one 'x'. */
.mast .lg-icon{width:46px;display:block}   /* mark = dominant element, per brand lockups */
.mast .lg-word{width:84px;display:block}
.mast .lg-icon svg,.mast .lg-word svg{display:block;width:100%;height:auto}
/* brand mark + logotype in brand green (overrides the SVGs' inline ink fill) */
.mast .lg-icon svg,.mast .lg-icon svg path,
.mast .lg-word svg,.mast .lg-word svg path{fill:var(--grass)}
/* desktop masthead nav — scoped to the DIRECT nav so these rules never bleed
   into the ported mobile burger panel's own <nav> (which also lives in .mast) */
.mast>.wrap>nav{display:flex;gap:clamp(.5rem,2vw,1.1rem);align-items:center;flex-wrap:wrap;justify-content:flex-end}
.mast>.wrap>nav a{font-family:var(--f-mono);font-size:.74rem;letter-spacing:.1em;text-transform:uppercase;text-decoration:none;
  display:inline-flex;align-items:center;min-height:44px;
  border:2px solid var(--ink);border-radius:5px;padding:.4em .7em;background:var(--paper);
  box-shadow:2px 2px 0 0 var(--ink);transition:transform .08s, box-shadow .08s}
.mast>.wrap>nav a:focus-visible{outline:3px solid var(--lazuli);outline-offset:2px}
.mast>.wrap>nav a:nth-child(2){transform:rotate(1.4deg)}
.mast>.wrap>nav a:nth-child(3){transform:rotate(-1.2deg)}
.mast>.wrap>nav a:hover{transform:rotate(0) translate(-1px,-1px);box-shadow:3px 3px 0 0 var(--grass)}

/* ---------- hero ---------- */
.hero{padding:clamp(2.4rem,7vw,5rem) 0 clamp(1.5rem,4vw,3rem)}
.hero .inner{padding:clamp(1.8rem,5vw,3.6rem)}
.hero .eyebrow{margin-bottom:1rem}
.hero h1{font-family:var(--f-display);font-style:italic;font-weight:700;line-height:1;letter-spacing:-.012em;
  text-wrap:balance;font-size:var(--fs-display);margin:0;color:var(--ink);max-width:15ch}
.hero h1 .stop{color:var(--grass)}   /* brand green (the logo green), not the muted grass-deep — the deep shade read as near-black next to the ink */
.hero .lede{font-family:var(--f-body);font-style:italic;font-weight:400;font-size:clamp(1.2rem,2.3vw,1.7rem);
  line-height:1.55;max-width:32ch;margin:clamp(1.4rem,3.5vw,2.2rem) 0 0;color:var(--ink)}
.hero .lede .dropcap{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:1.4em;line-height:1;color:var(--grass-deep)}
.hero .cta{display:flex;gap:1rem;flex-wrap:wrap;margin-top:clamp(1.6rem,4vw,2.4rem)}
.hero .pin{position:absolute;right:clamp(1rem,5vw,3rem);top:clamp(-.5rem,2vw,1rem);z-index:4;
  transform:rotate(4deg);text-align:center}
.hero .pin .scrawl{font-size:1.25rem;color:var(--sambas);max-width:12ch}
@media(max-width:880px){.hero .pin{display:none}}   /* below 881 the card goes full-width, so the pin lands ON the copy — and ≥881 the polaroid owns that corner. It has no viewport left. */

/* ===================================================================
   HERO ENVELOPE — drag-to-cut. The card hides in a clipped pocket; sealed,
   it is pushed down out of sight so the page opens as blank paper with a
   "cut here" seam + a hand-drawn "drag to cut" prompt. A pointer drag tears
   the seam (--cut 0→1); on completion the card rises out of the pocket and,
   in sequence, gains its shadow → its tape → the highlighter draws on.
   ALL sealed visuals are gated on html.sealed (set in <head> only when motion
   is allowed). reduced-motion / no-JS / the 6s failsafe show the hero normally.
   =================================================================== */
.envelope{position:relative}
/* tight top while sealed so the seam stays in view; on settle it grows so the
   risen card clears the mast (transitioned, so the card visibly drops into place). */
.hero{padding-block:clamp(2.4rem,5.5vw,4.2rem) clamp(1.5rem,4vw,3rem);transition:padding .7s ease}
/* card settle-drop RELOCATED from .hero padding onto .card-clip margin-top (below) so it
   no longer wraps the envelope-anchored photo — .hero padding stays constant (loose). */
/* the pocket: a BOUNDED blank area with the card sitting at its base (the seam),
   so a tall card can't shove the "cut here" line below the fold. */
.card-clip{position:relative;overflow:visible}
html.sealed .card-clip{display:flex;align-items:flex-end;min-height:clamp(220px,32vh,330px);transition:min-height .46s cubic-bezier(.33,1,.4,1),margin-top .46s cubic-bezier(.34,1,.45,1)}
html.sealed:not(.revealed) .card-clip{margin-top:calc(clamp(.7rem,1.8vw,1.4rem) - clamp(2.4rem,5.5vw,4.2rem))}  /* tight while sealed; reverts to 0 on settle = the card's downward drop, now CARD-ONLY */
html.sealed.revealed .card-clip{min-height:0}                     /* pocket blank collapses on settle */
html.sealed:not(.revealed) .card-clip{overflow:clip;height:calc(50vh - 136px);min-height:0}              /* clip through the rise + burst; opens only at the settle (revealed). height + min-height:0 = the FIRST-PAINT slit centring: the tall .hero-card would otherwise balloon this flex pocket to its full height (~965px) — min-height is inert against a taller child — and shove the seam far below the fold before initSlitCenter() runs. calc(50vh - 136px) lands the "cut here" line within ~3px of viewport centre on first paint (JS then refines to sub-px). :not(.revealed)-scoped (0,3,1 beats the min-height clamp on html.sealed .card-clip, and releases the moment the card settles so the full card shows). */

/* the card: sealed = pushed down into the pocket (clipped away → blank above) */
.hero-card{width:100%;transition:transform .58s cubic-bezier(.22,.7,.25,1)}  /* decel rise THROUGH the stationary slit (not a front-loaded slam) */
html.sealed .hero-card{transform:translateY(122%)}
html.sealed .envelope.opened .hero-card{transform:translateY(0)}
/* compact hero so the whole card + seam live in one view (the envelope is a single screen) */
.hero-card .inner{padding:clamp(1.1rem,2.4vw,1.7rem)}
/* Headline is static now (the rotating cadence slot retired with the classroom framing).
   Two sentences = two blocks: each wraps on its own and balances, so a line break can
   never straddle the full stop ("circle. Show and / tell"). .hl needs its phrase to stay
   on one line or the highlighter box tears, hence the nbsp in "small circle". */
/* NO font-size here. This rule used to carry clamp(1.5rem,2.9vw,2.15rem) at the same specificity
   as .hero h1 (0,1,1), so source order silently won and the headline rendered at 34px — smaller
   than every h2 on the page, and smaller than the h3 reading "Instagram". The apex is the one
   thing a landing page cannot get wrong. Size lives in .hero h1 / --fs-display now. */
/* 13ch is the card's real capacity at --fs-display max (561px inner ÷ 0.6em advance ÷ 72px).
   Left to its own devices `text-wrap:balance` orphans the "a" onto its own line; pinning the
   measure to the line the card can actually hold gives "Get good in a / small circle." */
.hero-card h1{max-width:13ch;line-height:1.02}
.hero-card h1 .h1s{display:block;text-wrap:balance}
/* Sentence two steps down a rank: the headline reads as two beats, not one wall of display type. */
.hero-card h1 .h1s+.h1s{margin-top:.1em;font-size:.62em;color:var(--ink-soft)}
.hero-card .lede{font-size:clamp(.95rem,1.5vw,1.15rem);max-width:32ch;margin-top:clamp(.7rem,1.6vw,1.05rem)}
.hero-card .cta{margin-top:clamp(1.3rem,3.2vw,1.9rem)}
/* the reassurance, in the margin, immediately under the scary half of the headline */
.hero-aside{font-family:var(--f-hand);font-size:clamp(1.05rem,1.6vw,1.3rem);line-height:1.1;
  color:var(--colorado);margin:.55rem 0 0;transform:rotate(-1.4deg);transform-origin:left center}

/* price + time + the permission to fail. The three things a burned buyer looks for. */
.hero-terms{font-family:var(--f-mono);font-size:clamp(.62rem,.85vw,.72rem);letter-spacing:.04em;
  color:rgba(65,77,87,.72);margin:.9rem 0 0;max-width:none;line-height:1.6}

/* inner shadow at the pocket mouth — the depth the card slides out of */
.pocket-shadow{display:none}
html.sealed .pocket-shadow{display:block;position:absolute;left:-6%;right:-6%;bottom:50%;height:clamp(56px,9vh,84px);z-index:6;
  pointer-events:none;background:linear-gradient(to top,rgba(65,77,87,.38),rgba(65,77,87,0));
  opacity:0;transition:opacity .35s ease}
html.sealed .envelope.cutting .pocket-shadow,
html.sealed .envelope.opened:not(.done) .pocket-shadow{opacity:1}

/* staged reveal: hard shadow, then washi tape, then the highlight draws */
.hero-card>.sheet{transition:box-shadow .5s ease}
html.sealed .hero-card>.sheet{box-shadow:none}
html.sealed .envelope.lit-shadow .hero-card>.sheet{box-shadow:8px 8px 0 0 var(--ink)}
html.sealed .hero-card .tape{opacity:0;transform:rotate(-5deg) translateY(-12px) scale(.6);
  transition:opacity .4s ease, transform .45s cubic-bezier(.2,.8,.3,1.25)}
html.sealed .envelope.lit-tape .hero-card .tape{opacity:1;transform:rotate(-5deg) translateY(0) scale(1)}
html.sealed .hero-card .hl::before{transform-origin:left center;scale:0 1;transition:scale .6s cubic-bezier(.2,.7,.2,1)}
html.sealed .envelope.lit-hl .hero-card .hl::before{scale:1 1}

/* ---- the seam (the "cut here" seal — now a drag handle) ---- */
.seam{--cut:0;--cut-x:0;position:relative;display:flex;align-items:center;justify-content:center;
  height:30px;margin:.2rem 0 0;color:rgba(65,77,87,.6);cursor:grab;touch-action:none;
  -webkit-tap-highlight-color:transparent}
.seam:active{cursor:grabbing}
.seam:focus-visible{outline:3px solid var(--lazuli);outline-offset:6px;border-radius:4px}
.seam .cut-rule{position:absolute;left:0;right:0;top:50%;height:0;border-top:2.6px dashed rgba(65,77,87,.5)}
.seam .cut-torn{position:absolute;left:0;top:50%;height:0;width:calc(var(--cut)*100%);
  border-top:2.8px solid var(--ink);filter:url(#roughsm)}
.seam .cut-scissors{position:absolute;top:50%;left:calc(var(--cut-x)*100%);transform:translate(-50%,-50%);
  width:26px;height:26px;color:var(--sambas);z-index:2;transition:opacity .3s ease;will-change:left}
.seam .cut-scissors svg{display:block;width:100%;height:100%}
.seam .label{position:relative;z-index:1;background:var(--oats);padding:0 .55rem;
  font-family:var(--f-mono);text-transform:uppercase;letter-spacing:.12em;font-size:.7rem;color:rgba(65,77,87,.6);
  opacity:calc(1 - var(--cut))}
.envelope.opened .seam .cut-scissors{opacity:0}
.seam.armed .cut-scissors{animation:scisnudge 1.6s ease-in-out infinite}
.envelope.cutting .seam.armed .cut-scissors,.envelope.opened .seam .cut-scissors{animation:none}
@keyframes scisnudge{0%,100%{transform:translate(-50%,-50%)}50%{transform:translate(-50%,-50%) rotate(-13deg)}}

/* not sealed (reduced-motion / no-JS / failsafe): show the hero, mute the game */
html:not(.sealed) .cut-prompt{display:none}
html:not(.sealed) .seam{cursor:default;pointer-events:none}
html:not(.sealed) .seam .cut-scissors{display:none}

/* ---- hand-drawn "drag to cut" indicator ---- */
.cut-prompt{display:none}
html.sealed .cut-prompt{display:flex;align-items:center;gap:.55rem;justify-content:center;margin:.9rem 0 0;
  color:var(--colorado);transition:opacity .35s ease;animation:cutbob 1.7s ease-in-out infinite}
html.sealed .envelope.cutting .cut-prompt,
html.sealed .envelope.opened .cut-prompt{opacity:0;pointer-events:none;animation:none}
.cut-prompt-star{width:28px;height:28px;flex:none;fill:var(--schoolbus);stroke:var(--ink);stroke-width:.8;
  filter:url(#rough);transform:rotate(-9deg)}
.cut-prompt-text{font-size:1.55rem;transform:rotate(-2deg)}
.cut-prompt-arrow{width:92px;height:22px;color:var(--colorado);filter:url(#rough)}
@keyframes cutbob{0%,100%{transform:translateY(0)}50%{transform:translateY(6px)}}

/* ---- pre-cut comprehension anchor: the green squigglevision hook + the steady
   craft tagline, sitting ABOVE the seam. While sealed it's the only readable
   copy; on the open (html.revealed) it fades and collapses, the same way the
   seam + .cut-prompt do. Hidden entirely when the hero shows un-sealed (no cut
   to make). CSS-only — html.revealed is already set by the cut JS. ---- */
.cut-hook{display:none}
html.sealed .cut-hook{display:block;text-align:center;margin:.7rem 0 .2rem;
  transition:opacity .5s ease, visibility .5s ease, height .6s ease, margin .6s ease}
html:not(.sealed) .cut-hook{display:none}
.cut-hook-line{margin:0;color:var(--grass-deep);font-size:clamp(1.35rem,3.4vw,1.9rem);line-height:1.1;
  transform:rotate(-1.4deg);filter:url(#rough);animation:boil-rough var(--boil-ink) step-end infinite}
.cut-hook-heart{font-style:normal}
/* SEEDED sealed state: kicker = the "what is this" anchor, above the problem hook; then a real
   zine cover proves "you make things" before the visitor cuts anything. All inside .cut-hook, so
   they fade + collapse together on html.revealed. */
.cut-hook-kicker{margin:0 0 .55rem;font-family:var(--f-mono);font-weight:500;
  font-size:var(--fs-label);letter-spacing:.15em;text-transform:uppercase;color:var(--ink)}
.cut-hook-zine{position:relative;width:clamp(120px,26vw,168px);margin:1rem auto 0}
.cut-hook-zine i{display:block;width:100%;aspect-ratio:3/4;background-size:cover;background-position:center 10%;
  border:2.8px solid var(--ink);box-shadow:6px 6px 0 0 var(--ink);transform:rotate(-3deg);filter:url(#soft)}
.cut-hook-zine .chz-tab{position:absolute;right:-10px;bottom:14px;transform:rotate(4deg);
  font-family:var(--f-hand);font-size:clamp(12px,2.4vw,14px);color:var(--ink);
  background:var(--happy);border:2px solid var(--ink);padding:2px 8px 3px;filter:url(#roughsm);
  box-shadow:2px 2px 0 0 rgba(65,77,87,.5)}
html[data-tier="lite"] .cut-hook-zine i,
html[data-tier="lite"] .cut-hook-zine .chz-tab{filter:none!important}
.cut-hook-tag{margin:.4rem 0 0;font-family:var(--f-mono);font-weight:500;font-size:clamp(.82rem,1.6vw,.95rem);
  letter-spacing:.04em;color:var(--ink)}                         /* STEADY: no wobble, high-contrast ink on cream */
/* fade out the moment cutting starts — in lockstep with the "drag to cut" prompt (same triggers) */
html.sealed .envelope.cutting .cut-hook,
html.sealed .envelope.opened .cut-hook{opacity:0;visibility:hidden;pointer-events:none}
html.sealed.revealed .cut-hook{opacity:0;visibility:hidden;height:0;margin:0;overflow:hidden;pointer-events:none}
html[data-tier="lite"] .cut-hook-line{filter:none!important;animation:none!important}
/* the reveal PAYOFF — the card itself rises saying only this, then it dissolves into the real
   card content. Scoped to .hero-card, so the pile/photo-smear behind is untouched. */
.cut-payoff{display:none}
html.sealed .envelope.opened .hero-card .cut-payoff{display:flex;position:absolute;inset:0;z-index:10;
  align-items:center;justify-content:center;text-align:center;padding:1.5rem;pointer-events:none;
  background:var(--paper);animation:cardFlashOut 3s ease both}
html:not(.sealed) .hero-card .cut-payoff{display:none}
.hero-card .cut-payoff .cut-payoff-line{margin:0;color:var(--grass-deep);line-height:1.08;max-width:13ch;
  font-size:clamp(2.8rem,9vw,5.4rem)}
@keyframes cardFlashOut{0%{opacity:1}62%{opacity:1}100%{opacity:0;visibility:hidden}}
/* On a phone the card is ~1300px tall, so centering the flash put "drex means you actually do." at the
   card's midpoint — right at/below the fold, so it was never seen. Anchor it to the TOP of the card so
   it lands in the first screen as the card rises. */
@media(max-width:880px){
  html.sealed .envelope.opened .hero-card .cut-payoff{align-items:flex-start;
    padding-top:clamp(5rem,30vh,13rem)}
}

/* ---- the cut opens the whole site ---- */
/* before the cut: only the hero envelope exists — everything below is hidden,
   so the page is one clean screen. JS adds html.revealed ~2s after the card lands. */
html.sealed:not(.revealed) main > section:not(.hero),
html.sealed:not(.revealed) footer{display:none}
/* the masthead, too, only appears WITH the rest of the site post-cut. visibility
   (not display) reserves its space so it fades in without shoving the hero down. */
html.sealed .mast{opacity:0;visibility:hidden;transition:opacity .6s ease}
html.sealed.revealed .mast{opacity:1;visibility:visible}
/* once the card is out, the seam fades (so its torn line stops colliding with the
   card's shadow), then on settle it + the prompt COLLAPSE their space so the gap
   below the card closes as everything drops into place. */
html.sealed .seam,html.sealed .cut-prompt{transition:opacity .55s ease, height .6s ease, margin .6s ease}
html.sealed .envelope.opened .seam{opacity:0;pointer-events:none}
html.sealed.revealed .seam,html.sealed.revealed .cut-prompt{height:0;margin:0;overflow:hidden;pointer-events:none}

/* ---- hand-drawn "there's more" scroll cue: appears after the reveal, fades on scroll ---- */
.scroll-cue{position:fixed;left:50%;bottom:clamp(.7rem,2.4vh,1.5rem);transform:translateX(-50%);z-index:40;
  display:flex;flex-direction:column;align-items:center;gap:.3rem;
  opacity:0;pointer-events:none;transition:opacity .5s ease}
html.revealed .scroll-cue{opacity:1;animation:scrollbob 1.6s ease-in-out infinite}
html.revealed.scrolled .scroll-cue{opacity:0;animation:none}
/* paper chip: gives the scrawl its own surface so it stops colliding with the
   hero text behind the fixed cue — flat cream, torn ink border, hard offset shadow */
.scroll-cue .scrawl{font-size:1.5rem;line-height:1;color:var(--colorado);transform:rotate(-1.5deg);
  background:var(--paper);padding:.15rem .55rem .25rem;border:2.2px solid var(--ink);
  border-radius:6px;box-shadow:3px 3px 0 0 var(--ink)}
.scroll-cue svg{width:60px;height:40px;color:var(--colorado);filter:url(#rough)}
.sc-down{font-family:var(--f-hand);font-size:1.35rem;line-height:1;color:var(--colorado);transform:rotate(-2.5deg);filter:url(#rough);animation:boil-rough var(--boil-ink) step-end infinite}
html[data-tier="lite"] .sc-down{filter:none!important;animation:none!important}
/* Circle glyph (the .cmark ring from the reader's ringMark) — decorative amber motif at Circle anchor points */
.cmark{display:inline-grid;place-items:center;width:.92em;height:.92em;vertical-align:-.08em;color:var(--schoolbus)}
.cmark svg{width:100%;height:100%;display:block;overflow:visible}
.cmark circle{fill:none;stroke:currentColor;stroke-width:2.7;stroke-linecap:round;stroke-dasharray:55 9;filter:url(#rough)}
html[data-tier="lite"] .cmark circle{animation:none!important}
/* Circle glyph stamped on the hero notecard, upper-right */
.hero-cmark{position:absolute;top:clamp(10px,1.5vw,18px);right:clamp(12px,1.8vw,26px);width:clamp(40px,4.8vw,62px);height:auto;color:var(--schoolbus);z-index:3;opacity:.92}
@keyframes scrollbob{0%,100%{transform:translateX(-50%) translateY(0)}50%{transform:translateX(-50%) translateY(10px)}}

/* ---------- the reel polaroid (Instagram reel cropped to an instax) ----------
   Lives PAPERCLIPPED inside .hero-card (.hero-reel) and rides the card out of the
   envelope pocket on the cut. .reel-window is a squarish photo box that CLIPS the
   IG /embed/ iframe: IG renders a header above the video + a like/comment footer
   below; --ig-top shifts the iframe up to drop the header, --ig-ratio sizes the
   window to the video so the footer falls below the bottom edge. All three knobs
   (--ig-top / --ig-h / --ig-ratio) are set inline on the figure to re-tune in one
   place if IG changes the embed. The iframe is INTERACTIVE (IG's inline player);
   .reel-play is a decorative cue that fades on hover/focus. */

/* the instax card (base; .hero-reel overrides size + position) */
.reel-instax{position:relative;width:min(330px,86vw);margin-inline:auto;
  padding:13px 13px 0;transition:transform .18s ease}
@media(min-width:760px){.reel-instax{rotate:-1.2deg}}
/* white backing (border + hard shadow) on its own layer so it can boil without warping the video */
.reel-instax::before{content:"";position:absolute;inset:0;z-index:0;background:var(--paper);
  border:2.6px solid var(--ink);border-radius:5px;box-shadow:8px 8px 0 0 var(--ink);
  filter:url(#soft);transition:box-shadow .18s ease}
.reel-instax:hover{transform:rotate(0) translateY(-6px)}
.reel-instax:hover::before{box-shadow:11px 12px 0 0 var(--ink)}

/* the photo window — clips IG's chrome */
/* Fallback matters more than it looks: the reel is a cross-origin Instagram embed, and a
   meaningful slice of this audience (ad-blockers, privacy browsers, iOS Lockdown, EU consent
   walls) never loads it. With a slate background, a blocked embed renders the LARGEST element
   in the hero as a black void — reads as "broken site" on first paint. Paper + a visible cue
   degrades it to an empty polaroid instead, which is on-brand and reads as intentional. */
.reel-window{position:relative;z-index:1;width:100%;aspect-ratio:var(--ig-ratio,100/108);overflow:hidden;
  background:var(--oats);border:1.5px solid rgba(65,77,87,.28)}
/* --ig-zoom cover-fills the video: IG bakes pillarbox bars into the reel embed
   (content is only ~67% of the media width), so we scale the iframe up ~1.5x to
   push the bars outside the window (clipped) and fill edge-to-edge. */
.reel-ig{position:absolute;top:calc(-1 * var(--ig-top,56px));left:50%;
  transform:translateX(-50%) scale(var(--ig-zoom,1));transform-origin:50% 20%;
  width:100%;height:var(--ig-h,780px);border:0;display:block;background:transparent;pointer-events:auto}   /* interactive → ONE tap reaches IG's play button (no wasted "arm" tap). Tear still works via the caption/frame. Transparent so a blocked embed shows the .reel-window paper, not a slate void. */
.reel-window.reel-playing .reel-ig{pointer-events:auto}

/* decorative play cue — the iframe underneath takes the click (IG's inline player);
   the cue fades once you engage so it never sits over the playing video */
/* DYMO label-tape "play me" cue, tucked in the bottom-left corner so it never
   covers the playing video (fixes the double-up over IG's own controls) */
.reel-play{position:absolute;left:9px;bottom:9px;z-index:2;
  font-family:var(--f-mono);font-weight:600;text-transform:uppercase;letter-spacing:.14em;font-size:.66rem;line-height:1;
  color:#fff;background:#212c30;padding:.34em .62em .3em;border-radius:4px;transform:rotate(-3deg);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22), inset 0 -1px 0 rgba(0,0,0,.32), 2px 2px 0 rgba(0,0,0,.3);
  pointer-events:none;transition:opacity .25s ease, transform .25s ease}   /* decorative — never intercepts; the click goes straight to IG's player underneath */
.reel-window.reel-playing .reel-play{opacity:0;transform:rotate(-3deg) scale(.85);pointer-events:none}

/* the bottom lip caption */
.reel-cap{position:relative;z-index:1;display:block;font-family:var(--f-hand);text-align:center;
  padding:.7rem .3rem .85rem;margin:0;font-size:1.25rem;line-height:1.1;color:var(--ink);transform:rotate(-1deg)}
html[data-tier="lite"] .reel-instax::before{filter:none;animation:none}

/* ---- the reel paperclipped into the hero card (rides the card out of the pocket) ----
   DESKTOP (>=881px): the card narrows to the LEFT and the polaroid is LARGE on the
   RIGHT, vertically centred and OVERLAPPING the card's right edge (overlap is the look).
   It stays a child of .hero-card so it still rises out of the pocket with the card. */
/* the reel lives in .reel-stage, anchored to .envelope (NOT the card) so it never rides the
   card's rise or settle — fully decoupled in both phases. */
.reel-stage{position:absolute;left:0;right:0;z-index:4;pointer-events:none;top:calc(clamp(.7rem,1.8vw,1.4rem) - clamp(2.4rem,5.5vw,4.2rem));height:clamp(220px,32vh,330px)}
html.sealed .envelope:not(.done) .reel-stage{overflow:visible;clip-path:inset(-100vh 0 calc(100% - var(--reel-clip, clamp(220px,32vh,330px))) 0)}    /* clip at the CARD's mask line (JS-measured --reel-clip) so reel + card share ONE slit at every scale */
html.sealed .envelope.done .reel-stage{overflow:visible;clip-path:none}
.hero-reel{position:absolute;z-index:4;margin:0;pointer-events:auto;
  left:calc(clamp(420px,54%,620px) - clamp(20px,2.5vw,56px));   /* card right edge minus stick-out, re-anchored to the wider stage */
  top:calc(50% + 120px);translate:0 -50%;   /* base sits ON-SCREEN so the emerge lands here (was too high → parked off-screen before settle) */
  width:clamp(300px,34vw,440px);rotate:6.5deg;
  --reel-settle:clamp(16px,2.4vh,26px);   /* small settle pop so the emerge never parks off-screen */
  transition:transform .6s cubic-bezier(.2,.78,.28,1) .16s}   /* emerge: trails the card by ~160ms, shares the slit; NO 1.06 spring (can't fly off-screen) */
.hero-reel:hover{transform:none}               /* neutralise .reel-instax:hover lift; centring is the translate property */
.hero-reel:hover::before{box-shadow:10px 11px 0 0 var(--ink)}
/* the reel comes out of the slit SEPARATELY from the card: while sealed it sits
   DEEPER in the pocket and at a STEEPER angle; on the cut it releases ~0.22s after
   the card (which rises straight) and twists into place on its own beat. transform
   composes with the resting translate(centre) + rotate(tilt) longhands. */
html.sealed .hero-reel{transform:translateY(var(--reel-hide,150%)) rotate(-11deg)}  /* hidden fully below the slit; --reel-hide is JS-measured per scale (150% fallback) */
html.sealed .envelope.opened .hero-reel{transform:none}
/* photo SETTLE — its OWN delayed beat (~t=2770), 200ms AFTER the card settle ends. Specificity (0,5,1) beats the emerge rule (0,4,1) so it wins once revealed. */
html.sealed.revealed .envelope.opened .hero-reel{transform:translateY(var(--reel-settle));transition:transform .42s cubic-bezier(.33,1,.5,1) .12s}   /* settle: nudges down right after the card settle (revealed now fires ~800ms) */
.hero-reel .reel-cap{font-size:clamp(1rem,1.5vw,1.3rem);padding:.55rem .25rem .7rem}
@media(min-width:881px){
  .hero .paper.hero-card{width:clamp(420px,54%,620px)}   /* the card sits on the left, narrower (beats .hero .paper 97%) */
  .hero .pin{display:none}                       /* the big polaroid owns the right side now */
}
/* metal paperclip straddling the polaroid's TOP-LEFT corner onto the card (the overlap seam) */
/* washi tape (on-brand) holding the reel to the card — replaces the off-brand paperclip */
.hero-clip{position:absolute;left:50%;top:-14px;z-index:5;width:116px;height:34px;
  transform:translateX(-50%) rotate(-4deg);pointer-events:none;
  background:linear-gradient(94deg,rgba(36,150,201,.5),rgba(36,150,201,.3) 55%,rgba(36,150,201,.46)); /* lazuli washi */
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.22);filter:url(#roughsm);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 8px,#000 calc(100% - 8px),transparent);
  mask-image:linear-gradient(90deg,transparent,#000 8px,#000 calc(100% - 8px),transparent)}
.hero-clip svg{display:none}
.hero-clip::after{content:"";position:absolute;inset:0;background:repeating-linear-gradient(90deg,transparent 0 11px,rgba(255,255,255,.1) 11px 12px)}
.reel-credit{color:var(--grass-deep);text-decoration:underline;text-underline-offset:2px}
/* paperclip settles in on the EXISTING lit-tape beat (reuses the cut state machine) */
html.sealed .hero-reel .hero-clip{opacity:0;transform:translateX(-50%) translateY(-8px) rotate(-9deg) scale(.85)}
html.sealed .envelope.lit-tape .hero-reel .hero-clip{opacity:1;transform:translateX(-50%) rotate(-4deg);
  transition:opacity .4s ease, transform .45s cubic-bezier(.2,.8,.3,1.1)}

/* mobile (<=880px): card is full-bleed → stack the reel below the copy (still a card
   child, so it still rides the rise); paperclip back to top-centre */
@keyframes reel-mob-in{from{opacity:0;transform:translateY(24px)}to{opacity:1;transform:none}}
@media(max-width:880px){
  .reel-stage{display:contents;clip-path:none}   /* stage box dissolves on mobile; desktop slit mechanism inert even if a var leaks */
  html.sealed:not(.revealed) .hero-reel{display:none}   /* HIDDEN pre-cut on mobile: out of flow, invisible even on scroll */
  .hero-reel{position:static;left:auto;top:auto;translate:none;width:min(330px,86vw);margin:1.2rem auto 0;rotate:-1.2deg;transition:none}
  .hero-reel:hover{transform:none}
  html.sealed.revealed .envelope.opened .hero-reel{transform:none;animation:reel-mob-in .5s cubic-bezier(.2,.85,.3,1.08) .25s both}   /* revealed AFTER the cut: fade + slide-up, no slit choreography */
  .hero-clip{left:50%;top:-14px;transform:translateX(-50%) rotate(3deg)}
  html.sealed .hero-reel .hero-clip{transform:translateX(-50%) translateY(-10px) rotate(-4deg) scale(.7)}
  html.sealed .envelope.lit-tape .hero-reel .hero-clip{transform:translateX(-50%) rotate(3deg)}
}

/* ---------- about = dark cut-paper ---------- */
.about{padding:clamp(1rem,3vw,2rem) 0}
.about .paper>.sheet{background:var(--sambas);box-shadow:none}
/* clean (untorn) grass print-pull behind the torn sheet — reads as a real riso misregistration */
.about .paper::before{content:"";position:absolute;inset:0;z-index:0;background:var(--grass);border-radius:6px;filter:url(#torn);translate:8px 8px}  /* torn, not a machined rect — matches the hand-cut page */
.about .inner{padding:clamp(2rem,6vw,4rem)}
.about .eyebrow{color:var(--happy)}   /* warm accent on the dark sheet; Happy clears AA, School Bus is dark-ink-only per §4 */
.about h2{font-family:var(--f-slab);font-style:italic;font-weight:700;line-height:1.04;letter-spacing:-.01em;
  font-size:clamp(1.8rem,4.6vw,2.9rem);margin:.4rem 0 0;color:var(--oats);max-width:18ch}
.about h2 em{color:var(--happy)}   /* Happy ties to the hero highlighter and clears AA on dark; grass/schoolbus failed here */
.about .body{margin-top:1.4rem;max-width:56ch;display:grid;gap:1rem}
.about .body p{margin:0;color:rgba(254,246,228,.92)}
.about .body p.lead{font-family:var(--f-body);font-style:italic;font-size:clamp(1.18rem,1.8vw,1.5rem);color:var(--oats)}
.about .vals{margin-top:1.8rem;font-family:var(--f-mono);text-transform:uppercase;letter-spacing:.12em;
  font-size:.8rem;color:rgba(254,246,228,.95);line-height:1.9}
.about .vals span{white-space:nowrap}
.about .vals span:not(:last-child)::after{content:"·";color:rgba(254,246,228,.5);font-weight:700;margin:0 .6em}

/* ---------- three doors = littered postcards (.splay, NOT a grid) ---------- */
.doors{padding:clamp(1.5rem,4vw,3rem) 0 clamp(2rem,5vw,3.5rem)}
.doors .head{margin-bottom:clamp(2rem,5vw,3rem)}
.doors .head h2{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:clamp(1.8rem,6vw,3rem);
  line-height:.98;margin:.3rem 0 0;color:var(--ink);text-wrap:balance}
.splay{display:flex;flex-wrap:wrap;justify-content:center;gap:clamp(1.6rem,3vw,2.6rem);align-items:flex-start}
.card{position:relative;width:min(318px,100%)}
.card .inner{padding:clamp(1.6rem,2.6vw,2.1rem);display:flex;flex-direction:column;min-height:250px}
.card.big{width:min(410px,100%)}  /* the Circle is the primary door — unmistakably dominant */
.card.big .inner{min-height:312px}
.card h3{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:clamp(1.7rem,2.7vw,2.3rem);
  line-height:1;margin:.3rem 0 0;color:var(--ink)}
.card.big h3{font-size:clamp(2.1rem,3.2vw,2.9rem)}
.card .cap{font-family:var(--f-hand);font-size:1.15rem;color:var(--sambas);transform:rotate(-1deg);display:inline-block}
.card p{margin:.9rem 0 1.4rem;font-size:1rem;line-height:1.5;color:rgba(65,77,87,.85)}
.card .foot{margin-top:auto;display:flex;flex-direction:column;gap:.7rem}
.card .url{font-family:var(--f-mono);font-size:.74rem;letter-spacing:.06em;color:var(--sambas);text-transform:lowercase}
/* resting tilts — littered on the table; straighten + lift on hover */
.splay,.crew{overflow-x:clip}
.splay .card:nth-child(1){transform:rotate(-3deg)}
.splay .card:nth-child(2){transform:rotate(2.4deg)}
.splay .card:nth-child(3){transform:rotate(-2.2deg)}
@media(max-width:480px){.splay{padding-inline:16px} .splay .card,.crew .polaroid{transform:rotate(0)} .tape{width:92px;height:26px}}
.splay .card{transition:transform .18s ease}
.splay .card:hover{transform:rotate(0) translateY(-7px);z-index:6}
.splay .card:hover>.sheet{box-shadow:13px 14px 0 0 var(--ink)}
.card>.sheet{transition:box-shadow .18s ease}

/* ---------- how a Circle works = the 5-beat loop, named + sequenced ---------- */
.how{padding:clamp(2rem,5vw,3.5rem) 0 clamp(1.5rem,4vw,3rem)}
.how .head{margin-bottom:clamp(2.6rem,6vw,4.2rem);text-align:center}
.how .head .eyebrow{color:var(--lazuli)}
.how .head h2{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:clamp(1.8rem,6vw,3rem);
  line-height:.98;margin:.3rem 0 0;color:var(--ink);text-wrap:balance}
.how .head h2 .stop{color:var(--grass-deep)}
.how-sub{font-family:var(--f-body);font-style:italic;font-size:clamp(1.05rem,1.8vw,1.3rem);color:rgba(65,77,87,.85);max-width:42ch;margin:.85rem auto 0}
/* the loop = a Circle: 5 stations around a hand-drawn ring, arrow looping back to Gather */
/* container-query units keep the WHOLE diagram one scalable unit → the circle holds its
   proportions at every width (never overlaps), instead of collapsing to a linear stack */
/* the ring and its footnote share a stage, so the note can be parked in the dead margin beside the
   ring on desktop and simply fall underneath it on phone. */
.how-stage{position:relative;width:min(560px,94vw);margin:0 auto;padding-top:clamp(.6rem,2.6vw,1.7rem)}
.how-loop{position:relative;width:100%;aspect-ratio:1;container-type:inline-size}
.how-ring{position:absolute;inset:0;width:100%;height:100%;z-index:0;overflow:visible}
.how-center{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%) rotate(-5deg);z-index:1;
  font-family:var(--f-hand);font-size:5.6cqw;line-height:1.02;text-align:center;color:var(--colorado);opacity:.85;
  animation:how-spin 18s linear infinite}
@keyframes how-spin{from{transform:translate(-50%,-50%) rotate(0)}to{transform:translate(-50%,-50%) rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.how-center{animation:none;transform:translate(-50%,-50%) rotate(-5deg)}}
.how-loopback{display:none}   /* desktop: the ring shows the loop; this is the mobile-only loop-back cue */
.how .flow{list-style:none;margin:0;padding:0;position:absolute;inset:0;z-index:2}
/* width tuned so a side station (centre at 86%/14% on the ring) + its note stays inside the 100cqw box at every size */
.how .step{position:absolute;width:24cqw;transform:translate(-50%,-50%);text-align:center}
/* each station sits on a STICKY NOTE → the loop threads BEHIND it (contrast + no ring-through-icon) */
.how .step::before{content:"";position:absolute;inset:-2.3cqw -1.7cqw;z-index:-1;background:var(--happy);
  border:.35cqw solid var(--ink);border-radius:.7cqw;box-shadow:.72cqw .72cqw 0 0 var(--ink);filter:url(#roughsm)}
.how .step:nth-child(even)::before{filter:url(#roughsm2)}   /* vary the hand-cut edge per note */
/* the folded-up sticky corner */
@media(min-width:341px){
  .how .step::after{content:"";position:absolute;z-index:-1;right:-1.7cqw;bottom:-2.3cqw;width:0;height:0;
    border-left:3.6cqw solid transparent;border-bottom:3.6cqw solid var(--schoolbus);filter:url(#roughsm)}
  /* the three OBJECT nodes have no sticky note under them — so they get no folded corner either,
     or it floats in the ring like a stray scrap. */
  .how .step.is-clock::after,.how .step.is-globe::after,.how .step.is-think::after{display:none}
}
/* tap "every week": the words stop — and the ring takes over the spinning.
   .flow sits above the center (z2 vs z1) — let clicks fall through it except on the notes. */
.how .flow{pointer-events:none}
.how .step{pointer-events:auto}
.how-center{cursor:pointer;pointer-events:auto;padding:1.2cqw}
.how-loop.spin-swap .how-center{animation:none}
.how-loop.spin-swap .how-ring{transform-origin:50% 50%;animation:how-spin-ring 16s linear infinite}
@keyframes how-spin-ring{from{transform:rotate(0)}to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.how-loop.spin-swap .how-ring{animation:none}}
/* Four nodes, not five: Practice was already one of the four words on the clock face, so as a step
   it counted itself twice. Four lands on a clean compass at R=38 on the ring. */
.how .step:nth-child(1){top:12%;left:50%}      /* Challenge   — top (in the ring's gap) */
.how .step:nth-child(2){top:50%;left:88%}      /* Circle Time — right */
.how .step:nth-child(3){top:88%;left:50%}      /* Reflect     — bottom */
.how .step:nth-child(4){top:50%;left:12%}      /* Show & tell — left */
.how .step .n{font-family:var(--f-mono);font-weight:600;font-size:2.05cqw;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink);display:block;margin-bottom:1cqw}
.how .step .ico{width:10cqw;height:10cqw;margin:0 auto 1.3cqw;display:block}
.how .step .ico svg{width:100%;height:100%;display:block;overflow:visible}
.how .step .ico svg>*{filter:url(#roughsm)}              /* same hand-drawn boil as the collage scraps */
.how .step:nth-child(odd) .ico{transform:rotate(-4deg)}
.how .step:nth-child(even) .ico{transform:rotate(4deg)}
.how .step h3{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:4.3cqw;
  line-height:1;margin:0;color:var(--ink)}
.how .step p{font-family:var(--f-hand);font-size:3.3cqw;line-height:1.15;margin:.8cqw 0 0;color:var(--sambas)}
/* very small screens only: a legible circle can't hold 5 text stations below ~340px,
   so fall back to the unwound vertical stack with down-arrows */
@media(max-width:340px){
  .how-loop{display:flex;align-items:stretch;justify-content:center;gap:6px;width:auto;aspect-ratio:auto;margin-top:.4rem}
  .how-ring,.how-center{display:none}
  .how .flow{position:static;display:grid;grid-template-columns:1fr;gap:clamp(1.6rem,6vw,2.2rem);width:12.5rem;max-width:66vw;margin:0}
  .how .step{position:relative;transform:none;width:auto}
  .how .step::before{display:none}   /* notes are a circle-only treatment; the stack stays clean */
  .how .flow .step:nth-child(1),.how .flow .step:nth-child(2),.how .flow .step:nth-child(3),.how .flow .step:nth-child(4),.how .flow .step:nth-child(5){top:auto;left:auto}  /* unset the circular coords so the stack centers */
  .how .step .ico{width:50px;height:50px}
  .how .step p{font-size:1.02rem}
  .how .step:not(:last-child)::after{content:"";position:absolute;left:50%;bottom:calc(-0.5 * clamp(1.6rem,6vw,2.2rem) - 7px);
    transform:translateX(-50%) rotate(90deg);width:24px;height:15px;background:no-repeat center/contain
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='20' viewBox='0 0 30 20' fill='none' stroke='%23414D57' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 10 H24'/%3E%3Cpath d='M17 4 L26 10 L17 16'/%3E%3C/svg%3E");opacity:.5}
  /* loop-back: a real curved arrow hugging the stack, Share (bottom) → Gather (top) */
  .how-loopback{display:block;order:-1;flex:none;align-self:stretch;position:relative}
  .how-loopback .lb-arrow{height:100%;width:auto;display:block;overflow:visible}
  .how-loopback span{position:absolute;top:50%;right:-2px;transform:translateY(-50%) rotate(-90deg);transform-origin:center;
    white-space:nowrap;font-family:var(--f-hand);color:var(--colorado);font-size:.92rem;pointer-events:none}
}

/* ---------- the prompt card = the product, as one object ----------
   An index card pinned to the page. Two beats only: the thing to MAKE, and the thing to
   ANSWER — which is exactly what issues.workPrompt + issues.reflectionQuestion are. */
.promptcard{margin:clamp(2rem,5vw,3.2rem) auto 0;width:min(430px,92vw);text-align:center}
.pc-card{position:relative;background:var(--paper);border:2.6px solid var(--ink);border-radius:7px;
  box-shadow:9px 10px 0 0 var(--ink);padding:clamp(1.5rem,3.4vw,2rem) clamp(1.3rem,3vw,1.8rem) clamp(1.3rem,3vw,1.7rem);
  transform:rotate(-1.3deg);text-align:left;
  background-image:repeating-linear-gradient(to bottom,transparent 0 27px,rgba(65,77,87,.11) 27px 28px)}
.pc-pin{position:absolute;top:-11px;left:50%;width:19px;height:19px;margin-left:-9px;border-radius:50%;
  background:var(--colorado);border:2.4px solid var(--ink);box-shadow:2px 2px 0 0 rgba(65,77,87,.35)}
.pc-kicker{display:block;font-family:var(--f-mono);font-size:.6rem;letter-spacing:.17em;text-transform:uppercase;
  color:var(--grass-deep)}
.pc-kicker-q{color:var(--lazuli)}
.pc-do,.pc-q{font-family:var(--f-hand);line-height:1.22;margin:.35rem 0 0;color:var(--ink)}
.pc-do{font-size:clamp(1.45rem,3.1vw,1.85rem)}
.pc-q{font-size:clamp(1.15rem,2.4vw,1.4rem);color:rgba(65,77,87,.9)}
.pc-rule{display:block;height:2.2px;background:var(--ink);opacity:.18;border-radius:2px;
  margin:1.15rem 0 1.15rem;filter:url(#roughsm)}
.pc-cap{margin:.95rem 0 0;color:var(--colorado);font-size:1.12rem;transform:rotate(-1deg)}
@media(prefers-reduced-motion:reduce){.pc-card{transform:none}}

/* the "btw, that's called situated learning" beat — a torn note taped under the loop.
   Reads as an aside, never as a lecture: that's the entire reason it lands. */
.reveal-name{position:relative;isolation:isolate;width:min(560px,92vw);
  margin:clamp(4.2rem,8vw,6rem) auto clamp(2rem,4.5vw,3rem);padding:clamp(1.1rem,2.4vw,1.5rem) clamp(1rem,2.2vw,1.4rem);
  transform:rotate(-1.9deg)}
/* D · the sticky note: yellow Post-it, hand-cut edge (#soft), solid offset shadow, a peeled corner */
.reveal-name::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--happy);
  border:2.4px solid var(--ink);border-radius:5px;box-shadow:6px 8px 0 0 var(--ink);
  filter:url(#soft)}
.reveal-name::after{content:"";position:absolute;right:-3px;bottom:-4px;width:34px;height:34px;z-index:-1;
  background:linear-gradient(135deg,transparent 44%,rgba(65,77,87,.28) 45% 49%,#E4CE3F 52%);
  border-bottom-right-radius:6px;filter:url(#roughsm)}
/* DYMO TAPE. The beat is "that loop has a name" — and a label maker is the object whose entire
   purpose is giving a thing a name. So the aside marker stops being a scrawl and becomes embossed
   tape: dark strip, letters lighter than the strip (plastic whitens where it's stretched), wide
   tracking, rounded ends, stuck on at an angle over the note's torn edge. */
.rn-arrow{position:absolute;top:-1rem;left:1.1rem;z-index:1;
  font-family:var(--f-mono);font-weight:600;font-size:.78rem;letter-spacing:.22em;
  text-transform:uppercase;text-indent:.22em;                 /* balance the trailing letter-space */
  color:#FFF8EC;background:var(--coral-ink);                   /* classic Dymo: red tape, white embossed letters */
  padding:.42em .7em .38em;border-radius:5px;
  text-shadow:0 1px 0 rgba(93,18,22,.55);                      /* the raised-letter bite */
  box-shadow:2px 2px 0 0 rgba(65,77,87,.4);
  transform:rotate(-2.2deg);
  filter:url(#roughsm);animation:boil-roughsm var(--boil-paper) step-end infinite}
.reveal-name p{margin:0;font-size:clamp(.98rem,1.5vw,1.08rem);line-height:1.55;color:rgba(65,77,87,.9)}
.reveal-name b{color:var(--ink)}
.reveal-name em{font-style:italic}
.rn-link{display:inline-block;margin-top:.75rem;font-family:var(--f-mono);font-size:.74rem;
  letter-spacing:.08em;text-transform:uppercase;color:var(--grass-deep);text-decoration:underline;
  text-decoration-thickness:1.5px;text-underline-offset:3px;text-decoration-color:rgba(12,110,57,.45)}
.rn-link:hover{text-decoration-color:var(--grass-deep)}

/* ---------- THE KIT = a corkboard, not a paragraph ----------
   Was 288 words of prose nobody read. Now every tool is a pinned tag: icon + name at a glance,
   gloss on hover. Grouped by resource type, colour-coded (people are yellow).
   NOTE: this BASE layout must stay above the squigglevision retrofit further down, which strips
   these borders/backgrounds onto ::before layers so they can ride the roughen filter. Deleting it
   (as an over-eager CSS splice once did) collapses the board to a 15,000px stack. */
.kit{padding:clamp(1.9rem,4vw,2.7rem) 0}
/* the kit is now a single compact beat (heading + the funding line, no body). The head's old
   margin-bottom reserved space for a body that no longer exists — zeroing it stops the beat from
   floating in a void between the bring card and the makers board (tight group, balanced margins). */
.kit .head{margin-bottom:0;text-align:center}
.kit .head h2{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:clamp(1.8rem,5.4vw,2.9rem);
  line-height:.98;margin:.3rem 0 0;color:var(--ink)}
.kit .head h2 .stop{color:var(--grass-deep)}
.kit-sub{font-family:var(--f-body);font-style:italic;font-size:clamp(1.02rem,1.7vw,1.26rem);line-height:1.5;
  color:rgba(65,77,87,.85);max-width:52ch;margin:.85rem auto 0}
.kit-sub b{font-style:normal;color:var(--ink)}

.corkboard{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(.9rem,2vw,1.5rem);
  padding:clamp(.9rem,2vw,1.4rem)}
.cluster{position:relative;padding:.5rem .4rem 0}
.cl-tag{display:inline-block;font-family:var(--f-mono);font-size:.62rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink);padding:.28em .6em;transform:rotate(-1.5deg)}
.c-people{--c:var(--schoolbus)}
.c-virtual{--c:var(--lazuli)}
.c-material{--c:var(--colorado)}
.c-virtual .cl-tag,.c-material .cl-tag{color:var(--oats)}
.cl-line{font-family:var(--f-body);font-size:clamp(.9rem,1.35vw,1.02rem);line-height:1.35;
  color:#3B2A16;margin:.6rem 0 0;min-height:2.7em;text-shadow:0 1px 0 rgba(255,255,255,.18)}
.cl-line b{color:#241708}
.cl-line em{font-style:italic}
.cl-soon{display:block;font-family:var(--f-mono);font-size:.6rem;letter-spacing:.08em;
  color:rgba(59,42,22,.75);margin-top:.2rem}
/* base-kit vs power-ups: a dashed cut-line under each column's base pins, then the
   pool-funded unlocks as handwritten luggage-tags. Material is stamped "coming soon"
   (the pool isn't built yet — copy: "We're still building that pool"). */
.pu-div{position:relative;margin:1.15rem .1rem .9rem;border-top:2.4px dashed rgba(47,33,16,.55)}
.pu-div .pu-lab{position:absolute;top:-.7em;left:.4rem;background:var(--c,var(--schoolbus));color:#2f2110;
  font-family:var(--f-mono);font-size:.6rem;letter-spacing:.12em;text-transform:uppercase;padding:.14rem .45rem;
  transform:rotate(-2deg);box-shadow:1px 1px 0 rgba(40,26,10,.4)}
.c-virtual .pu-lab,.c-material .pu-lab{color:var(--oats)}   /* light text on the blue/red grounds */
@media(max-width:900px){
  /* single column (matches the .corkboard 1-col breakpoint): the full-width dashed cut-line
     reads as a stray rule with nothing beside it — drop it and let the POWER-UPS tab sit as a
     plain inline label above the unlocks. The dashed line only earns its keep across 3 columns. */
  .pu-div{border-top:0;margin:.7rem .1rem 0}
  .pu-div .pu-lab{position:static;display:inline-block}
}
.pu-list{display:flex;flex-wrap:wrap;justify-content:center;gap:.9rem .8rem;padding:.9rem .1rem 0;position:relative}
.pu-tag{position:relative;display:inline-flex;align-items:center;font-family:var(--f-hand);font-size:.94rem;
  color:#2f2110;background:transparent;border:0;padding:.4rem .72rem .4rem .46rem;isolation:isolate}
.pu-tag::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--paper);
  border:1.9px solid var(--ink);filter:url(#roughsm);box-shadow:2px 3px 0 rgba(40,26,10,.42)}
/* prefix = the Circle ring glyph (amber) with a plus in the column's own colour */
.pu-tag .pu-ic{display:inline-grid;place-items:center;margin-right:.4rem;vertical-align:-.34em}
.pu-tag .pu-ic .cmark{grid-area:1/1;width:1.75em;height:1.75em;color:var(--schoolbus)}
.pu-tag .pu-ic .pu-x{grid-area:1/1;font-family:var(--f-slab);font-weight:800;font-size:1.05em;line-height:1;
  color:var(--c,var(--grass-deep))}
/* material = coming soon: greyscale the base cards + a text tag, plus the rough stamp over them */
.c-material{position:relative}
.c-material .pins .pinit{filter:grayscale(.92);opacity:.7}
.pu-list .pu-tag{filter:grayscale(.92);opacity:.72}   /* every power-up unlock is coming-soon */
.cl-soon2{font-family:var(--f-mono);font-size:.58rem;letter-spacing:.08em;text-transform:uppercase;
  font-weight:700;color:var(--colorado)}
/* every cluster: the coming-soon stamp overlays its OWN power-ups list (pu-list is position:relative),
   centered over the now-centered tags. Material's base pins already read coming-soon via greyscale +
   the inline "(coming soon)" tag, so the stamp belongs on the power-ups here too, same as the rest. */
.pu-stampwrap{position:absolute;inset:0;display:grid;place-items:center;z-index:6;pointer-events:none}
.pu-stamp2{font-family:var(--f-mono);font-weight:700;font-size:1.02rem;letter-spacing:.16em;
  text-transform:uppercase;color:rgba(196,44,26,.62);border:3px solid rgba(196,44,26,.58);border-radius:7px;
  padding:.22rem .6rem;transform:rotate(-9deg);filter:url(#roughsm);white-space:nowrap}

.pins{list-style:none;margin:.9rem 0 0;padding:0 0 .6rem;display:flex;flex-wrap:wrap;
  justify-content:center;align-items:flex-start;gap:.55rem .5rem}
.pinit{position:static;width:clamp(112px,11.5vw,146px);transform:rotate(var(--r,0deg));
  padding:.5rem .45rem .45rem;text-align:center;cursor:default;
  transition:transform .16s ease, box-shadow .16s ease}
.pinit:nth-child(2n){margin-top:.85rem}
.pinit:nth-child(3n){margin-top:.35rem}
.pinit:hover,.pinit:focus-within{transform:rotate(0) translateY(-5px) scale(1.04);z-index:4}
.pin{position:absolute;top:-7px;left:50%;margin-left:-6px;width:12px;height:12px;border-radius:50%;
  background:var(--c,var(--colorado));border:2px solid var(--ink);
  box-shadow:1px 1px 0 0 rgba(40,26,10,.5)}
.pinic{display:block;width:clamp(28px,3.2vw,36px);height:clamp(28px,3.2vw,36px);margin:.15rem auto .3rem}
.pinit b{display:block;font-family:var(--f-slab);font-style:italic;font-weight:700;
  font-size:clamp(.74rem,1vw,.84rem);line-height:1.15;color:var(--ink)}
/* The gloss used to be a hover reveal — which meant the corkboard read as fourteen bare labels
   and the actual explanation was invisible to anyone not fishing for it (and to every screenshot).
   The tags are short; just show them. Hover now only lifts the tag off the board. */
.pinit i{display:block;font-family:var(--f-hand);font-style:normal;font-size:.82rem;line-height:1.15;
  color:var(--colorado);margin-top:.25rem}
@media(max-width:900px){
  .corkboard{grid-template-columns:1fr;gap:1.6rem}
  .pins{height:auto}
  .cl-line{min-height:0}
}
@media(prefers-reduced-motion:reduce){.pinit{transition:none}}

/* ---------- the long game = durability, drawn ----------
   One circle's own shelf, 001 to 012, each spine a little taller. The growth IS the argument:
   these are not strangers cycling through, they're the same people getting good together. */
.longgame{padding:clamp(1.8rem,4.5vw,3rem) 0 clamp(1.2rem,3vw,2rem)}
.longgame .head{margin-bottom:clamp(1.6rem,3.6vw,2.4rem);text-align:center}
.longgame .head h2{font-family:var(--f-slab);font-style:italic;font-weight:700;
  font-size:clamp(1.7rem,4.8vw,2.7rem);line-height:1;margin:.3rem 0 0;color:var(--ink);text-wrap:balance}
.longgame .head h2 .stop{color:var(--grass-deep)}
.lg-sub{font-family:var(--f-body);font-style:italic;font-size:clamp(1.02rem,1.7vw,1.24rem);line-height:1.5;
  color:rgba(65,77,87,.85);max-width:50ch;margin:.85rem auto 0}

.shelf{margin:clamp(1.4rem,3vw,2.2rem) auto 0;width:min(760px,94vw)}
.spines{list-style:none;margin:0;padding:0;display:flex;align-items:flex-end;justify-content:center;
  gap:clamp(3px,.6vw,7px);height:clamp(120px,15vw,175px)}
/* These must read as ZINE SPINES ON A SHELF, not as bars on a chart — a chart implies the group
   is growing, and the whole point is that it doesn't: the same people get better. So: uneven
   widths (books aren't a histogram), head/tail bands like printed spines, and one leaning. */
.spine{position:relative;flex:0 0 auto;width:var(--w,30px);height:var(--h,50%);
  border-radius:2px 2px 0 0;transition:transform .16s ease}
.spine::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--c,var(--lazuli));
  border:2.4px solid var(--ink);border-radius:2px 2px 0 0;
  filter:url(#roughsm)}
/* the printed bands near the head and tail of a spine */
.spine::after{content:"";position:absolute;left:16%;right:16%;top:9px;height:2px;
  background:rgba(0,0,0,.3);box-shadow:0 5px 0 0 rgba(0,0,0,.22);border-radius:2px}
.spine:last-child{transform:rotate(6deg);transform-origin:bottom left}   /* the leaner */
.spine:last-child:hover{transform:rotate(6deg) translateY(-6px)}
.spine{position:relative;isolation:isolate}
.spine:nth-child(even)::before{animation-delay:-.6s}
.spine:nth-child(3n)::before{animation-delay:-1.15s}
.spine:hover{transform:translateY(-6px)}
.sp-n{position:absolute;bottom:.5rem;left:50%;transform:translateX(-50%) rotate(-90deg);
  transform-origin:center;font-family:var(--f-mono);font-size:.56rem;letter-spacing:.1em;
  color:var(--oats);white-space:nowrap}
.spine:nth-child(2) .sp-n,.spine:nth-child(5) .sp-n,.spine:nth-child(8) .sp-n,
.spine:nth-child(11) .sp-n{color:var(--ink)}      /* yellow spines need ink numerals */

/* the shelf they stand on — a drawn plank, not a rule */
.shelf-rule{height:5px;border-radius:3px;background:var(--ink);filter:url(#rough)}
.shelf-ends{display:flex;justify-content:space-between;gap:1rem;margin-top:.85rem}
.se-a,.se-b{font-size:1.05rem;line-height:1.25;color:var(--sambas);max-width:20ch}
.se-a{text-align:left;transform:rotate(-1.2deg)}
.se-b{text-align:right;transform:rotate(1.2deg);color:var(--grass-deep)}
.se-a b,.se-b b{display:block;font-family:var(--f-hand);font-size:1.18rem;color:var(--ink)}
.se-b b{color:var(--grass-deep)}
@media(prefers-reduced-motion:reduce){.spine{transition:none}}
/* three real issues under the shelf, then the reward line */
.lg-picks{display:flex;flex-wrap:wrap;justify-content:center;align-items:flex-end;gap:clamp(1rem,3.5vw,2.2rem);max-width:600px;margin:clamp(2rem,5vw,3.4rem) auto 0}
.lg-pick{margin:0;width:min(30%,164px);transform:rotate(var(--r,0deg))}
.lg-pick img{display:block;width:100%;height:auto;background:var(--paper);border:3px solid var(--ink);border-radius:2px;box-shadow:4px 6px 0 0 rgba(20,24,28,.14)}
.lg-pick figcaption{margin-top:.55rem;text-align:center;font-family:var(--f-hand);font-size:1.06rem;color:var(--ink-soft)}
.lg-earn{max-width:26ch;margin:clamp(1.7rem,4vw,2.6rem) auto 0;text-align:center;font-family:var(--f-hand);font-size:clamp(1.25rem,2.7vw,1.75rem);line-height:1.2;color:var(--sambas)}
.lg-earn b{color:var(--grass-deep)}
/* moved zine proof (featured pair) + small book examples inside #long-game */
.longgame .zine-pair.lg-feature{display:flex;justify-content:center;margin:clamp(1.6rem,4vw,2.6rem) auto 0}
.lg-books{display:flex;flex-wrap:wrap;justify-content:center;align-items:flex-end;gap:clamp(1.2rem,3.5vw,2.4rem);margin:clamp(1.4rem,3.5vw,2.4rem) auto 0}
.lg-books .zpola.zbook{width:clamp(92px,12vw,120px);margin:0}
.lg-books .zpola{transition:transform .18s ease, box-shadow .18s ease}
.lg-books .zpola:hover,.lg-books .zpola:focus-visible{transform:translateY(-6px) scale(1.05);z-index:5}
@media(prefers-reduced-motion:reduce){.lg-books .zpola{transition:none}.lg-books .zpola:hover{transform:none}}
.lg-close{max-width:32ch;margin:clamp(1.5rem,3.5vw,2.4rem) auto 0;text-align:center;font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:clamp(1.2rem,2.5vw,1.7rem);line-height:1.15;color:var(--ink)}
.lg-close b{color:var(--grass-deep)}
/* twelve fixed-width spines sum to ~391px + gaps, which overflows a 390px phone. Scale the
   whole shelf down rather than dropping issues — the full run of twelve IS the argument. */
@media(max-width:560px){
  .spines{gap:2px;height:clamp(96px,26vw,130px)}
  .spine{width:calc(var(--w,30px) * .62)}
  .spine::after{top:6px;box-shadow:0 4px 0 0 rgba(0,0,0,.22)}
  .sp-n{display:none}
}
/* the widening: learning is the mechanism, not the goal */
.lg-punch{max-width:54ch;margin:clamp(2rem,4vw,2.8rem) auto 0;text-align:center;
  font-family:var(--f-slab);font-style:italic;font-weight:700;
  font-size:clamp(1.15rem,2.3vw,1.5rem);line-height:1.28;color:var(--ink)}
.lg-punch em{font-style:italic;color:var(--colorado)}
.lg-punch b{color:var(--grass-deep)}
.lg-punch span{display:block;margin-top:.6rem;font-family:var(--f-body);font-style:italic;
  font-weight:400;font-size:clamp(.98rem,1.5vw,1.08rem);line-height:1.5;color:rgba(65,77,87,.8)}

/* the horizon: the far rung above a zine. Quieter than the punch, set off by a dotted rule so it
   reads as "and later…" rather than competing with the emotional close above it. */
.lg-horizon{max-width:50ch;margin:clamp(1.6rem,3.4vw,2.2rem) auto 0;padding-top:clamp(1.3rem,2.8vw,1.8rem);
  text-align:center;font-family:var(--f-body);font-size:clamp(1rem,1.6vw,1.14rem);line-height:1.55;
  color:rgba(65,77,87,.85);position:relative}
.lg-horizon::before{content:"";position:absolute;top:0;left:50%;transform:translateX(-50%);
  width:min(220px,60%);height:0;border-top:2.6px dotted var(--sambas);opacity:.5}
.lg-horizon b{font-family:var(--f-slab);font-style:italic;font-weight:700;color:var(--grass-deep)}
.lg-horizon-k{display:block;margin-bottom:.5rem;color:var(--colorado);font-size:1.15rem;
  transform:rotate(-1.2deg)}

/* ---------- gifts = the range. Torn tags, littered, deliberately unranked ---------- */
.gifts{padding:clamp(1.6rem,4vw,3rem) 0 clamp(1.2rem,3vw,2.2rem)}
.gifts .head{margin-bottom:clamp(1.5rem,3.6vw,2.2rem);text-align:center}
.gifts .head h2{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:clamp(1.7rem,4.6vw,2.6rem);
  line-height:1.02;margin:.3rem auto 0;color:var(--ink);max-width:22ch;text-wrap:balance}
.gifts .head h2 .stop{color:var(--grass-deep)}
.gifts-sub{font-family:var(--f-body);font-style:italic;font-size:clamp(1rem,1.7vw,1.24rem);line-height:1.5;
  color:rgba(65,77,87,.85);max-width:44ch;margin:.85rem auto 0}
.gift-pile{list-style:none;margin:0 auto;padding:0;display:flex;flex-wrap:wrap;justify-content:center;
  align-items:center;gap:.6rem .55rem;max-width:68ch}
/* --fg lets the light tags (schoolbus/happy) carry ink text — cream on yellow fails AA */
.gift-pile li{transform:rotate(var(--r,0deg));font-family:var(--f-mono);font-size:clamp(.78rem,1.3vw,.92rem);
  letter-spacing:.04em;color:var(--fg,var(--oats));background:var(--c,var(--ink));
  border:2.2px solid var(--ink);border-radius:5px;padding:.4em .75em;
  box-shadow:3px 3px 0 0 var(--ink);white-space:nowrap;transition:transform .16s ease}
.gift-pile li:hover{transform:rotate(0) translateY(-3px)}
.gifts-foot{text-align:center;margin:clamp(1.1rem,2.6vw,1.6rem) 0 0;color:var(--colorado);font-size:1.25rem}
@media(prefers-reduced-motion:reduce){.gift-pile li{transition:none}}

/* ---------- the CRAFTBOARD: the range as instant photos pinned to cork. Chip colour -> label ink
   + pushpin; photo stays neutral so the accent lives on pin + label. ---------- */
.craftboard{position:relative;isolation:isolate;margin:clamp(1.2rem,3vw,1.9rem) auto 0;
  max-width:940px;padding:clamp(1rem,3vw,2rem) clamp(.6rem,2vw,1.3rem);border-radius:9px;
  display:flex;flex-wrap:wrap;justify-content:center;align-items:flex-start;
  gap:clamp(.55rem,1.5vw,1.05rem) clamp(.4rem,1.2vw,.85rem)}
/* THE corkboard, ONE definition shared by every board on the page (craft / makers / kit): the app's
   own cork texture (pulled from a live Circle wall) — warm tan ground, six offset radial speckle
   layers for fleck grain, a top-lit vignette. Radial-gradients here are the pointillist TEXTURE
   technique, not a slick gradient fill. Every board wears the SAME fill + the SAME hand-drawn torn
   edge (#torn) so no board is a dead-straight rectangle. */
:root{
  --cork-fill:
    radial-gradient(170% 105% at 50% 8%, rgba(255,244,214,.22) 0, rgba(255,244,214,.05) 42%, rgba(120,85,40,.05) 78%, rgba(90,60,25,.1) 100%),
    radial-gradient(circle at 18% 26%, rgba(120,80,40,.22) 0 2px, transparent 3px) 0 0/43px 59px,
    radial-gradient(circle at 63% 58%, rgba(150,105,55,.2) 0 2.5px, transparent 3px) 0 0/71px 67px,
    radial-gradient(circle at 41% 82%, rgba(105,70,35,.18) 0 2px, transparent 3px) 0 0/53px 83px,
    radial-gradient(circle at 84% 13%, rgba(130,90,45,.16) 0 1.5px, transparent 2.5px) 0 0/37px 97px,
    radial-gradient(circle at 7% 67%, rgba(110,75,38,.18) 0 2px, transparent 3px) 0 0/61px 47px,
    radial-gradient(circle at 55% 34%, rgba(140,98,52,.14) 0 1.5px, transparent 2.5px) 0 0/89px 73px,
    rgb(220,196,154);
}
.craftboard::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:8px;
  background:var(--cork-fill);
  border:3px solid var(--ink);box-shadow:8px 8px 0 0 var(--ink),inset 0 0 40px rgba(90,60,25,.28);
  filter:url(#torn)}
html[data-tier="lite"] .craftboard::before{filter:none;animation:none}

/* photography + penmanship tiles link to their real Circle postcard in #proof. display:contents =
   the anchor emits no box, so the tile lays out and hovers exactly as before (zero visual change). */
.craft-a{display:contents;color:inherit;text-decoration:none}
.craft-a:focus-visible .craft{outline:3px solid var(--lazuli);outline-offset:4px;border-radius:4px}
.craft{position:relative;margin:0;width:clamp(92px,10.5vw,122px);padding:7px 7px 0;
  transform:rotate(var(--r,0deg));transition:transform .17s ease}
.craft::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--paper);
  border:2.2px solid var(--ink);border-radius:3px;box-shadow:3px 4px 0 0 rgba(40,26,10,.5);
  filter:url(#roughsm)}
.craft:nth-child(even)::before{animation-delay:-.6s}
.craft:nth-child(3n)::before{animation-delay:-1.15s}
.craft:hover{transform:rotate(0) translateY(-5px) scale(1.05);z-index:5}
.craft:hover::before{box-shadow:5px 7px 0 0 rgba(40,26,10,.55)}
/* a little vertical scatter so the board reads pinned-by-hand, not a spreadsheet */
.craft:nth-child(3n){margin-top:clamp(.5rem,1.6vw,1.15rem)}
.craft:nth-child(5n){margin-top:clamp(.85rem,2.2vw,1.55rem)}

/* the pushpin — the chip's colour, domed with a little highlight */
.cr-pin{position:absolute;top:-7px;left:50%;margin-left:-6.5px;width:13px;height:13px;border-radius:50%;
  background:var(--c,var(--colorado));border:2px solid var(--ink);z-index:2;
  box-shadow:1px 2px 0 0 rgba(40,26,10,.5)}
.cr-pin::after{content:"";position:absolute;top:2px;left:2.4px;width:3.6px;height:3.6px;border-radius:50%;
  background:rgba(255,255,255,.65)}

/* the "photo": neutral ground + the craft's line-icon. Swap to a real photo by setting
   background-image on .cr-ph and adding .has-photo (the icon steps aside). */
.cr-ph{position:relative;display:grid;place-items:center;width:100%;aspect-ratio:1/1;overflow:hidden;
  background:#EDE4CF;border:2px solid var(--ink);color:rgba(65,77,87,.5);
  background-size:cover;background-position:center}
.cr-ph.has-photo .cr-ico{display:none}
.cr-ico{width:52%;height:52%;display:block}

/* the caption strip — handwritten, inked in the chip's colour (deep gold for the yellow ones) */
.cr-cap{padding:.34rem .18rem .42rem;text-align:center;font-family:var(--f-hand);font-style:normal;
  font-size:clamp(.84rem,1.5vw,1rem);line-height:1.08;color:var(--label,var(--c,var(--ink)))}
@media(prefers-reduced-motion:reduce){.craft{transition:none}}
/* mobile: a tidy 3-up grid instead of an 18-tall single column, scatter off so it stays compact */
@media(max-width:560px){
  .craftboard{padding:.85rem .5rem .95rem;gap:.55rem .4rem;max-width:none}
  .craft{width:30%;min-width:0;margin-top:0!important}
  .cr-cap{font-size:.72rem;padding:.28rem .1rem .34rem}
}

/* ---------- why not a group chat = the objection, answered side by side ----------
   The chat column is deliberately the drab one (desaturated, tilted the "wrong"
   way); the Circle column carries the grass accent. The kicker is the payload. */
.versus{padding:clamp(1.5rem,4vw,3rem) 0 clamp(2rem,5vw,3.5rem)}
.versus .head{margin-bottom:clamp(1.8rem,4.5vw,2.6rem);text-align:center}
.versus .head h2{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:clamp(1.8rem,6vw,3rem);
  line-height:.98;margin:.3rem 0 0;color:var(--ink);text-wrap:balance}
.versus .head h2 .stop{color:var(--grass-deep)}
.vs-sub{font-family:var(--f-body);font-style:italic;font-size:clamp(1.05rem,1.8vw,1.3rem);line-height:1.5;
  color:rgba(65,77,87,.85);max-width:40ch;margin:.9rem auto 0}

.vs-pair{display:flex;flex-wrap:wrap;justify-content:center;align-items:stretch;gap:clamp(1.4rem,3.4vw,2.6rem)}
.vs-card{position:relative;width:min(380px,100%);transition:transform .18s ease}
.vs-card.vs-chat{transform:rotate(-1.6deg)}
.vs-card.vs-circle{transform:rotate(1.6deg)}
.vs-card:hover{transform:rotate(0) translateY(-6px);z-index:5}
.vs-card .paper{height:100%}
/* the chat column reads greyed-out — the life has gone out of it */
.vs-card.vs-chat .inner{color:rgba(65,77,87,.62)}
.vs-card.vs-chat>.paper{filter:saturate(.35)}

.vs-tab{position:absolute;z-index:4;top:-13px;left:50%;transform:translateX(-50%) rotate(-2deg);
  font-family:var(--f-mono);font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--oats);border-radius:4px;padding:.32em .7em;white-space:nowrap;background:var(--ink)}
.vs-tab-glad{background:var(--grass-deep)}

/* the dead group chat, drawn. Reads in two seconds; a bullet list took twelve. */
.chatmock{background:var(--paper);border:2.6px solid var(--ink);border-radius:8px;
  box-shadow:7px 8px 0 0 var(--ink);padding:.9rem .8rem 1rem;display:flex;flex-direction:column;gap:.42rem;
  background-image:repeating-linear-gradient(to bottom,transparent 0 25px,rgba(65,77,87,.05) 25px 26px)}
.ch-day{align-self:center;font-family:var(--f-mono);font-size:.56rem;letter-spacing:.16em;
  color:rgba(65,77,87,.5);margin:.15rem 0}
.bub{max-width:82%;font-size:.92rem;line-height:1.35;padding:.45em .7em;border:2.2px solid var(--ink);
  border-radius:12px;margin:0}
.bub em{font-style:italic}
.bub.them{align-self:flex-start;background:var(--oats);border-bottom-left-radius:3px}
.bub.me{align-self:flex-end;background:var(--lazuli);color:var(--oats);border-bottom-right-radius:3px}
/* the silence is the punchline, so give it room */
.ch-gap{display:flex;align-items:center;gap:.55rem;margin:.7rem 0;font-family:var(--f-hand);
  font-size:.95rem;color:var(--colorado);white-space:nowrap}
.ch-gap i{flex:1;height:2px;background:var(--colorado);opacity:.35;border-radius:2px}
.ch-typing{align-self:flex-start;display:flex;gap:4px;padding:.5em .7em;background:var(--oats);
  border:2.2px solid var(--ink);border-radius:12px;border-bottom-left-radius:3px;opacity:.55}
.ch-typing i{width:6px;height:6px;border-radius:50%;background:var(--ink);opacity:.45}

/* the circle's answer: a challenge, an arrow, a finished thing */
.circlemock{display:flex;flex-direction:column;align-items:center;gap:.5rem;
  background:var(--paper);border:2.6px solid var(--ink);border-radius:8px;
  box-shadow:7px 8px 0 0 var(--ink);padding:1.1rem .9rem 1.2rem}
.cm-note{position:relative;width:100%;background:var(--oats);border:2.4px solid var(--ink);border-radius:6px;
  padding:.9rem .8rem .7rem;transform:rotate(-1.2deg);
  background-image:repeating-linear-gradient(to bottom,transparent 0 22px,rgba(65,77,87,.09) 22px 23px)}
.cm-pin{position:absolute;top:-8px;left:50%;margin-left:-7px;width:14px;height:14px;border-radius:50%;
  background:var(--colorado);border:2.2px solid var(--ink)}
.cm-kick{display:block;font-family:var(--f-mono);font-size:.56rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--grass-deep)}
.cm-do{font-family:var(--f-hand);font-size:clamp(1.05rem,2vw,1.28rem);line-height:1.2;margin:.25rem 0 0;color:var(--ink)}
.cm-due{display:inline-block;margin-top:.45rem;font-family:var(--f-mono);font-size:.58rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--oats);background:var(--colorado);border-radius:3px;padding:.2em .45em}
.cm-arrow{transform:rotate(90deg);margin:.15rem 0}
.cm-arrow svg{width:64px;height:28px;display:block}
/* the cards carry a hard offset shadow, so a bare figcaption collides with it */
.vs-card .cap{display:block;font-family:var(--f-hand);font-size:1.08rem;color:var(--sambas);
  text-align:center;margin:1.35rem auto 0;transform:rotate(-1deg);max-width:26ch}
.vs-card.vs-circle .cap{color:var(--grass-deep)}
.cm-out{display:flex;flex-direction:column;align-items:center;gap:.35rem;text-align:center}
.cm-zine{width:clamp(56px,7vw,70px);height:auto;filter:drop-shadow(3px 4px 0 rgba(65,77,87,.55))}
.cm-out b{font-family:var(--f-slab);font-style:italic;font-size:.88rem;color:var(--grass-deep);line-height:1.2}

.vs-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.95rem}
.vs-list li{position:relative;padding-left:1.9rem;font-size:clamp(.98rem,1.5vw,1.06rem);line-height:1.5}
.vs-list em{font-style:italic}
.vs-mark{position:absolute;left:0;top:.08em;width:1.25rem;height:1.25rem;display:grid;place-items:center;
  font-family:var(--f-slab);font-weight:700;line-height:1}
.vs-x{color:var(--colorado);font-size:1.35rem}
.vs-c{color:var(--grass-deep)}
.vs-c svg{width:1.05rem;height:1.05rem}

.vs-kicker{margin:clamp(1.8rem,4vw,2.6rem) auto 0;text-align:center;max-width:52ch;
  font-family:var(--f-body);font-size:clamp(1.05rem,1.9vw,1.32rem);line-height:1.55;color:rgba(65,77,87,.9)}
.vs-kicker em{font-style:italic}
.vs-kicker b{display:inline-block;margin-top:.5rem;font-family:var(--f-slab);font-style:italic;font-weight:700;
  font-size:clamp(1.2rem,2.6vw,1.7rem);line-height:1.18;color:var(--ink);text-wrap:balance}
.vs-kicker .stop{color:var(--grass-deep)}
@media(max-width:480px){.vs-card.vs-chat,.vs-card.vs-circle{transform:rotate(0)}}
/* the other two comparisons people arrive with — a course, and a community tool */
.vs-also{list-style:none;margin:clamp(1.6rem,3.4vw,2.2rem) auto 0;padding:0;max-width:56ch;
  display:flex;flex-direction:column;gap:.6rem;text-align:center}
.vs-also li{font-size:clamp(.98rem,1.5vw,1.08rem);line-height:1.5;color:rgba(65,77,87,.7)}
.vs-also li b{color:var(--ink)}
.vs-also li:last-child{color:rgba(65,77,87,.92);margin-top:.35rem}
.vs-also li:last-child b{color:var(--grass-deep)}

/* ---------- the pile = MEET YOUR MAKERS, folded under the hand/bot demo ----------
   Same card shape as .zine-pair, shrunk and littered. The two big ones teach HOW a zine gets
   made; the pile underneath is the quiet proof that real circles actually do it. Keeping them
   in one section means the evidence never reads as a separate marketing claim. */
.exemplar{max-width:56ch;margin:clamp(1.8rem,3.6vw,2.4rem) auto 0;text-align:center;
  font-family:var(--f-body);font-size:clamp(.98rem,1.5vw,1.08rem);line-height:1.55;
  color:rgba(65,77,87,.78)}
.exemplar b{color:var(--ink)}
/* the earn line trails the exemplar as a follow-on, not a louder headline: same body weight as its
   parent, with only the payoff words in grass-deep so the unlock still pops without out-shouting
   "a portfolio you never meant to build" above it. */
.exemplar-earn{margin-top:clamp(.55rem,1.3vw,.85rem);color:rgba(65,77,87,.82);font-family:var(--f-body);
  font-style:italic;font-weight:400;font-size:clamp(.98rem,1.5vw,1.08rem);line-height:1.5}
.exemplar-earn b{color:var(--grass-deep);font-weight:700}
.pc-cap2{display:block;margin-top:.3rem;font-size:.92rem;color:var(--sambas);line-height:1.3}
.pc-cap2 em{font-style:italic}
.pile-lead{text-align:center;margin:clamp(1.6rem,3.4vw,2.2rem) 0 clamp(1rem,2.4vw,1.5rem);
  color:var(--colorado);font-size:1.2rem;transform:rotate(-1deg)}
/* The work is the whole point of this section, so give it a wider track than the 1150px .wrap —
   at 1038px inner the zines were shrunk to thumbnails to fit three across. */
#zine .wrap{max-width:1500px;padding-inline:clamp(1rem,2.2vw,1.75rem)}
/* The gutter rails are pinned to the 1150px column (left: calc(50vw - 601px)). #zine runs a wider
   1500px track, so its scraps land ON the artwork — they were appearing inside the maker polaroids.
   The board and the pile are decoration enough; drop the collage here. */
#zine .cg-collage{display:none}

/* Empty slots ("on the press", "photo soon") sat on the slate photo background, which at
   thumbnail size passed but at full size reads as a dead black rectangle — the same failure the
   hero reel had. A waiting slot should look like a blank page, not a void. */
.zines .zpola .ph:has(.bot-ico){background:var(--oats);
  box-shadow:inset 0 0 0 2.4px rgba(65,77,87,.22)}
.zines .zpola .ph:has(.bot-ico) .soon-stamp{color:var(--colorado);border-color:var(--colorado)}

/* THE PILE — three real circles. Blurbs and issue names removed (the tab already names the
   circle, and the work should do the talking), which frees the height to make the artefacts big.
   Grid, not flex: three equal columns means the polaroids can be sized as a % of the card and
   grow with the viewport instead of being pinned to a clamp that was tuned for a narrower track. */
.pile-lead{text-align:center;margin:clamp(1.6rem,3.4vw,2.2rem) 0 clamp(1rem,2.4vw,1.5rem);
  color:var(--colorado);font-size:1.2rem;transform:rotate(-1deg)}
.zine-pile{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(.6rem,1.2vw,1rem);
  align-items:start;justify-items:center}
.zine-pile .zine-card{width:100%;min-width:0;margin-inline:0}
/* The duo must sum to <= 100% of the card or it escapes the grid cell and pushes the page wide.
   The -8% tuck was tuned when these were thumbnails; at full size the zine (66%) sliced ~55px off
   the photo (40%) and both read as CLIPPED rather than tucked. Bring the two objects closer in
   size and barely overlap them, so each is legible as a whole thing: 46 + 58 - 4 = 100%. */
.zine-pile .zine-duo{justify-content:center}
.zine-pile .zpola.zbook{width:58%}
.zine-pile .zpola{width:46%}
.zine-pile .zine-duo .zpola:nth-child(2){margin-left:-4%;margin-top:6%}
/* the base rule stacks the maker photo ON TOP (z-index 2), which was fine at thumbnail size but now
   slices the zine's cover text. The artefact is the point of this section — put the zine in front
   and let the photo tuck behind it. */
.zine-pile .zine-duo .zpola:nth-child(1){z-index:1}
.zine-pile .zine-duo .zpola:nth-child(2){z-index:3}

/* the invite line under the pile — replaces the old empty "your Circle?" card, so the pile can be
   three real circles instead of two and a blank. */
.pile-cta{text-align:center;margin:clamp(1.6rem,3.2vw,2.2rem) auto 0;max-width:46ch;
  font-family:var(--f-body);font-style:italic;font-size:clamp(1.02rem,1.6vw,1.18rem);
  color:rgba(65,77,87,.8)}
.pile-cta a{font-style:normal;font-family:var(--f-mono);font-size:.82rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--grass-deep);text-decoration:underline;
  text-decoration-thickness:1.5px;text-underline-offset:3px;text-decoration-color:rgba(12,110,57,.45);
  white-space:nowrap}
.pile-cta a:hover{text-decoration-color:var(--grass-deep)}
/* The pile reuses .hand/.bot purely for rotation, but those classes also drive tab colour in the
   main pair (.bot = lazuli, default = ink). So the pile's tabs came out grey/blue by accident,
   which reads as a distinction that means nothing. Give each circle its own accent, deliberately. */
.zine-pile .zine-tab{font-size:.62rem;background:transparent;color:var(--oats)}
.zine-pile .zine-card:nth-child(1) .zine-tab{--tabbg:var(--colorado)}
.zine-pile .zine-card:nth-child(2) .zine-tab{--tabbg:var(--lazuli)}
.zine-pile .zine-card:nth-child(3) .zine-tab{--tabbg:var(--grass-deep)}
@media(max-width:820px){
  .zine-pile{grid-template-columns:1fr;gap:1.6rem}
  .zine-pile .zine-card{max-width:420px}
}

/* ---------- THE MAKER BOARD = vicarious experience, pinned ----------
   A polaroid is a photo plus a caption strip; the strip is where the handwritten quote lives.
   All eleven makers visible at once: the repetition is the argument, and no one waits 6s to read
   the second quote. Masonry columns so nothing orphans and it reflows 4 -> 3 -> 2 -> 1. */
.makerboard{position:relative;isolation:isolate;margin:clamp(2rem,4.4vw,3rem) auto 0;
  padding:clamp(1.8rem,3vw,2.6rem) clamp(1.2rem,2.4vw,2rem)}
.makerboard::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:8px;
  background:var(--cork-fill);
  border:3px solid var(--ink);
  box-shadow:8px 8px 0 0 var(--ink), inset 0 0 40px rgba(90,60,25,.28);
  filter:url(#torn)}
html[data-tier="lite"] .makerboard::before{filter:none;animation:none}

/* the question they were all answering — without it the quotes are just nice words */
.mb-head{text-align:center;margin:0 0 clamp(1.2rem,2.4vw,1.7rem)}
.mb-k{display:block;font-family:var(--f-mono);font-size:.56rem;letter-spacing:.16em;
  text-transform:uppercase;color:#5A3E1C;margin-bottom:.25rem}
.mb-q{margin:0;font-family:var(--f-slab);font-style:italic;font-weight:700;
  font-size:clamp(1.1rem,2.2vw,1.5rem);line-height:1.2;color:#2C1D0B;
  text-shadow:0 1px 0 rgba(255,255,255,.2)}
.mb-challenge{margin:.15rem 0 .55rem;font-family:var(--f-hand);line-height:1.2;
  font-size:clamp(1.3rem,2.8vw,1.7rem);color:#2C1D0B}
.mb-k-q{color:var(--lazuli-deep);margin-bottom:.25rem}

.mb-grid{columns:4;column-gap:clamp(.7rem,1.4vw,1.1rem)}
@media(max-width:1080px){.mb-grid{columns:3}}
@media(max-width:760px){.mb-grid{columns:2}}
@media(max-width:460px){.mb-grid{columns:1}}

.mpol{position:relative;isolation:isolate;break-inside:avoid;margin:0 0 clamp(.7rem,1.4vw,1.1rem);
  padding:8px 8px 0;transform:rotate(var(--r,0deg));transition:transform .18s ease}
.mpol::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--paper);
  border:2.4px solid var(--ink);border-radius:3px;box-shadow:4px 5px 0 0 rgba(40,26,10,.5);
  filter:url(#roughsm)}
.mpol:nth-child(even)::before{animation-delay:-.6s}
.mpol:nth-child(3n)::before{animation-delay:-1.2s}
.mpol:hover{transform:rotate(0) translateY(-6px) scale(1.03);z-index:9}
.mpol:hover::before{box-shadow:7px 9px 0 0 rgba(40,26,10,.55)}
.mv-pin{position:absolute;top:-8px;left:50%;margin-left:-7px;width:15px;height:15px;border-radius:50%;
  background:var(--c,var(--colorado));border:2.2px solid var(--ink);z-index:2;
  box-shadow:1px 2px 0 0 rgba(40,26,10,.5)}

/* PHOTO. The placeholder is muted paper, not a saturated colour block — eleven loud squares made
   the board shout and buried the handwriting. The accent lives on the pin and the handle instead. */
.mv-ph{position:relative;display:grid;place-items:center;width:100%;aspect-ratio:1/1;overflow:hidden;
  background:#EDE4CF;border:2px solid var(--ink);background-size:cover;background-position:center}
.mv-ini{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:2.3rem;
  color:rgba(65,77,87,.22)}
/* the instant a real photo lands at assets/makers/<handle>.jpg, JS sets it as the background and
   flips this class — the initial and the stamp get out of the way. Nothing else changes. */
.mv-ph.has-photo .mv-ini,.mv-ph.has-photo .mv-soon{display:none}
.mv-soon{position:absolute;bottom:6px;left:50%;transform:translateX(-50%);
  font-family:var(--f-mono);font-size:.46rem;letter-spacing:.12em;text-transform:uppercase;
  color:var(--colorado);border:1.6px solid var(--colorado);border-radius:3px;padding:.15em .35em;
  filter:url(#roughsm)}
.mv-vid{position:absolute;right:6px;bottom:6px;width:22px;height:22px;border-radius:50%;
  background:var(--colorado);border:2px solid var(--ink);display:grid;place-items:center;z-index:2}
.mv-vid::after{content:"";border-left:7px solid var(--oats);border-top:4.5px solid transparent;
  border-bottom:4.5px solid transparent;margin-left:2px}

/* THE STRIP — the whole idea: the quote IS the caption, in handwriting */
.mv-strip{padding:.55rem .35rem .6rem;text-align:center}
.mv-strip q{display:block;font-family:var(--f-hand);font-size:1rem;line-height:1.2;color:var(--ink);
  quotes:'\201C' '\201D'}
.mpol.lead .mv-strip q{font-size:1.22rem;line-height:1.18}
.mv-strip b{display:block;margin-top:.35rem;font-family:var(--f-mono);font-weight:400;font-size:.54rem;
  letter-spacing:.08em;color:var(--c,var(--colorado))}

/* the echo sits BELOW the cycling deck. It was getting covered as the stack fanned downward, so it
   now clears the deck's footprint and rides above it (z-index) as insurance against a stray card. */
.mb-echo{position:relative;z-index:41;margin:clamp(2.2rem,4vw,3rem) auto 0;text-align:center;
  font-size:1.16rem;color:#3B2A16;max-width:48ch;text-shadow:0 1px 0 rgba(255,255,255,.22)}
.mb-echo a{color:#0C6E39;text-decoration:underline;text-underline-offset:3px;white-space:nowrap}
@media(prefers-reduced-motion:reduce){.mpol{transition:none}}

/* B · makerboard as a CYCLING DECK (saves the tall 11-tile grid). JS adds .mb-stack by default
   (the deck); tapping removes it -> the columns grid (splay). Hover pauses the cycle. */
.mb-hint{display:none;text-align:center;font-family:var(--f-hand);color:#5A3E1C;font-size:1.02rem;
  margin:0 0 clamp(.9rem,1.8vw,1.3rem)}
.makerboard.decked .mb-hint{display:block}
.mb-grid.mb-stack{columns:auto;position:relative;height:clamp(392px,50vw,470px);
  max-width:min(330px,88%);margin:0 auto}
.mb-grid.mb-stack .mpol{position:absolute;left:50%;top:0;width:min(300px,82vw);
  margin:0 0 0 calc(min(300px,82vw) / -2);
  transform:translate(calc(var(--i,0)*5px),calc(var(--i,0)*8px)) rotate(var(--r)) scale(calc(1 - var(--i,0)*.03));
  z-index:calc(40 - var(--i,0));transition:transform .5s cubic-bezier(.2,.8,.2,1),opacity .4s}
.mb-grid.mb-stack .mpol:hover{transform:translate(calc(var(--i,0)*5px),calc(var(--i,0)*8px)) rotate(var(--r)) scale(calc(1 - var(--i,0)*.03))}


/* The Circle card sits on a yellow sticky note — the group chat is a cold slab of paper, the Circle
   is the warm thing somebody stuck on the wall. Cheapest possible way to make the good column FEEL
   good, and it brands the moment in schoolbus yellow. */
.vs-card.vs-circle .circlemock::before{background:var(--happy)}
.vs-card.vs-circle .cm-note::before{background:var(--paper)}
/* the curled corner + the shadow that says "stuck on, not printed" */
.vs-card.vs-circle .circlemock{position:relative}
.vs-card.vs-circle .circlemock::after{content:"";position:absolute;right:-2px;bottom:-2px;
  width:38px;height:38px;z-index:1;
  background:linear-gradient(135deg, transparent 50%, rgba(65,77,87,.16) 50%, var(--schoolbus) 52%);
  border-bottom-right-radius:8px;filter:url(#roughsm)}
.vs-card.vs-circle .cm-out b{color:#4A3A08}
.vs-card.vs-circle .cap{color:var(--grass-deep)}


/* CIRCLE TIME is the heart of the loop, so it gets to be the biggest note on the ring — and it
   carries Chielo's four "people resources" inline. Inline, not stacked: four words wrapping on one
   line reads as a PROPERTY of the hour; four bullets on four lines reads as a to-do list and blows
   the ring's geometry. If this node lands, the page needs no separate section explaining it. */
/* 30cqw pushed the node outside the ring at the 3 o'clock position. 26 keeps it emphasised and
   inside the circle; the happy-yellow ground does the rest of the work. */
.how .step.is-key{width:26cqw;z-index:3}
.how .step.is-key::before{inset:-2.6cqw -2cqw;background:var(--happy)}
.how .step .mechs{margin:.45rem 0 0;padding-top:.45rem;position:relative;
  font-family:var(--f-hand);font-size:2.6cqw;letter-spacing:.01em;line-height:1.25;
  color:var(--ink);text-transform:lowercase;text-wrap:balance}
/* a hand-drawn rule, because nothing here is drawn with a ruler */
.how .step .mechs::before{content:"";position:absolute;top:0;left:12%;right:12%;height:2.2px;
  background:var(--colorado);opacity:.4;border-radius:2px;filter:url(#rough)}
.how .step p b{color:var(--ink)}


/* CIRCLE TIME IS A CLOCK, not a sticky note. Breaking the ring's own visual system is the point:
   four notes and one OBJECT says "this one is different" without a word of copy. The hour is
   quartered into the four ways you use it. Hands sweep, because a clock that doesn't move is a
   drawing of a clock. */
.how .step.is-clock::before{display:none}          /* no sticky ground under the object */
.how .step.is-clock .ico{width:100%;height:auto;margin:0 auto .3rem}
.ctclock{width:clamp(104px,20cqw,168px);height:auto;display:block;margin:0 auto;overflow:visible;
  filter:drop-shadow(4px 5px 0 rgba(65,77,87,.55))}
.ct-hands{transform-origin:60px 60px}
.ct-min{transform-origin:60px 60px;animation:ct-sweep 8s linear infinite}
.ct-hr{transform-origin:60px 60px;animation:ct-sweep 96s linear infinite}
@keyframes ct-sweep{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.ct-min,.ct-hr{animation:none}}
/* the name goes ABOVE the object: you read the label, then look at the thing it names. */
.how .step.is-clock h3,.how .step.is-globe h3,.how .step.is-cal h3{margin:0 0 .4cqw}
.how .step.is-globe h3{font-size:3.9cqw;white-space:nowrap}


/* SHOW & TELL IS A GLOBE. Two objects in a ring of notes: the CLOCK at 02 (the hour, small, your
   people) and the GLOBE at 05 (the world, big, everyone else). That pairing IS the thesis —
   make small, show and tell big — built into the loop instead of bolted on as a stunt.
   The paper plane was already the Show icon; now it orbits. */
.how .step.is-globe::before{display:none}
.how .step.is-globe .ico{width:100%;height:auto;margin:0 auto .3rem}
.ctglobe{width:clamp(104px,20cqw,168px);height:auto;display:block;margin:0 auto;overflow:visible;
  filter:drop-shadow(4px 5px 0 rgba(65,77,87,.55))}
/* plane + contrail are ONE group: the trail is the path already flown, so it must ride with the
   plane. (It used to be a full ring counter-rotating on its own, which read as a hoop drawn around
   the globe and, worse, moved the wrong way.) */
.ct-orbit{transform-origin:60px 62px;animation:ct-orbit 11s linear infinite}
@keyframes ct-orbit{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.ct-orbit{animation:none}}
/* the plane drags a banner, the way a little plane over a beach does. One word fits, and the one
   word is the product: the thing that goes around the world is the ZINE. */
/* the word has to survive at ~30px of rendered banner: heaviest weight, tightest tracking that
   still separates the letters, and a hairline ink stroke to hold the counters open against red. */
.ct-banner{font-family:var(--f-mono);font-weight:700;font-size:8.4px;letter-spacing:.3px;
  fill:var(--oats);paint-order:stroke;stroke:rgba(65,77,87,.35);stroke-width:.5px}


/* REFLECT IS A THOUGHT BUBBLE. It had a sticky note with a speech-bubble icon drawn on it, which
   is a picture of a thing on a picture of a thing. Make the note BE the bubble and the icon is
   redundant — so it's gone. The ring now runs: card, CLOCK, THOUGHT, GLOBE.
   A cartoon thought balloon is SCALLOPED — convex, near-semicircular lobes, uneven, overlapping
   (see any Garfield balloon). Two things this got wrong before: (1) CSS border-radius can only ever
   give you a smooth blob, and (2) stretching an SVG cloud to the note's box turns every round lobe
   into a squashed ellipse. So: real path, real aspect ratio, no stretching — the TEXT fits the
   balloon, not the other way round. The tail bubbles live inside the same SVG, so they scale and
   boil with it instead of drifting around as absolutely-positioned divs. */
.how .step.is-think{position:relative;width:22cqw}
.how .step.is-think::before,.how .step.is-think::after{display:none}   /* the balloon IS the ground */
.thoughtb{position:absolute;left:50%;top:50%;
  /* the viewBox is 180 tall but the BALLOON only occupies the top 140 — its centre is 20 units
     above the SVG's centre, so the whole thing shifts DOWN to put the balloon (not the tail) around
     the text. Getting this sign wrong is what was pushing the copy out through the bottom lobes. */
  transform:translate(-50%,-50%) translateY(4.6cqw);
  width:46cqw;aspect-ratio:200/180;height:auto;z-index:-1;overflow:visible;
  filter:drop-shadow(4px 5px 0 rgba(65,77,87,.5))}
/* THE BALLOON BOILS. Everything else in the ring is a drawn object holding still; the balloon is
   the one that represents THINKING, so it's the one that never settles. Fast cadence (--boil-ink,
   the marker speed) rather than the calm paper breath — a thought still forming. The tail bubbles
   are offset so the four shapes don't all jump on the same frame. */
.thoughtb path,.thoughtb circle{filter:url(#roughsm)}
.thoughtb circle:nth-of-type(1){animation-delay:-.17s}
.thoughtb circle:nth-of-type(2){animation-delay:-.33s}
.thoughtb circle:nth-of-type(3){animation-delay:-.08s}
@media(prefers-reduced-motion:reduce){.thoughtb path,.thoughtb circle{animation:none}}

/* a balloon holds less air than a square note of the same width — keep the text off the scallops */
.how .step.is-think h3{font-size:3.6cqw}
.how .step.is-think p{max-width:15ch;margin-inline:auto;font-size:2.6cqw;line-height:1.12}
.how .step.is-think .n{margin-bottom:.35cqw}


/* THE DEADLINE IS THE OBJECT. A stamped "DUE FRIDAY" tag was a sticker on a picture of a thing;
   a tear-off desk calendar IS the thing — it carries the day, the fact that a fresh page comes
   every week, and the challenge scrawled on it, without a word of prose. Now all four nodes are
   objects: CALENDAR, CLOCK, THOUGHT BALLOON, GLOBE. */
.how .step.is-cal::before,.how .step.is-cal::after{display:none}
.how .step.is-cal .ico{width:100%;height:auto;margin:0 auto .3rem}
.ctcal{width:clamp(96px,18cqw,152px);height:auto;display:block;margin:0 auto;overflow:visible;
  filter:drop-shadow(4px 5px 0 rgba(65,77,87,.55));transform:rotate(-2deg)}
/* the pad boils on the calm cadence — paper breathing, not marker jitter (that's the balloon's job).
   Staggered per layer so the pages don't all wobble on the same frame. */
.ctcal>path,.ctcal>g>path,.ctcal>g>circle{filter:url(#roughsm)}
.ctcal>path:nth-of-type(2){animation-delay:-.4s}
.ctcal>path:nth-of-type(3){animation-delay:-.8s}
.ctcal>path:nth-of-type(4){animation-delay:-1.1s}
@media(prefers-reduced-motion:reduce){.ctcal>path,.ctcal>g>path,.ctcal>g>circle{animation:none}}
.cal-day{font-family:var(--f-mono);font-weight:600;font-size:15px;letter-spacing:2px;fill:var(--oats)}

/* THE FOOTNOTE IS A STICKY NOTE. It's the only thing on the ring that isn't part of the ring, so it
   gets the ring's discarded furniture: the yellow note the Practice step used to sit on. On desktop
   it's parked in the empty margin beside the clock it annotates (the ring is 560px inside a 1150px
   column — that margin is dead space). On phone there is no margin, so it just falls in underneath. */
/* z-index at ALL widths: the thought balloon hangs well below the ring's box (it's a 46cqw object on
   a node parked at 88%), so when the note falls into flow underneath it, the balloon was painting
   straight over it. The clearance below is sized to the balloon's overhang, not to taste. */
.how-fn{position:relative;z-index:4;display:flex;align-items:flex-start;gap:.5rem;
  margin:clamp(5rem,13vw,6.5rem) auto 0;max-width:32ch;padding:.9rem 1rem;
  transform:rotate(-1.4deg)}
.how-fn::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--happy);
  border:2.6px solid var(--ink);border-radius:4px;box-shadow:4px 4px 0 0 var(--ink);
  filter:url(#roughsm2)}
/* the folded-up sticky corner. It has to peel up from INSIDE the note's own square — hung off the
   outside edge it just looked like a triangle sitting on the drop shadow. Same construction as the
   Circle card downpage: a diagonal split with a shadow on the fold line. */
.how-fn::after{content:"";position:absolute;right:1px;bottom:1px;z-index:0;width:26px;height:26px;
  background:linear-gradient(135deg, transparent 47%, rgba(65,77,87,.22) 47%, var(--schoolbus) 50%);
  filter:url(#roughsm)}
/* the arrow back to the asterisk it answers. Desktop only — on phone the note sits directly
   underneath, so an arrow pointing sideways into nothing would be a lie. */
.fn-link{display:none}
/* The note only gets parked in the margin when there IS a margin. The ring is 560px inside a 1150px
   column, so the gutter is ~295px a side — the note needs ~258px of it. Below ~1180px viewport the
   column narrows, the gutter closes, and the note would hang off the page: so it drops back into
   flow under the ring and the yarn (which would then point at nothing) goes away with it.
   The yarn's box is stage-relative: at every width where it's visible the stage is a rigid 560px,
   the clock sits at 74.1%/34% and the note's left edge at 104.8%, so these percentages hold. */
@media(min-width:1180px){
  .fn-link{display:block;position:absolute;left:92%;top:52%;width:16%;height:14%;
    overflow:visible;filter:url(#rough);
    z-index:5;pointer-events:none}
}
.fn-star{font-family:var(--f-slab);font-weight:700;color:var(--colorado);
  font-size:clamp(2.2rem,4vw,3rem);line-height:.62;flex:none;
  filter:url(#rough)}
.fn-body{font-family:var(--f-hand);font-size:clamp(1rem,1.4vw,1.14rem);line-height:1.22;
  color:var(--ink);padding-top:.1rem}
/* no highlighter on a highlighter-coloured note — the note IS the emphasis. The punch line
   picks up the asterisk's red instead. */
.fn-body b{font-weight:400;color:var(--coral-ink)}
/* the marker on the clock's own word */
.how .step .mechs sup{font-size:1.2em;line-height:0;vertical-align:baseline;color:var(--colorado)}
@media(min-width:1180px){
  .how-fn{position:absolute;right:-46%;top:52%;width:41%;max-width:none;margin:0;z-index:4}
}


/* THE STACKED-LAYOUT YARN. Below 1180px the note drops beneath the ring, so the string runs from
   the CLOCK'S MECHANISM LINE — the "practice* · observe · ask · be seen" the asterisk actually lives
   in — diagonally down into the note's top-left... er, top-right corner.
   Every number here is derived, because eyeballing it at one width is what kept breaking it:
     · the note is centred and min(32ch, stage) wide, so only the note knows where its corner is —
       hence the tie hangs off the NOTE (bottom:100%).
     · the mechanism line's right edge sits at stage.left + 1.01 * ring, so its offset from the
       note's right edge is (.51 * ring - noteWidth/2). That's the `right`/`width` calc below:
       50% of .how-fn IS noteWidth/2, so CSS can express it exactly.
     · the drop is the note's own top margin (same clamp, so they can't drift) + 20% of the ring
       (mechanism line down to the ring's bottom edge).
   Cord stretches (preserveAspectRatio:none + non-scaling-stroke keeps an even thickness); the knots
   are CSS circles, so they stay round however the box distorts. */
.fn-tie{display:none}
@media(max-width:1179px){
  .fn-tie{display:block;position:absolute;bottom:100%;z-index:1;pointer-events:none;
    right:calc(50% - .51 * min(560px,94vw) + 20px);
    width:max(8px, .51 * min(560px,94vw) - 50% - 6px);
    height:calc(clamp(5rem,13vw,6.5rem) + .2 * min(560px,94vw));
    filter:url(#rough)}
  .fn-tie svg{width:100%;height:100%;display:block;overflow:visible}
  .fn-tie::before,.fn-tie::after{content:"";position:absolute;width:9px;height:9px;
    margin-left:-4.5px;border-radius:50%;background:var(--lazuli);border:1.6px solid var(--ink)}
  .fn-tie::before{top:-4px;left:90%}                       /* knot on the mechanism line */
  .fn-tie::after{bottom:-5px;left:15%;width:8px;height:8px;margin-left:-4px}   /* knot on the note */
}

/* THE LOOP TURNS. The ring is the one thing on the page that is literally a cycle, so let it cycle:
   the arrow track rotates slowly, forever. Yellow (happy) rather than colorado — the red was
   shouting over the notes, and the loop should feel like the warm thing holding them, not an alarm.
   The "every week" scrawl is gone: the ring says it by moving. */
.how-ring{animation:how-turn 18s linear infinite;transform-origin:50% 50%}
@keyframes how-turn{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.how-ring{animation:none}}

/* ---------- bring your group = the organizer's door ---------- */
.bring{padding:clamp(1.5rem,4vw,2.6rem) 0}
/* the pitch is a single ~44ch column now; keep the paper skinny around it instead of
   letting the sheet stretch the full .wrap and frame an empty gutter on both sides. */
.bring .paper{max-width:52ch;margin-inline:auto}
.bring .inner{padding:clamp(1.4rem,3vw,2.3rem)}
.bring-grid{display:grid;grid-template-columns:1fr;gap:clamp(1.4rem,3.4vw,2.8rem);align-items:center;max-width:44ch;margin-inline:auto}
.bring .head h2,.bring h2{font-family:var(--f-slab);font-style:italic;font-weight:700;
  font-size:clamp(1.6rem,4vw,2.4rem);line-height:1.02;margin:.35rem 0 0;color:var(--ink);max-width:18ch}
.bring h2 .stop{color:var(--grass-deep)}
.bring-body{font-size:clamp(1rem,1.5vw,1.1rem);line-height:1.55;color:rgba(65,77,87,.9);margin:.95rem 0 0;max-width:46ch}
.bring-body em{font-style:italic}
/* the payload line — gets its own weight instead of hiding at the end of a paragraph */
.bring-punch{font-family:var(--f-slab);font-style:italic;font-weight:700;
  font-size:clamp(1.1rem,2vw,1.32rem);line-height:1.25;color:var(--ink)}
/* .bring-cap and the old inline .bring-money were the pre-rebuild left-border callout paragraphs.
   The cap is folded into .bring-fine now and the money answer is a card (see the #bring rebuild block
   at the end of this file); their old rules are deleted so they can't collide with the card's ::before. */
.bring-cta{display:flex;flex-wrap:wrap;align-items:center;gap:.9rem;margin:1.5rem 0 0}
.bring-note{color:var(--colorado);font-size:1.1rem;transform:rotate(-1.5deg)}
.bring-honest{font-family:var(--f-body);font-size:clamp(.88rem,1.25vw,.95rem);line-height:1.55;
  color:rgba(65,77,87,.66);margin:1.3rem 0 0;max-width:52ch;font-style:italic}
.bring-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.9rem}
.bring-list li{position:relative;padding-left:1.9rem;font-size:clamp(.95rem,1.4vw,1.02rem);line-height:1.45;
  color:rgba(65,77,87,.9)}
.bring-list li:nth-child(odd){color:rgba(65,77,87,.6)}
.bl-x,.bl-c{position:absolute;left:0;top:.05em;width:1.25rem;height:1.25rem;display:grid;place-items:center;
  font-family:var(--f-slab);font-weight:700;line-height:1}
.bl-x{color:var(--colorado);font-size:1.3rem}
.bl-c{color:var(--grass-deep)}
.bl-c svg{width:1.05rem;height:1.05rem}
@media(max-width:900px){.bring-grid{grid-template-columns:1fr}}

/* ---------- the zine = the tangible keepsake (hand-made vs bot-made) ---------- */
.zines{padding:clamp(1.5rem,4vw,3rem) 0 clamp(2rem,5vw,3.5rem)}
.zines .head{margin-bottom:clamp(1.8rem,4.5vw,2.6rem);text-align:center}
.zines .head h2{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:clamp(1.8rem,6vw,3rem);
  line-height:.98;margin:.3rem 0 0;color:var(--ink);text-wrap:balance}
.zines .head h2 .stop{color:var(--grass-deep)}
.zines-sub{font-family:var(--f-body);font-style:italic;font-size:clamp(1.05rem,1.8vw,1.35rem);line-height:1.5;
  color:rgba(65,77,87,.85);max-width:46ch;margin:.9rem auto 0}
.zine-pair{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:clamp(1.2rem,3vw,2.4rem)}
.zine-card{position:relative;width:min(320px,100%);transition:transform .18s ease}
.zine-card.hand{transform:rotate(-2deg)}
.zine-card.bot{transform:rotate(2deg)}
.zine-card:hover{transform:rotate(0) translateY(-6px);z-index:5}
.zine-tab{position:absolute;z-index:4;top:-13px;left:50%;transform:translateX(-50%) rotate(-2deg);
  font-family:var(--f-mono);font-size:.66rem;letter-spacing:.14em;text-transform:uppercase;
  background:var(--ink);color:var(--oats);border-radius:4px;padding:.32em .7em;white-space:nowrap}
.zine-card.bot .zine-tab{background:var(--lazuli)}
/* the framed window — fixed height so the cover shows and the rest is implied (there's more inside) */
.zine-frame{position:relative;display:block;height:clamp(300px,52vw,380px);overflow:hidden;
  border:2.6px solid var(--ink);border-radius:6px;background:var(--paper);
  box-shadow:8px 8px 0 0 var(--ink);text-decoration:none;transition:box-shadow .18s ease}
.zine-card:hover .zine-frame{box-shadow:12px 13px 0 0 var(--ink)}
.zine-frame img{width:100%;display:block}
/* "flip through it" CTA fading up from the bottom of the window */
.zine-more{position:absolute;left:0;right:0;bottom:0;padding:1.9rem .9rem .75rem;
  font-family:var(--f-mono);font-size:.8rem;letter-spacing:.08em;text-transform:uppercase;color:var(--ink);
  display:flex;align-items:center;justify-content:center;gap:.45rem;
  background:linear-gradient(to top,var(--paper) 24%,rgba(254,246,228,.82) 56%,transparent)}
.zine-card:hover .zine-more{color:var(--grass-deep)}
/* the hand-scrawled "or" between the two paths */
.zine-or{font-family:var(--f-hand);font-size:clamp(1.6rem,3vw,2.3rem);color:var(--sambas);transform:rotate(-4deg)}
/* Pre-existing bug: the hand/bot pair could never fit on one row, so it silently stacked and
   stranded the "or" off to the side, dividing two things that weren't beside each other.
   Cause: .zine-card is a flex item, so its default min-width:auto pins it to min-content (560px)
   and the declared width:min(320px,100%) never applies. Release min-width, then size the
   polaroids so the duo actually fits the card. */
@media(min-width:1000px){
  /* the cards also carry 40px side margins, which pushed the row past the track */
  .zine-pair .zine-card{width:530px;min-width:0;margin-inline:0}
  .zine-pair .zpola.zbook{width:300px}
  .zine-pair .zpola{width:170px}
  /* the -20px tuck was sized for the old book width; keep the video polaroid's caption legible */
  .zine-pair .zine-duo .zpola:nth-child(2){margin-left:-8px}
}
@media(max-width:999px){
  /* below the desktop breakpoint the -20px base tuck slid under the video polaroid's
     caption ("watch it get made" → "tch it get made"); match the desktop tuck. */
  .zine-pair .zine-duo .zpola:nth-child(2){margin-left:-8px}
}
@media(max-width:520px){
  /* on phones the polaroids are proportionally larger, so -8px still clipped the leading
     "w"; tuck tighter so the whole caption clears. */
  .zine-pair .zine-duo .zpola:nth-child(2){margin-left:-2px}
}
/* bot placeholder = ghosted, dashed, "coming soon" */
.zine-frame.ghost{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.9rem;
  text-align:center;padding:1.4rem;border-style:dashed;box-shadow:6px 6px 0 0 rgba(65,77,87,.25);
  background:repeating-linear-gradient(0deg,transparent 0 26px,rgba(65,77,87,.05) 26px 27px),var(--paper)}
.zine-card.bot:hover .zine-frame.ghost{box-shadow:9px 10px 0 0 rgba(65,77,87,.3)}
.bot-ico{width:clamp(54px,9vw,72px);height:clamp(54px,9vw,72px)}
.bot-ico svg{width:100%;height:100%;display:block;overflow:visible}
.bot-ico svg>*{filter:url(#roughsm)}
.soon-stamp{font-family:var(--f-mono);font-weight:500;font-size:.74rem;letter-spacing:.18em;text-transform:uppercase;
  color:var(--colorado);border:2.4px solid var(--colorado);border-radius:5px;padding:.3em .7em;transform:rotate(-5deg);opacity:.9}
.bot-line{font-size:1.05rem;color:rgba(65,77,87,.7);line-height:1.3}
.zines .cap{font-family:var(--f-hand);font-size:1.1rem;color:var(--sambas);text-align:center;display:block;margin:.7rem auto 0;transform:rotate(-1deg)}
@media(max-width:560px){.zine-card.hand,.zine-card.bot,.zine-or{transform:rotate(0)}}
/* ---------- peek = browse Circles by their zines + the zinemaker (all placeholders) ---------- */
.peek{padding:clamp(1.5rem,4vw,3rem) 0 clamp(2rem,5vw,3.5rem)}
.peek .head{margin-bottom:clamp(1.8rem,4.5vw,2.6rem);text-align:center}
.peek .head h2{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:clamp(1.8rem,6vw,3rem);line-height:.98;margin:.3rem 0 0;color:var(--ink);text-wrap:balance}
.peek .head h2 .stop{color:var(--grass-deep)}
.peek-sub{font-family:var(--f-body);font-style:italic;font-size:clamp(1.05rem,1.8vw,1.35rem);line-height:1.5;color:rgba(65,77,87,.85);max-width:48ch;margin:.9rem auto 0}
.peek-sub em{color:var(--colorado)}
.peek-row{display:grid;grid-template-columns:repeat(3,1fr);align-items:stretch;gap:clamp(1.2rem,2.6vw,2rem);max-width:1000px;margin-inline:auto}
.peek-card{position:relative;display:flex;flex-direction:column;transition:transform .18s ease}
.peek-card:nth-child(1){transform:rotate(-1.6deg)}
.peek-card:nth-child(3){transform:rotate(1.6deg)}
.peek-card:hover{transform:rotate(0) translateY(-5px);z-index:4}
.peek-tab{position:absolute;z-index:4;top:-13px;left:50%;transform:translateX(-50%) rotate(-2deg);
  font-family:var(--f-mono);font-size:.64rem;letter-spacing:.14em;text-transform:uppercase;
  background:var(--ink);color:var(--oats);border-radius:4px;padding:.3em .7em;white-space:nowrap}
.peek-tab.tool{background:var(--grass-deep)}
.peek-frame{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.55rem;text-align:center;
  min-height:clamp(228px,30vw,272px);padding:1.6rem 1.2rem;border:2.6px dashed rgba(65,77,87,.4);border-radius:6px;
  background:repeating-linear-gradient(0deg,transparent 0 26px,rgba(65,77,87,.05) 26px 27px),var(--paper);
  box-shadow:6px 6px 0 0 rgba(65,77,87,.22)}
.peek-card:hover .peek-frame{box-shadow:9px 10px 0 0 rgba(65,77,87,.28)}
.peek-ico{width:clamp(50px,8vw,66px);height:clamp(50px,8vw,66px)}
.peek-ico svg{width:100%;height:100%;display:block;overflow:visible}
.peek-ico svg>*{filter:url(#roughsm)}
.peek-frame h3{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:clamp(1.15rem,1.8vw,1.4rem);line-height:1.05;margin:.1rem 0 0;color:var(--ink)}
.peek-hint{font-family:var(--f-hand);font-size:1.05rem;color:var(--sambas)}
/* center card = the product (zinemaker), emphasised */
.peek-card.is-tool .peek-frame{border-color:var(--grass-deep);background:repeating-linear-gradient(0deg,transparent 0 26px,rgba(28,171,91,.07) 26px 27px),var(--paper)}
.peek-card.is-tool .soon-stamp{color:var(--grass-deep);border-color:var(--grass-deep)}
@media(min-width:840px){.peek-card.is-tool{transform:scale(1.06)}.peek-card.is-tool:hover{transform:scale(1.06) translateY(-5px)}}
@media(max-width:760px){.peek-row{grid-template-columns:1fr;max-width:22rem}}
@media(max-width:560px){.peek-card,.peek-card:nth-child(1),.peek-card:nth-child(3){transform:none}}

/* shared play badge for video placeholders */
.play-badge{display:inline-flex;width:clamp(38px,6vw,50px);height:clamp(38px,6vw,50px)}
.play-badge svg{width:100%;height:100%;display:block;overflow:visible}
.play-badge svg circle{fill:rgba(254,246,228,.16);stroke:var(--oats);stroke-width:2.2}
.play-badge svg path{fill:var(--oats);stroke:none}

/* zine-duo — paired polaroids: the finished product + the editor video */
.zine-card.hand,.zine-card.bot,.zine-card.hand:hover,.zine-card.bot:hover{transform:none}  /* tilt lives on the polaroids now */
.zine-duo{display:flex;justify-content:center;align-items:flex-start;padding-top:8px}
.zpola{position:relative;width:clamp(122px,15vw,156px);background:var(--paper);border:2.4px solid var(--ink);
  border-radius:5px;box-shadow:6px 6px 0 0 var(--ink);padding:8px 8px 0;text-decoration:none;
  transition:transform .18s ease, box-shadow .18s ease}
.zine-duo .zpola:nth-child(1){transform:rotate(-4deg);z-index:2}
.zine-duo .zpola:nth-child(2){transform:rotate(4deg);margin-left:-20px;margin-top:22px;z-index:1}
.zine-duo .zpola:hover{transform:rotate(0) translateY(-5px);z-index:5;box-shadow:10px 11px 0 0 var(--ink)}
.zpola .ph{position:relative;width:100%;aspect-ratio:5/6;overflow:hidden;background:var(--sambas);
  border:1.5px solid rgba(65,77,87,.28);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.45rem}
.zpola .ph img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:top}
.zpola-cap{display:block;font-family:var(--f-hand);text-align:center;font-size:1rem;color:var(--ink);padding:.42rem .2rem .55rem;line-height:1}
.zpola.is-zine .zpola-cap{color:var(--grass-deep)}
.zpola .ph .bot-ico{width:clamp(38px,6vw,50px);height:clamp(38px,6vw,50px)}
.zpola .ph .bot-ico svg{width:100%;height:100%;display:block;overflow:visible}
.zpola .ph .soon-stamp{font-size:.58rem;padding:.2em .45em}
.zpola.is-vid .ph{background:#212c30}
.zpola.is-vid .soon-stamp{color:var(--oats);border-color:var(--oats)}

/* the Zinemaker peek card → a reel of the zine viewer */
.peek-frame.is-reel{justify-content:flex-start;gap:.65rem;padding-top:1.4rem}
.peek-vid{position:relative;width:100%;aspect-ratio:4/3;border-radius:5px;overflow:hidden;background:#212c30;
  border:1.5px solid rgba(65,77,87,.3);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.55rem}
.peek-vid .soon-stamp{color:var(--oats);border-color:var(--oats)}

/* ---------- team = taped polaroids ---------- */
.team{padding:clamp(1.5rem,4vw,3rem) 0}
.team .head{margin-bottom:clamp(1.9rem,4.5vw,2.8rem);text-align:center}
.team .head h2{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:clamp(1.9rem,5vw,2.8rem);line-height:1.02;margin:.35rem auto 0;color:var(--ink);max-width:20ch}
.team-sub{font-family:var(--f-body);font-style:italic;font-size:clamp(1rem,1.6vw,1.18rem);line-height:1.5;
  color:rgba(65,77,87,.85);max-width:52ch;margin:.9rem 0 0}
.crew{display:flex;flex-wrap:wrap;justify-content:center;gap:clamp(1.7rem,4vw,3.2rem);align-items:flex-start}
.polaroid{position:relative;width:min(300px,84%);padding:13px 13px 0;transition:transform .18s ease}
/* border + hard shadow live on a backing layer so they can boil without warping the photo */
.polaroid::before{content:"";position:absolute;inset:0;z-index:0;background:var(--paper);
  border:2.6px solid var(--ink);border-radius:5px;box-shadow:8px 8px 0 0 var(--ink);
  filter:url(#soft);transition:box-shadow .18s ease}
.polaroid>.ph,.polaroid>.cap{position:relative;z-index:1}
.polaroid .ph{position:relative;width:100%;aspect-ratio:5/6;overflow:hidden;background:var(--sambas);border:1.5px solid rgba(65,77,87,.28)}
.polaroid .ph img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;filter:saturate(.94) contrast(1.03)}
.polaroid .cap{font-family:var(--f-hand);text-align:center;padding:.6rem .2rem .75rem;line-height:1.1}
.polaroid .cap b{display:block;font-weight:400;font-size:1.4rem;color:var(--ink)}
.polaroid .cap span{font-family:var(--f-hand);font-size:1.02rem;color:rgba(65,77,87,.92)}
.crew .polaroid:nth-child(1){transform:rotate(-4.5deg)}
.crew .polaroid:nth-child(2){transform:rotate(3.3deg)}
.crew .polaroid:nth-child(3){transform:rotate(-2.2deg)}
.crew .polaroid:nth-child(1)::before{animation-delay:-.6s}
.crew .polaroid:nth-child(2)::before{animation-delay:-1.15s}
.crew .polaroid:nth-child(3)::before{animation-delay:-.25s}
.crew .polaroid:hover{transform:rotate(0) translateY(-7px);z-index:6}
.crew .polaroid:hover::before{box-shadow:11px 12px 0 0 var(--ink)}

/* ---------- founder's note (a handwritten letter, photo taped on) ---------- */
.note{padding:clamp(1.5rem,4vw,3rem) 0}
.note .inner{padding:clamp(1.9rem,5vw,3.6rem)}
.note-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(1.6rem,4vw,2.8rem);align-items:center}  /* minmax(0,…) stops the single mobile column blowing out to text max-content */
@media(min-width:760px){.note-grid{grid-template-columns:1fr auto}}
.note .eyebrow{color:var(--colorado)}
.note-punch{font-family:var(--f-slab);font-style:italic;font-weight:700;
  font-size:clamp(1.05rem,1.9vw,1.28rem);line-height:1.25;color:var(--ink)}
.note-body{font-family:var(--f-body);font-style:italic;font-weight:400;font-size:clamp(1.2rem,2.1vw,1.6rem);line-height:1.5;color:var(--ink);max-width:min(36ch,100%);margin:.9rem 0 0}
.note-body b{font-weight:700;color:var(--grass-deep)}
.sign{font-family:var(--f-hand);font-size:clamp(2.2rem,4.5vw,3.2rem);color:var(--grass-deep);margin:1.1rem 0 0;line-height:1}
.sign-role{font-family:var(--f-mono);text-transform:uppercase;letter-spacing:.14em;font-size:.72rem;color:var(--sambas);margin:.35rem 0 0}
.snap{position:relative;width:min(312px,84vw);justify-self:center;padding:12px;transform:rotate(2.6deg)}
.snap::before{content:"";position:absolute;inset:0;z-index:0;background:var(--paper);border:2.6px solid var(--ink);border-radius:5px;
  box-shadow:8px 8px 0 0 var(--ink);filter:url(#soft)}
.snap>.ph{position:relative;z-index:1}
.snap .ph{position:relative;width:100%;aspect-ratio:5/6;overflow:hidden;background:var(--sambas);border:1.5px solid rgba(65,77,87,.28)}
.snap .ph img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;filter:saturate(.94) contrast(1.03)}
@media(max-width:480px){.snap{transform:rotate(0)}}
/* the note carries the whole team: three near-equal snaps in one tight row, shoulder to
   shoulder with a hair of overlap, so it reads as a hand-laid strip rather than a hierarchy. */
.note-crew{display:flex;flex-wrap:wrap;justify-content:center;align-items:flex-start;gap:0}
.snap.trio{width:min(150px,29vw);padding:9px;margin:0 -6px}
.snap.trio:nth-child(1){transform:rotate(-3deg);z-index:2}
.snap.trio:nth-child(2){transform:rotate(2.6deg);z-index:1}
.snap.trio:nth-child(3){transform:rotate(-2deg);z-index:2}
.snap.trio:hover{transform:rotate(0) translateY(-5px);z-index:5}
.snap.trio::before{border-width:2.2px}
.snap.trio .cap-mini{position:relative;z-index:1;font-family:var(--f-hand);text-align:center;
  font-size:1.1rem;line-height:1;color:var(--ink);margin:.35rem 0 .05rem}
.snap.trio .cap-mini.scrawl{color:var(--colorado)}
@media(max-width:480px){.snap.trio{transform:rotate(0)}}

/* demo gate */
.locktag{font-family:var(--f-mono);font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(--sambas);display:inline-flex;align-items:center;gap:.4rem}
.gate{display:none;margin-top:.2rem}
.gate.open{display:block}
.gate form{display:flex;gap:.5rem;flex-wrap:wrap}
.gate input{font-family:var(--f-mono);font-size:.95rem;letter-spacing:.14em;padding:.6em .8em;min-height:46px;
  background:var(--paper);border:2.4px dashed var(--lazuli);border-radius:5px;color:var(--ink);width:min(10ch,100%)}
.gate input:focus{outline:none;border-style:solid}
.gate .msg{font-family:var(--f-hand);font-size:1.05rem;margin:.5rem 0 0;min-height:1.2em}
.gate .msg.err{color:var(--colorado)} .gate .msg.ok{color:var(--grass)}
.shake{animation:shake .35s}
@keyframes shake{10%,90%{transform:translateX(-2px)}30%,70%{transform:translateX(4px)}50%{transform:translateX(-4px)}}

/* ---------- footer = torn band ---------- */
footer{position:relative;background:var(--grass-deep);margin-top:clamp(2.5rem,6vw,4.5rem);
  padding:clamp(2.6rem,6vw,4.2rem) 0 clamp(1.8rem,4vw,2.6rem);color:var(--oats)}  /* deep grass: oats text clears AA on the band */
footer::before{content:"";position:absolute;left:0;right:0;top:-15px;height:30px;background:var(--grass-deep);filter:url(#tornbig2)}
footer .top{display:flex;justify-content:space-between;align-items:flex-start;gap:2rem;flex-wrap:wrap}
footer .ft-word{width:clamp(150px,24vw,240px);display:block}
footer .ft-word svg{display:block;width:100%;height:auto}
footer .tagline{font-family:var(--f-slab);font-style:italic;font-weight:700;font-size:clamp(1.5rem,3.4vw,2.3rem);color:var(--oats);max-width:13ch;margin:.8rem 0 0;line-height:1.05}
footer .links{display:flex;flex-direction:column;gap:.35rem}
footer .links a{font-family:var(--f-mono);font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;color:var(--oats);
  display:inline-flex;align-items:center;min-height:44px;                       /* >=44px tap target */
  text-decoration:underline;text-decoration-thickness:1.5px;text-underline-offset:4px;text-decoration-color:rgba(254,246,228,.55)}
footer .links a:hover,footer .links a:focus-visible{text-decoration-color:var(--oats)}
footer .links a:focus-visible{outline:2px solid var(--oats);outline-offset:2px}
footer .stamp{display:inline-block;margin-top:1.4rem;font-family:var(--f-mono);text-transform:uppercase;letter-spacing:.14em;
  font-size:.72rem;color:rgba(254,246,228,.85);border:2.4px solid rgba(254,246,228,.7);border-radius:6px;
  padding:.5em .8em;transform:rotate(-3deg);filter:url(#roughsm)}
footer .legal{margin-top:2rem;border-top:1.6px solid rgba(254,246,228,.4);padding-top:1.1rem;display:flex;
  justify-content:space-between;gap:1rem;flex-wrap:wrap;font-family:var(--f-mono);font-size:.72rem;letter-spacing:.05em;color:rgba(254,246,228,.9)}

/* ===================================================================
   R5 composition — break the centered, same-width stack into laid leaves:
   tiny resting tilts + differing widths + alternating offset, and the
   founder photo bleeds past the letter's edge across the section boundary.
   Desktop only; mobile stays upright + full-width for legibility.
   =================================================================== */
@media(min-width:760px){
  .hero .paper{width:97%;rotate:-.6deg}
  .about .paper{width:99.5%;margin-left:auto;rotate:.55deg}
  .note .paper{width:95%;margin-right:auto;rotate:-.9deg}
  .note .note-crew{translate:14px 0}   /* the trio strip nudges toward the letter's right edge */
}

/* ===================================================================
   M1 feature layer — reveals, highlighter/marker draw-on, sound toggle.
   All entrance states are gated on body[data-motion="full"], so under
   calm / reduced-motion (data-motion="calm") nothing is ever hidden.
   The FPS governor's html[data-tier="lite"] forces everything instant.
   The `translate` / `scale` properties (not `transform`) are used so the
   motion composes with each element's resting tilt/skew.
   =================================================================== */

/* ---- reveals: paper LANDS — quick fade, settle with a hair of overshoot,
       keeping each element's resting tilt (translate composes with transform) -- */
body[data-motion="full"] .reveal{opacity:0;translate:0 16px;
  transition:opacity .24s ease, translate .52s cubic-bezier(.2,.85,.3,1.12)}
body[data-motion="full"] .reveal.in{opacity:1;translate:0 0}

/* SLAM-IN: polaroids + door cards drop from above and SMACK onto the page, then
   the washi tape sticks — gives scrolling weight + visual hierarchy. translate /
   scale are individual props so they compose with each piece's resting tilt. */
body[data-motion="full"] .slam{opacity:0;translate:0 -96px;scale:1.04}
body[data-motion="full"] .slam.in{animation:slamin .44s cubic-bezier(.5,0,.8,.45) both}     /* ease-IN = it accelerates down (gravity) */
@keyframes slamin{
  0%  {opacity:0; translate:0 -96px; scale:1.04}
  58% {opacity:1; translate:0 0;     scale:1.04}        /* it reaches the page... */
  70% {translate:0 1px; scale:1.09 .86}                 /* ...and SMACKS flat (squash) */
  84% {translate:0 0;   scale:.98 1.05}                 /* rebound */
  100%{translate:0 0;   scale:1}}
/* the washi tape then SWINGS down and slaps on to stick it */
body[data-motion="full"] .slam .tape{opacity:0;translate:0 -18px;rotate:16deg}
body[data-motion="full"] .slam.in .tape{animation:tapeslap .32s cubic-bezier(.34,1.4,.5,1) .4s both}
@keyframes tapeslap{0%{opacity:0;translate:0 -18px;rotate:16deg}55%{opacity:1}100%{opacity:1;translate:0 0;rotate:0}}
/* the "pick a door" cards hit HARDER: drop from higher, heavier impact (L->R cascade in JS) */
body[data-motion="full"] .doors .card.slam{translate:0 -140px;scale:1.07}
body[data-motion="full"] .doors .card.slam.in{animation:slamhard .5s cubic-bezier(.5,0,.82,.42) both}
@keyframes slamhard{
  0%  {opacity:0; translate:0 -140px; scale:1.07}
  56% {opacity:1; translate:0 0;      scale:1.07}
  68% {translate:0 2px; scale:1.13 .82}
  82% {translate:0 0;   scale:.97 1.06}
  100%{translate:0 0;   scale:1}}
/* the slam is a compositor-only transform animation — cheap even on weak devices,
   so it survives the lite tier (only the expensive SVG-filter effects get cut). */

/* ---- highlighter band: swipe left→right (composes with its skew) ---- */
body[data-motion="full"] .hl.draw::before{scale:0 1;transform-origin:left center;
  transition:scale .55s cubic-bezier(.2,.7,.2,1)}
body[data-motion="full"] .hl.draw.in::before{scale:1 1}

/* ---- marker underline: draw left→right just after ------------------ */
body[data-motion="full"] .ul.draw::after{scale:0 1;transform-origin:left center;
  transition:scale .5s cubic-bezier(.2,.7,.2,1) .12s}
body[data-motion="full"] .ul.draw.in::after{scale:1 1}

/* ---- FPS governor demoted the page: kill all entrance motion ------- */
html[data-tier="lite"] .reveal{opacity:1!important;translate:none!important;transition:none!important}
html[data-tier="lite"] .hl.draw::before,
html[data-tier="lite"] .ul.draw::after{scale:1 1!important;transition:none!important}
/* and drop the live feTurbulence/feDisplacement filters — the real paint cost.
   Torn edges fall back to clean edges; the page stays whole, just lighter. */
html[data-tier="lite"] .paper>.sheet,
html[data-tier="lite"] .about .paper::before,
html[data-tier="lite"] .mast::after,
html[data-tier="lite"] footer::before,
html[data-tier="lite"] .tape,
html[data-tier="lite"] footer .stamp,
html[data-tier="lite"] .hl::before,
html[data-tier="lite"] .ul::after,
html[data-tier="lite"] .polaroid::before,
html[data-tier="lite"] .snap::before,
html[data-tier="lite"] .cutline .cut-torn{filter:none!important}

/* ---- footer opt-in sound toggle (sits in the legal row) ------------ */
footer .legal .snd{font-family:var(--f-mono);font-size:.72rem;letter-spacing:.05em;text-transform:lowercase;
  color:var(--oats);background:none;border:1.6px solid rgba(254,246,228,.5);border-radius:5px;
  display:inline-flex;align-items:center;min-height:44px;padding:.28em .8em;cursor:pointer;
  transition:border-color .12s, color .12s}
footer .legal .snd:hover,
footer .legal .snd[aria-pressed="true"]{border-color:var(--oats);color:var(--oats)}
footer .legal .snd:focus-visible{outline:2px solid var(--oats);outline-offset:2px}

/* ===================================================================
   M4 — tear-away: pull a taped piece free; the washi flutters down.
   The grab affordance + the "peeling up" lift while you pull (the hard
   registration shadow deepens with --pull), then the detached washi tape's
   feather fall. The fall of the page itself is driven inline by app.js.
   =================================================================== */
[data-tearable]{cursor:grab;touch-action:pan-y}
[data-tearable].tearing{cursor:grabbing;position:relative;z-index:60;user-select:none}
/* the photos inside polaroids/snaps are draggable by default; stop the native
   image drag so the whole piece tears instead of the picture peeling off it */
[data-tearable] img{-webkit-user-drag:none;user-select:none;-webkit-touch-callout:none}
/* peel-up: the deeper you pull, the higher it lifts off the page */
.paper.tearing>.sheet,
.polaroid.tearing,
.snap.tearing{
  box-shadow:calc(8px + var(--pull,0)*16px) calc(8px + var(--pull,0)*20px) 0 0 var(--ink);
}

/* the washi, no longer holding anything, drifts down on its own and fades */
.tape-fall{position:fixed;z-index:90;pointer-events:none;will-change:transform,opacity;
  animation:drex-feather 2.7s cubic-bezier(.37,.13,.5,.92) forwards}
.tape-fall>.tape{position:absolute;inset:auto}
@keyframes drex-feather{
  0%  {transform:translate(0,0)        rotate(0deg)   scale(1);   opacity:1}
  12% {transform:translate(-13px,7vh)  rotate(-15deg)}
  30% {transform:translate(15px,21vh)  rotate(13deg)}
  48% {transform:translate(-13px,37vh) rotate(-12deg)}
  66% {transform:translate(12px,55vh)  rotate(11deg);  opacity:.92}
  84% {transform:translate(-9px,74vh)  rotate(-8deg);  opacity:.5}
  100%{transform:translate(6px,96vh)   rotate(5deg)    scale(.96); opacity:0}
}

@media(prefers-reduced-motion:reduce){
  *{transition:none!important;animation:none!important}
  .tape,.eyebrow,.btn,.card,.splay .card,.mast nav a,.about .cap,.card .cap,.hero .pin,footer .stamp,.polaroid,.crew .polaroid,.ul,.hl{transform:none!important}
  .reveal{opacity:1!important;translate:none!important}
  .slam .tape{opacity:1!important;scale:none!important;translate:none!important;rotate:none!important}
  .hl.draw::before,.ul.draw::after{scale:1 1!important}
}

/* ================================================================
   SQUIGGLE VISION — the hand-drawn wobble, now ALIVE (brand §2 "Alive")
   The site already wobbles via feTurbulence/feDisplacementMap; every wobble
   was frozen. Here those exact filters boil: 3 seed-frames cycled with
   step-end = stop-motion redraw a few times a second. Intensity is tiered by
   element SIZE so big paper doesn't induce motion sickness. One dial below.
   Composes with envelope's reveal (those animate `scale`; this animates
   `filter`) and its lite tier (filter:none!important there beats animation,
   so the boil + its paint cost go dormant). prefers-reduced-motion freezes
   everything to the static frame via the *{animation:none} guard above.
   The masthead/footer torn bands and the LOGO are deliberately NOT boiled.
   ================================================================ */
/* ================================================================
   BOIL POLICY (post-beta): THE MARKER MOVES, THE PAPER DOESN'T.

   Boil used to run on ~104 elements — 20 craft tiles, 12 spines, 10 pins, 7 sheets,
   6 makerboard polaroids, every board, every chip. Each boiling element re-rasterises
   an SVG filter on a step-end loop forever, on and off screen alike, and this page is
   ~20,000px tall: most of that work was never visible to anyone. It is now ~20.

   The line is not a perf hack, it is a hierarchy. Boil is how the page POINTS. So the
   animation is reserved for ink that is being drawn FOR you — the marker family, whose
   whole job is "look here" — and everything that is merely hand-MADE sits still:

     BOILS   .ul::after            underlines, "the heart of squigglevision"  (10)
             .hl::before           highlighter swipes                          (6)
             .hl-rot .mark::before the H1 blank's marker — the fold's moment    (1)
             .cut-hook-line        the only copy readable while sealed          (1)
             .sc-down              the scroll cue                               (1)
             .rn-arrow             the Dymo aside that names the loop           (1)

     STILL   every sheet, board, tile, pin, chip, polaroid, stamp and card.

   THEY ALL KEEP filter:url(#...). Losing the animation costs nothing in stillness — a
   static SVG filter rasterises once and is cached, so the hand-drawn EDGE, which is what
   carries the style, is untouched on all 129 of them. Only the motion was removed.

   Before adding boil to anything: it is an attention device, and attention does not
   scale. If everything wobbles, nothing is being pointed at — and the FPS governor
   (app-post-beta.js:44) starts killing animations that matter more.
   ================================================================ */
:root{
  --boil-ink:.5s;     /* underlines + highlighter — smallest, pure marker, liveliest */
  --boil-paper:1.5s;  /* section sheet edges + photo borders/shadows — calm breathing */
  --boil-stamp:1.1s;  /* footer rubber stamp */
}
@keyframes boil-rough  {0%{filter:url(#rough)}  33%{filter:url(#rough2)}  66%{filter:url(#rough3)}}
@keyframes boil-torn   {0%{filter:url(#torn)}   33%{filter:url(#torn2)}   66%{filter:url(#torn3)}}
@keyframes boil-roughsm{0%{filter:url(#roughsm)}33%{filter:url(#roughsm2)}66%{filter:url(#roughsm3)}}
@keyframes boil-soft   {0%{filter:url(#soft)}   33%{filter:url(#soft2)}   66%{filter:url(#soft3)}}

/* UNDERLINES — the heart of squigglevision (marker redrawn every ~1/6s) */
.ul::after  {animation:boil-rough var(--boil-ink) step-end infinite}
/* highlighter is a big translucent fill → boil it ~2x slower to avoid shimmer */
.hl::before {animation:boil-rough calc(var(--boil-ink) * 2.1) step-end infinite}

/* SECTION BORDERS — cut-paper sheets; border + hard shadow ride the same
   filter so they boil together. Per-section phase offsets break lockstep. */
.paper>.sheet{}
.hero .sheet{animation-delay:-.3s}
.about .paper>.sheet{animation-delay:-.95s}
.note .sheet{animation-delay:-1.4s}
.splay .card:nth-child(1)>.sheet{animation-delay:-.5s}
.splay .card:nth-child(2)>.sheet{animation-delay:-1.05s}
.splay .card:nth-child(3)>.sheet{animation-delay:-.2s}

/* footer rubber stamp — alive ink badge */
footer .stamp{}

/* ============================================================
   SQUIGGLEVISION RETROFIT — nothing on this site is drawn with a ruler.
   Everything added in the kit / group-chat / challenge-card / pile work was
   built with crisp CSS borders. Push each one's border+shadow onto a pseudo
   layer so it can ride a roughen filter and boil like the rest of the page.
   ============================================================ */

/* the corkboard itself — a torn slab, not a rectangle */
.corkboard{background:transparent;border:0;box-shadow:none;border-radius:0}
.corkboard::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:8px;
  background:var(--cork-fill);
  border:3px solid var(--ink);
  box-shadow:8px 8px 0 0 var(--ink), inset 0 0 40px rgba(90,60,25,.28);
  filter:url(#torn)}
html[data-tier="lite"] .corkboard::before{filter:none;animation:none}
.corkboard{position:relative;isolation:isolate}

/* the pinned tags */
.pinit{background:transparent;border:0;box-shadow:none}
.pinit::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--paper);
  border:2.4px solid var(--ink);border-radius:5px;box-shadow:3px 4px 0 0 rgba(40,26,10,.5);
  filter:url(#roughsm)}
.pinit:nth-child(even)::before{animation-delay:-.55s}
.pinit:nth-child(3n)::before{animation-delay:-1.1s}
.pinit:hover::before,.pinit:focus-within::before{box-shadow:6px 8px 0 0 rgba(40,26,10,.55)}
.cl-tag{background:transparent;border:0;box-shadow:none}
.cl-tag::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--c,var(--schoolbus));
  border:2.2px solid var(--ink);border-radius:4px;box-shadow:2px 2px 0 0 var(--ink);
  filter:url(#roughsm)}
.cl-tag{position:relative;isolation:isolate}

/* the group chat — bubbles are drawn by hand, not by a UI kit */
.chatmock,.circlemock{background:transparent;border:0;box-shadow:none;position:relative;isolation:isolate}
.chatmock::before,.circlemock::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--paper);
  border:2.6px solid var(--ink);border-radius:8px;box-shadow:7px 8px 0 0 var(--ink);
  filter:url(#torn)}
.circlemock::before{animation-delay:-.85s}
.chatmock{background-image:repeating-linear-gradient(to bottom,transparent 0 25px,rgba(65,77,87,.05) 25px 26px)}
.bub{background:transparent!important;border:0;position:relative;isolation:isolate}
.bub::before{content:"";position:absolute;inset:0;z-index:-1;border:2.2px solid var(--ink);
  border-radius:12px;filter:url(#roughsm)}
.bub.them::before{background:var(--oats);border-bottom-left-radius:3px}
.bub.me::before{background:var(--lazuli);border-bottom-right-radius:3px}
.bub.me{color:var(--oats)}
.bub:nth-of-type(even)::before{animation-delay:-.6s}
.ch-gap i{filter:url(#rough)}
.ch-typing{background:transparent;border:0;position:relative;isolation:isolate}
.ch-typing::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--oats);
  border:2.2px solid var(--ink);border-radius:12px;border-bottom-left-radius:3px;filter:url(#roughsm)}

/* the challenge note + its due stamp */
.cm-note{background:transparent;border:0;position:relative;isolation:isolate}
.cm-note::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--oats);
  border:2.4px solid var(--ink);border-radius:6px;
  filter:url(#roughsm)}
.cm-note{background-image:repeating-linear-gradient(to bottom,transparent 0 22px,rgba(65,77,87,.09) 22px 23px)}
.cm-due{background:transparent;position:relative;isolation:isolate}
.cm-due::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--colorado);
  border-radius:3px;filter:url(#roughsm)}

/* the challenge index card in HOW */
.pc-card{background:transparent;border:0;box-shadow:none;position:relative;isolation:isolate}
.pc-card::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--paper);
  background-image:repeating-linear-gradient(to bottom,transparent 0 27px,rgba(65,77,87,.11) 27px 28px);
  border:2.6px solid var(--ink);border-radius:7px;box-shadow:9px 10px 0 0 var(--ink);
  filter:url(#torn)}

/* the gift tags */
.gift-pile li{background:transparent!important;border:0;box-shadow:none;position:relative;isolation:isolate}
.gift-pile li::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--c,var(--ink));
  border:2.2px solid var(--ink);border-radius:5px;box-shadow:3px 3px 0 0 var(--ink);
  filter:url(#roughsm)}
.gift-pile li:nth-child(odd)::before{animation-delay:-.7s}
.gift-pile li:nth-child(3n)::before{animation-delay:-1.3s}


/* ===================================================================
   M4 — Founder's note: click-to-unfold 3D paper crumple overlay.
   Visual-only chrome; the WebGL canvas is injected by app.js. JS skips the
   whole feature under reduced-motion / calm / lite, so nothing to hide here.
   =================================================================== */
.crumple-host{position:absolute;inset:0;z-index:6;cursor:pointer}
.crumple-hint{position:absolute;left:50%;bottom:16px;transform:translateX(-50%);z-index:8;pointer-events:auto;
  font-family:var(--f-hand);font-size:1.1rem;color:var(--ink);background:rgba(254,246,228,.92);
  border:2.4px solid var(--ink);border-radius:7px;padding:.25em .8em;cursor:pointer;
  box-shadow:3px 3px 0 0 var(--ink);animation:crumpleBob 1.7s ease-in-out infinite}
/* folded/readable state: a quiet corner chip, no bob, so it never fights the letter's copy */
.crumple-hint.is-fold{left:auto;right:12px;bottom:12px;transform:none;animation:none;
  font-size:.92rem;opacity:.82;box-shadow:2px 2px 0 0 var(--ink);transition:opacity .15s ease,transform .15s ease}
.crumple-hint.is-fold:hover{opacity:1;transform:translateY(-1px)}
.crumple-hint:focus-visible{outline:3px solid var(--lazuli);outline-offset:3px}
@keyframes crumpleBob{0%,100%{transform:translateX(-50%) translateY(0)}50%{transform:translateX(-50%) translateY(-4px)}}
@media(prefers-reduced-motion:reduce){.crumple-hint{animation:none}}

/* ====================================================================
   PORTED FEATURES (collage / mobile burger / attention CTA)
   Re-ported from feat/collage-sound onto the app.css/app.js split.
   Sound module intentionally omitted — app.js already has marker draw-on.
   ==================================================================== */
/* =================================================================
   MODULE: COLLAGE SCRAPS — littered scrapbook ephemera in the gutters
   (cg- namespace). Flat color only, hard offset shadows only.
   Decorative: aria-hidden + pointer-events:none, low z, never over text.
   ================================================================= */
.hero, .about, .team, .note, .doors{
  position:relative;  /* anchor the absolutely-positioned .cg-collage layers at the FULL-BLEED
                         section so scrap offsets are viewport-relative, never cut by the body's
                         overflow-x at the wrap edge (footer is already relative) */
}
.cg-collage{
  position:absolute; inset:0; z-index:0;
  pointer-events:none;
  overflow:visible;
}
.cg-collage.cg-fore{z-index:3}  /* foreground layer: scraps taped OVER a paper corner (never near text) */
/* gutter rails: hug the 1150px content column on wide screens, never closer than
   10px (6px inboard rail) to the viewport edge on small ones */
.cg-gl{left:max(10px, calc(50vw - 601px))}
.cg-gr{right:max(10px, calc(50vw - 601px))}
.cg-gl2{left:max(6px, calc(50vw - 561px))}   /* inboard rail — lands under the paper edge for tucked scraps */
.cg-gr2{right:max(6px, calc(50vw - 561px))}
.cg-scrap.cg-shadow svg{filter:drop-shadow(3px 3px 0 var(--ink))}  /* zero-blur = solid offset shadow; light grounds only */
.cg-scrap{
  position:absolute;
  display:block;
  pointer-events:none;
  opacity:0;
  transform:translate(var(--cg-dx,0), var(--cg-ty,14px)) rotate(0deg) scale(.96);
  transition:opacity .6s ease, transform .62s cubic-bezier(.2,.8,.25,1);
  will-change:transform,opacity;
}
.cg-scrap svg{display:block; overflow:visible; width:var(--cg-w,auto); height:auto}
@media(max-width:720px){
  .cg-scrap svg{width:calc(var(--cg-w) * .8)}  /* uniform downscale so bigger scraps don't crowd small layouts */
}
.cg-scrap.cg-in{
  opacity:1;
  transform:translate(var(--cg-dx,0), var(--cg-py,0px)) rotate(var(--cg-rot,0deg)) scale(1);
}
.cg-scrap.cg-s1{transition-delay:.04s}
.cg-scrap.cg-s2{transition-delay:.13s}
.cg-scrap.cg-s3{transition-delay:.22s}
.cg-scrap.cg-s4{transition-delay:.31s}
.cg-scrap.cg-s5{transition-delay:.40s}
.cg-scrap.cg-s6{transition-delay:.50s}

/* ---- SEAM BURST: hero marginalia erupts UPWARD out of the slit on the cut ----
   The hero collage carries .cg-burst (eruption easing + targeting). app.js
   initCollage measures each scrap's resting centre vs the slit centre once at
   env.done and writes the additive origin (--bx/--by), then arms .cg-burst-armed to
   collapse every scrap to a zero-size dot ON the slit — all while opacity:0, so the
   collapse is invisible. At html.revealed the collapse rule stops matching and the
   existing .cg-in rest rule + this transition interpolate slit->gutter. --bx/--by and
   --cg-py are ADDITIVE terms in ONE translate(), so the parallax loop (writes --cg-py)
   and the burst never fight over `transform`. No @keyframes, no fill-mode. */
.cg-burst .cg-scrap{transition:opacity .45s ease, transform .82s cubic-bezier(.26,1.36,.44,1)}  /* back-out overshoot = a POP, scraps fly slightly past then settle (overshoot goes outward off the gutter edges, swallowed by body overflow-x:clip) */
/* burst-specific stagger: near-simultaneous (a single explosion) with a little jitter,
   tighter than the per-section settle delays it overrides */
.cg-burst .cg-scrap.cg-s1{transition-delay:0s}
.cg-burst .cg-scrap.cg-s2{transition-delay:.04s}
.cg-burst .cg-scrap.cg-s3{transition-delay:.07s}
.cg-burst .cg-scrap.cg-s4{transition-delay:.03s}
.cg-burst .cg-scrap.cg-s5{transition-delay:.09s}
.cg-burst .cg-scrap.cg-s6{transition-delay:.12s}
/* armed = every scrap is a dot on the slit (additive origin). Specificity (0,4,1)+!important
   beats .cg-scrap.cg-in (0,2,0); the opacity gate below still owns opacity. */
html.sealed:not(.revealed) .cg-burst-armed .cg-scrap{
  transform:translate(calc(var(--cg-dx,0) + var(--bx,0px)), calc(var(--cg-py,0px) + var(--by,0px)))
    rotate(var(--cg-r0,0deg)) scale(0)!important;
  transform-origin:50% 50%;
}
/* used only during the synchronous measure/arm snap so it never animates (invisible at opacity:0) */
.cg-burst.cg-nofade .cg-scrap{transition:none!important}
/* no-JS safety: without html.js, .cg-in is never added and scraps would be stuck
   opacity:0 (the .cg-scrap base) — show them at rest instead. No effect on the JS path. */
html:not(.js) .cg-scrap{opacity:1;transform:translate(var(--cg-dx,0),0) rotate(var(--cg-rot,0deg)) scale(1)}
/* hold every doodle until the envelope is cut — they fade in with the page
   reveal (html.revealed lands ~2s after the cut; the existing opacity
   transition + s1/s2/s3 stagger then plays). Sealed is never set under
   reduced-motion, so the instant-show override below is unaffected. */
html.sealed:not(.revealed) .cg-scrap{opacity:0!important}
.cg-scrap .cg-wob{filter:url(#roughsm)}
.cg-scrap .cg-torn{filter:url(#torn)}
@media(max-width:560px){
  .cg-scrap.cg-drop-sm{display:none}
}
@media(max-width:1199px){
  .cg-scrap.cg-drop-lg{display:none}  /* hero gutter pieces: the envelope fills the column below ~1200px */
}
@media(min-width:1200px){
  .cg-mob{display:none}  /* the mobile confetti burst only exists where the gutter scraps are dropped */
}
@media(prefers-reduced-motion:reduce){
  .cg-scrap{
    opacity:1 !important;
    transition:none !important;
    transform:translate(var(--cg-dx,0),0) rotate(var(--cg-rot,0deg)) scale(1) !important;
  }
}

/* =================================================================
   MODULE: MOBILE BURGER MENU
   Hidden on desktop; the inline .mast nav stays as-is above 720px.
   ================================================================= */
.burger{display:none}
.m-panel{display:none}
@media(max-width:720px){
  .mast>.wrap>nav{display:none}  /* hide ONLY the desktop masthead nav, not the panel's inner <nav> */
  .burger{
    display:inline-flex;align-items:center;justify-content:center;
    width:48px;height:48px;min-width:48px;min-height:48px;padding:0;cursor:pointer;
    background:var(--paper);border:2.6px solid var(--ink);border-radius:6px;
    box-shadow:3px 3px 0 0 var(--ink);transform:rotate(-2deg);
    transition:transform .09s ease, box-shadow .09s ease;
    position:relative;z-index:42;
  }
  .burger:hover{transform:rotate(0)}
  .burger:active{transform:translate(3px,3px) rotate(0);box-shadow:0 0 0 0 var(--ink)}
  .burger:focus-visible{outline:3px solid var(--lazuli);outline-offset:3px}
  .burger svg{display:block;width:26px;height:26px}
  .burger .bl{
    stroke:var(--ink);stroke-width:3;stroke-linecap:round;fill:none;
    filter:url(#roughsm);
    transition:transform .22s ease, opacity .16s ease;
    transform-box:fill-box;transform-origin:center;
  }
  .burger[aria-expanded="true"] .b1{transform:translateY(7px) rotate(45deg)}
  .burger[aria-expanded="true"] .b2{opacity:0}
  .burger[aria-expanded="true"] .b3{transform:translateY(-7px) rotate(-45deg)}
  .m-panel{
    display:block;position:absolute;top:calc(100% - 6px);right:14px;z-index:40;
    width:min(300px,calc(100vw - 28px));
    background:var(--paper);border:2.6px solid var(--ink);border-radius:8px;
    box-shadow:7px 8px 0 0 var(--ink);
    padding:1.5rem 1.1rem 1.2rem;
    transform:translateY(-10px) rotate(-1deg);opacity:0;visibility:hidden;
    pointer-events:none;
    transition:transform .2s ease, opacity .18s ease, visibility 0s linear .18s;
  }
  .m-panel[data-open="true"]{
    opacity:1;visibility:visible;pointer-events:auto;
    transform:translateY(0) rotate(-1deg);
    transition:transform .2s ease, opacity .18s ease, visibility 0s;
  }
  .m-panel .tape{top:-15px;left:50%;margin-left:-59px;transform:rotate(-2.5deg)}
  .m-panel ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.55rem}
  .m-panel li{display:block}
  .m-panel .m-link{
    display:flex;align-items:center;min-height:48px;
    font-family:var(--f-mono);font-size:.92rem;letter-spacing:.1em;text-transform:uppercase;
    text-decoration:none;color:var(--ink);
    border:2px solid var(--ink);border-radius:6px;padding:.55em .9em;background:var(--paper);
    box-shadow:3px 3px 0 0 var(--ink);
    transition:transform .08s ease, box-shadow .08s ease;
  }
  .m-panel li:nth-child(odd) .m-link{transform:rotate(-1.6deg)}
  .m-panel li:nth-child(even) .m-link{transform:rotate(1.6deg)}
  .m-panel .m-link:hover{transform:rotate(0) translate(-1px,-1px);box-shadow:4px 4px 0 0 var(--grass)}
  .m-panel .m-link:focus-visible{outline:3px solid var(--lazuli);outline-offset:3px}
  .m-panel .m-cta{margin-top:1.05rem;display:flex;justify-content:center}
  .m-panel .m-cta .btn{width:100%;justify-content:center;transform:rotate(-1.2deg)}
  .m-panel .m-cta .btn:hover{transform:rotate(0)}
}
@media(min-width:721px){
  .burger{display:none!important}
  .m-panel{display:none!important}
}
@media(prefers-reduced-motion:reduce){
  .burger,.m-panel,.m-panel .m-link,.m-panel .m-cta .btn{transform:none!important}
  .m-panel{transition:opacity 0s, visibility 0s!important}
  .m-panel[data-open="true"]{transform:none!important}
  .burger .bl{transition:opacity .12s ease!important}
  .burger[aria-expanded="true"] .b1{transform:translateY(7px) rotate(45deg)!important}
  .burger[aria-expanded="true"] .b3{transform:translateY(-7px) rotate(-45deg)!important}
  .m-panel .tape{transform:none!important}
}

/* =================================================================
   MODULE: ATTENTION-GRABBING PRIMARY CTA — idle "look at me" loop
   Flat color only, solid offset shadows, zero blur. Stops on intent
   (.cta-quiet) or reduced-motion.
   ================================================================= */
.cta-attn{position:relative;display:inline-flex;isolation:isolate}
.cta-attn .btn{position:relative;z-index:1}
.cta-attn .cta-ring{
  position:absolute;z-index:0;pointer-events:none;
  inset:-9px -11px;
  border:2.6px solid var(--colorado);
  border-radius:10px;
  filter:url(#roughsm);
  opacity:0;
}
.cta-scrawl{
  position:absolute;z-index:2;pointer-events:none;
  left:50%;bottom:calc(100% + 8px);
  transform:translateX(-50%) rotate(-3deg);
  display:flex;flex-direction:column;align-items:center;gap:1px;
  white-space:nowrap;
}
.cta-scrawl .cta-words{
  font-family:var(--f-hand);font-weight:400;line-height:1;
  font-size:1.35rem;color:var(--colorado);
}
.cta-scrawl .cta-arrow{
  display:block;width:26px;height:30px;color:var(--colorado);
}
.cta-scrawl .cta-arrow svg{display:block;width:100%;height:100%}
@keyframes ctaShimmy{
  0%   {transform:rotate(0) scale(1)}
  3%   {transform:rotate(-2deg) scale(1.03)}
  6%   {transform:rotate(2deg) scale(1.03)}
  9%   {transform:rotate(-1.6deg) scale(1.02)}
  12%  {transform:rotate(1.4deg) scale(1.02)}
  15%  {transform:rotate(0) scale(1)}
  100% {transform:rotate(0) scale(1)}
}
@keyframes ctaRing{
  0%   {opacity:0;transform:scale(.94)}
  4%   {opacity:.9;transform:scale(1)}
  14%  {opacity:.55;transform:scale(1.06)}
  22%  {opacity:0;transform:scale(1.12)}
  100% {opacity:0;transform:scale(1.12)}
}
@keyframes ctaBob{
  0%   {transform:translateX(-50%) rotate(-3deg) translateY(0)}
  6%   {transform:translateX(-50%) rotate(-3deg) translateY(-5px)}
  14%  {transform:translateX(-50%) rotate(-3deg) translateY(0)}
  100% {transform:translateX(-50%) rotate(-3deg) translateY(0)}
}
.cta-attn:not(.cta-quiet){animation:ctaShimmy 5.2s ease-in-out infinite}
.cta-attn:not(.cta-quiet) .cta-ring{animation:ctaRing 5.2s ease-in-out infinite}
.cta-attn:not(.cta-quiet) .cta-scrawl{animation:ctaBob 5.2s ease-in-out infinite}
.cta-attn.cta-quiet{animation:none}
.cta-attn.cta-quiet .cta-ring{animation:none;opacity:0}
.cta-attn.cta-quiet .cta-scrawl{
  animation:none;
  opacity:0;
  transition:opacity .4s ease;
  transform:translateX(-50%) rotate(-3deg);
}
.card .cta-scrawl{font-size:1.2rem;bottom:calc(100% + 6px)}
/* hero CTA: gap above the button is tight (lede sits close) — lay the cue out
   horizontally ("tap me! ↓") so it tucks into the gap without crowding the lede */
.hero .cta-scrawl{flex-direction:row;align-items:flex-end;gap:5px;bottom:calc(100% + 9px)}
.hero .cta-scrawl .cta-words{font-size:1.08rem}
.hero .cta-scrawl .cta-arrow{width:16px;height:19px}
@media(prefers-reduced-motion:reduce){
  .cta-attn,
  .cta-attn .cta-ring,
  .cta-attn .cta-scrawl{animation:none!important}
  .cta-attn .cta-ring{opacity:0!important}
  .cta-attn:not(.cta-quiet) .cta-scrawl{
    opacity:1!important;
    transform:translateX(-50%) rotate(-3deg)!important;
  }
  .cta-attn.cta-quiet .cta-scrawl{opacity:0!important}
}

/* ============ THE SHOWPIECE — firecracker "Join a Circle" CTA (initFirecrackerCta
   in app.js, ported from the wall's WallCta). On click the button casing SPLITS in
   half (the halves fly apart and tumble away), its guts spray out across the viewport,
   debris rushes the screen, then the branded CircleMark zooms in on its own stroke
   until the whole screen is grass green → navigate. ~3s. ============ */
.cta-attn.is-firing{animation:none}
.cta-attn.is-firing .btn,
.btn.is-firing{visibility:hidden}
.cta-attn.is-firing .cta-ring,
.cta-attn.is-firing .cta-scrawl{opacity:0!important;animation:none!important}

.detonation{position:fixed;inset:0;z-index:9999;pointer-events:none;overflow:hidden}
.deto-origin{position:absolute;left:var(--ox);top:var(--oy);width:0;height:0}

/* the two casing halves — matched to the real .btn (grass-deep fill, ink border, r6) */
.cta-half{position:absolute;left:0;top:0;width:var(--half-w);height:var(--half-h);
  background:var(--grass-deep);border:2.6px solid var(--ink);will-change:transform,opacity}
.cta-half.l{margin-left:calc(var(--half-w) * -1);margin-top:calc(var(--half-h) * -0.5);
  border-radius:6px 0 0 6px;border-right:none;animation:fc-split-l 760ms cubic-bezier(.2,.7,.3,1) both}
.cta-half.r{margin-top:calc(var(--half-h) * -0.5);
  border-radius:0 6px 6px 0;border-left:none;animation:fc-split-r 760ms cubic-bezier(.2,.7,.3,1) both}
@keyframes fc-split-l{0%{transform:translate(0,0) rotate(0);opacity:1}100%{transform:translate(-46vw,38vh) rotate(-210deg);opacity:0}}
@keyframes fc-split-r{0%{transform:translate(0,0) rotate(0);opacity:1}100%{transform:translate(46vw,40vh) rotate(220deg);opacity:0}}

/* outward-spraying guts */
.deto-origin .p{position:absolute;left:0;top:0;color:var(--p-color);will-change:transform,opacity;
  animation:fc-fly var(--dur) cubic-bezier(.2,.7,.3,1) var(--delay) both}
.deto-origin .p svg{display:block;width:100%;height:100%}
.deto-origin .p-word{font-family:var(--f-hand);font-size:1.35rem;white-space:nowrap;transform-origin:50% 50%}
@keyframes fc-fly{
  0%{transform:translate(0,0) rotate(0) scale(.1);opacity:0}
  8%{opacity:1}
  55%{transform:translate(calc(var(--tx) * .72),calc(var(--ty) * .72 - 40px)) rotate(calc(var(--rot) * .6)) scale(var(--sc));opacity:1}
  100%{transform:translate(var(--tx),var(--ty)) rotate(var(--rot)) scale(calc(var(--sc) * .9));opacity:0}}

/* debris that RUSHES the screen (scales up toward the viewer) */
.deto-origin .p-rush{position:absolute;left:0;top:0;color:var(--p-color);will-change:transform,opacity;
  animation:fc-rush var(--dur) cubic-bezier(.55,.06,.68,.19) var(--delay) both}
.deto-origin .p-rush svg{display:block;width:100%;height:100%}
@keyframes fc-rush{
  0%{transform:translate(0,0) scale(.12);opacity:0}
  14%{opacity:1}
  100%{transform:translate(calc(var(--tx) * .5),calc(var(--ty) * .5)) scale(var(--rush-sc)) rotate(var(--rot));opacity:0}}

/* the hero CircleMark: zooms straight at the screen; a grass core guarantees full coverage */
.fill-ring{position:absolute;left:0;top:0;width:120px;height:120px;margin:-60px 0 0 -60px;transform-origin:50% 50%;color:var(--fill-color)}
.fill-mark{position:absolute;inset:0;animation:fc-mark 3000ms cubic-bezier(.5,0,.85,.4) both;will-change:transform}
.fill-mark svg{width:100%;height:100%;display:block}
.fill-mark svg circle{stroke:var(--fill-color)}
.fill-core{position:absolute;left:50%;top:50%;width:120px;height:120px;margin:-60px 0 0 -60px;border-radius:50%;
  background:var(--fill-color);animation:fc-core 3000ms cubic-bezier(.7,0,.9,.45) both;will-change:transform}
@keyframes fc-mark{0%,8%{transform:scale(0);opacity:0}16%{opacity:1}60%{transform:scale(3.4) rotate(28deg);opacity:1}100%{transform:scale(42) rotate(70deg);opacity:1}}
@keyframes fc-core{0%,45%{transform:scale(0);opacity:0}55%{opacity:1}88%,100%{transform:scale(var(--fill-scale));opacity:1}}

/* SACRED a11y: the JS already bails to instant nav under reduced-motion; hide the overlay as a belt */
@media(prefers-reduced-motion:reduce){.detonation{display:none}}

/* subordinate secondary CTA — "or start one →" rides to the same /join-online/
   flow but stays visually quiet next to the primary stamp button: a small
   grass underline-link, never a second button. */
.cta-alt{font-family:var(--f-mono);font-weight:500;font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;
  color:var(--grass-deep);text-decoration:underline;text-decoration-thickness:1.5px;text-underline-offset:3px;
  text-decoration-color:rgba(12,110,57,.45);
  display:inline-flex;align-items:center;gap:.3rem;min-height:44px;align-self:flex-start;
  transition:text-decoration-color .12s ease, transform .12s ease}
.cta-alt .arr{font-family:var(--f-mono)}
.cta-alt:hover,.cta-alt:focus-visible{text-decoration-color:var(--grass-deep);transform:translateY(-1px)}
.cta-alt:focus-visible{outline:2px solid var(--lazuli);outline-offset:3px;border-radius:3px}
.hero .cta{align-items:center}          /* keep the quiet link baseline-aligned with the stamp button */
/* the organizer's door — a DIFFERENT door, not a third flavour of the same one, so it
   reads as "this page has a path for me" rather than more small print. */
.cta-org{color:var(--colorado);text-decoration-color:rgba(247,84,88,.5)}
.cta-org:hover,.cta-org:focus-visible{text-decoration-color:var(--colorado)}

/* ===================================================================
   M5 — Photo VANDALISM: sharpie doodles scrawled onto a tapped photo.
   The layer pins to the photo box but overflows it (a stroke can spill past
   the edge). Marks are hand-drawn irregular SVG — no live boil filter, so 20+
   of them stay cheap. Each draws on via a stroke wipe + a quick pop. JS skips
   the whole feature under reduced-motion, so there's nothing to gate here.
   =================================================================== */
.vandal-layer{position:absolute;z-index:4;overflow:visible;pointer-events:none}
.sharpie{position:absolute;left:50%;top:50%;width:62%;
  transform:translate(-50%,-50%) rotate(var(--vr,0)) scale(var(--vs,1));
  color:var(--vc,var(--ink));will-change:transform;
  animation:sharpie-pop .19s cubic-bezier(.3,1.5,.5,1) both}
.sharpie svg{display:block;width:100%;height:auto;overflow:visible;
  filter:drop-shadow(.5px .8px 0 rgba(65,77,87,.18))}
/* every stroke carries pathLength="1" → one wipe length fits all */
.sharpie [pathLength]{stroke-dasharray:1;stroke-dashoffset:1;animation:sharpie-draw .3s ease-out forwards}
.sharpie .googly{animation:none}
@keyframes sharpie-draw{to{stroke-dashoffset:0}}
@keyframes sharpie-pop{from{opacity:0;transform:translate(-50%,-50%) rotate(var(--vr,0)) scale(calc(var(--vs,1)*.55))}
  to{opacity:1;transform:translate(-50%,-50%) rotate(var(--vr,0)) scale(var(--vs,1))}}
@media(prefers-reduced-motion:reduce){.sharpie,.sharpie [pathLength]{animation:none;stroke-dashoffset:0;opacity:1}}

/* ============================================================

/* ===================================================================
   M5 — THE FINALE. Reward reveal + zine-stamp confetti + the crumple host.
   The reward sits full-bleed with its own paper ground so it cleanly covers
   the husk in every path (shader success, lite fade, or capture failure).
   z: reward 80 < confetti 85 < crumple host 95 (the ball falls in front).
   =================================================================== */
html.finale-on, html.finale-on body{overflow:hidden!important;touch-action:none}
html.finale-hide body>header, html.finale-hide body>main, html.finale-hide body>footer{visibility:hidden}
html.finale-hide-soft body>header, html.finale-hide-soft body>main, html.finale-hide-soft body>footer{
  transition:opacity .42s ease, transform .5s cubic-bezier(.5,0,.8,.4);
  opacity:0;transform:scale(.86) rotate(-2deg);pointer-events:none}

#finale-host{position:fixed;inset:0;z-index:95;pointer-events:none;will-change:transform,opacity}
#finale-host canvas{position:absolute;left:0;top:0;width:100%;height:100%}

#finale-reward{position:fixed;inset:0;z-index:80;display:flex;align-items:center;justify-content:center;
  padding:24px;opacity:0;visibility:hidden;pointer-events:none;
  background:radial-gradient(circle at 50% 38%, var(--oats) 0%, var(--oats) 58%, rgba(65,77,87,.10) 100%)}
#finale-reward.show{opacity:1;visibility:visible;pointer-events:auto}
.finale-card{text-align:center;max-width:min(560px,90vw);transform:scale(.8);
  animation:finale-pop .6s cubic-bezier(.2,1.5,.45,1) .05s both}
.finale-card:focus{outline:none}
.finale-star{width:clamp(74px,14vw,108px);height:auto;display:block;margin:0 auto .55rem;
  fill:var(--happy);stroke:var(--ink);stroke-width:1.1;
  filter:drop-shadow(4px 5px 0 var(--ink));
  transform-origin:50% 55%;animation:finale-star-in .7s cubic-bezier(.2,1.6,.4,1) .12s both, finale-star-idle 3.4s ease-in-out 1s infinite}
.finale-head{font-family:var(--f-hand);font-weight:400;line-height:1.05;
  font-size:clamp(2.4rem,8vw,4.6rem);color:var(--ink);margin:.1rem 0 .2rem;transform:rotate(-1.6deg)}
.finale-sub{font-family:var(--f-hand);font-size:clamp(1.05rem,3.2vw,1.45rem);color:var(--sambas);
  margin:.1rem auto .9rem;max-width:30ch;opacity:.92}
.finale-card .btn{transform:rotate(-1.4deg)}
@keyframes finale-pop{from{opacity:0;transform:scale(.8) rotate(1.5deg)}to{opacity:1;transform:scale(1) rotate(0)}}
@keyframes finale-star-in{from{transform:scale(0) rotate(-90deg)}to{transform:scale(1) rotate(0)}}
@keyframes finale-star-idle{0%,100%{transform:rotate(-5deg) scale(1)}50%{transform:rotate(5deg) scale(1.05)}}

/* zine-stamp confetti: bursts up/out from centre, then rains down */
#finale-confetti{position:fixed;inset:0;z-index:85;pointer-events:none;overflow:hidden}
.zine-confetti{position:fixed;top:46%;width:11px;height:15px;border-radius:2px;
  display:flex;align-items:center;justify-content:center;line-height:1;white-space:nowrap;
  transform:translate(-50%,-50%);will-change:transform,opacity;
  animation:confetti-fall var(--dur,2.4s) cubic-bezier(.3,.5,.5,1) var(--delay,0s) forwards}
.zine-confetti.zc-round{border-radius:50%}
.zine-confetti.zc-star{width:auto;height:auto;background:none!important;font-size:1.5rem}
.zine-confetti.zc-word{width:auto;height:auto;font-family:var(--f-hand);font-size:.9rem;font-weight:400;
  background:var(--oats);border:1.5px solid currentColor;border-radius:3px;padding:1px 6px}
@keyframes confetti-fall{
  0%  {opacity:0;transform:translate(-50%,-50%) translate(0,0) scale(var(--scale,1)) rotate(0)}
  8%  {opacity:1}
  24% {transform:translate(-50%,-50%) translate(calc(var(--dx,0)*18vw), calc(var(--kick,-.6)*16vh)) scale(var(--scale,1)) rotate(calc(var(--rot,180deg)*.4))}
  86% {opacity:1}
  100%{opacity:0;transform:translate(-50%,-50%) translate(calc(var(--dx,0)*32vw), 80vh) scale(var(--scale,1)) rotate(var(--rot,180deg))}}
@media(prefers-reduced-motion:reduce){
  .finale-card,.finale-star,.zine-confetti{animation:none}
  .finale-card{transform:none}.finale-star{transform:none}}
=======
   M5 — THE HAMBURGER THAT LIES. Tap the burger: it flops onto a string and a
   torn slit opens where it sat. The whole nav strand — links + the dangling
   burger, all on ONE string — feeds out of the cut as you DRAG THE BURGER down
   (--pull 0→1). Yank past DANGER and the string TEARS (strand falls, burger
   respawns); click the fallen burger to reel it home. Keyboard / reduced-motion
   get a plain menu. Shown on all viewports (the burger IS the nav).
   =================================================================== */
.mast .wrap{position:relative}
.mast > .wrap > nav{display:none}
.hb{position:relative;--pull:0;z-index:40;display:inline-flex}

.burger{display:inline-flex!important;align-items:center;justify-content:center;width:48px;height:44px;
  background:var(--paper);border:2.6px solid var(--ink);border-radius:7px;box-shadow:3px 3px 0 0 var(--ink);
  cursor:pointer;transition:opacity .2s ease, transform .1s, box-shadow .1s;transform:rotate(-1.5deg)}
.burger:hover{transform:rotate(0)}
.burger:active{transform:translate(3px,3px) rotate(0);box-shadow:0 0 0 0 var(--ink)}
.burger:focus-visible{outline:3px solid var(--lazuli);outline-offset:3px}
.bars{display:flex;flex-direction:column;gap:4.5px;width:22px}
.bars i{height:2.8px;background:var(--ink);border-radius:2px;display:block}
.hb[data-state="fallen"] .burger,.hb[data-state="open"] .burger,.hb[data-state="torn"] .burger{opacity:0;pointer-events:none}

/* hanging rig — interactive parts only (mouth area stays click-through) */
.hb-rig{position:absolute;top:40px;right:0;width:320px;opacity:0;pointer-events:none;transition:opacity .2s ease}
.hb[data-state="fallen"] .hb-rig,.hb[data-state="open"] .hb-rig,.hb[data-state="torn"] .hb-rig,.hb[data-state="plain"] .hb-rig{opacity:1}
/* mouth overhangs the rig by 32px so the sway arc (480 * sin 3.5° ≈ 29px max,
   plus 3px hard shadows) never crosses the clip edge; strand padding + thread
   right + sway origin all carry the same 32px so the rest pose is unchanged */
.hb-mouth{position:absolute;top:0;right:-32px;width:352px;height:480px;overflow:clip;pointer-events:none}
.hb-sway{transform-origin:calc(100% - 32px) top;will-change:transform}
.hb[data-state="fallen"]:not(.is-dragging) .hb-sway{animation:hbdropin .5s cubic-bezier(.34,1.4,.5,1), hbsway 2.8s ease-in-out infinite}
@keyframes hbsway{0%,100%{transform:rotate(var(--hb-amp,3.5deg))}50%{transform:rotate(calc(-1 * var(--hb-amp,3.5deg)))}}
@media(max-width:520px){.hb{--hb-amp:2.2deg}}  /* mast gutter bottoms out at 1rem; keep the swing inside it */
@keyframes hbdropin{from{translate:0 -52px}60%{translate:0 7px}to{translate:0 0}}

/* ONE strand: links + string + dangling burger move together with --pull */
.hb-strand{position:relative;display:flex;flex-direction:column;align-items:flex-end;gap:15px;padding:44px 35px 0 0;
  transform:translateY(calc((var(--pull) - 1) * 260px))}
.hb[data-state="fallen"] .hb-strand,.hb[data-state="open"] .hb-strand{transition:transform .08s linear}
.hb-tray{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;align-items:flex-end;gap:15px;position:relative;z-index:1;pointer-events:none}
.hb-tray li{display:block}
.hb-tray a{font-family:var(--f-mono);font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;text-decoration:none;
  color:var(--ink);background:var(--paper);border:2.4px solid var(--ink);border-radius:6px;box-shadow:3px 3px 0 0 var(--ink);
  padding:.5em .85em;display:inline-block;white-space:nowrap;pointer-events:none}
.hb[data-state="open"] .hb-tray,.hb[data-state="open"] .hb-tray a,.hb[data-state="plain"] .hb-tray a{pointer-events:auto}
.hb-tray li:nth-child(odd) a{transform:rotate(-1.6deg)}
.hb-tray li:nth-child(even) a{transform:rotate(1.4deg)}
.hb-tray a:hover{transform:rotate(0) translate(-1px,-1px);box-shadow:4px 4px 0 0 var(--grass)}
.hb-tray .hb-cta .btn{font-size:.72rem;pointer-events:none}
.hb[data-state="open"] .hb-tray .hb-cta .btn,.hb[data-state="plain"] .hb-tray .hb-cta .btn{pointer-events:auto}
/* string is ROOTED at the slit and STRETCHES as you over-pull (top counters the
   strand's translate so it never slides out of the cut) — taut, then it snaps */
.hb-thread{position:absolute;top:calc((1 - var(--pull)) * 260px);bottom:0;right:57px;width:4px;border-radius:3px;z-index:0;
  background:repeating-linear-gradient(48deg, var(--lazuli) 0 4px, var(--lazuli-deep) 4px 8px);filter:url(#roughsm)}
.hb-fallen{position:relative;z-index:1;margin-top:22px;width:48px;height:44px;display:inline-flex;align-items:center;justify-content:center;
  background:var(--paper);border:2.6px solid var(--ink);border-radius:7px;box-shadow:3px 3px 0 0 var(--ink);
  cursor:grab;touch-action:none;pointer-events:auto}
.hb.is-dragging .hb-fallen{cursor:grabbing}
.hb.pulled .hb-fallen{margin-top:44px}

/* coaching bubble — teaches the hidden pull. Lives inside #hb-fallen, so it rides
   --pull / sway / tear / respawn for free. data-coach carries visibility + tone + copy. */
.hb-bubble{position:absolute;right:40px;top:-16px;z-index:2;pointer-events:none;
  width:152px;height:99px;opacity:0;transform:rotate(-3deg);transition:opacity .18s ease}
.hb-cloud,.hb-face{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
.hb-face{display:none}
/* once opened, the pulled-out burger square itself goes happy-yellow + smiles (same face) */
.hb-facesm{display:none;width:28px;height:26px}
.hb.hb-happy .hb-fallen{background:var(--happy);transition:background .35s ease}
.hb.hb-happy .hb-fallen .bars{display:none}
.hb.hb-happy .hb-fallen .hb-facesm{display:block}
/* torn off: the falling burger goes red with a hand-drawn X-eyes dead face */
.hb-facex{display:none;width:30px;height:28px}
.hb[data-state="torn"] .hb-fallen{background:var(--colorado)}
.hb[data-state="torn"] .hb-fallen .bars{display:none}
.hb[data-state="torn"] .hb-fallen .hb-facex{display:block}
.hb-say{position:absolute;left:9%;top:28%;width:74%;height:44%;display:flex;align-items:center;justify-content:center;
  text-align:center;font-family:var(--f-hand);font-weight:700;font-size:.96rem;line-height:1.02;color:var(--hb-ink,var(--ink));padding:0 1px}
/* visibility gate: a data-coach key present AND the rig is out */
.hb[data-state="fallen"] .hb-bubble[data-coach],.hb[data-state="open"] .hb-bubble[data-coach],.hb[data-state="torn"] .hb-bubble[data-coach]{opacity:1}
/* idle downward bob (points the way) */
.hb-bubble[data-coach="pull"],.hb-bubble[data-coach="keep"]{animation:hbcoachbob 1.4s ease-in-out infinite}
/* tone ramp: neutral paper -> cool blue -> GREEN just-right -> yellow -> red. Cloud fill = --hb-tone, text = --hb-ink */
.hb-bubble[data-coach="almost"]{--hb-tone:var(--lazuli);--hb-ink:var(--oats)}
.hb-bubble[data-coach="release"]{--hb-tone:var(--grass);--hb-ink:var(--oats)}
.hb-bubble[data-coach="strain"]{--hb-tone:var(--schoolbus);--hb-ink:var(--ink)}
.hb-bubble[data-coach="danger"],.hb-bubble[data-coach="tear"]{--hb-tone:var(--colorado);--hb-ink:var(--oats)}
.hb-bubble[data-coach="danger"]{animation:hbcoachshake .12s linear infinite}
/* fully pulled out: happy cloud becomes a hand-drawn smiley, words hidden, then it auto-fades */
.hb-bubble[data-coach="open"]{--hb-tone:var(--happy);animation:hbcoachbye .5s ease 1.15s forwards}
.hb-bubble[data-coach="open"] .hb-say{display:none}
.hb-bubble[data-coach="open"] .hb-face{display:block}
@keyframes hbcoachbob{0%,100%{transform:rotate(-3deg) translateY(0)}50%{transform:rotate(-3deg) translateY(4px)}}
@keyframes hbcoachshake{0%,100%{transform:rotate(-3deg) translateX(0)}50%{transform:rotate(-3deg) translateX(2.5px)}}
@keyframes hbcoachbye{to{opacity:0}}
/* localized confetti on the first successful open (reuses the site's spray glyphs) */
.hb-conf{position:fixed;inset:0;z-index:90;pointer-events:none;overflow:hidden}
.hb-conf-bit{position:absolute;top:-6%;width:16px;height:16px;opacity:0;animation:hbconffall var(--dur,2s) linear var(--dl,0ms) forwards}
.hb-conf-bit svg{width:100%;height:100%;display:block}
@keyframes hbconffall{0%{opacity:0;transform:translateY(0) translateX(0) rotate(0)}
  7%{opacity:1}90%{opacity:1}
  100%{opacity:.85;transform:translateY(112vh) translateX(var(--drift,0)) rotate(var(--rot,360deg))}}
@media(prefers-reduced-motion:reduce){.hb-bubble{transition:none}.hb-conf{display:none}
  .hb-bubble[data-coach="pull"],.hb-bubble[data-coach="keep"],.hb-bubble[data-coach="danger"]{animation:none}}

/* the cut, drawn ON TOP so the strand reads as emerging from the paper */
.hb-pocket{display:none;position:absolute;top:-3px;right:-6px;width:150px;height:24px;pointer-events:none;z-index:2;
  background:linear-gradient(to bottom, rgba(65,77,87,.16), rgba(65,77,87,0))}
.hb[data-state="rest"] .hb-pocket,.hb[data-state="plain"] .hb-pocket{opacity:0}
.hb-slit{position:absolute;top:-1px;right:0;width:132px;height:0;border-top:3px solid var(--ink);filter:url(#roughsm);z-index:3;pointer-events:none}
.hb[data-state="rest"] .hb-slit,.hb[data-state="plain"] .hb-slit{opacity:0}

/* danger: string reddens + stretches as you over-pull */
.hb.is-straining .hb-thread{background:repeating-linear-gradient(48deg, var(--colorado) 0 4px, var(--coral-ink) 4px 8px)}
.hb.is-straining .hb-strand{transition:none}
.hb.is-straining .hb-fallen{margin-top:52px}
.hb.is-straining .hb-tray a{border-color:var(--colorado)}

/* TORN: the strand drops away */
.hb[data-state="torn"] .hb-mouth{overflow:visible}   /* let the snapped burger fall past the clip, all the way off-screen */
.hb[data-state="torn"] .hb-strand{animation:hbdrop 1s cubic-bezier(.5,0,.9,.45) forwards}
@keyframes hbdrop{to{transform:translateY(120vh) rotate(34deg)}}

/* keyboard / reduced-motion / no-JS: an honest dropdown */
.hb[data-state="plain"] .hb-mouth{position:static;overflow:visible;width:auto;height:auto;pointer-events:auto}
.hb[data-state="plain"] .hb-sway,.hb[data-state="plain"] .hb-strand{transform:none;animation:none!important}
.hb[data-state="plain"] .hb-string,.hb[data-state="plain"] .hb-fallen{display:none}
.hb.respawning .hb-rig{opacity:0!important;transition:none!important}
@media(prefers-reduced-motion:reduce){ .hb-sway,.hb-fall{animation:none!important} }


/* ===== VOLCANO eruption overlay - paste into app.css ===== */
/* fixed, contained, pointer-inert layer that holds the eruption */
.vol-layer{
  position:fixed; inset:0;
  z-index:70;                 /* over hero + envelope card; under .tape-fall(90) and #finale-*(80-95) */
  pointer-events:none;
  overflow:hidden;            /* arcs off the edges are clipped, never produce scrollbars */
  contain:layout paint size;  /* isolate: 170 particles never reflow/repaint the page */
}
.vol-p{
  position:absolute; top:0; left:0;
  will-change:transform, opacity;
  transform-origin:50% 50%;
  backface-visibility:hidden; /* nudge each onto its own GPU layer */
}
.vol-p svg{ display:block; overflow:visible; }      /* keep native width/height; JS scales per particle */
/* real ZINE covers erupt WITH the doodles — the cut births the OUTPUT, not just marginalia */
.vol-p.vz{ width:clamp(50px,7.5vw,88px); }
.vol-p.vz i{ display:block; width:100%; aspect-ratio:3/4; background-size:cover; background-position:center 12%;
  border:2.6px solid var(--ink); box-shadow:3px 3px 0 0 rgba(65,77,87,.5);
  filter:url(#soft); }   /* hand-drawn edge — never a dead-straight border on paper/photo */
html[data-tier="lite"] .vol-p.vz i{ filter:none; }   /* weak devices only: drop the SVG filter cost */
/* drop the hand-drawn boil filters on clones - flat shape + brand colour is the confetti
   (JS already strips filter attrs on the pool; this is belt-and-braces for any CSS-applied ones) */
.vol-p svg *{ filter:none !important; }
/* reduced motion: spawnVolcano already early-returns and never builds the layer; final belt */
@media (prefers-reduced-motion: reduce){ .vol-layer{ display:none !important; } }

/* ============ ZBOOK — zine links read as a cute little booklet, never a polaroid ============ */
.zpola.zbook{background:transparent;border:none;box-shadow:none;width:clamp(158px,20vw,210px)}
.zpola.zbook .ph{aspect-ratio:4/5;border:2.6px solid var(--ink);border-radius:3px 9px 9px 3px;
  box-shadow:3.4px 3.4px 0 0 var(--oats),4.8px 4.8px 0 0 var(--ink),8px 8px 0 0 var(--oats),9.6px 9.6px 0 0 var(--ink)}
.zpola.zbook .zpola-cap{padding-top:.75rem}
.zine-duo .zpola.zbook:hover{box-shadow:none}

/* bigger objects — the evidence is the point: polaroids ~1.6x, booklets ~2x */
.zpola{width:clamp(180px,23vw,250px)}
.zpola.zbook{width:clamp(230px,30vw,330px)}
.zine-card{width:min(560px,100%)}
.zine-duo .zpola:nth-child(2){margin-left:-30px;margin-top:30px}
@media(max-width:480px){.zpola{width:42vw}.zpola.zbook{width:54vw}}

/* ============ PEGBOARD — the showing-up kit, six tools hung on a workshop wall ============ */
.pegwall{position:relative;max-width:960px;margin:0 auto;padding:clamp(1.6rem,4vw,3rem) clamp(1rem,3vw,2.4rem) clamp(2rem,4.5vw,3.4rem)}
/* the board itself lives on a filtered layer so its edges wobble like everything else */
.pegwall::before{content:"";position:absolute;inset:0;z-index:0;
  background:var(--oats);border:3px solid var(--ink);border-radius:12px;
  box-shadow:10px 11px 0 0 var(--ink);
  background-image:radial-gradient(circle, rgba(65,77,87,.22) 2.4px, transparent 3px);
  background-size:36px 36px;background-position:14px 18px;filter:url(#rough)}
.pegwall>*{position:relative;z-index:1}
.peg-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(1.4rem,3.4vw,2.6rem) clamp(.8rem,2vw,1.6rem)}
.peg-tool{position:relative;display:flex;flex-direction:column;align-items:center;margin:0;
  transform:rotate(var(--rot,0deg));transition:transform .18s ease}
.peg-tool:hover{transform:rotate(0deg) translateY(-5px)}
.peg-hook{width:26px;height:18px;margin-bottom:-6px}
.peg-obj{width:clamp(96px,12vw,132px);height:auto;filter:drop-shadow(4px 5px 0 rgba(65,77,87,.9))}
.peg-string{width:2.5px;height:16px;background:var(--ink);margin:2px 0 0;filter:url(#roughsm)}
.peg-tag{position:relative;margin-top:2px;padding:.5rem .7rem .55rem;max-width:22ch;text-align:center;
  transform:rotate(var(--tagrot,0deg))}
.peg-tag::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--paper);
  border:2.4px solid var(--ink);box-shadow:4px 5px 0 0 var(--ink);filter:url(#roughsm)}
.peg-tag b{display:block;font-family:var(--f-mono);font-weight:700;font-size:.98rem;letter-spacing:.02em;color:var(--ink)}
.peg-tag span{display:block;font-family:var(--f-hand);font-size:.95rem;line-height:1.15;margin-top:.15rem;color:var(--sambas)}
.peg-tag .capline{display:block;font-family:var(--f-hand);font-size:.8rem;line-height:1;margin-bottom:.2rem}
@media (max-width:720px){.peg-grid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:430px){.peg-grid{gap:1.2rem .6rem}.peg-tag{max-width:18ch}}
/* the parts tray under the pegboard: the orb, then the small stuff */
.peg-tray{margin-top:clamp(1.8rem,3.6vw,2.6rem);text-align:center;position:relative}
.tray-rule{display:block;width:96%;height:12px;margin:0 auto 1.1rem}
/* two instruments in labeled compartments, then six parts bins (wabi-sabi tilts) */
.tray-duo2{display:flex;justify-content:center;gap:clamp(.9rem,2.4vw,1.5rem);flex-wrap:wrap;margin-bottom:1.25rem}
.tray-inst{position:relative;display:flex;align-items:center;gap:.75rem;padding:.6rem .95rem;max-width:34ch;
  text-align:left;transform:rotate(var(--irot,0deg))}
.tray-inst::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--paper);
  border:2.4px solid var(--ink);box-shadow:4px 5px 0 0 var(--ink);filter:url(#roughsm)}
.tray-inst>svg{width:54px;height:54px;flex:none;overflow:visible}
.tray-inst b{display:block;font-family:var(--f-mono);font-weight:700;font-size:.98rem;color:var(--ink)}
.tray-inst i{display:block;font-style:normal;font-family:var(--f-hand);font-size:1rem;line-height:1.2;color:var(--sambas);margin-top:.1rem}
.tray-label{display:inline-block;font-family:var(--f-hand);color:var(--colorado);font-size:1.18rem;transform:rotate(-1.5deg);margin-bottom:.6rem}
.bin-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.85rem;max-width:850px;margin:0 auto}
.bin{position:relative;display:flex;align-items:center;gap:.6rem;padding:.55rem .7rem;text-align:left;
  transform:rotate(var(--brot,0deg))}
.bin::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--oats);
  border:2.2px solid var(--ink);box-shadow:3px 4px 0 0 var(--ink);filter:url(#roughsm)}
.bin .bi{width:30px;height:30px;flex:none;overflow:visible}
.bin span{font-family:var(--f-hand);font-size:1.04rem;line-height:1.15;color:var(--ink)}
@media(max-width:720px){.bin-grid{grid-template-columns:repeat(2,1fr)}}
@media(max-width:460px){.bin-grid{grid-template-columns:1fr;max-width:22rem}}
.tray-letters{margin:1.1rem auto 0;max-width:52ch;font-size:1.08rem;line-height:1.35;color:var(--sambas);transform:rotate(-.7deg)}
.tray-letters a{color:var(--grass-deep);text-underline-offset:3px}

/* ============ nothing straight: filtered frame layers for the newer components ============ */
/* polaroids (people + video slots): frame moves to a wobbled layer; content stays crisp */
.zpola{background:transparent;border:none;box-shadow:none}
.zpola::before{content:"";position:absolute;inset:0;z-index:0;background:var(--paper);
  border:2.4px solid var(--ink);border-radius:5px;box-shadow:6px 6px 0 0 var(--ink);
  filter:url(#roughsm);transition:box-shadow .18s ease}
.zpola>*{position:relative;z-index:1}
.zine-duo .zpola:hover{box-shadow:none}
.zine-duo .zpola:hover::before{box-shadow:10px 11px 0 0 var(--ink)}
/* zbooks: no polaroid frame; the booklet edge + a HARD page-stack shadow, wobbled */
.zpola.zbook::before{display:none}
.zpola.zbook .ph{border:none;box-shadow:none;overflow:visible}
.zpola.zbook .ph img{border-radius:2px 7px 7px 2px}
.zpola.zbook .ph::after{content:"";position:absolute;inset:0;pointer-events:none;
  border:2.6px solid var(--ink);border-radius:3px 9px 9px 3px;
  box-shadow:4px 4px 0 0 var(--oats),5.5px 5.5px 0 0 var(--ink),9px 9px 0 0 var(--paper),11px 11px 0 0 var(--ink);
  filter:url(#roughsm)}
/* tabs + stamps wobble too (tiny text survives the small-scale boil) */
.zine-tab{background:transparent}
.zine-tab::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--tabbg,var(--ink));
  border-radius:4px;filter:url(#roughsm)}
.zine-card.bot .zine-tab{background:transparent;--tabbg:var(--lazuli)}
.soon-stamp{filter:url(#roughsm)}

/* ============ scrawled section closers: the zines knock line + the showup pulse line ============ */
.zines-knock,.showup-pulse{ margin:clamp(1.6rem,3.4vw,2.4rem) auto 0; max-width:36ch; text-align:center;
  font-size:clamp(1.05rem,2vw,1.3rem); line-height:1.3; color:var(--colorado); transform:rotate(-1.4deg); }

/* ============ hero headline rotator — "…become a ____": the blank types itself in ============
   The word is DELETED a letter at a time and the next one TYPED in its place, and the marker
   swipes across each word once it lands. Two constraints that pull against each other:

   1. THE FULL STOP MUST FOLLOW THE TEXT. It's the last character of the sentence, so it has to
      sit against the word's last letter at every length, exactly as it would if someone were
      writing the line. That means it lives INSIDE the slot, as the tail of the typed run.
   2. THE SLOT MUST NEVER RESIZE. If it breathed, the headline would re-wrap and gain or lose a
      display line — the hero card visibly grows and shrinks once per word.

   Both hold because the live run (.rw, holding .mark + the stop) shares ONE inline-grid cell
   with a hidden ghost of every word, each carrying its own stop. The ghosts never change, so
   the track is permanently as wide as "photographers." even while the live word is two letters
   down. No measuring, no hard-coded ch width, no reflow. The fixed width is invisible now —
   it does nothing but stop the line moving.

   LEFT-aligned: letters grow rightward off a fixed edge. Centred, a word collapses toward its
   own middle as it deletes and the stop drifts left with it, which reads as nothing at all. */
.hl-rot{display:inline-grid;vertical-align:baseline;text-align:left}
.hl-rot .rw{grid-area:1/1;justify-self:start;white-space:nowrap;
  font-style:normal;font-weight:600;color:var(--ink)}
.hl-rot .ghost{visibility:hidden}   /* sizers only — they hold the track open, they never animate */
/* the sentence a screen reader actually gets. The rotator itself is aria-hidden, so without
   this it would end "They're becoming ." — or worse, "becoming photograp". */
.rot-a11y{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
/* The swatch hugs the WORD, not the slot — which is only possible because it's a resting state:
   it shows when the word is at full length and lifts before a letter is touched. Deliberately
   NOT built on .hl: the hero's .hl swatches are already driven by the envelope reveal, the FPS
   tier and the draw-on, and .hl::before's transition is set from a selector I can't outrank
   from here. So this is a standalone marker that opts INTO the two parts it wants — the rough
   filter and the boil — and owns its own transform. No caret: a blinking I-beam is a keyboard's
   punctuation, not a hand's, and on a page of marker and tape it looked like software. */
.hl-rot .mark{position:relative;z-index:0}
.hl-rot .mark::before{content:"";position:absolute;left:-.17em;right:-.06em;top:.08em;bottom:-.04em;
  z-index:-1;background:var(--happy);mix-blend-mode:multiply;opacity:.95;border-radius:2px;
  filter:url(#rough);animation:boil-rough calc(var(--boil-ink) * 2.1) step-end infinite;
  transform:rotate(-.9deg) skewX(-5deg) scaleX(0);transform-origin:left center;
  transition:transform .24s ease-in}                     /* lifting off before a delete: quick */
.hl-rot.lit .mark::before{transform:rotate(-.9deg) skewX(-5deg) scaleX(1);
  transition:transform .46s cubic-bezier(.2,.7,.2,1)}    /* the swipe across a finished word */
/* the FPS governor's bargain everywhere else on the page: keep the mark, drop the live filter */
html[data-tier="lite"] .hl-rot .mark::before{filter:none;animation:none}
/* Sealed, this swatch would be the ONE highlighter already drawn on a card whose others are
   all still scaled to 0 waiting for the cut. Hold it back and let it swipe on with them —
   same .lit-hl beat the rest of the hero uses. Both rules must outrank .hl-rot.lit, hence
   the long selectors; neither sets transition, so the .24s/.46s pair below still governs. */
html.sealed .hero-card .hl-rot .mark::before{transform:rotate(-.9deg) skewX(-5deg) scaleX(0)}
html.sealed .envelope.lit-hl .hero-card .hl-rot.lit .mark::before{transform:rotate(-.9deg) skewX(-5deg) scaleX(1)}

/* ============ the READER section — zines flip THROUGH the phone, one at a time ============ */
.flip2-stage{display:flex;justify-content:center;margin:clamp(1rem,2.6vw,1.8rem) auto 0}
.flip2{width:min(640px,92vw);margin:0}
.flip2 figcaption{text-align:center;font-family:var(--f-hand);color:var(--grass-deep);
  font-size:clamp(1rem,1.9vw,1.2rem);margin-top:.6rem;transform:rotate(-1.2deg)}
.belt{position:relative;overflow:hidden}
.belt-phone{position:relative;z-index:2;display:block;width:100%;height:auto;pointer-events:none}
.belt-rail{position:absolute;inset:0;display:flex;align-items:center;z-index:0}
.belt-track{display:flex;gap:26px;will-change:transform;margin-left:calc(50% - 312px);
  animation:belt-step 13s cubic-bezier(.65,-0.15,.25,1.12) infinite}
.bz{width:104px;flex:none;height:auto;overflow:visible}
/* six holds, six snaps — one zine slot (130px) per flip, looping seamlessly */
@keyframes belt-step{
  0%,12.5%{transform:translateX(0)}
  16.66%,29.16%{transform:translateX(-130px)}
  33.33%,45.83%{transform:translateX(-260px)}
  50%,62.5%{transform:translateX(-390px)}
  66.66%,79.16%{transform:translateX(-520px)}
  83.33%,95.83%{transform:translateX(-650px)}
  100%{transform:translateX(-780px)}
}
.belt-ui{position:absolute;left:50%;bottom:14%;transform:translateX(-50%) rotate(-2deg);z-index:3}
/* the stamp is a fixed-size label; on phones the phone shrinks but the stamp didn't, so it
   spilled past the bezel onto the neighbouring zines. Scale it to the small screen. */
@media(max-width:640px){.belt-ui .soon-stamp{font-size:.55rem;letter-spacing:.08em;padding:.32em .5em}}
/* the open-and-read overlay: the landed cover grows to fill the screen, then scrolls.
   Six panels, one per belt window, phased on the same 13s clock. */
.belt-open{position:absolute;left:32.03%;top:22.5%;width:35.94%;height:55%;overflow:hidden;z-index:1}
.bo{position:absolute;inset:0;opacity:0;transform:scale(.5);transform-origin:50% 50%;
  animation:bo-pop 13s infinite;animation-delay:calc(var(--d) * 13s / 6)}
.bo-scroll{position:absolute;inset:0;animation:bo-scroll 13s infinite;animation-delay:inherit}
.bo-scroll svg{display:block;width:100%;height:auto}
@keyframes bo-pop{
  0%,1.4%{opacity:0;transform:scale(.5)}
  1.5%{opacity:1;transform:scale(.5)}
  3.4%{transform:scale(1)}
  10.4%{opacity:1;transform:scale(1)}
  12.3%,100%{opacity:0;transform:scale(.6)}
}
@keyframes bo-scroll{
  0%,4.2%{transform:translateY(0)}
  10.6%{transform:translateY(-46%)}
  12.4%{transform:translateY(-46%)}
  12.6%,100%{transform:translateY(0)}
}
@media(prefers-reduced-motion:reduce){.belt-track,.bo,.bo-scroll{animation:none}.bo{opacity:0}}
.showup-pulse{ color:var(--grass-deep); transform:rotate(1.2deg); max-width:40ch; }
/* =====================================================================
   THE HEADING SYSTEM  (brand book §06 — restored)
   ---------------------------------------------------------------------
   The brand defines TWO display faces and the site had collapsed them into one:

     Pitch      (--f-display)  "moments where we need maximum impact"  → the h1. Nothing else.
     Pitch Sans (--f-head)     "Headings and Subheadings"              → every h2 and h3.

   Pitch Sans is an upright SANS; it had been substituted with DM Mono, a monospace. That made
   the hero and all ten section heads the same face, in the same italic, at the same weight —
   so SIZE was the only rank signal left, and size was broken too (the h1 rendered at 34px,
   under every h2 on the page). Hierarchy is carried by FAMILY first, size second. Restore both
   and it holds even at 25% zoom.

   These rules come last on purpose: they match the per-section selectors' specificity and win on
   source order, so the ~11 legacy `.x .head h2` blocks above are neutralised in one place rather
   than edited in eleven. Delete those blocks when convenient; nothing here depends on them.
   ===================================================================== */
.how .head h2,.zines .head h2,.versus .head h2,.doors .head h2,
.kit .head h2,.longgame .head h2,.gifts .head h2,.team .head h2,
.proof .head h2,
.bring .head h2,.bring h2{
  font-family:var(--f-head);font-style:normal;font-weight:700;
  letter-spacing:-.015em;line-height:1.06;text-wrap:balance;
  /* margin-inline:auto is NOT optional: the .head containers are text-align:center, so a
     max-width'd h2 block without it hugs the left edge and only its text centres inside the
     narrow box — which reads as "every heading is off-centre". */
  color:var(--ink);max-width:24ch;margin-inline:auto;
  font-size:var(--fs-2);                    /* TIER B — the supporting cast */
}
/* TIER A — the spine of the pitch: what it is → what you make → how you find people →
   why not a group chat. Someone who reads only these four heads has the whole product.
   ID selectors (1,1,1) outrank the class rules above (0,2,1), so this is the only place tier
   lives. To promote a section, add its id here. That's the whole mechanism. */
#how .head h2,#zine .head h2,#reader .head h2,#why-not-chat .head h2{font-size:var(--fs-1)}

/* h3s. `.card.big h3` used to sit at clamp(2.1rem,3.2vw,2.9rem) — 41px — which made the word
   "Instagram" outrank six section headings and the h1. An h3 never outranks an h2. */
.card h3,.card.big h3{
  font-family:var(--f-head);font-style:normal;font-weight:700;
  font-size:var(--fs-3);letter-spacing:-.01em;line-height:1.12;text-wrap:balance;
}
/* The loop's ring nodes keep their container-query sizes (cqw): the ring is a self-contained
   illustration and must scale as one object, not on the page's rem ladder. Family only. */
.how .step h3{font-family:var(--f-head);font-style:normal;font-weight:700}

/* =====================================================================
   THE HERO — "Most creative groups never finish anything. Yours will."
   ---------------------------------------------------------------------
   The pile of real work sits BEHIND the card and spills out on every side.
   That ordering is the entire trick, and it's why a dozen earlier arrangements
   read as dead: the card's paper is opaque, so the pile can be as chaotic and
   overlapping as it likes and it can never cover a word. Any layout that puts
   the work BESIDE the type has to keep the work tidy — and tidy has no energy.

   Craft rules, all learned the expensive way:
     · #torn is scale 12 (calibrated). #tornbig is 28 and SHREDS a thin border.
     · An SVG displacement filter smears the element's CONTENT. It goes on a
       ::before paper layer — never on anything holding text or a photograph.
     · Flat fill, ink outline, hard SOLID offset shadow. No gradient, no blur.
   ===================================================================== */
.card-clip{z-index:3}                    /* the card, and its type, above the pile. always. */

.hero-pile{position:absolute;inset:-8% -15% -8% -6%;z-index:1;pointer-events:none}
.hero-pile .hp{position:absolute;margin:0;isolation:isolate;
  top:var(--t);left:var(--l);width:var(--w);transform:rotate(var(--r))}
/* the polaroid card. The tear lives HERE, on the paper — not on the photo. */
.hero-pile .hp::before{content:"";position:absolute;inset:-8px -8px -26px;z-index:0;
  background:var(--paper);border:2.6px solid var(--ink);border-radius:4px;
  box-shadow:7px 8px 0 0 var(--ink);filter:url(#torn)}
.hero-pile .hp i{position:relative;z-index:1;display:block;aspect-ratio:1;
  background-size:cover;background-position:center}   /* clean cut-out edges. never filtered. */
.hero-pile .hp figcaption{position:relative;z-index:1;display:block;font-family:var(--f-hand);
  font-size:.86rem;color:var(--ink);margin-top:5px}
@media(max-width:880px){.hero-pile{display:none}}   /* the card owns the phone; the pile would bury it */

/* the two beats of the headline: the problem in ink, the promise in grass */
.hero-card h1 .h1-green{color:var(--grass-deep)}
.hero-card h1 .h1-green .stop{color:var(--grass-deep)}
.hero-scrawl{font-family:var(--f-hand);color:var(--grass-deep);margin:.5rem 0 0;
  font-size:clamp(1.05rem,1.45vw,1.36rem);transform:rotate(-.8deg)}
.hero-card .lede b{font-weight:600;color:var(--ink)}
.hero-rule{display:block;height:4px;max-width:22ch;margin:1.2rem 0 1.1rem;
  background:var(--ink);opacity:.5;filter:url(#rough)}   /* hand-drawn. never a straight border. */

/* one primary + two subs. three colours. each says who it's for. */
.cta-who{font-family:var(--f-hand);font-size:1rem;color:var(--ink-faint);
  margin:.4rem 0 0 .3rem;transform:rotate(-.6deg)}
.cta-subs{display:flex;gap:1.3rem;flex-wrap:wrap;margin-top:1rem}
.door{display:flex;flex-direction:column;gap:.12rem;text-decoration:none}
.door-lbl{position:relative;isolation:isolate;display:inline-block;font-family:var(--f-mono);
  font-weight:700;font-size:.8rem;letter-spacing:.09em;text-transform:uppercase;padding:.52rem .9rem}
/* the wobble is on the BUTTON, not on its letters — a filter on the element smears the text */
.door-lbl::before{content:"";position:absolute;inset:0;z-index:-1;border:2.4px solid currentColor;
  border-radius:4px;background:var(--paper);box-shadow:4px 4px 0 0 currentColor;filter:url(#roughsm)}
.door.org .door-lbl{color:var(--lazuli-deep)}     /* the organizer — the scarce side of the market */
.door.key .door-lbl{color:var(--coral-ink)}       /* already has a key */
.door-who{font-family:var(--f-hand);font-size:.94rem;color:var(--ink-faint);margin-left:.2rem}
.door:hover .door-lbl{transform:translate(1px,1px)}
.door:hover .door-lbl::before{box-shadow:3px 3px 0 0 currentColor}

/* The card was sized to leave a gutter for the instax polaroid that used to sit beside it.
   That polaroid is gone (it was a cross-origin iframe that painted black for ad-blocker users),
   and the pile now lives BEHIND the card instead of next to it — so the card can finally take
   the width it needs. At 54% the new headline broke to four cramped lines. */
@media(min-width:881px){
  .hero .paper.hero-card{width:clamp(480px,63%,760px)}
  .hero-pile{inset:-10% -13% -6% -10%}     /* spill on every side, not just the right */
}
/* the red "scroll down!" scrawl is absolutely positioned and was landing on top of the CTA
   copy. It has no business overlapping a call to action. */
.hero .sc-down{display:none}

/* "Yours will." is not a subtitle — it's the second half of the sentence, and it's the promise.
   It carries the same weight as the problem it answers. Full size, grass. (An earlier rule
   dropped sentence two to .62em to make a *different* headline fit; that rule dies here.) */
.hero-card h1 .h1s+.h1s{font-size:1em;margin-top:.14em;color:var(--ink)}
.hero-card h1 .h1-green,.hero-card h1 .h1-green .stop{color:var(--grass-deep)}
/* the scrawl steps back to lazuli so it reads as an aside, not a third shout in the same voice */
.hero-scrawl{color:var(--lazuli-deep)}

/* The green lost on specificity: `.h1s+.h1s` is (0,3,1) and `.h1-green` was (0,2,1).
   Match the sibling selector's weight so the promise actually reads as the promise. */
.hero-card h1 .h1s+.h1s.h1-green,
.hero-card h1 .h1s+.h1s.h1-green .stop{color:var(--grass-deep)}

/* .sc-down lives in .scroll-cue (a sibling of .hero), so `.hero .sc-down` never matched it.
   It's absolutely positioned and was landing on top of the primary CTA's caption. */
.sc-down{display:none}
/* .hero .cta is a flex ROW, so the caption became a column beside the button instead of a
   line beneath it. It belongs under the stamp — it's telling you who that door is for. */
.hero .cta{flex-direction:column;align-items:flex-start;gap:0}
.hero .cta .cta-attn{margin-bottom:.1rem}

/* the clock's four words — Birdie, so they read as annotation on a drawn object, not as UI */
.ctclock .ct-words text{font-family:var(--f-hand);font-weight:400}

/* =====================================================================
   THE HERO CARD IS LOOSELEAF — blue rules, pink margin, punched holes.
   The card was faint grey lines on cream. Real filler paper is blue-ruled with a
   pink/red vertical margin and a punched edge, and that's the object the whole
   product is about: a page from a notebook that a group filled in together.
   ===================================================================== */
.hero-card>.sheet.ruled{
  background:
    /* the pink margin rule — one vertical line, down the left */
    linear-gradient(90deg, transparent 0 60px, rgba(247,84,88,.42) 60px 61.6px, transparent 61.6px) no-repeat,
    /* the blue horizontal rules */
    repeating-linear-gradient(0deg, transparent 0 26px, rgba(36,150,201,.24) 26px 27.4px),
    var(--paper);
}
/* the punched edge. Holes are the paper's colour with an ink lip, so they read as holes in the
   sheet rather than dots on it — and they sit OUTSIDE the pink margin, where they belong. */
.hero-card .holes{position:absolute;left:20px;top:0;bottom:0;z-index:2;width:22px;
  display:flex;flex-direction:column;justify-content:space-evenly;align-items:center;
  pointer-events:none}
.hero-card .holes i{display:block;width:19px;height:19px;border-radius:50%;
  background:var(--oats);box-shadow:inset 0 0 0 2.2px rgba(65,77,87,.55);filter:url(#roughsm)}
@media(max-width:880px){
  .hero-card>.sheet.ruled{background:
    repeating-linear-gradient(0deg, transparent 0 26px, rgba(36,150,201,.22) 26px 27.4px), var(--paper)}
  .hero-card .holes{display:none}
}
/* the copy starts to the RIGHT of the pink margin rule — that's what a margin is for */
@media(min-width:881px){ .hero-card>.inner{padding-left:84px} }

/* The headline was taking five lines and pushing the doors below the fold — which is the one
   thing that must never happen: above the fold is the invest-or-leave moment. Tune the display
   size to the card's real measure and tighten the vertical rhythm so all three doors clear it. */
@media(min-width:881px){
  .hero-card h1{font-size:clamp(2.4rem,3.7vw,3.35rem);line-height:1.06}
  .hero-card .lede{margin-top:.75rem;font-size:clamp(1rem,1.1vw,1.1rem)}
  .hero-scrawl{margin-top:.45rem}
  .hero-rule{margin:.9rem 0 .85rem}
  .hero .cta{margin-top:1rem}
  .cta-subs{margin-top:.75rem}
  .hero-card .holes i{width:16px;height:16px}
}

/* The copy was being strangled inside the paper: the lede was capped at 320px on a 662px card
   (58% of the page it's printed on) and the h1 at 416px, both from `ch` caps sized for the old
   34px headline in the old 561px card. The page is the measure now — let the type use it.
   Right padding was 27px against 84px on the left; a page has margins on both sides. */
@media(min-width:881px){
  .hero-card h1{max-width:none}
  .hero-card .lede{max-width:none}
  .hero-card .hero-scrawl{max-width:none}
  .hero-card>.inner{padding-right:52px}
  .hero-rule{max-width:30ch}
}

/* the clock carries four words now, so it needs the room to say them. Bigger face = bigger type
   at the same viewBox units, without the words overflowing the dial. */
.how .step.is-clock .ico{width:13.2cqw;height:13.2cqw}
@media(max-width:900px){ .how .step.is-clock .ico{width:66px;height:66px} }
/* the pile wraps ALL FOUR sides of the card — it's a heap the card is buried in, not a backdrop */
@media(min-width:881px){ .hero-pile{inset:-12% -14% -10% -14%} }

/* Craft icons: one per colour block, in the block's OWN ink (currentColor). Monochrome is not a
   style choice here — a multicolour icon ON a coloured block is colour-on-colour and turns to mud
   at this size. And a one-ink set reads as ONE system, which is precisely the section's argument:
   skateboarding, nail art, bonsai and pour-over all belong to the same world. */
.gift-pile li{display:inline-flex;align-items:center;gap:.42em}
.gift-pile .g-ico{width:1.15em;height:1.15em;flex:none;display:block;
  filter:url(#roughsm)}                  /* the same hand-drawn boil as every other mark */

/* ======================= HERO HOTFIXES ==============================
   1. THE RULES WERE BEING WARPED. The blue lines and pink margin were painted on
      .sheet, which carries filter:url(#torn) — so the displacement filter chewed the
      lines the same way it chews the edge, and they skipped and wandered. Same bug as
      everything else today: the tear belongs on the paper, never on what's printed on
      it. Rules move to their own unfiltered layer, inset inside the torn edge. */
.hero-card>.sheet.ruled{background:var(--paper)}          /* paper only. no printing. */
.hero-card .rules{position:absolute;inset:5px;z-index:1;border-radius:5px;pointer-events:none;
  background:
    linear-gradient(90deg, transparent 0 60px, rgba(247,84,88,.42) 60px 61.6px, transparent 61.6px) no-repeat,
    repeating-linear-gradient(0deg, transparent 0 26px, rgba(36,150,201,.26) 26px 27.4px);}
@media(max-width:880px){
  .hero-card .rules{background:repeating-linear-gradient(0deg, transparent 0 26px, rgba(36,150,201,.24) 26px 27.4px)}
}

/* 2. THE PILE WAS SHOWING BEFORE THE CUT. The whole point of the envelope is that
      nothing has come out of it yet. The pile is a sibling of .card-clip, so the seal's
      clip never touched it. It now rises with the card instead of sitting there waiting. */
.hero-pile{opacity:1;transition:opacity .75s ease .45s, transform .9s cubic-bezier(.22,.7,.25,1) .45s}
html.sealed:not(.revealed) .hero-pile{opacity:0;transform:translateY(34px) scale(.97)}
@media(prefers-reduced-motion:reduce){
  .hero-pile{transition:opacity .3s ease}
  html.sealed:not(.revealed) .hero-pile{transform:none}
}

/* 3. THE PILE WAS BLEEDING INTO THE NEXT SECTION — and the first fix for it was wrong.
      Raising the following sections above the pile does nothing, because those sections have
      no background: z-index decides who paints on top, not who is opaque, so the polaroids
      went right on showing through the paper under "How a Circle works". The only thing that
      actually contains them is a clip. `overflow:clip` on the pile bounds it to its own box,
      which ends just above the seam — so the heap gets cut off at the CUT HERE line, which is
      the one place on this page where a hard straight edge through a photograph reads as the
      point rather than as a bug. */
.hero{position:relative;z-index:0}
.hero+*,.hero~section{position:relative;z-index:1}
@media(min-width:881px){ .hero-pile{inset:-12% -14% 4% -14%;overflow:clip} }


/* ---- WAVY RULES, RESTORED (and lighter) --------------------------------
   Printing the rules on the .sheet means filter:url(#torn) warps them — and that wave is the
   whole charm: it reads as paper someone actually ruled by hand, not a CSS grid. Keep it.
   Lighter, so the type wins the page it's printed on. */
.hero-card .rules{display:none}
.hero-card>.sheet.ruled{
  background:
    linear-gradient(90deg, transparent 0 60px, rgba(247,84,88,.28) 60px 61.4px, transparent 61.4px) no-repeat,
    repeating-linear-gradient(0deg, transparent 0 26px, rgba(36,150,201,.14) 26px 27.2px),
    var(--paper);
}
@media(max-width:880px){
  .hero-card>.sheet.ruled{background:
    repeating-linear-gradient(0deg, transparent 0 26px, rgba(36,150,201,.13) 26px 27.2px), var(--paper)}
}

/* ---- THE CLOCK, ACTUALLY BIGGER ---------------------------------------
   My earlier 13.2cqw rule overrode an existing `width:100%` and SHRANK the dial from 155px to
   79px — the opposite of the ask. The clock now carries four words; give it the room to say them. */
.how .step.is-clock .ico{width:132%;height:auto;margin:0 -16% .3rem}
@media(max-width:900px){ .how .step.is-clock .ico{width:118%;margin:0 -9% .3rem} }

/* Polaroids carry the maker's OWN words — their reflection answer from the ledger. Nobody was
   asked for a testimonial, which is exactly why they land. Never invent one of these. */
.hero-pile .hp figcaption{display:block;margin-top:6px;line-height:1.2}
.hero-pile .hp figcaption q{display:block;quotes:"\201C" "\201D";font-family:var(--f-hand);
  font-size:.82rem;color:var(--ink);margin-bottom:2px}
.hero-pile .hp figcaption b{display:block;font-family:var(--f-hand);font-weight:400;
  font-size:.78rem;color:var(--colorado)}
.hero-pile .hp::before{inset:-8px -8px -52px}   /* deeper chin: the quote needs the room */

/* ---- MOBILE: the pile comes out from behind the card ------------------
   On desktop the pile hides behind the card and spills round the edges. On a phone the card
   fills the width, so "behind" means invisible — and the work IS the proof. So below 1100px it
   stops being a backdrop and becomes a littered heap under the card: overlapping, tilted, still
   unmistakably a pile, just one you scroll to instead of one you're buried in. */
@media(max-width:880px){
  .hero-pile{display:flex;position:static;inset:auto;flex-wrap:wrap;justify-content:center;
    align-items:flex-start;gap:0;margin:2.2rem auto 0;padding:0 4vw;max-width:640px;
    opacity:1;transform:none}
  .hero-pile .hp{position:relative;top:auto;left:auto;width:46%;margin:0 -3% 2.4rem;
    transform:rotate(var(--r))}
  .hero-pile .hp:nth-child(n+7){display:none}   /* six is a heap; thirteen is a scroll */
  .hero-pile .hp::before{inset:-6px -6px -46px}
  .hero-pile .hp figcaption q{font-size:.78rem}
  html.sealed:not(.revealed) .hero-pile{opacity:0;transform:translateY(20px)}
}

/* Mobile, take 2: the pile goes ABOVE and the card lies ON it. On desktop the card is BURIED in
   the work; putting the heap below the card on a phone told a different story (card first, work
   as an afterthought). Same relationship, stacked: a pile of finished issues, with this week's
   page lying across them. */
@media(max-width:880px){
  .hero-pile{margin:0 auto -3.6rem;padding:0 3vw;position:relative;z-index:0}
  .card-clip{position:relative;z-index:3}      /* the card lies ON the heap, same as desktop */
  .hero-pile .hp{margin:0 -4% 2.2rem}
  .hero-pile .hp:nth-child(n+5){display:none}  /* four reads as a heap without pushing the card down a screen */
  .hero-pile .hp:nth-child(1){width:50%;--r:-6deg}
  .hero-pile .hp:nth-child(2){width:44%;--r:5deg;margin-top:1.6rem}
  .hero-pile .hp:nth-child(3){width:42%;--r:-3deg;margin-top:-.6rem}
  .hero-pile .hp:nth-child(4){width:46%;--r:7deg}
}

/* ---- MOBILE, take 3: a strip across the top + a scatter down both sides ----
   Four big polaroids stacked above the card read as a gallery you scroll past, not a heap the
   card is lying in. On a phone the card is 355px of a 390px viewport, so there's only ~18px of
   margin — side polaroids have to overhang the card and bleed off the screen edge, which is
   exactly what a real pile does. Small, many, overlapping, half-hidden behind the card. */
@media(max-width:880px){
  .hero-pile{display:block;position:absolute;inset:-7% -17% -1% -17%;z-index:1;
    margin:0;padding:0;max-width:none;opacity:1;transform:none}
  .hero-pile .hp{position:absolute;margin:0;
    top:var(--mt);left:var(--ml);width:var(--mw);transform:rotate(var(--mr))}
  .hero-pile .hp::before{inset:-5px -5px -30px}
  .hero-pile .hp figcaption{margin-top:4px}
  .hero-pile .hp figcaption q{font-size:.6rem;line-height:1.15}
  .hero-pile .hp figcaption b{font-size:.58rem}
  .hero-pile .hp:nth-child(n+13){display:none}

  /* the strip across the top — the card lies on its lower half */
  .hero-pile .hp:nth-child(1){--mt:0%;--ml:2%;--mw:19%;--mr:-9deg}
  .hero-pile .hp:nth-child(2){--mt:2.5%;--ml:20%;--mw:18%;--mr:6deg}
  .hero-pile .hp:nth-child(3){--mt:0.5%;--ml:37%;--mw:19%;--mr:-4deg}
  .hero-pile .hp:nth-child(4){--mt:3%;--ml:55%;--mw:18%;--mr:8deg}
  .hero-pile .hp:nth-child(5){--mt:0%;--ml:72%;--mw:19%;--mr:-6deg}

  /* down the LEFT edge — mostly behind the card, overhanging off the page */
  .hero-pile .hp:nth-child(6){--mt:22%;--ml:-3%;--mw:17%;--mr:-11deg}
  .hero-pile .hp:nth-child(7){--mt:40%;--ml:-5%;--mw:16%;--mr:7deg}
  .hero-pile .hp:nth-child(8){--mt:58%;--ml:-2%;--mw:17%;--mr:-5deg}
  .hero-pile .hp:nth-child(9){--mt:76%;--ml:-4%;--mw:16%;--mr:10deg}

  /* down the RIGHT edge */
  .hero-pile .hp:nth-child(10){--mt:20%;--ml:86%;--mw:17%;--mr:9deg}
  .hero-pile .hp:nth-child(11){--mt:39%;--ml:88%;--mw:16%;--mr:-8deg}
  .hero-pile .hp:nth-child(12){--mt:57%;--ml:85%;--mw:17%;--mr:5deg}
  .hero-pile .hp:nth-child(13){--mt:75%;--ml:88%;--mw:16%;--mr:-10deg}

  html.sealed:not(.revealed) .hero-pile{opacity:0;transform:translateY(22px)}
  .card-clip{position:relative;z-index:3}
}
/* an earlier mobile pass capped the pile at four (`:nth-child(n+5){display:none}`) and that rule
   outranks a plain `.hp{display:block}`. Match its weight to bring the rest of the heap back. */
@media(max-width:880px){
  .hero-pile .hp:nth-child(n+5){display:block}
  .hero-pile .hp:nth-child(n+7){display:block}
  .hero-pile .hp:nth-child(n+13){display:none}
}

/* ---- MOBILE, take 4: the sides sit ON the card's edge, not behind it -------
   Measured: the card is 355px of a 390px viewport, so there are only 18px of margin. Anything
   tucked BEHIND the card shows an 18px sliver and reads as a rendering bug, not a pile. So the
   side scatter goes IN FRONT — clipped to the card's outer edge, well clear of the text (which
   starts ~42px in) and bleeding off the screen. That's what a real collage does: things land on
   the page. Captions come off the side ones — there's no room, and the top strip carries them. */
@media(max-width:880px){
  .hero-pile{inset:-8% -11% -1% -11%}
  /* the strip across the top — bigger, and it clears the card so you actually see the work */
  .hero-pile .hp:nth-child(1){--mt:0%;--ml:0%;--mw:23%;--mr:-9deg}
  .hero-pile .hp:nth-child(2){--mt:3%;--ml:21%;--mw:22%;--mr:6deg}
  .hero-pile .hp:nth-child(3){--mt:0.5%;--ml:41%;--mw:23%;--mr:-4deg}
  .hero-pile .hp:nth-child(4){--mt:3.5%;--ml:62%;--mw:22%;--mr:8deg}
  .hero-pile .hp:nth-child(5){--mt:0%;--ml:80%;--mw:22%;--mr:-6deg}

  /* the side scatter — ON the card's edge, clear of the copy, running off the page */
  .hero-pile .hp:nth-child(n+6){z-index:5}
  .hero-pile .hp:nth-child(n+6) figcaption{display:none}
  .hero-pile .hp:nth-child(n+6)::before{inset:-4px}
  .hero-pile .hp:nth-child(6){--mt:24%;--ml:-6%;--mw:15%;--mr:-12deg}
  .hero-pile .hp:nth-child(7){--mt:44%;--ml:-7%;--mw:14%;--mr:8deg}
  .hero-pile .hp:nth-child(8){--mt:63%;--ml:-6%;--mw:15%;--mr:-5deg}
  .hero-pile .hp:nth-child(9){--mt:81%;--ml:-7%;--mw:14%;--mr:11deg}
  .hero-pile .hp:nth-child(10){--mt:22%;--ml:91%;--mw:15%;--mr:10deg}
  .hero-pile .hp:nth-child(11){--mt:42%;--ml:92%;--mw:14%;--mr:-9deg}
  .hero-pile .hp:nth-child(12){--mt:61%;--ml:91%;--mw:15%;--mr:6deg}
  .hero-pile .hp:nth-child(13){display:block;--mt:80%;--ml:92%;--mw:14%;--mr:-11deg}
}

/* ---- MOBILE, take 5: give the strip air, widen the side peek ---------------
   The strip had ~38px between the nav and the card's top edge — not enough to read as
   photographs, so it looked like a rendering glitch. Push the card down and let the work
   breathe above it. Side pieces get wider so they read as photos rather than slivers. */
@media(max-width:880px){
  .hero{padding-top:clamp(6.5rem,20vw,8.5rem)}
  .hero-pile{inset:-13% -13% -1% -13%}
  .hero-pile .hp:nth-child(1){--mt:0%;--ml:-1%;--mw:25%;--mr:-9deg}
  .hero-pile .hp:nth-child(2){--mt:3.5%;--ml:21%;--mw:24%;--mr:6deg}
  .hero-pile .hp:nth-child(3){--mt:0.5%;--ml:42%;--mw:25%;--mr:-4deg}
  .hero-pile .hp:nth-child(4){--mt:4%;--ml:64%;--mw:24%;--mr:8deg}
  .hero-pile .hp:nth-child(5){--mt:0%;--ml:84%;--mw:23%;--mr:-6deg}
  /* the sides: wide enough to read as a photograph, still clear of the copy */
  .hero-pile .hp:nth-child(6){--mt:26%;--ml:-8%;--mw:19%;--mr:-12deg}
  .hero-pile .hp:nth-child(7){--mt:45%;--ml:-9%;--mw:18%;--mr:8deg}
  .hero-pile .hp:nth-child(8){--mt:64%;--ml:-8%;--mw:19%;--mr:-5deg}
  .hero-pile .hp:nth-child(9){--mt:82%;--ml:-9%;--mw:18%;--mr:11deg}
  .hero-pile .hp:nth-child(10){--mt:24%;--ml:89%;--mw:19%;--mr:10deg}
  .hero-pile .hp:nth-child(11){--mt:43%;--ml:90%;--mw:18%;--mr:-9deg}
  .hero-pile .hp:nth-child(12){--mt:62%;--ml:89%;--mw:19%;--mr:6deg}
  .hero-pile .hp:nth-child(13){--mt:81%;--ml:90%;--mw:18%;--mr:-11deg}
}

/* =====================================================================
   POLAROIDS PASTED ON THE CARD — the right column of the page
   ---------------------------------------------------------------------
   The heap behind the card was doing all the work and the card's right half was dead
   paper. So the copy takes a left column and the photos get stuck into the gap it
   leaves — which is how anyone actually fills a notebook page: write down one side,
   paste the photos in the space. Tilted, overlapping, taped, running past the edge.
   ===================================================================== */
@media(min-width:881px){
  /* the copy holds a column; the photos take the rest */
  .hero-card>.inner{padding-right:clamp(230px,30%,330px)}
  .card-stack{position:absolute;z-index:4;top:5%;bottom:6%;right:-4%;
    width:clamp(220px,31%,320px);pointer-events:none}
  .card-stack .cs{position:absolute;margin:0;isolation:isolate;
    top:var(--t);left:var(--l);width:var(--w);transform:rotate(var(--r))}
  /* the tear is on the polaroid's PAPER. Never on the photograph. */
  .card-stack .cs::before{content:"";position:absolute;inset:-7px -7px -16px;z-index:0;
    background:var(--paper);border:2.4px solid var(--ink);border-radius:4px;
    box-shadow:6px 7px 0 0 var(--ink);filter:url(#torn)}
  .card-stack .cs i{position:relative;z-index:1;display:block;aspect-ratio:1;
    background-size:cover;background-position:center}
  /* washi holding the collage down, same as every other scrap on this page */
  .card-stack .cs-tape{position:absolute;z-index:9;width:74px;height:22px;
    background:rgba(241,221,1,.55);box-shadow:inset 0 0 0 1px rgba(255,255,255,.28);
    filter:url(#roughsm)}
  .card-stack .cs-tape.t1{top:1%;left:26%;transform:rotate(-7deg)}
  .card-stack .cs-tape.t2{bottom:3%;left:34%;transform:rotate(5deg)}
}
/* ---- THE PHONE CARD GETS THE COLLAGE TOO --------------------------------------
   The pile behind the card is framing, not proof. On a phone it only ever peeks
   through a 30px margin, so the card itself — the thing you actually read — stayed
   a clean sheet of paper. Wrong. The work belongs ON the page.

   WHY THE PHOTOS ARE ANCHORED TO THE BOTTOM EDGE, IN PIXELS.
   The first cut of this used percentages of the card's height. It looked right at
   390px and fell apart at 360, because the h1 wraps to six lines there, the card
   grows, and every percentage anchor slides — the top polaroid landed on the word
   "finish". Percentages measured against copy that reflows is the same bug this hero
   has now shipped three times.

   The fix is to anchor to something that cannot move. The card's lower stack —
   rule, CTA, the two doors, the terms line — is a fixed height at every width. So
   the collage hangs off the card's BOTTOM edge in px, and no amount of headline
   rewrapping can push it into a word. The h1 and the lede keep their full width and
   are never touched; the three blocks in the lower stack reserve the gutter
   explicitly (they'd otherwise run full-bleed under the photos).

   Five polaroids, five different sizes, overlapping, two taped, two hanging off the
   right edge. Mixed size and overlap are the whole point: evenly-spaced same-size
   thumbnails read as a stock-photo column, which is the deadness we keep killing.
   --------------------------------------------------------------------------- */
@media(max-width:880px){
  /* the lower stack gives up its right column so the collage has somewhere to live */
  .hero-card .cta{padding-right:24%}
  .hero-card .cta-subs{padding-right:24%}
  .hero-card .hero-terms{padding-right:26%}

  .card-stack{display:block;position:absolute;z-index:4;inset:0;pointer-events:none}
  .card-stack .cs{position:absolute;margin:0;isolation:isolate;
    bottom:var(--mb);right:var(--mrt);width:var(--mw);transform:rotate(var(--mr))}
  /* the tear is on the paper, never on the photograph. #rough, not #torn — at 70px a
     scale-12 displacement chews a 2px border into a caterpillar. */
  .card-stack .cs::before{content:"";position:absolute;z-index:0;inset:-4px -4px -10px;
    background:var(--paper);border:2px solid var(--ink);border-radius:3px;
    box-shadow:4px 5px 0 0 var(--ink);filter:url(#rough)}
  .card-stack .cs i{position:relative;z-index:1;display:block;aspect-ratio:1;
    background-size:cover;background-position:center}
  .card-stack .cs figcaption{display:none}   /* a quote at 70px wide is not legible; don't pretend */

  /* Sizes and offsets in px, stacked bottom-up. The tallest piece tops out 322px above
     the card's bottom edge; the lower stack is ~345px tall, so the collage always ends
     below the lede. Negative `right` = hanging off the card onto the pile behind. */
  .card-stack .cs:nth-child(1){--mw:58px;--mb:250px;--mrt:8px; --mr:-10deg}
  .card-stack .cs:nth-child(2){--mw:70px;--mb:178px;--mrt:-4px;--mr:8deg}
  .card-stack .cs:nth-child(3){--mw:86px;--mb:100px;--mrt:2px; --mr:-5deg}   /* the biggest */
  .card-stack .cs:nth-child(4){--mw:64px;--mb:44px; --mrt:16px;--mr:11deg}
  .card-stack .cs:nth-child(5){--mw:76px;--mb:4px;  --mrt:-8px;--mr:-7deg}

  .card-stack .cs-tape{position:absolute;z-index:9;width:44px;height:14px;
    background:rgba(241,221,1,.55);box-shadow:inset 0 0 0 1px rgba(255,255,255,.28);
    filter:url(#roughsm)}
  .card-stack .cs-tape.t1{bottom:296px;right:26px;transform:rotate(-18deg)}
  .card-stack .cs-tape.t2{bottom:172px;right:4px; transform:rotate(12deg)}
}
/* wider phones and small tablets have a fatter gutter, so the pieces grow with it —
   still bottom-anchored, still bounded by the same 345px lower stack. */
@media(min-width:561px) and (max-width:880px){
  .card-stack .cs:nth-child(1){--mw:78px; --mb:232px;--mrt:10px;--mr:-10deg}
  .card-stack .cs:nth-child(2){--mw:94px; --mb:158px;--mrt:-6px;--mr:8deg}
  .card-stack .cs:nth-child(3){--mw:112px;--mb:78px; --mrt:4px; --mr:-5deg}
  .card-stack .cs:nth-child(4){--mw:84px; --mb:30px; --mrt:20px;--mr:11deg}
  .card-stack .cs:nth-child(5){--mw:100px;--mb:2px;  --mrt:-12px;--mr:-7deg}
  .card-stack .cs-tape.t1{bottom:288px;right:30px}
  .card-stack .cs-tape.t2{bottom:164px;right:6px}
}

/* "Yours will." is the promise and it cannot break across two lines. The photo column stole the
   width it needed. Give the copy back enough measure, and size the display to the column it
   actually has — measured, not guessed: 11 chars of Courier Prime at 49px ≈ 323px. */
@media(min-width:881px){
  .hero-card>.inner{padding-right:clamp(205px,26%,268px)}
  .hero-card h1{font-size:clamp(2.2rem,3.35vw,3.05rem);line-height:1.05}
  .card-stack{width:clamp(200px,27%,272px);right:-5%}
  /* tighter, more overlapped — a collage someone pasted, not a column of thumbnails */
  .card-stack .cs{--w:64%}
  .card-stack .cs:nth-child(1){--t:1%;--l:2%;--r:-7deg}
  .card-stack .cs:nth-child(2){--t:17%;--l:34%;--r:8deg}
  .card-stack .cs:nth-child(3){--t:36%;--l:0%;--r:-4deg}
  .card-stack .cs:nth-child(4){--t:55%;--l:36%;--r:10deg}
  .card-stack .cs:nth-child(5){--t:74%;--l:4%;--r:-9deg}
}

/* ---- MOBILE, take 6: the side scatter goes BACK BEHIND the card -------------
   I put it in front because behind it only showed an 18px sliver at 390px. That was the wrong
   trade. At 600px those pieces become slabs sitting ON the page, cutting into the card — which
   is worse than a thin peek at any width. A sliver of paper showing from under a page reads as
   a pile; a photo slapped across the copy reads as a bug. Behind, always. Captions come back. */
@media(max-width:880px){
  .hero-pile .hp:nth-child(n+6){z-index:2}          /* behind the card (card-clip is 3) */
  .hero-pile .hp:nth-child(n+6) figcaption{display:block}
  .hero-pile .hp:nth-child(n+6)::before{inset:-5px -5px -30px}
  /* wider + pushed further out, so the part that clears the card is a real photograph */
  .hero-pile .hp:nth-child(6){--mt:25%;--ml:-11%;--mw:22%;--mr:-12deg}
  .hero-pile .hp:nth-child(7){--mt:46%;--ml:-12%;--mw:21%;--mr:8deg}
  .hero-pile .hp:nth-child(8){--mt:66%;--ml:-11%;--mw:22%;--mr:-5deg}
  .hero-pile .hp:nth-child(9){--mt:85%;--ml:-12%;--mw:21%;--mr:11deg}
  .hero-pile .hp:nth-child(10){--mt:23%;--ml:89%;--mw:22%;--mr:10deg}
  .hero-pile .hp:nth-child(11){--mt:44%;--ml:90%;--mw:21%;--mr:-9deg}
  .hero-pile .hp:nth-child(12){--mt:64%;--ml:89%;--mw:22%;--mr:6deg}
  .hero-pile .hp:nth-child(13){--mt:83%;--ml:90%;--mw:21%;--mr:-11deg}
}

/* ---- THE 881–1100 BAND: the desktop card was starving its own headline -------
   Must sit at the END of the file: the rules it corrects live ~200 lines up at the same
   specificity, so source order is the only thing that decides this, and it took a wasted
   verification pass to notice.

   `padding-right` on the copy was clamp(205px, 26%, 268px) — a hard 205px floor, sized for
   the 760px card you get at 1440. At 900px the card is only 526px wide, so 84px of left
   padding plus 205px of right left a 237px column, and "Most creative groups" shattered into
   one word per line. The photo column and the padding that reserves it have to shrink WITH
   the card (padding always a little wider than the column, or the photos land on the words),
   and the display steps down to the measure it actually has.
   ------------------------------------------------------------------------- */
@media(min-width:881px) and (max-width:1100px){
  .hero-card>.inner{padding-right:clamp(146px,27%,205px)}
  .card-stack{width:clamp(138px,25%,196px)}
  .hero-card h1{font-size:clamp(1.9rem,3.05vw,2.4rem)}
}

/* ---- THE ON-CARD PHOTOS ARE CUTOUTS, NOT POLAROIDS --------------------------
   The pieces BEHIND the card are polaroids: paper, chin, border, hard offset shadow —
   they're objects in a heap, and a heap has depth. The pieces ON the card are a different
   thing entirely. They were glued down. So:

     no chin, no border   — a polaroid frame says "object lying there"; we want "cut out
                            with scissors and pasted", which has no frame at all
     no shadow            — nothing glued flat to a page casts one. The shadow was the
                            single strongest cue that these were floating ABOVE the card,
                            which is exactly the wrong reading
     nothing hangs off    — a shadowless cutout crossing the card's edge stops looking
                            pasted and starts looking like a clipping bug. Overlapping each
                            OTHER is still good, and does all the depth work the shadow used
                            to do. Overlapping the card's border is not.

   What's left is a 3px ragged rim of paper — the margin scissors leave — carrying the
   #rough filter. The tear stays on that rim; the photograph itself is never filtered.
   ------------------------------------------------------------------------- */
.card-stack .cs::before{
  inset:-3px;                 /* a scissor margin, not a polaroid chin */
  border:0;
  border-radius:0;
  box-shadow:none;            /* glued flat. Nothing to cast a shadow. */
  filter:url(#rough);
}

/* Bringing the column inside the card costs width, so the column and the padding that
   reserves it both shrink. Measured: the widest cutout plus its rotation must clear the
   copy's right edge at 881, 1024, 1280 and 1440 — the collision check covers all four. */
/* NOTE the variable names. Each <figure class="cs"> carries --t/--l/--w/--r in an INLINE
   style attribute, and an inline custom property beats any stylesheet — so every desktop
   number written against those names was silently doing nothing, and the cutouts kept
   rendering at the markup's sizes. Declaring the geometry through --dt/--dl/--dw/--dr, which
   the markup never sets, is what actually lands. (The mobile block dodged this by accident:
   --mt/--ml/--mw/--mr aren't inline either.) */
@media(min-width:881px){
  .card-stack{right:14px;width:clamp(126px,26%,184px)}
  .card-stack .cs{width:var(--dw);top:var(--dt);left:var(--dl);transform:rotate(var(--dr))}
  /* Big, and stacked hard into each other. With the shadow gone, OVERLAP is the only thing
     left doing the depth work, so it has to be real overlap — 50-60px of it — and not five
     photos in a tidy vertical line pretending to be a collage. */
  .card-stack .cs:nth-child(1){--dw:92%;--dt:0%; --dl:0%;--dr:-7deg}
  .card-stack .cs:nth-child(2){--dw:92%;--dt:16%;--dl:6%;--dr:8deg}
  .card-stack .cs:nth-child(3){--dw:92%;--dt:33%;--dl:0%;--dr:-4deg}
  .card-stack .cs:nth-child(4){--dw:92%;--dt:50%;--dl:2%;--dr:10deg}
  .card-stack .cs:nth-child(5){--dw:92%;--dt:65%;--dl:4%;--dr:-9deg}
}
@media(min-width:881px) and (max-width:1100px){
  .hero-card>.inner{padding-right:clamp(178px,29%,205px)}
}

/* The phone cutouts come in off the edge too. The offsets look over-generous on paper
   because they aren't clearing the photo, they're clearing its ROTATION: a 112px square
   turned 5deg has a bounding box ~10px wider than the square, and that corner is what was
   crossing the card's border. */
@media(max-width:880px){
  .card-stack .cs:nth-child(1){--mrt:14px}
  .card-stack .cs:nth-child(2){--mrt:11px}
  .card-stack .cs:nth-child(3){--mrt:9px}
  .card-stack .cs:nth-child(4){--mrt:18px}
  .card-stack .cs:nth-child(5){--mrt:11px;--mb:12px}
}
@media(min-width:561px) and (max-width:880px){
  .card-stack .cs:nth-child(1){--mrt:18px}
  .card-stack .cs:nth-child(2){--mrt:14px}
  .card-stack .cs:nth-child(3){--mrt:12px}
  .card-stack .cs:nth-child(4){--mrt:24px}
  .card-stack .cs:nth-child(5){--mrt:16px;--mb:16px}
}

/* the proof section's head keeps the page's standard centred-head treatment */
.proof .head{margin-bottom:clamp(1.6rem,3.6vw,2.4rem);text-align:center}

/* The in-person / online line. Set at body size in solid ink, not tucked into the marginalia —
   it answers "am I even allowed to want this", which is a question you cannot afford to
   whisper. The example runs quieter, because it's evidence for the claim, not the claim. */
.hero-card .hero-where{font-family:var(--f-body);font-size:var(--fs-body);line-height:1.5;
  color:var(--ink);margin:.85rem 0 0;text-wrap:pretty}
.hero-card .hero-where b{font-weight:600;color:var(--grass-deep)}
.hero-card .hero-where .hw-eg{display:block;margin-top:.2rem;
  font-size:var(--fs-small);color:var(--ink-faint)}

/* the kit's honest admission that it has been trimmed */
.kit .kit-more{max-width:52ch;margin:.7rem auto 0;font-family:var(--f-body);
  font-size:var(--fs-small);line-height:1.5;color:var(--ink-faint)}

/* =====================================================================
   HERO — THE TYPE LADDER   (/design-shotgun winner: hero-A)
   ---------------------------------------------------------------------
   Same object. The hierarchy inside it was measurably upside down:

     - The LEDE — the one sentence that answers "what the fuck is this app" — was
       18.4px, while the geography line UNDER it was 19px. Rank 2 in the argument
       was rank 5 in the type.
     - The EYEBROW was 25.6px of Patrick Hand: the least important line on the card
       was its second-biggest thing, set in the hand face, at heading scale. Birdie
       is margin annotation. At 25.6px it is a heading whatever you call it.
     - .hero-terms was 10px at .72 ink — 30% under the type floor and under the ink
       floor, on the price and the cadence, which are the three things a wary buyer
       actually scans for. That is not restraint, it is hiding the terms.
     - The h1 wrapped to SIX lines, because max-width:13ch was reasoning about copy
       that no longer exists, and because the photo column was stealing the measure.

   FIVE RANKS. Every one is a token. No invented clamp, nothing under --fs-small,
   no ink under --ink-faint:
     1 h1     --fs-display  Courier Prime italic   the argument
     2 lede   --fs-lede     Bitter ROMAN           what the app is
     3 where  --fs-body     Bitter                 who is allowed to want it
     4 asides --fs-small    Patrick Hand / Bitter  marginalia + the terms
     5 labels --fs-label    Space Grotesk tracked  eyebrow, buttons, doors

   THE STRUCTURAL MOVE: the headline now owns the FULL width of the page, and the
   glued cutouts start BELOW it, flanking the CTA. Faces beat type unconditionally —
   so no photograph is given the chance to sit in the headline's optical field. That,
   not a font-size, is what takes the h1 from six lines to three.
   ===================================================================== */
@media(min-width:881px){
  /* the h1 gets the whole page; only the blocks BELOW it reserve the photo gutter */
  .hero-card>.inner{padding-right:44px}
  .hero-card .lede,
  .hero-card .hero-where,
  .hero-card .hero-rule,
  .hero-card .cta,
  .hero-card .cta-subs,
  .hero-card .hero-terms{padding-right:clamp(150px,17%,215px)}
  .hero-card .hero-scrawl{padding-right:clamp(150px,17%,215px)}

  /* the cutouts drop below the headline and flank the CTA */
  .card-stack{top:auto;bottom:5%;height:min(58%,430px);right:14px;width:clamp(126px,15%,190px)}
  .card-stack .cs:nth-child(1){--dw:92%;--dt:0%; --dl:0%;--dr:-7deg}
  .card-stack .cs:nth-child(2){--dw:92%;--dt:20%;--dl:6%;--dr:8deg}
  .card-stack .cs:nth-child(3){--dw:92%;--dt:41%;--dl:0%;--dr:-4deg}
  .card-stack .cs:nth-child(4){--dw:92%;--dt:62%;--dl:2%;--dr:10deg}
  .card-stack .cs:nth-child(5){--dw:92%;--dt:80%;--dl:4%;--dr:-9deg}

  .hero-card h1{font-size:var(--fs-display);max-width:24ch;line-height:1.05}
}
@media(min-width:881px) and (max-width:1180px){
  /* the page is narrower than the sentence at 72px. Step a rank rather than invent a size. */
  .hero-card h1{font-size:var(--fs-1)}
}

/* RANK 5 — the eyebrow is a LABEL, so it is set as one. Not 25px of Birdie. */
.hero-card .eyebrow{font-family:var(--f-head);font-weight:500;font-size:var(--fs-label);
  letter-spacing:.16em;text-transform:uppercase;color:var(--ink-faint);
  transform:none;margin:0 0 1.05rem;display:block}

/* RANK 2 — Bitter ROMAN, not italic. Italic serif at a cramped measure is the single worst
   legibility configuration there is, and it was what the product explanation was wearing. */
.hero-card .lede{font-family:var(--f-body);font-weight:300;font-style:normal;
  font-size:var(--fs-lede);line-height:1.5;color:var(--ink);max-width:52ch}
.hero-card .lede b{font-weight:600}

/* RANK 3 */
.hero-card .hero-where{font-size:var(--fs-body);color:var(--ink-soft);max-width:58ch}

/* RANK 4 — the terms are not hidden. 14px floor, .80 ink floor. */
.hero-card .hero-terms{font-family:var(--f-head);font-weight:400;font-size:var(--fs-small);
  line-height:1.45;color:var(--ink-faint);max-width:62ch}
.hero-card .cta-who{font-size:var(--fs-small);color:var(--ink-faint)}
.hero-card .door-who{font-size:var(--fs-small);color:var(--ink-faint)}
.hero-card .door-lbl{font-size:var(--fs-label)}
.hero-card .hero-scrawl{font-size:var(--fs-small)}

/* the three lines of the headline are set explicitly; each is its own block */
.hero-card h1 .h1s{display:block}

/* ---- THE DISPLAY SIZE IS SET BY THE MEASURE, NOT BY TASTE --------------------
   :root already says it: "--fs-display is capped at 72px because that is the hard ceiling of
   the hero's LAYOUT, not a taste call." That reasoning was right and then went stale — the card
   is 667px wide, which leaves 539px of column, and the longest line ("never finish anything.",
   22 characters of a 0.6em mono) therefore caps out at FORTY pixels. Forty. Smaller than a
   section heading. Setting --fs-display and hoping is what put the headline back on six lines.

   Two moves, and they have to happen together:
     1. Give the headline the measure it needs. The card widens on big screens; the heap still
        has ~190px a side to spill through, which is all it ever showed anyway.
     2. Derive the size FROM the card instead of asserting it. 6cqw of the card's inline size is
        the largest Courier that fits 22 monospaced characters in the column, whatever the card
        turns out to be — so the headline can never again outgrow the page it is printed on.
        min() keeps --fs-display as the ceiling, so it stays the one off-scale size on the page.
   --------------------------------------------------------------------------- */
@media(min-width:881px){
  .hero-card{container-type:inline-size}
  .hero-card h1{font-size:min(var(--fs-display),6cqw)}
}
@media(min-width:1181px){
  .hero .paper.hero-card{width:clamp(760px,74%,1080px)}
}

/* The card was still capped at 776px because the ENVELOPE it slides out of is the real
   constraint — the card is a percentage of it, so widening the card alone did nothing. The
   envelope opens up on big screens; the heap keeps ~160px a side to spill through, which is
   more than it ever actually showed. */
@media(min-width:1181px){
  .hero .wrap{max-width:1300px}
  .hero-card h1{max-width:23ch}
}


/* =====================================================================
   HERO — THE EDITORIAL SPREAD   (/design-shotgun r2 winner: h2)
   ---------------------------------------------------------------------
   The card had grown to ELEVEN separate text objects. It read as a form, not a promise.
   Six now, in three zones: the headline alone with air around it; ONE standfirst; and the
   CTA printed as a coupon, cut from the page with a dashed rule and a pair of scissors,
   with the terms inside it.

   The plates cross the card's right edge on purpose, and that is not a contradiction of the
   earlier rule. These carry paper, a border and a hard shadow — they are PRINTS lying on the
   page, and an object with a shadow may overlap an edge. The glued cutouts had no shadow, so
   crossing the border made them read as a clipping bug, which is why they had to stay inside.
   The overlap is the only thing stitching the card to the heap behind it.
   ===================================================================== */

/* =====================================================================
   h2-editorial — the hero as the OPENING SPREAD of a magazine feature.
   The page is one sheet of paper. On it: a departmental slug, a hairline,
   a Courier headline with room to breathe, a standfirst with a real
   initial, and the work PASTED ON THE SHEET — two zine spreads and a
   photo of the making, running off the right deckle so the paper and the
   pictures are one object, not two paintings stacked.
   Five text objects. One hand. One button. Sizes are tokens only.
   ===================================================================== */
.ed{--gut:clamp(1.25rem,10%,132px)}
.ed-stage{position:relative;max-width:1100px;margin:0 auto}

/* the sheet: reuse .paper/.sheet (torn ink border + hard solid registration shadow) */
.ed-sheet{transform:rotate(-.8deg)}
.ed-sheet>.inner{padding:clamp(1.75rem,3.4vw,3.25rem) clamp(1.25rem,3vw,2.25rem)
                 clamp(2.5rem,5vw,3.75rem) var(--gut)}
/* the margin rule of a ruled page — the one Colorado on the object */
.ed-rule{position:absolute;left:calc(var(--gut) - 26px);top:14px;bottom:14px;z-index:1;
  width:1.6px;background:rgba(247,84,88,.42);filter:url(#roughsm);pointer-events:none}
@media(max-width:880px){.ed-rule{display:none}}

/* --- the interior grid: copy hangs on ONE left axis, pictures own the right --- */
.ed-inner{display:grid;grid-template-columns:minmax(0,1.02fr) minmax(0,1fr);
  column-gap:clamp(1rem,3vw,2.5rem);align-items:start}
.ed-head{grid-column:1/-1;position:relative}
.ed-body{grid-column:1;max-width:34ch}
.ed-foot{grid-column:1}
.ed-plates{grid-column:2;grid-row:2/4}

/* ZONE 1 — nothing but headline. The eyebrow (.ed-kicker) and the hairline under it (.ed-hair)
   were retired with the copy they carried: the eyebrow's job was to hold the mechanism while the
   H1 stayed a warm invite, and the H1 states the mechanism itself now. Their rules are gone with
   them. One lesson worth keeping out of the hairline: a displacement filter does not wobble a
   rule thinner than its own scale, it CHEWS it — #roughsm on a 1.5px line came out as a broken
   run of dashes. A hand-drawn rule needs ~3px of ink for the tremor to read. */
.ed-h1{margin:0;font-family:var(--f-display);font-weight:700;font-size:var(--fs-display);
  line-height:1.02;letter-spacing:-.03em;color:var(--ink);text-wrap:pretty}
.ed-h1 .l{display:block}
.ed-h1 .ed-stop{color:var(--grass-deep)}

/* the ONE hand object: marginalia in the gutter, pointing at the pain. */
.ed-scrawl{position:absolute;left:calc(-1 * var(--gut) + 8px);top:.35em;width:calc(var(--gut) - 42px);
  margin:0;font-family:var(--f-hand);font-size:var(--fs-body);line-height:1.12;
  color:var(--lazuli-deep);transform:rotate(-4deg)}
.ed-scrawl svg{display:block;width:52px;height:22px;margin-top:.3rem;color:var(--lazuli-deep)}
@media(max-width:880px){
  .ed-scrawl{position:static;width:auto;max-width:24ch;margin:.9rem 0 0;transform:rotate(-1.6deg)}
  .ed-scrawl svg{display:none}
}

/* ZONE 2 — the standfirst. A large initial, generous leading, short measure. */
.ed-stand{margin:clamp(1.4rem,3vw,2.1rem) 0 0;font-family:var(--f-body);font-weight:300;
  font-size:var(--fs-lede);line-height:1.72;color:var(--ink)}
.ed-stand .ed-drop{float:left;font-family:var(--f-head);font-weight:700;font-size:var(--fs-display);
  line-height:.82;color:var(--grass-deep);margin:.02em .1em -.02em 0}
.ed-stand b{font-weight:600}

/* ZONE 3 — the CTA is a printed coupon, cut from the page. */
.ed-foot{margin-top:clamp(2rem,5vw,3.5rem)}
.ed-coupon{position:relative;isolation:isolate;display:flex;flex-wrap:wrap;align-items:center;
  gap:clamp(.9rem,2vw,1.4rem);max-width:min(32rem,100%);padding:clamp(1rem,2vw,1.3rem) clamp(1.1rem,2.2vw,1.5rem);
  transform:rotate(-.9deg)}
.ed-coupon::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--paper);
  border:2.4px dashed var(--ink);border-radius:4px;box-shadow:6px 6px 0 0 var(--ink);
  filter:url(#rough)}
.ed-snip{position:absolute;left:-14px;top:-16px;z-index:1;width:30px;height:30px;color:var(--ink);
  transform:rotate(-16deg)}
.ed-snip svg{width:100%;height:100%;display:block}
.ed-stamp{font-family:var(--f-head);font-weight:500;font-size:var(--fs-label);letter-spacing:.13em;
  text-transform:uppercase;display:inline-flex;align-items:center;gap:.5rem;text-decoration:none;
  background:var(--grass-deep);color:var(--oats);border:2.6px solid var(--ink);border-radius:5px;
  padding:.9em 1.35em;min-height:46px;box-shadow:5px 5px 0 0 var(--ink);transform:rotate(-1.4deg);
  transition:transform .09s ease,box-shadow .09s ease}
.ed-stamp:hover{transform:rotate(0)}
.ed-stamp:active{transform:translate(5px,5px) rotate(0);box-shadow:0 0 0 0 var(--ink)}
.ed-stamp:focus-visible{outline:3px solid var(--lazuli);outline-offset:3px}
.ed-terms{margin:0;flex:1 1 12rem;font-family:var(--f-body);font-size:var(--fs-small);
  line-height:1.45;color:var(--ink-faint)}
/* the sub-links sit INSIDE the coupon (a flex row), to the RIGHT of the button — ONE sub-CTA per line,
   stacked. On a narrow card the coupon row wraps and the whole stack drops under the button. */
.ed-links{margin:0;flex:1 1 12rem;display:flex;flex-direction:column;gap:.1rem;
  font-family:var(--f-body);font-size:var(--fs-small);color:var(--ink-soft)}
.ed-links a{display:inline-flex;align-items:baseline;gap:.4rem;width:fit-content;
  color:var(--ink);text-decoration:none;padding:.2rem 0;
  border-bottom:1.6px solid transparent;line-height:1.3}
.ed-links a:hover{border-bottom-color:var(--grass-deep)}
.ed-links a .arr{color:var(--grass-deep);font-weight:600}
/* The first sub-link is a DOOR, the other two are "sell me" moves (read a zine, open the demo), and
   the coupon should say so. Green text, not a second filled button: the stamp is the one loud thing
   in here, and a second box would split the primary action in two so that neither is the answer to
   "what do I do". This is the same green as the stamp's fill, at text weight — "also a way in".
   --grass-deep, never --grass: on oats, grass is 2.78:1 and fails AA outright; grass-deep is 5.91:1.
   And deliberately NO resting underline — .ed-links a:hover already spends the green rule, so a
   permanent one would leave hover with nothing to say and read as a visited link. */
.ed-links a.is-door{color:var(--grass-deep);font-weight:600}

/* --- HERO COPY v2 (2026-07-15): category line · tagline lead-in · four beats · tiny sign-off.
   Layout (where the beats sit, smear-vs-video) is deliberately left for /design-shotgun; this is
   the COPY in place so it can be read in context. --- */
.ed-cat{margin:0;font-family:var(--f-display);font-weight:700;
  font-size:var(--fs-display);line-height:1.06;letter-spacing:-.022em;
  color:var(--ink);text-wrap:balance;max-width:18ch}
/* the category highlight must WRAP (the phrase is long): a cloned background per line-box, not the
   single-rectangle .hl::before swatch, so it never runs off the card on narrow widths. */
.ed-cat b{color:var(--grass-deep)}   /* "Yours will." — the promise beat, in the payoff colour */
.ed-cat .hl{white-space:normal;background:var(--happy);mix-blend-mode:multiply;
  -webkit-box-decoration-break:clone;box-decoration-break:clone;
  padding:.02em .16em;border-radius:3px;box-shadow:0 0 0 .5px var(--happy)}
.ed-cat .hl::before{content:none}

/* ============ HERO H1 v3 (2026-07-24) — the headline is a SENTENCE, and it ends in the blank.
   Read the specificity before touching anything here: `.ed-cat` is (0,1,0) and loses to
   `.hero h1` (app.css:179) and `.hero-card h1` (231 / 3410 / 3459 / 3471), all (0,1,1). The live
   values it inherits are max-width 13ch under 881px and 24ch/23ch above, line-height 1.02/1.05,
   letter-spacing -.012em, and ITALIC. Anything written on plain `.ed-cat` silently does nothing,
   so every override below is `.hero-card h1.ed-cat` (0,2,1).

   Two hard numbers govern this block. Courier Prime is monospace at a 0.6em advance, so with the
   inherited -.012em tracking the blank's ghost track — "photographer." — is exactly
   13 x .588em = 7.644em WIDE AND UNBREAKABLE (.hl-rot .rw is white-space:nowrap, and an
   inline-grid is an atomic inline box). And html,body are overflow-x:clip, so if it doesn't fit
   it does not scroll — it is silently guillotined at the card's edge, mid-word.
   At the inherited size that blank is 98% of the mobile measure: 290px of ghost against a 290px
   column at 360px. The headline also went from 28 characters to 52. Both problems have the same
   fix — the sentence is set smaller than the old category line was, at every width. ============ */
.hero-card h1.ed-cat{max-width:26ch;line-height:1.13}
@media(min-width:881px){
  /* 6cqw (app.css:3459) was sized for a two-line category line. The fielded cut's 52-character
     sentence set at that size was four display lines and pushed the coupon off the card, so it was
     cut to 5.3cqw (~43px in an 818px card).
     POST-BETA: the sentence is 33 characters. "Together, you become a ___." is two display lines at
     6.1cqw (~50px), which is what the fold is worth — this is the page's one headline and it had been
     paying, in points, for words that have since moved to the sub. Still min()'d against --fs-display
     so it can never outgrow the type scale's own 72px ceiling. */
  .hero-card h1.ed-cat{font-size:min(var(--fs-display),6.1cqw)}
}
@media(max-width:880px){
  /* the ONLY size that keeps 7.644em of unbreakable blank inside the sheet: at 360px the inner
     column is 290px, so the ceiling is 37.9px and --fs-display's own floor (38px) already misses
     it by a letter — and under 521px the H1 also gives up 40px to the corner ring (below), which
     takes the ceiling to 32px at 360 and 27.5px at 320. 8.2vw = 29.5px / 26.2px: clears both,
     with the measure released so the sentence uses the full sheet instead of the 13ch column
     that was cut for "small circle."
     min(), not clamp(): a rem FLOOR would be the one term of a clamp that doesn't track the
     viewport, so a reader running a 20px or 24px browser default font would push the headline
     back through the ceiling this whole rule exists to hold — and the blank doesn't wrap or
     scroll, it gets clipped. The ceiling is the invariant; the floor is not.
     POST-BETA: this ceiling does NOT move even though the sentence got 19 characters shorter. It was
     never set by the sentence — it is set by the ghost track, "photographer." at 7.644em, which is
     unbreakable and unchanged. Shortening the copy buys headline size on desktop (above) and buys
     nothing at all here. Do not "match" the two. */
  .hero-card h1.ed-cat{font-size:min(2.6rem,8.2vw);max-width:none;line-height:1.15;
    /* the amber Circle ring sits in the card's top-right corner and zone 1's FIRST line now runs
       the full sheet — reserve its column. This lived at max-width:520px when it was protecting a
       one-line eyebrow; the H1 is display type across the whole under-881 branch, and between 521
       and 575 the ring was landing on the "h" of "with". */
    padding-right:40px}
}
/* the blank is the headline's last word, so it takes the headline's face, slant and weight.
   .hl-rot .rw (app.css:2643) hard-sets font-style:normal + 600 + --ink, which was a deliberate
   contrast against the ITALIC body sub it used to live in; inside an italic display headline the
   same rule renders one upright word in a slanted line and reads as a paste-up error. */
.hero-card h1.ed-cat .hl-rot .rw{font:inherit;letter-spacing:inherit;color:inherit}
/* the swatch was tuned against the sub: .96em of marker inside a 1.4 line box. In the headline the
   line box is 1.13-1.15em, so at those proportions the mark touches the lines above and below and
   reads as a redaction bar. Pull it in — it hugs the word, and only the word. */
.hero-card h1.ed-cat .hl-rot .mark::before{left:-.1em;right:-.05em;top:.17em;bottom:.02em}

/* the hero subtitle: handles the "do I need a group?" question right under the headline */
.ed-sub{margin:clamp(.7rem,1.7vw,1.15rem) 0 0;font-family:var(--f-body);font-style:italic;font-weight:400;
  font-size:var(--fs-lede);line-height:1.4;color:var(--ink);max-width:34ch}
.ed-sub .stop{color:var(--grass);font-weight:700;font-style:normal;white-space:nowrap}   /* brand green + bold + upright, so it reads as the same green token as "Together" in the H1.
   nowrap because the token is three words now ("you all made") and the 34ch measure was breaking it
   across two lines, which reads as two green things rather than one phrase. It is 12 characters
   against a 34ch measure, so it can always be pushed whole onto the next line. */
/* the beats' lead-in ("How show-and-tell works:"). It was defined at --fs-lede for a tagline it
   never got used for; as a lead-in it must sit a rank UNDER the sub, or the card has two lede-sized
   lines in a row and the second one reads as a competing headline. Body size, head face, 700 — a
   label on the small print, not a claim. */
.ed-lead{margin:clamp(1.3rem,2.8vw,2rem) 0 clamp(.6rem,1.3vw,.85rem);
  font-family:var(--f-head);font-weight:700;font-size:var(--fs-body);line-height:1.3;color:var(--ink)}
.ed-lead+.beats{margin-top:0}   /* the lead-in owns the gap; .beats' own top margin would double it */
.beats{list-style:none;margin:clamp(1.2rem,2.6vw,1.8rem) 0 0;padding:0;display:flex;flex-direction:column;
  gap:clamp(.55rem,1.3vw,.85rem);counter-reset:beat}
.beats li{font-family:var(--f-body);font-weight:300;font-size:var(--fs-body);
  line-height:1.42;color:var(--ink);position:relative;padding-left:2em}
.beats li::before{counter-increment:beat;content:counter(beat,decimal-leading-zero);
  position:absolute;left:0;top:.14em;font-family:var(--f-head);font-size:.72em;font-weight:700;
  letter-spacing:.04em;color:var(--ink-faint)}
.beats .hl{white-space:nowrap;font-weight:600}
.ed-signoff{margin:clamp(1.3rem,2.6vw,1.9rem) 0 0;font-family:var(--f-slab);font-style:italic;
  font-size:var(--fs-small);color:var(--ink-soft)}
.ed-signoff b{font-weight:700;font-style:normal;color:var(--grass-deep)}
.ed-signoff i{font-style:normal;color:var(--colorado)}   /* the middot stays a colored separator, like the old kicker */

/* --- THE WORK, PASTED ON THE SHEET. Two real spreads + the making of one,
       overlapping and running off the right deckle so the paper and the
       pictures read as ONE object. The tear is on the paper (::before); the
       photographs are never filtered. --- */
.ed-plates{position:relative;min-height:clamp(300px,40vw,520px);margin-right:-12%}
.ed-plate{position:absolute;margin:0;isolation:isolate;
  top:var(--t);left:var(--l);width:var(--w);transform:rotate(var(--r))}
.ed-plate::before{content:"";position:absolute;inset:-9px -9px -14px;z-index:0;background:var(--paper);
  border:2.6px solid var(--ink);border-radius:4px;box-shadow:8px 9px 0 0 var(--ink);filter:url(#torn)}
.ed-plate i{position:relative;z-index:1;display:block;background-size:cover;background-position:center}
.ed-plate figcaption{position:relative;z-index:1;display:block;max-width:19ch;margin-top:.45rem;
  font-family:var(--f-hand);font-size:var(--fs-small);line-height:1.2;color:var(--ink)}
.ed-p1 i{aspect-ratio:720/1306}   /* exact source ratio — a portrait spread is never cropped to 4/3 */
.ed-p2 i{aspect-ratio:720/895}
.ed-p3 i{aspect-ratio:4/3}
.ed-plate .tape{width:78px;height:22px}

@media(max-width:880px){
  .ed{--gut:clamp(1.1rem,5vw,1.6rem)}
  .ed-sheet{transform:rotate(-.5deg)}
  .ed-inner{display:block}
  .ed-body{max-width:none}
  .ed-plates{min-height:0;margin:clamp(1.75rem,6vw,2.5rem) -2% 0 0;
    display:flex;align-items:flex-start;justify-content:center;padding-top:14px}
  .ed-plate{position:relative;top:auto;left:auto;width:auto;flex:0 1 43%}
  .ed-plate+.ed-plate{margin-left:-5%;margin-top:1.6rem}
  .ed-p3{display:none}     /* two sheets is a spread; three is a pile, and there's no room */
  .ed-coupon{max-width:none}
}
@media(max-width:420px){
  .ed-plate figcaption{max-width:15ch}
}
@media(prefers-reduced-motion:reduce){
  .ed-stamp{transition:none}
}

/* =====================================================================
   ONE PHOTO SYSTEM, NOT TWO.
   The sheet carried three plates (both zine spreads + a making-of shot)
   pasted over its right half — sitting directly on top of the heap that
   already fills that same square, and showing the same two spreads that
   #proof shows full-bleed 600px later. Claire's face appeared four times
   above the fold. Two picture systems in one optical field is not a
   composition, it is a collision.
   The heap wins: it is the older object, it is the atmosphere, and it is
   not repeated anywhere else. So the sheet narrows to a real column, the
   copy runs down it as ONE column, and the photographs get the right of
   the stage — a page laid on a heap, which is what the plates were faking.
   ===================================================================== */
.ed-plates{display:none}
@media(min-width:881px){
  /* .hero .paper.hero-card (0,3,0) sets the width and .hero-card>.inner still
     reserved a 205-330px right column for the polaroid that used to live there.
     Both are stale. Match the specificity and take the column back. */
  .hero .paper.hero-card.ed-sheet{width:clamp(560px,70%,880px)}
  .hero .paper.hero-card.ed-sheet>.inner{padding-right:clamp(1.25rem,3vw,2.25rem)}
  .ed-inner{display:block}
  .ed-body{max-width:34ch}
  /* The display size is DERIVED from the measure, not asserted. Courier advances a flat
     0.6em, the longest line is 22 characters, and the measure is inner ≈ card − 120px,
     so the ceiling is (card − 120) / 13.2 — about 6.2cqw, with a little slack. Push past
     it and line 2 breaks in half; fall to 6cqw and the h1 renders BELOW the 43px section
     heads, which is the one thing a headline can never do. `nowrap` makes the three lines
     structural: if the ceiling is ever wrong again it overflows visibly instead of
     silently reflowing into four. */
  .hero-card.ed-sheet .ed-h1{font-size:min(var(--fs-display),6.2cqw)}
  .hero-card.ed-sheet .ed-h1 .l{white-space:nowrap}
}
/* 881-1099: the heap can give up more of the stage than it can at 1440, and it has to —
   at 64% the card was 579px and the h1 derived to 38px, exactly TYING the section heads.
   An h1 that does not outrank an h2 is not a headline. */
@media(min-width:881px) and (max-width:1099px){
  .hero .paper.hero-card.ed-sheet{width:clamp(560px,86%,800px)}
  .hero-card.ed-sheet .ed-h1{font-size:min(var(--fs-display),5.9cqw)}   /* the padding overhead is a bigger share of a 650px card, so the ceiling is lower here */
}
/* The desktop half of the card-stack pasted five photos onto the card's right column —
   the exact collision the editorial hero was rebuilt to remove, and that column no longer
   exists anyway (the sheet is a narrow measure now, and the heap owns the stage). The
   cutouts are a PHONE treatment only, where the heap can't reach the card. */
@media(min-width:881px){
  .card-stack{display:none}
}
@media(max-width:880px){
  /* The phone cutouts are bottom-anchored, so they land on the card's lower right — which is
     exactly where the coupon and the door links sit. The old reservation was keyed to .cta /
     .cta-subs / .hero-terms, classes the editorial hero does not have, so it silently stopped
     reserving anything and five photos sat on top of the price. Reserve the column again. */
  .ed-foot{padding-right:24%}
  .ed-scrawl{max-width:26ch}
}

/* "Yours will." is the promise, and the promise is the brand's colour. The full stop alone
   was carrying it, which is a whisper where a claim belongs. */
.ed-h1 .l:last-child{color:var(--grass-deep)}

@media(max-width:880px){
  /* A glued cutout carries no shadow, and a shadowless thing hanging off the paper's edge
     reads as a rendering bug, not a collage. Every piece stays on the sheet. */
  .card-stack .cs:nth-child(2){--mrt:6px}
  .card-stack .cs:nth-child(5){--mrt:6px}
}
@media(max-width:520px){
  .hero-cmark{top:6px;right:8px;width:34px}
}

/* The hand line is the tagline, not an annotation, so it does not belong in the gutter — and
   it no longer fits there anyway: the sheet's gutter is ~83px wide, the punch holes already
   live in it, and 41 characters wrapped to six lines straight through the holes. It sits under
   the headline, on the copy's own left axis, which is where it sat before this hero was rebuilt. */
.ed-scrawl{position:static;width:auto;max-width:44ch;margin:.9rem 0 0;
  transform:rotate(-.5deg);color:var(--ink-soft)}

/* The coupon's dashed rule is a CUT LINE — it is printed on the sheet, not lying on it. A drop
   shadow under it claims the line is floating above the paper it is drawn on. The stamp inside
   keeps its shadow: the button is an object. The line is ink. */
.ed-coupon::before{box-shadow:none;background:none}


/* =====================================================================
   THE MASTHEAD — no bar. The cream slab (plus a torn cream strip hanging off its
   bottom) was cutting a hard horizontal line across the top of the page and boxing
   the heap in. The mast comes out of flow and sits ON the heap: the photographs run
   right up under it, and the lockup reverses to white — one solid colour, upright,
   no filter and no tilt, which is what the logo rule actually requires. The heap is
   what gives the white something to be white against, so the hero's top padding now
   has to clear the mast on its own.
   ===================================================================== */
.mast{position:absolute;top:0;left:0;right:0;background:none;z-index:60}
.mast::after{display:none}
.mast .lg-icon svg,.mast .lg-icon svg path,
.mast .lg-word svg,.mast .lg-word svg path{fill:#fff}
.mast>.wrap>nav a{color:#fff}
.hero{padding-top:clamp(6.2rem,9vw,7.6rem)}
/* White on a photograph is only white where the photograph is dark, and this heap is not: measured
   under the lockup, the bright patches give white a contrast ratio of 1.11 — it vanishes — and the
   photo that lands there changes with the viewport, so it would vanish at SOME widths and not others.
   The bible's own rule for paper-coloured type on an image is "only over an opaque flat shape".
   So the lockup gets one: a small hand-cut ink sticker, not a bar. The logo itself stays clean —
   one solid colour, upright, no filter, no tilt, no shadow, exactly as the brand rule requires. */
/* THE LOGO IS ON A TICKET. It needed an opaque bed (white on a photograph is only white where the
   photograph is dark, and measured under the lockup the bright patches give white a contrast ratio of
   1.11 — it vanishes). But a bed is not an object, and a plain ink rectangle is just a grey blob
   floating on the heap. A ticket is an object: notched on both edges, perforated for a tear-off stub,
   hard-shadowed, hand-cut.
   Grass-deep, not grey: it is the palette's AA-safe green — white on it clears 4.83 — and it is the
   same fill as the primary button, so the masthead reads as the brand's own colour instead of a slab.
   Two pseudos, because a mask clips a box-shadow out of existence: ::before is the ticket, ::after is
   its shadow, and both carry the same notches. The logo itself stays clean — upright, one solid
   colour, no filter, no tilt, no shadow. The tear is on the ticket, never on the mark. */
.mast .brand{position:relative;isolation:isolate;padding:.62rem 2.1rem .62rem 1.1rem}
.mast .brand::before,
.mast .brand::after{content:"";position:absolute;inset:-3px -6px;border-radius:5px;
  filter:url(#rough);
  /* the two notches punched out of the left and right edges — transparent, so the heap shows
     THROUGH them, which is the whole reason it reads as a ticket and not a rounded rectangle */
  -webkit-mask-image:radial-gradient(circle at 0 50%, transparent 0 8px, #000 8.5px),
                     radial-gradient(circle at 100% 50%, transparent 0 8px, #000 8.5px);
  -webkit-mask-composite:source-in;
  mask-image:radial-gradient(circle at 0 50%, transparent 0 8px, #000 8.5px),
             radial-gradient(circle at 100% 50%, transparent 0 8px, #000 8.5px);
  mask-composite:intersect}
.mast .brand::before{z-index:-1;border:2.4px solid var(--ink);
  background:
    /* the perforation: a dashed tear-line, with a blank stub beyond it */
    repeating-linear-gradient(180deg, rgba(254,246,228,.62) 0 5px, transparent 5px 10px) no-repeat,
    var(--grass-deep);
  background-size:1.7px 100%;
  background-position:calc(100% - 24px) 0}
.mast .brand::after{z-index:-2;background:var(--ink);transform:translate(4px,5px)}
@media(prefers-reduced-motion:reduce){ .mast .brand::before,.mast .brand::after{animation:none} }
html[data-tier="lite"] .mast .brand::before,
html[data-tier="lite"] .mast .brand::after{animation:none}

/* =====================================================================
   THE PHOTO WELL — whitespace you can PROVE is empty.

   The founder: "the smattering of photos should be in all the whitespace yet not
   covering the text in the hero card. i know it's tricky because responsive."

   It is tricky, and the reason is that the old .card-stack was ABSOLUTELY POSITIONED
   over the card's right side. That is a guess: it puts pictures where text happens
   not to be *today*, and text moves — with the viewport, with a font that loads late,
   with a word someone edits next month — and then a photograph lands on a sentence.
   No amount of tuning fixes a guess; it only postpones it.

   So the empty region becomes STRUCTURAL. .ed-inner is a two-column grid. Every text
   block is pinned to column 1 by grid-column:1. The well IS column 2. A photograph can
   therefore only cover a word if a word can enter column 2 — and nothing in this grid
   places anything there. The guarantee is the grid, not the coordinates: the pieces can
   be splayed anywhere inside the well and the proof still holds.

   The headline spans both columns on purpose: it is white-space:nowrap and its size is
   derived from the CARD's width (6.2cqw), so narrowing it to a column would shrink the
   h1 below the section heads — the exact bug this hero was rebuilt to fix.

   The one piece that rises out of the well (--t:0 with the well's top at the standfirst)
   sits beside the headline's short last line. That is safe by arithmetic, not by eye:
   "Yours will." is nowrap and fixed at 11 characters, Courier advances a flat 0.6em, and
   the h1 is 6.2cqw — so the line always ends at 10% (the left padding) + 11 x 0.6 x 6.2%
   = ~51% of the card, and column 2 does not start until 58%. Seven percent of clearance
   at every width, and the audit re-checks it anyway.
   ===================================================================== */
@media(min-width:881px){
  .ed-inner{display:grid;grid-template-columns:minmax(0,58fr) minmax(0,42fr);
    column-gap:clamp(1.5rem,3vw,2.4rem);align-items:start}
  .ed-head{grid-column:1/-1}
  .ed-body{grid-column:1;max-width:none}
  .ed-foot{grid-column:1}

  /* the well: a column with no text in it, ever */
  .card-stack{display:block;position:relative;grid-column:2;grid-row:2/4;
    align-self:stretch;min-height:clamp(300px,34vw,430px);
    margin-top:clamp(.4rem,1.2vw,1rem);pointer-events:none}
  .card-stack .cs{top:var(--t);left:var(--l);width:var(--w);transform:rotate(var(--r))}
  .card-stack .cs-tape.t1{top:-2%;left:20%}
  .card-stack .cs-tape.t2{bottom:-1%;left:30%}
}
/* ONE rule, not two. The phone half of the collage was still the old guess: pieces bottom-anchored
   in px inside a right column reserved with padding on .ed-foot only. It held at 390 because it was
   tuned at 390. The audit found it breaking from 430 to 820 — as the card widens the copy needs fewer
   lines, the card gets SHORTER, and the bottom-anchored stack rides up out of the foot and into the
   standfirst, which reserved nothing. So the well is the well at every width: same grid, same proof,
   only the column ratio changes. The px bottom-anchoring goes away entirely. */
.ed-inner{display:grid;grid-template-columns:minmax(0,66fr) minmax(0,34fr);
  column-gap:clamp(.7rem,2.5vw,2.4rem);align-items:start}
.ed-head{grid-column:1/-1}
.ed-body{grid-column:1;max-width:none}
/* the coupon spans the FULL width on its own row BELOW the deck (the deck only occupies the beats' row
   now), so it is no longer squeezed into column 1 beside the stack. */
.ed-foot{grid-column:1/-1;padding-right:0}
.card-stack{display:block;position:relative;grid-column:2;grid-row:2/4;align-self:stretch;
  inset:auto;width:auto;height:auto;                 /* four earlier rules pin a width (down to
     clamp(126px,15%,190px)) and a height on this element, from when it was an absolute box floating
     over the card's right side. As a grid item it must take the COLUMN's width, or the well is a
     126px sliver inside a 227px column and the pictures shrink to postage stamps. */
  min-height:clamp(210px,44vw,430px);margin-top:.4rem;pointer-events:none}
.card-stack .cs{position:absolute;top:var(--t);left:var(--l);width:var(--w);bottom:auto;right:auto;
  transform:rotate(var(--r))}
.card-stack .cs-tape.t1{top:-2%;left:18%;bottom:auto;right:auto}
.card-stack .cs-tape.t2{bottom:-1%;left:28%;top:auto;right:auto}
/* The topmost cutout and its washi were poking up out of the well into the hand tagline at 360-430:
   the piece's ::before paper lip is inset -7px and the tape sat at top:-2%, so both reached above the
   well's own top edge — and the row above is .ed-head, which spans BOTH columns, so its text is in
   column 2's x-range. Give the well enough top margin to swallow the lip, and stop the tape climbing
   out of the box that is doing the proving. */
.card-stack{margin-top:1.15rem}
.card-stack .cs-tape.t1{top:3%}

/* The heap is clipped above 881 but was never clipped below it, so on a phone its photos ran ~90px
   past the right edge of the viewport and the whole page scrolled sideways. Same clip, every width. */
.hero-pile{overflow:clip}

/* ============ HERO CARD DECK — auto-rotating challenge stack (replaces .card-stack) ============
   The card's 5 inner photos become a cycling deck of real challenges. Desktop: floats in the card's
   reserved right column, hover pauses the cycle so you can read the top card. Mobile: sits below the
   text, taps open into a grid. Squigglevision paper edges via #soft (static). */
/* the deck sits BESIDE the feature list at EVERY width: a grid item in column 2, on the beats' ROW
   (grid-row 2/3), pinned to the top so it lines up with "A challenge". Column 2 is narrow, so the deck
   overflows it and spills off the card's right edge when the screen is tight; the coupon drops BELOW
   (its own full-width row) instead of being boxed beside the deck. */
/* SIZE (post-beta): --pw goes 205px -> 300px, ~46% up. Measured, not guessed: at 1440px the hero card
   spans x 121-963 and a 340px deck spans 683-1028, so it overflows the card's right edge by 65px into
   the gutter — the same deliberate spill the min-width:900px rule below already does — and the card's
   bottom third is empty ruled paper, so there is vertical room to spare. Below 205px the two bands
   stop being readable, which is what made the old deck need a sticky note in the first place. */
.hero-card-deck{--pw:clamp(210px,26vw,300px);grid-column:2;grid-row:2/3;align-self:start;
  justify-self:start;position:relative;z-index:4;width:clamp(232px,29vw,340px);
  height:clamp(300px,36vw,470px);margin-top:clamp(-2.4rem,-3vw,-1.7rem)}  /* lift beside the subtitle's 2nd line + the beats (clear of its long 1st line) */
/* Roomy screens: column 2 is wider than the deck, so anchor it to the column's RIGHT edge and spill it
   into the margin (the right "gutter"), and lift it UP beside the subtitle. There's room here to sit
   clear of the subtitle's text on the left; on a narrow card there isn't, so it stays beside the beats
   (the base rule above). */
@media(min-width:900px){
  /* The lift was -6.5rem when zone 1 was an eyebrow + a hairline + a two-line headline + a THREE-line
     subtitle: it pulled the deck up beside the sub's lower lines. Zone 1 is a three-line sentence and
     a one-line sub now, and the sentence's last line ends in the blank's 7.644em slot — so the old
     lift put the front polaroid on top of the headline's full stop from ~910px to ~1210px. Half the
     lift keeps the deck beside the copy without reaching into the line above it. */
  .hero-card-deck{justify-self:end;margin-right:calc(-1 * clamp(4rem,9.5vw,6.5rem));
    margin-top:clamp(-2rem,-2vw,-1rem)}
}
/* Mid / skinny screens (500-899px): keep the subtitle inside column 1 (wrap it a touch narrower) so it
   clears the deck's column, then lift the deck up beside it (top of the tape ~ top of the green text)
   and nudge it right. Below 500 the deck is nearly half the card, so clearing the subtitle would force
   it into 4 cramped lines — there it keeps the base placement (beside the beats). */
@media(min-width:500px) and (max-width:899px){
  .ed-sub{max-width:23ch}
  .hero-card-deck{margin-top:clamp(-4.6rem,-7vw,-2.8rem);margin-left:clamp(6px,2.4vw,20px)}
}
.hero-card-deck .pola{position:absolute;left:50%;margin-left:calc(var(--pw) / -2);top:4px;width:var(--pw);
  padding:0;cursor:pointer;pointer-events:auto;text-decoration:none;color:var(--ink);
  transform:translate(calc(var(--i,0)*4px),calc(var(--i,0)*7px)) rotate(var(--r)) scale(calc(1 - var(--i,0)*.03));
  z-index:calc(40 - var(--i,0));transition:transform .5s cubic-bezier(.2,.8,.2,1),opacity .4s;
  /* THE SETTLE. Each card carries two SVG-filtered ::before layers (the tape and the green band)
     and the stack transform includes a per-depth scale(1 - i*.03). An SVG filter is evaluated in
     the element's own coordinate space, so when the card scales the browser rasterises the filter
     result at one size, transforms that bitmap for the .5s transition, and then re-rasterises it
     sharply at the end — which reads as the card "settling" a beat after it lands. It is loudest
     on the green band because that is the largest filtered area with a hard edge.
     will-change:transform promotes the card to its own compositor layer, so the filter rasterises
     ONCE and the transition just transforms that texture. The cards only ever scale DOWN from 1,
     so there is no upscaling blur to pay for. Six layers, one per card, is a fair price; do not
     spread will-change any wider than this without re-checking the FPS governor. */
  will-change:transform;
  /* booklet THICKNESS: layered paper/ink page edges behind the cover = a little magazine, not a flat card */
  box-shadow:2px 2px 0 0 var(--paper),3px 3px 0 0 var(--ink),6px 6px 0 0 var(--paper),7px 8px 0 0 var(--ink)}
.hero-card-deck .pola::before{display:none}   /* NO white polaroid mat */
/* the photograph fills the WHOLE card, edge to edge -> a magazine cover, not a polaroid photo.
   background-position is CENTER, not "center 14%": these are photographs chosen and cropped 3:4 for
   this card (assets/zines/post-beta/), not screenshots of a cover page whose title had to be kept in
   frame. The 14% offset existed to protect that title and now just crops the subject's head. */
.hero-card-deck .pola i{display:block;width:100%;height:calc(var(--pw) * 1.34);background-size:cover;
  background-position:center;border:2.4px solid var(--ink);filter:url(#soft)}

/* ===== THE TWO BANDS =====
   Red across the top is the assignment; green across the bottom is what the maker got out of it.
   Flush and full-bleed, no rotation, no drop shadow: at deck size a rotated stamp with a shadow costs
   ~2 characters of legibility per line and the bands are the only text on the card. The paste-up
   voice is carried by the torn #soft edge and the booklet shadow, which are still there.

   Every dimension ramps off --pw so one number resizes the whole card. Percentages of --pw, not vw:
   the deck also renders inside .dm-grid at a completely different size, and type that tracked the
   viewport would be wrong in one of the two places. */
/* THE CHALLENGE IS A DYMO STRIP. The prompt is ISSUED to you — by the editor, by the club, by the
   month — so it wants a labelling medium: embossed plastic, mechanical, uppercase, slapped on at a
   slight angle. The answer underneath stays handwriting, because it is yours. That split is the
   whole idea; putting the answer on green tape too collapses both voices into one and turns a
   quiet realisation ("i could do anything") into a slogan on a locker. It was tried; don't.

   THIS PAGE ALREADY HAS A DYMO TAPE — .rn-arrow at :665, the "btw" label in the reveal-name aside,
   whose own comment says "a label maker is the object whose entire purpose is giving a thing a
   name". So this is not a new component, it is a second instance of an existing one, and it
   follows that spec. Earlier passes here did not, and the result read as too skeuomorphic against
   the rest of the page. What the house spec is, and why each part of it matters:

     --coral-ink, not --colorado         the tape colour the page already uses (and the AA-safe
                                          one: white on #F75458 is 3.30:1, on #C9343A it is 5.20:1)
     #FFF8EC letters, not pure white     plastic whitens where it is stretched; it never goes white
     ONE text-shadow, tinted dark red    a black seat plus a white lip is a 3D bevel, which is
                                          realism; this page does cartoon-analog, not photoreal
     box-shadow 2px 2px 0 0              HARD offset, zero blur. The stylesheet has 103 zero-blur
                                          shadows; a blurred one was the single exception and it
                                          was this element. That was the tell.
     filter:url(#roughsm)                every other paper object on the page has hand-cut edges.
                                          A rigid rectangle with perfectly straight sides was the
                                          only thing in the hero that did not, and it showed.

   THE STATIC EDGE, BUT NOT THE BOIL. .rn-arrow pairs #roughsm with animation:boil-roughsm, and
   this deliberately does not. The hand-drawn EDGE is what buys the consistency; the BOIL is an
   animated SVG filter, which is the most expensive thing on the page per element — and .rn-arrow
   is ONE element where this is twelve (six cards x two bands), plus twelve more once the lightbox
   clones them. The FPS governor (app-post-beta.js:44) latches html[data-tier="lite"] when the
   average frame goes over 34ms, and lite then kills animations that matter more than this one —
   including the H1 highlighter's swipe at :2665. Boiling the deck risks trading the headline's
   marker for a wobble nobody asked for. Static edge, no boil.

   ONE DELIBERATE DIVERGENCE: .rn-arrow tracks at .22em; this tracks at .05em. Not a slip. That
   label carries one word ("btw") and this one carries up to 31 characters on a strip that may not
   wrap, and .22em tracking at a legible size overflows it by ~65px. Matching the tracking would
   mean dropping to ~10px type. Legibility wins; every other property matches exactly.

   ONE LINE, ALWAYS — white-space:nowrap. Real tape has no second row; a strip that wraps stops
   being tape and becomes a sign. Measured budget: the strip maxes at .90 * --pw = 270px, and
   Courier Prime at .042 * --pw with .05em tracking gives ~31 CHARACTERS. (An earlier comment here
   said 24, guessed rather than measured, and that guess did real damage — see below.)

   EVERY CHALLENGE MUST STAY AN IMPERATIVE. "doodle at the cafe", "come as your heritage", "make a
   dropcap", "take night photos of the unseen" — a challenge is an instruction, and the tape is
   the only place the instruction appears in the fold. A previous pass shortened one of these to
   "the overlooked, at night" to fit a budget that was not real, which turned an instruction into
   a noun phrase and quietly stopped it being a challenge at all. If a prompt is too long, rewrite
   it as a SHORTER INSTRUCTION; never trim it into a fragment.
   No --f-dymo webfont: --f-head (Space Grotesk 700) uppercase with tracking does the job, and the
   page is not spending another Google Fonts request on one strip. */
/* THE FILTER GOES ON A ::before, NEVER ON THE ELEMENT. An SVG displacement filter distorts
   everything inside the box it is applied to — including the type, which came out visibly chewed
   on a 13px monospace. The page already solves this and this follows it: .ed-coupon::before and
   .dm-panel::before each carry the background, the border and the filter on a pseudo-element at
   z-index:-1, and let the text sit above them unfiltered. Wobbly edges, crisp letters.
   Two consequences worth knowing: the element itself must carry NO background (or it would cover
   the ::before), and it must NOT be overflow:hidden — the displacement pushes ink a few px past
   the box, and clipping it gives back the straight edge this whole rule exists to remove. */
.hero-card-deck .pola .zchal{position:absolute;z-index:3;isolation:isolate;
  top:calc(var(--pw) * .055);left:calc(var(--pw) * .045);max-width:calc(var(--pw) * .90);
  white-space:nowrap;transform:rotate(-1.6deg);
  color:#FFF8EC;
  /* --coral-ink, matching .rn-arrow. This briefly used raw --colorado and the contrast is why it
     should not go back: white on #F75458 is 3.30:1, on #C9343A it is 5.20:1, and these glyphs are
     ~13px bold — normal text by WCAG, so the bar is 4.5:1 and the brand red misses it.
     Courier Prime (--f-mono) is the brand mono, and the same face .rn-arrow uses. It is a 0.6em
     advance monospace so it sets much wider than a geometric sans: letter-spacing .05em and size
     .042 are what keep the longest prompt on one strip. */
  font-family:var(--f-mono);font-weight:700;text-transform:uppercase;
  font-size:calc(var(--pw) * .042);letter-spacing:.05em;line-height:1.42;
  padding:calc(var(--pw) * .017) calc(var(--pw) * .032);text-indent:.05em;
  text-shadow:0 1px 0 rgba(93,18,22,.55)}
.hero-card-deck .pola .zchal::before{content:"";position:absolute;inset:0;z-index:-1;
  background:var(--coral-ink);border-radius:5px;box-shadow:2px 2px 0 0 rgba(65,77,87,.4);
  filter:url(#roughsm)}
/* THE CRAFT CHIP. The deck used to name its category in words — the old .zcat said "photography",
   "drawing", "photo essay", "game design" inside the yellow sticky note — and that information was
   lost when the note became a Dymo strip. This puts it back as a picture, which costs no width.

   It matters most on the two cards where the prompt does NOT imply the craft: "come as your
   heritage" could be anything, where "doodle at the cafe" and "take night photos of the unseen"
   already say it. It goes on all six anyway — one card with a badge and one without reads as a bug.

   BOTTOM-right, not top-right. Top-right is the obvious spot and it is wrong: the chip and the tape
   would share that row, so the tape has to give up ~28% of its width, and at .72 the longest prompt
   clips to "TAKE NIGHT PHOTOS OF THE U". Measured, not guessed. Bottom-right sits on the photograph,
   clear of the tape above and the green band below, and is empty on all six cards.

   The icons are LIFTED FROM .cr-ico in the craft grid one section down — same viewBox, same
   stroke-width 1.9, same round caps — so this is the page's existing hand, not a second one. Only
   the clothes hanger is new; the grid has sewing and jewelry but no fashion. Drawing uses the
   grid's watercolour BRUSH rather than a pencil, because a pencil and the penmanship nib are the
   same shape at 37px and the two cards sit next to each other in the cycle. */
/* A DOODLE, NOT A BADGE. This started as an oats paper chip with an ink border and a hard shadow —
   a UI badge pinned to a photograph, which is what it read as. Bare yellow marker on the picture is
   the page's own marginalia idiom instead (the hand-drawn arrows, circles and stars in .cg-scrap all
   sit directly on the artwork with nothing behind them).
   Three things make it survive without a chip:
     - #roughsm on the SVG. Wobbling TYPE is a defect and wobbling a DOODLE is the whole point, so
       the filter goes on the element here, unlike the two bands above.
     - stroke-width 2.3 via CSS, overriding the 1.9 baked into the markup as a presentation
       attribute. 1.9 is tuned for ink on oats in the craft grid; --happy on a photograph needs more.
     - ONE tight ink drop-shadow. Not a background and not an outline — without it the yellow
       vanishes on the Penman card, which is cream paper, and on the bright half of Claire's cafe. */
.hero-card-deck .pola .zcraft{position:absolute;z-index:4;
  right:calc(var(--pw) * .045);bottom:calc(var(--pw) * .20);
  width:calc(var(--pw) * .145);height:calc(var(--pw) * .145);
  display:flex;align-items:center;justify-content:center;
  color:var(--happy);transform:rotate(-6deg);
  filter:url(#roughsm) drop-shadow(0 1.5px 1px rgba(38,28,12,.75))}
.hero-card-deck .pola .zcraft svg{width:100%;height:100%;display:block;stroke-width:2.3}

/* the answer: flush green band, handwriting, with the credit under it */
/* The band gets the wobble too. Its border-top was the other perfectly straight line in the hero —
   a 2.4px ruler across a card whose every other edge is hand-cut. #roughsm plus the same boil the
   rest of the page's paper runs on. (A displacement filter needs ~3px of ink to read as tremor
   rather than chew it into dashes — see the note on the retired .ed-hair at :3519 — so the rule
   goes 2.4px -> 3px at the same time. That is the minimum that survives the filter.) */
.hero-card-deck .pola .zrefl{position:absolute;z-index:3;isolation:isolate;
  left:0;right:0;bottom:0;text-align:center;color:var(--oats);
  font-family:var(--f-hand);font-size:calc(var(--pw) * .062);line-height:1.08;
  padding:calc(var(--pw) * .022) calc(var(--pw) * .03) calc(var(--pw) * .028)}
/* inset -2px on the sides and bottom so the filter's displacement has somewhere to go without
   pulling the fill in off the card's edge; the band is meant to bleed, only its TOP rule wobbles */
.hero-card-deck .pola .zrefl::before{content:"";position:absolute;inset:0 -2px -2px;z-index:-1;
  background:var(--grass-deep);border-top:3px solid var(--ink);filter:url(#roughsm)}
/* The answers are in curly quotes (Sue's call, overriding an earlier objection of mine worth
   recording: these lines are COMPRESSED from longer ledger entries — Claire actually wrote "It
   helps me relax and focus when I draw at the cafe!" — and a quote mark asserts verbatim. The
   house rule permits it, since the rule is "no quotes on NON-testimonial copy" and these are real
   testimonial. If anyone ever tightens the claims audit, the fix is to quote the ledger exactly
   rather than to drop the marks: the marks are what make it read as a person talking. */
.hero-card-deck .pola .zrefl small{display:block;font-family:var(--f-head);font-weight:700;
  text-transform:uppercase;font-size:calc(var(--pw) * .029);letter-spacing:.11em;
  opacity:.7;margin-top:4px}
/* the FRONT card wears the "tap to flip through" cue below it. JS marks it .dt. */
.hero-card-deck .pola.dt::after{content:"real zines\00a0\2014\00a0tap to flip\00a0\2192";position:absolute;left:50%;bottom:-24px;
  transform:translateX(-50%) rotate(-3deg);white-space:nowrap;font-family:var(--f-hand);font-size:13.5px;
  font-weight:700;line-height:1;color:var(--coral-ink)}
.hcd-hint{display:none}

/* ===== CHALLENGE LIGHTBOX ===== tapping the hero deck (too small to fan out in place) opens this:
   every kind of challenge at a readable size, framing what "creative" means on Drex. Body-level, so
   position:fixed is viewport-relative and it can never run off-screen like the old in-place splay did. */
.deck-modal{position:fixed;inset:0;z-index:300;display:flex;align-items:center;justify-content:center;
  padding:clamp(1rem,4vw,3rem)}
.deck-modal[hidden]{display:none}
html.modal-open{overflow:hidden}
.dm-backdrop{position:absolute;inset:0;background:rgba(46,56,64,.62);backdrop-filter:blur(2px);
  animation:dmFade .2s ease both}
.dm-panel{position:relative;z-index:1;width:min(940px,96vw);max-height:90vh;overflow:auto;
  background:var(--oats);padding:clamp(1.6rem,3.5vw,2.6rem);animation:dmPop .24s cubic-bezier(.2,.9,.3,1.1) both}
.dm-panel::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--oats);
  border:2.8px solid var(--ink);box-shadow:11px 11px 0 rgba(65,77,87,.85);filter:url(#soft)}
.dm-close{position:absolute;top:.35rem;right:.5rem;z-index:2;width:40px;height:40px;display:flex;
  align-items:center;justify-content:center;font-size:27px;line-height:1;background:none;border:0;
  color:var(--ink);cursor:pointer;font-family:var(--f-head)}
.dm-close:hover{color:var(--colorado)}
.dm-close:focus-visible{outline:3px solid var(--lazuli);outline-offset:2px;border-radius:4px}
.dm-eyebrow{margin:0;font-family:var(--f-head);font-weight:500;font-size:var(--fs-label);
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink-faint)}
.dm-eyebrow .hl{background:var(--happy);mix-blend-mode:multiply;padding:.02em .18em;border-radius:3px;color:var(--ink)}
.dm-sub{margin:.45rem 0 0;font-family:var(--f-hand);font-size:1.16rem;line-height:1.2;color:var(--grass-deep)}
/* 150px -> 210px: the lightbox is the one place these are meant to be READ rather than glanced at,
   and at a 150px cell the two bands ate roughly half the card, leaving the photograph as a letterbox
   strip. At 210 the picture gets its 3:4 back and the answers still set at a comfortable size. */
.dm-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));
  gap:clamp(1.2rem,2.8vw,2rem) clamp(.9rem,2vw,1.4rem);margin-top:clamp(1.1rem,2.6vw,1.7rem)}
.dm-grid .pola{position:relative;width:auto;margin:0;padding:0;
  transform:rotate(var(--r));cursor:pointer;text-decoration:none;color:var(--ink);
  transition:transform .25s cubic-bezier(.2,.8,.2,1);
  box-shadow:2px 2px 0 0 var(--paper),3px 3px 0 0 var(--ink),6px 6px 0 0 var(--paper),7px 8px 0 0 var(--ink)}
.dm-grid .pola::before{display:none}   /* NO white polaroid mat */
.dm-grid .pola i{display:block;aspect-ratio:1/1.3;background-size:cover;background-position:center;
  border:2.4px solid var(--ink);filter:url(#soft)}
/* The lightbox clones deck.innerHTML wholesale (openModal), so it inherits the two bands and needs its
   own sizes for them. The grid cell is fluid (auto-fill minmax) rather than a --pw multiple, so these
   are absolute: the modal is where the deck is finally big enough to be READ rather than glanced at,
   and the answers deserve to be legible there. */
/* the same Dymo-and-handwriting split, at the modal's fixed cell size. The grid cell is fluid
   (auto-fill minmax) rather than a --pw multiple, so these are absolute values. */
.dm-grid .pola .zchal{position:absolute;z-index:3;isolation:isolate;top:11px;left:9px;
  max-width:calc(100% - 18px);white-space:nowrap;transform:rotate(-1.6deg);color:#FFF8EC;
  font-family:var(--f-mono);font-weight:700;text-transform:uppercase;
  font-size:10.5px;letter-spacing:.05em;line-height:1.42;padding:4px 8px;text-indent:.05em;
  text-shadow:0 1px 0 rgba(93,18,22,.55)}
.dm-grid .pola .zchal::before{content:"";position:absolute;inset:0;z-index:-1;
  background:var(--coral-ink);border-radius:3px;box-shadow:2px 2px 0 0 rgba(65,77,87,.4);
  filter:url(#roughsm)}
.dm-grid .pola .zcraft{position:absolute;z-index:4;right:9px;bottom:58px;
  width:34px;height:34px;display:flex;align-items:center;justify-content:center;
  color:var(--happy);transform:rotate(-6deg);
  filter:url(#roughsm) drop-shadow(0 1.5px 1px rgba(38,28,12,.75))}
.dm-grid .pola .zcraft svg{width:100%;height:100%;display:block;stroke-width:2.3}
.dm-grid .pola .zrefl{position:absolute;z-index:3;isolation:isolate;left:0;right:0;bottom:0;
  text-align:center;color:var(--oats);
  font-family:var(--f-hand);font-size:16px;line-height:1.1;padding:7px 10px 9px}
.dm-grid .pola .zrefl::before{content:"";position:absolute;inset:0 -2px -2px;z-index:-1;
  background:var(--grass-deep);border-top:3px solid var(--ink);filter:url(#roughsm)}
.dm-grid .pola .zrefl small{display:block;font-family:var(--f-head);font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;font-size:9px;opacity:.72;margin-top:4px}
.dm-grid .pola:hover,.dm-grid .pola:focus-visible{transform:rotate(0) translateY(-5px);outline:none}
@keyframes dmFade{from{opacity:0}to{opacity:1}}
@keyframes dmPop{from{opacity:0;transform:translateY(10px) scale(.975)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.dm-backdrop,.dm-panel{animation:none}}
/* Clipping the heap clips its CHILDREN to its own box — but the heap's box is itself wider than the
   viewport on a phone (negative insets, by design: the photographs are meant to run off the edge), and
   so is the hamburger's string. So the clip has to live on an ancestor. overflow-x:clip, not hidden:
   clip does not create a scroll container, so it cannot break anchor scrolling or sticky positioning. */
html,body{overflow-x:clip}   /* on <html> too: the burger's string is fixed-position, so it escapes a
   clip set only on <body>, and it alone was dragging the page 14px sideways on a phone. Root-level
   overflow propagates to the viewport, which is the only thing that contains a fixed element. */
/* The burger's string rig is absolutely positioned off the burger and its widest piece (.hb-mouth)
   reaches ~32px past the burger's right edge — which, at the right-hand end of the masthead, is past
   the viewport. Neither html nor body's overflow-x:clip contains it, so the page rubber-banded ~14px
   sideways on every phone. Clip the masthead row on X only; Y stays visible so the burger can still
   fall out of it on a string. */
.mast>.wrap{overflow-x:clip}
/* On a phone a 34% photo column starved the copy to a 201px measure and wrapped the CTA button onto
   two lines. The CTA is the most important object on the card and it does not negotiate for space:
   below 700 the coupon takes the FULL width as its own grid row, and the well shortens to sit beside
   the standfirst only. Still structural — the well is column 2 of the standfirst's row, and the foot
   is a full-width row BELOW it, so neither can reach the other. */
@media(max-width:700px){
  .ed-inner{grid-template-columns:minmax(0,70fr) minmax(0,30fr)}
  .ed-foot{grid-column:1/-1}
  .card-stack{grid-row:2/3;min-height:0}
}
/* THE LAST HOLE, and it is the same disease in miniature. The pieces are sized as a % of the well's
   WIDTH but positioned as a % of its HEIGHT, and the height came from whatever the copy beside it
   happened to need. So when the copy got short (at exactly 700px, where the coupon goes full-width and
   the well shortens to the standfirst's row), the stack was taller than the box that was doing the
   proving, and the bottom piece spilled onto the coupon.
   The well's height is now DERIVED from its own width instead of inherited from the text. The stack's
   deepest point is 69% of the height plus one piece (58% of the width), so it fits whenever
   height >= 1.87 x width. aspect-ratio 1/2.2 guarantees that at every viewport, with slack, and it
   cannot be broken by anything the copy does. */
.card-stack{align-self:start;height:auto;min-height:0;aspect-ratio:1/2.2}
@media(min-width:701px){
  /* a 40% well is wide enough that its derived height fills the copy column beside it */
  .ed-inner{grid-template-columns:minmax(0,60fr) minmax(0,40fr)}
}
/* Phones (<=640): the deck cannot survive as a floated stack in a ~90px column — it overflowed the
   card and got guillotined by overflow-x:clip, hiding half of every real zine cover. Collapse the hero
   to ONE column and give the deck its own full-width row UNDER the beats.

   POST-BETA: that row used to be a 2x2 GRID of four covers at natural size, on the argument that every
   cover should be visible whole. That argument dies with this deck. Four cells became five (an orphan
   row), and more to the point a grid cell here is ~151px wide, where the red band cannot hold
   "photograph the overlooked, at night" and the credit line under the green band is unreadable — which
   is the exact illegibility this whole change exists to fix. Rendered and checked at 165px before
   ruling: the bands do not survive it.

   So the phone KEEPS THE CYCLING STACK instead, at ~78vw. One card at a legible size, cycling, is
   worth more than five at an unreadable one — and the stack was only ever broken here because it was
   floated inside a ~90px grid column, which it no longer is. Tapping still opens the lightbox, where
   all five are laid out big and every answer can actually be read. */
@media(max-width:640px){
  .ed-inner{grid-template-columns:1fr}
  .hero-card-deck{--pw:min(300px,78vw);grid-column:1;grid-row:auto;justify-self:center;
    width:100%;height:calc(var(--pw) * 1.34 + 46px);margin:1.75rem 0 .3rem}
  /* .pola stays position:absolute — the stack, centred in the full-width row. Do NOT restore the
     static/grid override here: it is what un-stacks the deck, and un-stacked is what we just ruled out. */
  .hero-card-deck .pola{left:50%;margin-left:calc(var(--pw) / -2)}
}

/* THE THREE BEATS. The loop is a challenge, an hour, and a due date, and the sentence says so but
   does not SHOW so. Colouring the words themselves is not an option: on Oats, every brand colour
   fails WCAG AA as body text (grass 2.78, colorado 3.07, lazuli 3.11, schoolbus 1.82 — the floor is
   4.5). So the colour goes BEHIND the ink, the way a highlighter actually works. And a highlighter is
   translucent: at full strength ink-on-grass is 2.90 and unreadable, but at .42 it is 5.1 and passes,
   while still reading unmistakably as green.
   The marks sit on the three NOUNS, not the three clauses. .hl::before is one absolutely-positioned
   swatch, so on a phrase that wraps it paints a single box over every line in between — a redaction,
   not a highlight. nowrap keeps each mark on one line, which is the only state it is drawn for.
   Blue asks, green is where the people are, red is the deadline. Yellow stays the headline's alone. */
.ed-stand .hl,
.ed-terms .hl{white-space:nowrap}   /* .hl::before is ONE absolutely-positioned swatch: let the phrase
   wrap and it degenerates into a sliver spanning the line break. One line is the only state it draws. */
.hl-b::before{background:var(--lazuli);opacity:.42}
.hl-g::before{background:var(--grass);opacity:.42}
.hl-r::before{background:var(--colorado);opacity:.42}
.hl-gd::before{background:var(--grass-deep);opacity:.42}   /* the zine payoff — the ONE color break in the beats */
/* the mechanic beats (challenge / Circle Time / deadline) share one calm highlighter family so the
   four beats read as a sequence, not a four-color rainbow. Only beat 4 (Your zine) breaks to green. */
.hl-y::before{background:var(--happy);opacity:.5}
/* the terms are longer now (they carry the funding model), so give the coupon room to hold them
   without squeezing the stamp — and let the first sentence, the one that answers "what does it
   cost", carry weight instead of hiding at the end of a run-on. */
.ed-terms{flex:1 1 15rem;line-height:1.5}
.ed-terms b{font-weight:600;color:var(--ink)}
.ed-coupon{max-width:none}

/* =====================================================================
   #proof — THE LONG PAGE   (/design-shotgun r3 winner: P3-margin + grafts)
   ---------------------------------------------------------------------
   The old object drew each zine as a landscape, saddle-stapled, photocopied paper
   BOOK. But a drex zine is a TALL, portrait, variable-height SCROLLING WEB PAGE:
   spread-cafe.jpg is 720x1306 (ratio .55), spread-silk.jpg is 720x895 (.80). They
   are different heights because they are captures of pages of different lengths.
   Cropping a .55 portrait into a 1.46 landscape frame threw away 60% of the artifact
   and left a flat grey wall. The proportions were lying about what a zine is.
   Now: one issue at a time runs down a 300px gutter at its FULL uncropped height in a
   cartoon browser window (with a live URL bar — grafted from P1 — so it says "web page"
   out loud), a length ruler beside it (grafted from P5) marks how tall it truly is, and
   the caption (the product) is set calm in the wide margin. Craft on the facsimile,
   hierarchy in the type; they never trade jobs. Tabs swap the issue, so all three fit
   ONE object and the section is shorter than the 1148px it was.
   ===================================================================== */
.mg{position:relative}
.mg-head{max-width:46ch;margin:0 0 clamp(1.6rem,3.4vw,2.4rem)}
.mg-sub{font-family:var(--f-body);font-weight:300;font-size:var(--fs-body);line-height:1.55;
  color:var(--ink-soft);margin:.85rem 0 0;max-width:52ch}

/* the tabs: three paper index tabs */
.mg-r{position:absolute;width:1px;height:1px;opacity:0;margin:0;pointer-events:none}
.mg-tabs{position:relative;z-index:3;display:flex;flex-wrap:wrap;align-items:flex-end;
  gap:.55rem clamp(.6rem,1.4vw,1rem);margin:0 0 1.15rem}
.mg-tab{position:relative;display:inline-flex;align-items:center;min-height:48px;cursor:pointer;
  padding:.6rem .95rem;background:var(--paper);color:var(--ink-soft);
  border:2.6px solid var(--ink);border-radius:7px 7px 2px 2px;box-shadow:4px 4px 0 0 var(--ink);
  font-family:var(--f-head);font-weight:500;font-size:var(--fs-label);
  text-transform:uppercase;letter-spacing:.13em;
  transform:rotate(var(--tr,-1deg));transition:transform .1s ease,box-shadow .1s ease,background .1s ease}
.mg-tab:nth-of-type(2){--tr:1.2deg}
.mg-tab:nth-of-type(3){--tr:-.6deg}
.mg-tab:hover{transform:rotate(0)}
.mg-tab:active{transform:translate(4px,4px) rotate(0);box-shadow:0 0 0 0 var(--ink)}
/* the raised, current tab: Happy fill (ink on Happy = 6.2, passes AA), un-tilted, deeper shadow */
#mg-a:checked~.mg-tabs .mg-tab:nth-of-type(1),
#mg-b:checked~.mg-tabs .mg-tab:nth-of-type(2),
#mg-c:checked~.mg-tabs .mg-tab:nth-of-type(3){
  background:var(--happy);color:var(--ink);font-weight:700;transform:rotate(0) translateY(-3px);
  box-shadow:6px 6px 0 0 var(--ink)}
#mg-a:focus-visible~.mg-tabs .mg-tab:nth-of-type(1),
#mg-b:focus-visible~.mg-tabs .mg-tab:nth-of-type(2),
#mg-c:focus-visible~.mg-tabs .mg-tab:nth-of-type(3){outline:3px solid var(--lazuli);outline-offset:3px}
.mg-hint{align-self:center;font-family:var(--f-hand);font-size:var(--fs-small);color:var(--ink-faint);
  transform:rotate(-2deg);white-space:nowrap;margin-left:.2rem}

.mg-stage{position:relative;border-top:2.6px solid var(--ink);padding-top:clamp(1.6rem,3.2vw,2.4rem)}
.mg-issue{display:none;grid-template-columns:300px minmax(0,1fr);
  gap:clamp(1.75rem,3.6vw,3.25rem);align-items:start}
#mg-a:checked~.mg-stage .i1,
#mg-b:checked~.mg-stage .i2,
#mg-c:checked~.mg-stage .i3{display:grid}

/* ===== the noisy layer: the facsimile ===== */
.fac{position:relative;isolation:isolate;padding:12px;margin-left:34px}   /* 34px gutter for the ruler */
.fac::before{content:"";position:absolute;inset:0;z-index:0;background:var(--paper);
  border:2.6px solid var(--ink);border-radius:6px;filter:url(#torn);box-shadow:10px 10px 0 0 var(--ink)}
.fac-shot{position:relative;z-index:2;border:2.4px solid var(--ink);border-radius:4px;
  overflow:hidden;background:var(--oats)}
.fac-bar{display:flex;align-items:center;gap:7px;padding:7px 9px;background:var(--happy);
  border-bottom:2.4px solid var(--ink)}
.fac-bar i{width:9px;height:9px;border-radius:50%;background:var(--colorado);
  border:1.6px solid var(--ink);flex:none}
.fac-bar i:nth-child(2){background:var(--schoolbus)}
.fac-bar i:nth-child(3){background:var(--grass)}
.fac-url{flex:1;min-width:0;margin-left:3px;padding:2px 7px;background:var(--paper);
  border:1.6px solid var(--ink);border-radius:20px;
  font-family:var(--f-head);font-size:var(--fs-label);letter-spacing:.02em;color:var(--ink-soft);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fac-shot img,.fac-shot svg{display:block;width:100%;height:auto}
.fac .tape{top:-15px;left:-16px;width:104px;height:28px;z-index:4}
.fac .tape.r{left:auto;right:-18px;top:auto;bottom:34px;transform:rotate(6deg)}
.fac-curl{position:absolute;z-index:5;right:13px;bottom:13px;width:34px;height:34px;
  background:linear-gradient(135deg,transparent 47%,rgba(65,77,87,.26) 47%,var(--schoolbus) 50%);
  filter:url(#roughsm)}
.fac-note{font-family:var(--f-hand);font-weight:400;font-size:var(--fs-body);line-height:1.15;
  color:var(--coral-ink);margin:1.5rem 0 0;padding-left:.35rem;max-width:26ch;transform:rotate(-1.8deg)}
.fac-note .arr{display:inline-block;transform:rotate(6deg)}

/* the LENGTH RULER (graft from P5): a measured tick down the facsimile's left edge, so the
   different heights read as a fact even on the single-issue default view. */
.mg-ruler{position:absolute;left:-2px;top:12px;bottom:12px;width:26px;z-index:6;pointer-events:none;
  display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:.25rem;
  writing-mode:vertical-rl;transform:rotate(180deg);
  font-family:var(--f-head);font-weight:500;font-size:var(--fs-label);letter-spacing:.08em;
  text-transform:uppercase;color:var(--ink-faint)}
.mg-ruler::before{content:"";position:absolute;top:0;bottom:0;left:50%;width:2px;
  background:repeating-linear-gradient(0deg,var(--ink) 0 6px,transparent 6px 11px);
  opacity:.5;filter:url(#roughsm)}
.mg-ruler b{position:relative;background:var(--oats);padding:.15rem 0;font-weight:700;color:var(--ink)}
.mg-ruler span{position:relative;background:var(--oats);padding:.15rem 0}
.mg-ruler-play b{color:var(--grass-deep)}

/* ===== the calm layer: the margin ===== */
.mg-margin{border-left:2px dotted rgba(65,77,87,.30);
  padding-left:clamp(1.25rem,2.6vw,2.25rem);max-width:60ch}
.mg-kicker{font-family:var(--f-head);font-weight:500;font-size:var(--fs-label);
  text-transform:uppercase;letter-spacing:.15em;color:var(--ink-faint);margin:0}
.mg-title{font-family:var(--f-head);font-weight:700;font-size:var(--fs-2);line-height:1.1;
  letter-spacing:-.01em;color:var(--ink);margin:.5rem 0 0}
.mg-slug{font-family:var(--f-head);font-weight:500;font-size:var(--fs-label);
  text-transform:uppercase;letter-spacing:.13em;color:var(--ink-faint);margin:.55rem 0 0}
.mg-lab{font-family:var(--f-head);font-weight:700;font-size:var(--fs-label);
  text-transform:uppercase;letter-spacing:.15em;color:var(--ink-faint);margin:clamp(1.6rem,3vw,2.2rem) 0 .55rem}
.mg-q{font-family:var(--f-body);font-weight:300;font-style:italic;font-size:var(--fs-3);
  line-height:1.4;color:var(--ink-soft);margin:0;max-width:34ch}
.mg-a{font-family:var(--f-body);font-weight:400;font-size:var(--fs-2);line-height:1.32;
  color:var(--ink);margin:0;max-width:24ch;text-indent:-.44em}
.mg-cite{display:block;font-family:var(--f-head);font-weight:500;font-size:var(--fs-label);
  font-style:normal;text-transform:uppercase;letter-spacing:.13em;color:var(--ink-faint);margin:.85rem 0 0}
.mg-cta{margin:clamp(1.6rem,3vw,2.2rem) 0 0}
.mg-cta .btn{font-size:var(--fs-label)}
.mg-why{font-family:var(--f-body);font-weight:300;font-size:var(--fs-small);line-height:1.5;
  color:var(--ink-faint);margin:.9rem 0 0;max-width:40ch}
.mg-a.is-plain{font-style:normal;max-width:30ch;text-indent:0}
.mg-foot{font-family:var(--f-body);font-weight:300;font-size:var(--fs-small);line-height:1.5;
  color:var(--ink-faint);margin:clamp(1.6rem,3vw,2.2rem) 0 0;max-width:48ch}

@media(max-width:760px){
  .mg-issue{grid-template-columns:minmax(0,1fr);gap:1.4rem}
  .fac{max-width:252px;margin-left:32px}
  .mg-margin{border-left:0;border-top:2px dotted rgba(65,77,87,.30);
    padding-left:0;padding-top:1.4rem;max-width:none}
  .mg-tab{letter-spacing:.09em;padding:.6rem .7rem}
  .mg-hint{display:none}
  .mg-a{max-width:20ch}
  .fac .tape{width:82px}
}
@media(prefers-reduced-motion:reduce){
  .mg-tab{transition:none}
  .mg-tab:hover{transform:rotate(var(--tr,-1deg))}
}

/* =====================================================================
   #bring, rebuilt — the pitch is three beats, the right column carries weight.
   Was a 6-paragraph wall beside a 4-item list floating over an empty quadrant.
   Now the LEFT is promise / mechanism / relief with ONE emphasis (the highlighter
   on "show up"), and the RIGHT holds the before/after ledger AND the funding card,
   so it fills its height. The funding model was buried as paragraph four; it is its
   own object now, because it is the one fact that beats every paid competitor. The
   cap and the honest line are small print under the CTA, where footnotes belong.
   ===================================================================== */
.bring-grid{grid-template-columns:1fr;align-items:start}
.bring-lede{font-size:clamp(1.1rem,1.8vw,1.35rem);line-height:1.4;color:var(--ink);max-width:32ch}
.bring-lede .hl{white-space:nowrap}
.bring-fine{font-family:var(--f-body);font-size:var(--fs-small);line-height:1.55;
  color:var(--ink-faint);margin:1.4rem 0 0;max-width:52ch}

/* the before/after ledger — the X marks are drawn, not a glyph */
.bring-list{margin-top:.3rem}
.bring-list li{padding-left:2.2rem}
.bl-x,.bl-c{top:.02em;width:1.5rem;height:1.5rem}
.bl-x{position:absolute;left:0}
.bl-x::before,.bl-x::after{content:"";position:absolute;left:50%;top:12%;width:2.8px;height:76%;
  margin-left:-1.4px;background:var(--colorado);border-radius:2px;filter:url(#roughsm)}
.bl-x::before{transform:rotate(45deg)}
.bl-x::after{transform:rotate(-45deg)}

/* the funding card: paper, ink outline, hard shadow, a torn tab — a real object */
.bring-right{display:flex;flex-direction:column;gap:clamp(1.4rem,3vw,2.1rem)}
.bring-money{position:relative;isolation:isolate;margin-top:.4rem;
  padding:clamp(1.15rem,2.2vw,1.5rem) clamp(1.1rem,2.2vw,1.45rem) clamp(1.1rem,2vw,1.35rem);
  transform:rotate(-1deg)}
.bring-money::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--paper);
  border:2.6px solid var(--ink);border-radius:5px;box-shadow:7px 8px 0 0 var(--ink)}
  /* no tear filter: a displacement filter chews a thin straight border into a detached vertical
     squiggle on a tall card. A funding notice is a PRINTED card, not hand-torn paper — clean edges
     are correct here, the way the coupon and buttons are clean. */
.bm-tab{display:inline-block;font-family:var(--f-head);font-weight:700;font-size:var(--fs-label);
  text-transform:uppercase;letter-spacing:.09em;color:var(--oats);background:var(--grass-deep);
  border:2.2px solid var(--ink);border-radius:3px;padding:.28rem .6rem;margin:0 0 .7rem;
  transform:rotate(-1.4deg);box-shadow:2px 2px 0 0 var(--ink)}
.bm-lead{font-family:var(--f-body);font-weight:400;font-size:var(--fs-body);line-height:1.45;
  color:var(--ink);margin:0}
.bm-vs{font-family:var(--f-body);font-weight:300;font-style:italic;font-size:var(--fs-small);
  line-height:1.45;color:var(--ink-soft);margin:.65rem 0 0}
.bm-vs::before{content:"";display:block;width:34px;height:2px;background:var(--ink);opacity:.3;
  margin:0 0 .6rem;filter:url(#roughsm)}

@media(max-width:900px){
  /* collapse to one column. My unconditional .bring-grid rule above is later in source order than
     the original mobile rule, so it was overriding the collapse and leaving two cramped columns on
     a phone. Re-assert it here, after, where it wins. */
  .bring-grid{grid-template-columns:1fr;gap:1.6rem}
  .bring-right{margin-top:.2rem}
  .bring-money{transform:rotate(-.6deg);max-width:26rem}
}


/* =========================================================================
   #proof — THE PILE. A true messy heap of postcards scattered in x AND y.
   Each card: the zine screenshot FILLS the left; the maker's answer / circle
   blurb is written on the right; the circle name runs vertically up the
   bottom-left like a spine label. Tap a card to lift it to the top of the heap.
   Same messy pile on phones, just scaled. Merges "two issues you can read"
   with the "real circles and their zines" roster. Hand-inked outlines live on
   border-only ::before/::after layers so photos + type never smear.
   (Replaced the old .mg/.fac "long page" block; that CSS is now dead.)
   ========================================================================= */
.dk{max-width:900px;margin:0 auto;padding:clamp(.5rem,2vw,1.3rem) 1.25rem clamp(2.4rem,5.5vw,3.8rem)}
.dk-head{text-align:center;max-width:60ch;margin:0 auto clamp(1rem,2.4vw,1.6rem)}
.dk-head .eyebrow{color:var(--colorado);margin-bottom:.3rem}
.dk-head h2{font-family:var(--f-head);font-weight:700;font-size:var(--fs-2);line-height:1.03;
  letter-spacing:-.01em;color:var(--ink);margin:.1rem 0 .5rem}
.dk-head h2 .stop{color:var(--grass-deep)}
.dk-sub{font-family:var(--f-body);font-style:italic;font-size:var(--fs-lede);line-height:1.45;
  color:var(--ink-soft);max-width:54ch;margin:0 auto}

/* the heap stage */
.deck{position:relative;width:min(640px,96vw);height:clamp(400px,62vw,470px);margin:1.4rem auto 0}

.pc{--w:clamp(272px,70vw,428px);position:absolute;left:50%;top:50%;
  width:var(--w);aspect-ratio:1.62/1;
  margin-left:calc(var(--w) / -2);
  display:grid;grid-template-columns:44% 56%;
  background:var(--paper);border-radius:9px;
  box-shadow:6px 8px 0 0 rgba(65,77,87,.8);cursor:pointer;
  transform:translate(var(--x,0),calc(-50% + var(--y,0))) rotate(var(--r,0deg)) scale(var(--s,1));
  transition:transform .4s cubic-bezier(.34,1.28,.5,1),box-shadow .4s ease}
.pc.is-front{box-shadow:9px 13px 0 0 rgba(65,77,87,.9)}
/* the hand-inked card outline — border-only, filtered, drawn OVER the content
   so the wobble touches the ink line, never the photo or the type underneath */
.pc::before{content:"";position:absolute;inset:1px;border:2.6px solid var(--ink);
  border-radius:8px;filter:url(#roughsm);pointer-events:none;z-index:7}

/* LEFT — the screenshot, edge to edge, with a hand-drawn divider on its right */
.pc-img{position:relative;overflow:hidden;background:var(--ink);border-radius:7px 0 0 7px}
.pc-img img{display:block;width:100%;height:100%;object-fit:cover;object-position:top}
.pc-img::after{content:"";position:absolute;top:0;right:0;bottom:0;border-right:2.4px solid var(--ink);
  filter:url(#roughsm2);z-index:6;pointer-events:none}
/* a die-cut PLAY badge for the interactive card */
.pc-play{position:absolute;top:8px;right:8px;z-index:4;display:inline-flex;align-items:center;gap:.26em;
  font-family:var(--f-head);font-weight:700;font-size:11px;letter-spacing:.05em;text-transform:uppercase;
  color:var(--ink);background:var(--happy);border:2px solid var(--ink);border-radius:16px;
  padding:.22em .5em .22em .42em;box-shadow:2px 2px 0 0 var(--ink);transform:rotate(6deg)}
.pc-play svg{width:10px;height:10px}

/* the vertical spine name, bottom-left, sitting on the image.
   Fill + wobbly border live on ::before (filtered); the letters stay crisp. */
.pc-name{position:absolute;left:7px;bottom:8px;z-index:5;isolation:isolate;
  writing-mode:vertical-rl;transform:rotate(180deg);
  font-family:var(--f-head);font-weight:800;font-size:13px;letter-spacing:.02em;line-height:1;
  color:var(--oats);padding:.5em .34em}
.pc-name::before{content:"";position:absolute;inset:-1px;z-index:-1;
  background:var(--key,var(--ink));border:2px solid var(--ink);border-radius:4px;
  box-shadow:2px 2px 0 0 var(--ink);filter:url(#roughsm)}
.pc-name.on-yellow{color:var(--ink)}

/* the postage stamp + postmark */
.pc-post{position:absolute;top:9px;right:9px;width:76px;height:52px;color:var(--key,var(--ink));z-index:4;pointer-events:none}

/* RIGHT — the written message */
.pc-msg{position:relative;padding:14px 15px 13px 16px;display:flex;flex-direction:column;min-width:0}
.pc-type{position:relative;isolation:isolate;align-self:flex-start;font-family:var(--f-head);font-weight:700;
  text-transform:uppercase;letter-spacing:.06em;font-size:10px;color:var(--oats);padding:.16em .5em}
.pc-type::before{content:"";position:absolute;inset:-1px;z-index:-1;background:var(--key,var(--ink));
  border:2px solid var(--ink);border-radius:4px;box-shadow:2px 2px 0 0 var(--ink);filter:url(#roughsm2)}
.pc-type.on-yellow{color:var(--ink)}
.pc-title{font-family:var(--f-head);font-weight:700;font-size:var(--fs-3);line-height:1.02;
  color:var(--ink);margin:.42rem 0 .1rem;max-width:14ch}
.pc-slug{font-family:var(--f-body);font-style:italic;font-size:var(--fs-small);
  color:var(--ink-soft);line-height:1.26;margin:0}
.pc-slug b{font-style:normal;font-weight:600;color:var(--ink)}
.pc-a{font-family:var(--f-body);font-size:var(--fs-small);font-style:italic;line-height:1.3;
  color:var(--ink);margin:.5rem 0 0;padding-left:.55rem;border-left:3px solid var(--key,var(--grass))}
.pc-cite{display:block;font-family:var(--f-body);font-style:normal;font-size:11px;
  color:var(--ink-soft);margin-top:.28rem}
.pc-blurb{font-family:var(--f-body);font-size:var(--fs-small);line-height:1.32;color:var(--ink);margin:.5rem 0 0}
.pc-note{font-family:var(--f-hand);font-size:12px;line-height:1.15;color:var(--colorado);margin:.4rem 0 0}
.pc-cta{margin-top:auto;padding-top:.55rem;display:flex;gap:.5rem;align-items:baseline;flex-wrap:wrap}
.pc-cta .btn{font-size:.72rem;padding:.46rem .74rem}
.pc-ig{font-family:var(--f-head);font-weight:600;font-size:12px;color:var(--grass-deep);
  text-decoration:none;border-bottom:2px solid var(--grass)}

.dk-nav{display:flex;align-items:center;justify-content:center;gap:.5rem;margin-top:1.3rem}
.dk-dot{width:12px;height:12px;border-radius:50%;background:var(--oats);border:2.2px solid var(--ink);cursor:pointer;padding:0}
.dk-dot.on{background:var(--grass-deep);border-color:var(--grass-deep)}
.dk-dot:focus-visible{outline:3px solid var(--lazuli);outline-offset:2px}
.dk-hint{text-align:center;font-family:var(--f-hand);font-size:var(--fs-small);color:var(--ink-soft);margin:.6rem auto 0}
.dk-foot{text-align:center;max-width:54ch;margin:clamp(1.1rem,2.4vw,1.7rem) auto 0;
  font-family:var(--f-body);font-style:italic;font-size:var(--fs-body);color:var(--ink-soft);line-height:1.5}
.dk-foot b{font-style:normal;font-weight:600;color:var(--ink)}

@media(prefers-reduced-motion:reduce){.pc{transition:none}}

/* prev/next arrows flanking the dots — an easy way to cycle the pile.
   position:relative + high z keeps them clickable above any card that
   spills toward them (matters on phones where the heap sits lower). */
.dk-controls{position:relative;z-index:70;display:flex;align-items:center;justify-content:center;gap:.9rem;width:fit-content;margin:1.3rem auto 0}
.dk-controls .dk-nav{margin-top:0}
.dk-arrow{width:40px;height:40px;flex:0 0 auto;display:flex;align-items:center;justify-content:center;
  background:var(--oats);border:2.4px solid var(--ink);border-radius:50%;box-shadow:3px 3px 0 0 var(--ink);
  cursor:pointer;color:var(--ink);font-family:var(--f-head);font-size:1.15rem;line-height:1;padding:0}
.dk-arrow:active{transform:translate(2px,2px);box-shadow:1px 1px 0 0 var(--ink)}
.dk-arrow:focus-visible{outline:3px solid var(--lazuli);outline-offset:2px}
/* phones: give the heap headroom so it doesn't sit on the controls, and add
   a solid backer behind the controls row so it always reads clearly */
@media(max-width:620px){
  .deck{height:470px}
  .dk-controls{margin-top:1.7rem}
  .dk-controls::before{content:"";position:absolute;inset:-8px -16px;z-index:-1;background:var(--oats)}
}


/* ===== #why-not-chat: graveyard -> blooming flower (from _shotgun3/wnc) ===== */
/* A3 — CROSSED OUT, ONE CIRCLED (best messaging, illustrated, no clean lines). */
.wa{max-width:760px;margin:clamp(4.5rem,11vw,8rem) auto 0;position:relative}
.wa-lead{font-family:var(--f-head);font-weight:800;font-size:var(--fs-2);line-height:1.08;letter-spacing:-.01em;color:var(--ink);text-align:center;margin:0 auto 1.6rem;max-width:22ch}
.wa-lead em{font-style:normal;color:var(--colorado)}
.wa-list{display:grid;grid-template-columns:repeat(3,1fr);gap:1.1rem;position:relative;align-items:start}
/* each dead option is a skinny headstone with an arched top, side by side */
.wrong{position:relative;display:flex;flex-direction:column;align-items:center;text-align:center;
  background:var(--paper);border-radius:50% 50% 10px 10px / 42% 42% 10px 10px;
  box-shadow:5px 6px 0 0 rgba(65,77,87,.24);padding:3.2rem 1.05rem 1.4rem;transform:rotate(var(--t,0deg))}
.wrong.r1{--t:-1deg}.wrong.r2{--t:.7deg}.wrong.r3{--t:-.6deg}
.wrong::before{content:"";position:absolute;inset:1px;border:2.6px solid var(--ink);border-radius:50% 50% 9px 9px / 42% 42% 9px 9px;filter:url(#rough);pointer-events:none;z-index:5}
/* R.I.P. engraved into the arch */
.wrong::after{content:"R.I.P.";position:absolute;top:20px;left:50%;transform:translateX(-50%);
  font-family:var(--f-head);font-weight:700;letter-spacing:.14em;font-size:11px;color:var(--ink-faint);opacity:.65;z-index:6}
.wrong .ill{display:block;width:56px;height:54px;margin-bottom:.5rem}
.wrong .ill svg{display:block;width:56px;height:54px}
.wrong h3{font-family:var(--f-head);font-weight:700;font-size:var(--fs-3);color:var(--ink);margin:0 0 .32rem;text-decoration:line-through;text-decoration-color:rgba(247,84,88,.6);text-decoration-thickness:2px;line-height:1.05}
.wrong p{font-family:var(--f-body);font-size:var(--fs-small);color:var(--ink-soft);margin:0;line-height:1.35}
.wrong .gh{position:absolute;top:-32px;left:50%;margin-left:-21px;width:42px;height:50px;z-index:8;pointer-events:none;animation:ghostrise 3.2s ease-in-out infinite}
.wrong.r2 .gh{animation-delay:.7s}
.wrong.r3 .gh{animation-delay:1.4s}
@keyframes ghostrise{0%,100%{transform:translateY(0) rotate(-4deg)}50%{transform:translateY(-9px) rotate(5deg)}}
@media(prefers-reduced-motion:reduce){.wrong .gh{animation:none}}
.wa-face{position:absolute;top:-60px;right:-6px;width:102px;height:102px;transform:rotate(9deg);z-index:9}
.wa-turn{display:flex;align-items:center;justify-content:center;gap:.5rem;margin:1.6rem 0 1.1rem;font-family:var(--f-hand);font-size:1.15rem;color:var(--ink-soft)}
.wa-turn svg{width:24px;height:28px}
/* the antidote — a flower blooming against the graveyard: the text lives in the
   yellow centre, the petals spin round and round (the loop, alive) */
.antidote{position:relative;max-width:600px;margin:0 auto;min-height:0;display:flex;align-items:center;justify-content:center;padding:1rem}
.antidote .petals{position:absolute;top:50%;left:50%;width:452px;height:452px;margin:-226px 0 0 -226px;z-index:0;pointer-events:none;transform-origin:center;animation:spin 30s linear infinite}
.antidote .bloom{position:relative;z-index:1;width:292px;height:292px;border-radius:50%;background:var(--happy);
  display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:1.25rem}
.antidote .bloom::before{content:"";position:absolute;inset:0;border-radius:50%;border:3.4px solid var(--ink);filter:url(#rough);pointer-events:none}
.antidote .bloom h3{font-family:var(--f-head);font-weight:800;font-size:var(--fs-2);color:var(--grass-deep);margin:0 0 .5rem;line-height:1.06;max-width:12ch}
.antidote .bloom p{font-family:var(--f-body);font-size:var(--fs-small);color:var(--ink);margin:0;line-height:1.38;max-width:20ch}
.antidote .bloom p b{color:var(--grass-deep);font-weight:700}
@keyframes spin{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.antidote .petals{animation:none}}
@media(max-width:600px){.wa-list{grid-template-columns:1fr;gap:1.6rem}.wa-face{top:-46px;right:0;width:84px;height:84px}.antidote{flex-direction:column;text-align:center}.antidote .hero{margin-bottom:-.4rem}}

/* ============ #inside — LOOK INSIDE: clothesline / film-strip of app screens ============ */
.board{padding:clamp(2rem,5vw,3.5rem) 0 clamp(1.5rem,4vw,3rem)}
.board .head{margin-bottom:clamp(1.3rem,3.5vw,2.1rem);text-align:center}
.board .head .eyebrow{color:var(--lazuli)}
.board .head h2{font-family:var(--f-slab);font-style:italic;font-weight:700;
  font-size:clamp(1.8rem,6vw,3rem);line-height:.98;margin:.3rem 0 0;color:var(--ink);text-wrap:balance}
.board .head h2 .stop{color:var(--grass-deep)}
.board .bd-sub{font-family:var(--f-body);font-style:italic;font-size:clamp(1.05rem,1.8vw,1.3rem);
  color:var(--ink-soft);max-width:46ch;margin:.85rem auto 0;text-align:center}
/* the strip owns its OWN horizontal scroll — the page never scrolls sideways. */
.board .bd-line{overflow-x:auto;overflow-y:hidden;scroll-snap-type:x proximity;
  -webkit-overflow-scrolling:touch;scrollbar-width:thin;
  padding:6px clamp(1rem,4vw,2rem) 12px;margin-top:clamp(1rem,3vw,1.8rem);
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 2.5%,#000 98.5%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 2.5%,#000 98.5%,transparent 100%)}
.board .bd-line:focus-visible{outline:2.5px dashed var(--lazuli);outline-offset:2px;border-radius:6px}
.board .bd-track{position:relative;display:flex;align-items:flex-start;width:max-content;margin:0 auto;
  gap:clamp(1.1rem,3vw,1.7rem);padding-top:10px}
.board .bd-string{position:absolute;left:0;right:0;top:6px;height:3px;background:var(--ink);
  border-radius:2px;filter:url(#soft);z-index:0;pointer-events:none}
.board .bd-peg{position:relative;z-index:1;flex:0 0 auto;scroll-snap-align:center;
  padding-top:14px;transform:rotate(var(--r,0deg));transform-origin:top center;transition:transform .18s ease}
.board .bd-peg:hover,.board .bd-peg:focus-within{transform:rotate(0) translateY(-4px);z-index:4}
/* ---- "deal the photos in from the right": staggered slide onto the clothesline, the NEW opening
   beat that plays BEFORE the ball drops + the strip wiggles. Rides the independent `translate`
   property (never `transform`), so the resting rotate(var(--r)) tilt AND the hover
   rotate(0) translateY(-4px) are untouched — slide + tilt animate different properties, zero
   conflict, no jump. GPU transform(translate)+opacity only; no per-frame layout. */
.board .bd-peg{--deal-x:46px}                                   /* how far RIGHT of rest each card starts */
/* NO-FLASH GATE: JS adds .bd-deal-armed at load, before the section is on screen (it's below the
   fold), so this parked pose is never seen. Cards sit offset-right + invisible until the deal fires. */
.bd-scroller.bd-deal-armed .bd-peg{translate:var(--deal-x) 0;opacity:0}
@keyframes bd-deal-in{
  from{translate:var(--deal-x) 0;opacity:0}
  55% {opacity:1}                                              /* fade lands early, before the overshoot settles */
  to  {translate:0 0;opacity:1}                                /* == natural rest → forwards-fill reverts w/ zero delta */
}
/* GO: run the stagger. animation-delay steps by --i (leftmost = 0 = lands first). fill:both holds
   the armed 'from' during the delay (no flash) + the rest pose after. back-out curve overshoots
   ~7px left of rest then settles — reads as a card being dealt in. */
.bd-scroller.bd-deal-go .bd-peg{
  animation:bd-deal-in .42s cubic-bezier(.34,1.4,.5,1) both;
  animation-delay:calc(var(--i,0) * 55ms)}
/* reduced-motion: the global *{animation:none!important} freezes the keyframes, so neutralize the
   gate too — cards just rest, fully visible (JS also skips arming under reduce; this is belt+braces). */
@media(prefers-reduced-motion:reduce){
  .bd-scroller.bd-deal-armed .bd-peg,.bd-scroller.bd-deal-go .bd-peg{
    translate:none!important;opacity:1!important;animation:none!important}}
/* NOTE: intentionally NO html[data-tier="lite"] rule here — the deal is cheap GPU translate+opacity
   and must survive lite (which has been falsely demoting Firefox and stripping effects). */
.board .bd-clip{position:absolute;left:50%;top:-2px;width:13px;height:30px;transform:translateX(-50%);
  background:var(--paper);border:2.2px solid var(--ink);border-radius:4px;
  box-shadow:2px 2px 0 0 var(--ink);filter:url(#roughsm);z-index:3}
.board .bd-clip::after{content:"";position:absolute;left:50%;top:5px;bottom:5px;width:2px;
  transform:translateX(-50%);background:var(--ink);border-radius:2px;opacity:.55}
.board .bd-clip::before{content:"";position:absolute;left:50%;top:-4px;width:8px;height:8px;
  transform:translateX(-50%);border-radius:50%;background:var(--c,var(--colorado));border:1.6px solid var(--ink)}
.board .bd-line .zpola{width:clamp(154px,60vw,176px);margin:0}
.board .bd-line .zpola:focus-visible{outline:3px solid var(--lazuli);outline-offset:3px}
.board .bd-line .zpola .ph{aspect-ratio:5/6}
.board .bd-line .zpola .ph img{width:100%;height:100%;object-fit:cover;object-position:top center;display:block}
.board button.zpola{appearance:none;-webkit-appearance:none;background:none;border:0;padding:0;margin:0;
  font:inherit;color:inherit;text-align:inherit;cursor:pointer;display:block}
.board .bd-line .is-ghost .ph{background:var(--oats);gap:.7rem}
.board .bd-line .is-ghost .soon-stamp{color:var(--colorado);border-color:var(--colorado)}
.board .bd-glyph{width:clamp(34px,7vw,46px);height:clamp(34px,7vw,46px);color:var(--ink-faint)}
.board .bd-glyph svg{width:100%;height:100%;display:block;overflow:visible}
.board .bd-glyph svg>*{filter:url(#roughsm)}
.board .bd-foot{text-align:center;margin-top:clamp(1.1rem,3vw,1.7rem);
  font-family:var(--f-body);font-size:1.02rem;color:var(--ink-soft)}
.board .bd-foot a{color:var(--grass-deep);text-underline-offset:3px}
.board .bd-foot .arr{font-family:var(--f-mono)}
.board .bd-drag{display:inline-block;color:var(--colorado);font-size:1.1rem;margin-right:.4rem;transform:rotate(-2deg)}
@media(min-width:900px){.board .bd-drag{display:none}}
/* ---- swipe affordance: always-on paper arrows + a real half-card peek ---- */
.board .bd-scroller{position:relative}
/* stronger peek on phones: bump the card so ~1.6 fit — the next screen is clearly sliced,
   not a hairline. (Desktop keeps the smaller 176px cap from .bd-line .zpola above.) */
@media(max-width:600px){.board .bd-line .zpola{width:clamp(188px,64vw,220px)}}
/* the next-arrow rides a soft shadow so the sliced card reads as "continues under here" */
.board .bd-scroller::after{content:"";position:absolute;top:0;bottom:0;right:0;width:56px;z-index:4;
  pointer-events:none;opacity:0;transition:opacity .2s ease;
  background:linear-gradient(90deg,transparent,rgba(65,77,87,.16))}
.board .bd-scroller.has-next::after{opacity:1}
/* hand-cut paper chips with a sharpie chevron — torn edge (#roughsm), pinned to the strip edges */
.board .bd-arrow{position:absolute;top:calc(50% - 10px);z-index:6;
  width:44px;height:44px;display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0;
  background:var(--schoolbus);border:2.6px solid var(--ink);border-radius:49% 51% 52% 48%/48% 52% 49% 51%;
  box-shadow:2.5px 3px 0 0 var(--ink);filter:url(#roughsm);   /* squigglevision: chip + chevron boil together */
  opacity:0;visibility:hidden;transition:opacity .18s ease, transform .12s ease}
.board .bd-arrow svg{width:24px;height:24px;display:block;overflow:visible}
.board .bd-arrow svg path{fill:none;stroke:var(--colorado);stroke-width:3.2;
  stroke-linecap:round;stroke-linejoin:round}
.board .bd-arrow.is-on{opacity:1;visibility:visible}
.board .bd-arrow:hover{                                          /* --happy is too close to schoolbus to read a press; darken toward the red accent */
  background:#E8A21C;
  background:color-mix(in srgb, var(--schoolbus) 84%, var(--colorado));
  transform:rotate(-3deg)}
.board .bd-arrow:active{transform:translateY(1px)}
.board .bd-arrow:focus-visible{outline:3px solid var(--lazuli);outline-offset:3px}
.board .bd-arrow-prev{left:2px;transform:rotate(-2deg);animation-delay:-.6s}   /* desync the two boils */
.board .bd-arrow-next{right:2px;transform:rotate(2deg)}
.board .bd-arrow-prev:hover{transform:rotate(-5deg)}
.board .bd-arrow-next:hover{transform:rotate(5deg)}
html[data-tier="lite"] .board .bd-arrow{filter:none}
/* ---- "drop onto the clothesline": the ball falls from above + bobs once onto the strip ----
   Rides the independent `translate` property, so it never touches `filter` (the boil) or
   `transform` (the resting/hover tilt) — all three animate different properties, zero conflict. */
/* NO-FLASH GATE: update() flips .is-on on the next arrow at load, before the section is visible.
   Until JS arms the scroller, park the on-arrow hidden AND lifted up on the string.
   Specificity (0,4,0) beats the base .board .bd-arrow.is-on (0,3,0) regardless of source order. */
.bd-scroller:not(.bd-armed) .bd-arrow.is-on{opacity:0;visibility:hidden;translate:0 -64px}
@keyframes bd-drop{
  0%  {opacity:0;translate:0 -64px}
  18% {opacity:1;translate:0 -40px}
  100%{opacity:1;translate:0 0}          /* == resting translate → reverts with zero delta, no fill needed */
}
.board .bd-arrow.bd-fly{/* comma-list: boil (FILTER, infinite) + drop (TRANSLATE, once) */}
/* reduced-motion: global *{animation:none} already kills boil+drop; just clear the parked lift */
@media(prefers-reduced-motion:reduce){.bd-scroller .bd-arrow{translate:none!important}}
/* lite only sets filter:none (not animation); belt-and-suspenders backstop to the JS lite guard */
html[data-tier="lite"] .bd-scroller .bd-arrow{animation:none!important}   /* keep the park (translate) so the flight can still hide+land the real arrow under lite */
/* ---- NEXT-ball grand entrance: a body-level FIXED clone that falls from the top of the screen,
   grows to normal + fades in by the viewport floor, bounces once, flies into place (WAAPI-driven).
   Lives on <body> so position:fixed is viewport-true (no transformed/filtered ancestor). Self-contained:
   the .board .bd-arrow rules can't reach a body child, so every visual is restated to land pixel-identical. */
.bd-flyer{position:fixed;left:0;top:0;z-index:130;pointer-events:none;
  width:44px;height:44px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;padding:0;margin:0;
  background:var(--schoolbus);border:2.6px solid var(--ink);border-radius:49% 51% 52% 48%/48% 52% 49% 51%;
  box-shadow:2.5px 3px 0 0 var(--ink);filter:url(#roughsm);                 /* SVG filter id resolves document-wide */;               /* boils mid-flight (FILTER only, never transform) */
  transform-origin:50% 50%;will-change:transform,opacity;
  transform:translate(0,0) scale(1) rotate(2deg)}                           /* resting look pre-WAAPI = no first-frame flash */
.bd-flyer svg{width:24px;height:24px;display:block;overflow:visible}
.bd-flyer svg path{fill:none;stroke:var(--colorado);stroke-width:3.2;stroke-linecap:round;stroke-linejoin:round}
@media(prefers-reduced-motion:reduce){.bd-flyer{animation:none!important;transform:none!important;opacity:1!important}}
html[data-tier="lite"] .bd-flyer{animation:none}   /* under lite the ball still flies (transform), just without the boil-filter cost */
/* the click-to-open modal */
.bd-modal{position:fixed;inset:0;z-index:200;display:grid;place-items:center;
  background:rgba(65,77,87,.74);padding:clamp(1rem,4vw,2.5rem);animation:bd-fade .16s ease}
.bd-modal[hidden]{display:none}
.bd-modal-fig{position:relative;margin:0;max-width:min(92vw,500px);background:var(--paper);
  border:3px solid var(--ink);box-shadow:10px 12px 0 0 rgba(65,77,87,.5);padding:14px 14px 12px}
.bd-modal-img,.bd-modal-vid{display:block;width:100%;height:auto;max-height:70vh;object-fit:contain;
  border:1.5px solid var(--ink);background:var(--sambas)}
.bd-modal-embed{display:block;width:min(84vw,340px);aspect-ratio:9/16;max-height:72vh;
  border:1.5px solid var(--ink);background:var(--sambas)}
.bd-modal-img[hidden],.bd-modal-vid[hidden],.bd-modal-embed[hidden]{display:none}
.bd-modal-cap{font-family:var(--f-hand);font-size:1.2rem;color:var(--ink);margin:.65rem .2rem .15rem;text-align:center}
.bd-modal-play{display:block;width:max-content;margin:.6rem auto 0;font-family:var(--f-mono);font-weight:700;
  font-size:.95rem;color:var(--paper);background:var(--grass);border:2.5px solid var(--ink);
  box-shadow:3px 3px 0 0 var(--ink);padding:.5em .9em;text-decoration:none}
.bd-modal-play[hidden]{display:none}
.bd-modal-x{position:absolute;top:-17px;right:-17px;width:38px;height:38px;border-radius:50%;
  background:var(--colorado);color:var(--paper);border:2.5px solid var(--ink);box-shadow:2px 2px 0 0 var(--ink);
  font-size:1.5rem;line-height:33px;text-align:center;cursor:pointer;padding:0}
/* prev / next through the clothesline — paper buttons, hand-cut edge (in the design bible) */
.bd-modal-nav{position:absolute;top:50%;transform:translateY(-50%);z-index:3;width:54px;height:54px;
  display:flex;align-items:center;justify-content:center;cursor:pointer;padding-bottom:4px;
  background:var(--oats);color:var(--ink);border:2.8px solid var(--ink);border-radius:50%;
  box-shadow:4px 4px 0 0 rgba(65,77,87,.85);filter:url(#soft);
  font-family:var(--f-display);font-weight:700;font-size:2.1rem;line-height:1}
.bd-modal-prev{left:clamp(.5rem,3.5vw,2.2rem)}
.bd-modal-next{right:clamp(.5rem,3.5vw,2.2rem)}
.bd-modal-nav:hover{background:var(--happy);transform:translateY(-50%) rotate(-4deg)}
.bd-modal-nav:focus-visible{outline:3px solid var(--lazuli);outline-offset:3px}
@media(max-width:560px){.bd-modal-nav{width:44px;height:44px;font-size:1.7rem}
  .bd-modal-prev{left:.4rem}.bd-modal-next{right:.4rem}}
@keyframes bd-fade{from{opacity:0}to{opacity:1}}
html[data-tier="lite"] .board .bd-string,
html[data-tier="lite"] .board .bd-clip,
html[data-tier="lite"] .board .bd-glyph svg>*{filter:none!important}
@media(prefers-reduced-motion:reduce){
  .board .bd-peg,.board .bd-peg:hover,.board .bd-peg:focus-within,.board .bd-drag{transform:none!important;transition:none!important}
  .board .bd-line{scroll-behavior:auto}
  .bd-modal{animation:none}
}
