/* Sylph site: "Held Breath" (held.css v132, 2026-09-26).

   CONTRAST PROOF: tools/contrast.py in the site repo. RUN IT BEFORE ANY COLOUR OR SURFACE CHANGE IN
   THIS FILE, and it must exit 0, in all SIX tints. The proof rests on the caps declared here:
     GLOW      .sky .grad        rgba(--g2rgb,.16) over rgba(--g1rgb,.14)   the two sky washes
               never brighten the sky past this, over the gradient's brightest stop (--sky-b)
     PANE      --pane            rgba(11,17,29,.88)   every text block on the page
     SCRIM     .cue/.hint/.scap  rgba(8,13,23,.88)    the only text inside the sky panel
     CHIP      .chip             rgba(9,14,24,.88)    Take one breath, Hear it, Feel it
     FIXCHIP   .motion           rgba(9,14,24,.9)     the fixed Pause motion chip
     NAV       .nav              rgba(9,14,24,.84)    the fixed nav band
     EDGE      --edge            rgba(185,208,238,.5) every control edge and checked state
   NO BODY TEXT EVER SITS ON THE LIVE CANVAS: every text block sits on a PANE scrim (the footer
   included), and the four surfaces that CAN structurally cross the canvas (the nav band, the
   in-panel scrims, the two chip scrims) are additionally proven against PURE WHITE, because the
   mote sprites are drawn with globalCompositeOperation 'lighter' and their cores can stack to
   white. Raise mote exposure inside assets/held.js, NEVER these alphas, and mirror any colour or
   surface change into tools/contrast.py so it exits 0 again.

   Newsreader is self-hosted: the production CSP is default-src 'self' with no font-src, so the
   face is a FILE on this origin and the Google Fonts CDN is never linked. The descriptor below is
   Google's own css2 output for the latin subset, verbatim apart from the url()
   (assets/vendor/VENDOR.txt records the source URL, sha256 and byte count). No italic is shipped:
   nothing on this page is italic.

   Dusk sky, drifting seed and feather motes on a wind field, a glass sphere you press and hold.
   Nothing but the sphere, its glow, the motes and the sky ever moves. */
@font-face{font-family:"Newsreader";font-style:normal;font-weight:200 400;font-display:swap;src:url(fonts/newsreader-roman.woff2?v=130) format("woff2")}
*{box-sizing:border-box;margin:0;padding:0}
:root{
  --sky-a:#0f1a2b;
  --sky-b:#1d2540;
  --sky-c:#151e33;
  --night:#070c16;
  --ink:#f3f7fc;
  --text:#d2dbe8;
  --dim:#a4b2c4;
  --faint:#8a98ab;
  --line:rgba(185,208,238,.14);
  --line2:rgba(185,208,238,.32);
  --edge:rgba(185,208,238,.5);
  --pane:rgba(11,17,29,.88);
  --g1:#6f9fd0;
  --g2:#9b8fd6;
  --g1rgb:111,159,208;
  --g2rgb:155,143,214;
  --aqua:#bfe4e8;
  --lav:#d9d3f0;
  --free:#8fd6c6;
  --freebg:rgba(28,74,69,.55);
  --serif:"Newsreader",Georgia,"Times New Roman",serif;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --pad:clamp(1.1rem,4.4vw,3rem);
  --ease:cubic-bezier(.22,.75,.24,1);
  --navh:52px;
  --stageh:32svh;
  --orbw:min(40vw,140px);
  --depth:0;
}
html[data-tint="moss"]  {--g1:#6fae86;--g2:#a9cf9c;--g1rgb:111,174,134;--g2rgb:169,207,156}
html[data-tint="rose"]  {--g1:#d18fa2;--g2:#e6b2bd;--g1rgb:209,143,162;--g2rgb:230,178,189}
html[data-tint="gold"]  {--g1:#d0a765;--g2:#e7cb8d;--g1rgb:208,167,101;--g2rgb:231,203,141}
html[data-tint="violet"]{--g1:#9b8fd6;--g2:#c2b3ea;--g1rgb:155,143,214;--g2rgb:194,179,234}
html[data-tint="lagoon"]{--g1:#5aa9bb;--g2:#8fd3da;--g1rgb:90,169,187;--g2rgb:143,211,218}

html{background:var(--sky-a);color:var(--text);color-scheme:dark;overflow-x:clip;-webkit-text-size-adjust:100%;scroll-behavior:smooth}
html.rm{scroll-behavior:auto}
body{font-family:var(--sans);font-size:16px;line-height:1.66;background:var(--sky-a);color:var(--text);overflow-x:clip;min-height:100svh;-webkit-font-smoothing:antialiased}
img,svg,canvas,video{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
b,strong{font-weight:600;color:var(--ink)}
::selection{background:var(--lav);color:#0b1220}
[id]{scroll-margin-top:calc(var(--navh) + 14px)}

/* Focus. A browser with no :focus-visible support drops the middle rule whole and keeps the plain
   ring on every focus; a modern one paints the two-tone ring for keyboard focus only. */
:focus{outline:2px solid var(--ink);outline-offset:2px}
:focus:not(:focus-visible){outline:none}
:focus-visible{outline:2px solid transparent;outline-offset:2px;box-shadow:0 0 0 3px rgba(7,11,20,.95),0 0 0 5px var(--ink),0 0 0 8px rgba(7,11,20,.95);border-radius:10px}
/* The fallback ring above is a bare ink outline with no halo of its own. Two controls sit over
   the live mote canvas (the sphere always, the "Take one breath" chip inside the sky column on
   desktop) and mote cores are drawn with 'lighter', so there the bare ring would have to beat
   white: tools/contrast.py measured 1.08:1. Those two therefore get a dark plate under it. A
   modern engine never shows this plate: the :not(:focus-visible) pair below removes it for
   pointer focus, and the :focus-visible pair replaces it with the two-tone ring for keyboard
   focus. An engine with no :focus-visible drops both of those rules whole (an unknown
   pseudo-class inside :not() invalidates the selector) and keeps the plate, which is the point. */
.orb:focus,#breathBtn:focus{box-shadow:0 0 0 1px rgba(7,11,20,.95),0 0 0 6px rgba(7,11,20,.95)}
.orb:focus:not(:focus-visible),#breathBtn:focus:not(:focus-visible){box-shadow:none}
.orb:focus-visible,#breathBtn:focus-visible{box-shadow:0 0 0 3px rgba(7,11,20,.95),0 0 0 5px var(--ink),0 0 0 8px rgba(7,11,20,.95)}

.skip{position:absolute;left:-999px;top:.5rem;z-index:80;background:var(--ink);color:#0b1220;padding:.75em 1.15em;border-radius:10px;font-weight:600;min-height:44px;display:inline-flex;align-items:center;box-shadow:0 0 0 3px rgba(7,11,20,.95)}
.skip:focus{left:.6rem}
.vhide{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}

/* the fixed dusk sky the whole page sits in */
.sky{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden}
.sky .grad{position:absolute;inset:0;background:
  radial-gradient(120% 78% at 50% 116%, rgba(var(--g2rgb),.16), transparent 64%),
  radial-gradient(90% 60% at 76% -6%, rgba(var(--g1rgb),.14), transparent 62%),
  linear-gradient(178deg, #0c1524 0%, var(--sky-a) 26%, var(--sky-b) 62%, var(--sky-c) 82%, #101828 100%)}
.sky .deep{position:absolute;inset:0;background:var(--night);opacity:calc(.86*var(--depth))}
.sky .vig{position:absolute;inset:0;background:radial-gradient(128% 92% at 50% 40%, transparent 42%, rgba(4,7,14,.62) 100%)}
.prog{position:fixed;top:0;left:0;height:2px;width:100%;background:linear-gradient(90deg,var(--g1),var(--g2));transform:scaleX(0);transform-origin:0 50%;z-index:46;pointer-events:none}
html.rm .prog,html:not(.js) .prog{display:none}

/* nav */
.nav{position:fixed;top:0;left:0;right:0;z-index:40;padding:.55rem var(--pad);background:rgba(9,14,24,.84);border-bottom:1px solid rgba(185,208,238,.08);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}
.navin{display:flex;align-items:center;justify-content:space-between;gap:1rem;max-width:1460px;margin:0 auto}
.brand{display:inline-flex;align-items:center;gap:.6rem;min-height:38px;font-size:.76rem;letter-spacing:.42em;font-weight:500;color:var(--ink)}
.brand .logo-s{width:26px;height:26px;flex:none}
.navlinks{display:flex;gap:.1rem}
.navlinks a{font-size:.7rem;letter-spacing:.2em;text-transform:uppercase;color:var(--dim);padding:.7em .7em;min-height:26px;border-radius:999px;transition:color .35s}
.navlinks a:hover{color:var(--ink)}
@media (max-width:440px){
  .nav{padding-left:.7rem;padding-right:.7rem}
  .brand{font-size:.6rem;letter-spacing:.26em;gap:.4rem}
  .brand .logo-s{width:22px;height:22px}
  .navlinks a{font-size:.6rem;letter-spacing:.07em;padding:.7em .36em}
}
/* Get Merch joined the nav 2026-10-09 (five links). Measured: with the wordmark the row overflows up to ~540px
   and links broke inside, so up to 600px the wordmark beside the logo is visually hidden (the brand link keeps
   its name) and the links use the compact size above; below 360px tighter tracking and no gap. A nav link never
   breaks inside itself. */
.navlinks a{white-space:nowrap}
@media (max-width:600px){.brand > span{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}.navlinks a{font-size:.6rem;letter-spacing:.07em;padding:.7em .36em}}
@media (max-width:359px){.navlinks{gap:0}.navlinks a{letter-spacing:.03em;padding:.7em .26em}}

/* the motion chip, small and out of the way (bottom right only) */
.motion{position:fixed;right:12px;bottom:12px;z-index:44;font:inherit;font-size:.66rem;letter-spacing:.13em;text-transform:uppercase;color:var(--dim);background:rgba(9,14,24,.9);border:1px solid var(--edge);border-radius:999px;padding:.62em 1em;min-height:36px;cursor:pointer;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}
.motion::before{content:"";display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--dim);margin-right:.5em;vertical-align:1px}
.motion[aria-pressed="true"]{color:var(--ink);border-color:var(--ink)}
.motion[aria-pressed="true"]::before{background:var(--ink)}
html.rm .motion,html:not(.js) .motion{display:none}

/* ---------- the stage: the sky panel that holds the sphere ---------- */
.stage{position:relative;height:var(--stageh);z-index:3;overflow:hidden;
  -webkit-user-select:none;user-select:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:transparent}
html.enh .stage{position:sticky;top:0;background:
  radial-gradient(120% 90% at 50% 128%, rgba(var(--g2rgb),.16), transparent 64%),
  radial-gradient(90% 70% at 76% -14%, rgba(var(--g1rgb),.14), transparent 62%),
  linear-gradient(178deg, #0c1524 0%, var(--sky-a) 46%, #131c2f 100%);
  box-shadow:0 18px 40px -8px rgba(5,9,18,.9)}
html.enh .stage::after{content:"";position:absolute;inset:0;pointer-events:none;background:var(--night);opacity:calc(.86*var(--depth))}
html.rm .stage,html:not(.js) .stage{height:auto;padding:5svh 0 1svh;background:none;box-shadow:none}
#motes{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:1}
html.rm #motes,html:not(.js) #motes{display:none}

.orbwrap{position:absolute;left:50%;top:54%;transform:translate(-50%,-50%);width:var(--orbw);aspect-ratio:1;z-index:2;pointer-events:none}
html.rm .orbwrap,html:not(.js) .orbwrap{position:relative;left:auto;top:auto;transform:none;margin:0 auto;width:min(62vw,260px)}
.halo{position:absolute;inset:-48%;border-radius:50%;pointer-events:none;opacity:.46;
  background:radial-gradient(circle, rgba(var(--g1rgb),.36) 0%, rgba(var(--g2rgb),.2) 44%, rgba(var(--g2rgb),0) 72%)}
.orb{position:absolute;inset:0;display:block;padding:0;border:0;border-radius:50%;background:transparent;cursor:pointer;pointer-events:auto;touch-action:manipulation}
html.rm .orb{position:relative;width:100%;aspect-ratio:1}
/* REVIEW-B nit 2: with no JS the sphere has no handler at all, so it is not offered as a control
   and its "press and hold" label goes with it. The halo behind it still reads as a soft light. */
html:not(.js) .orb{display:none}
.glass{position:absolute;inset:0;border-radius:50%;
  background:radial-gradient(circle at 36% 29%, rgba(236,245,255,.26), rgba(150,180,215,.12) 44%, rgba(74,104,150,.1) 72%, rgba(60,90,140,.05) 100%);
  box-shadow:inset 0 0 26px rgba(200,226,255,.1), inset -14px -18px 44px rgba(7,12,24,.55), 0 24px 62px rgba(5,9,18,.6)}
.glass::after{content:"";position:absolute;inset:0;border-radius:50%;box-shadow:inset 0 0 0 1px rgba(214,234,255,.17)}
.fill{position:absolute;inset:7%;border-radius:50%;mix-blend-mode:screen;opacity:.46;
  background:radial-gradient(circle at 50% 54%, rgba(var(--g2rgb),.95), rgba(var(--g1rgb),.5) 46%, rgba(var(--g1rgb),0) 74%)}
.spec{position:absolute;left:20%;top:14%;width:32%;height:23%;border-radius:50%;opacity:.5;
  background:radial-gradient(closest-side, rgba(255,255,255,.55), rgba(255,255,255,0))}
.rim{position:absolute;inset:0;border-radius:50%;
  background:radial-gradient(circle at 70% 80%, rgba(var(--g2rgb),.2), transparent 44%)}
.ring{position:absolute;inset:-9%;width:118%;height:118%;pointer-events:none;opacity:0;transition:opacity .7s ease}
.ring .rbg{fill:none;stroke:rgba(190,214,244,.1);stroke-width:.8}
.ring .rfg{fill:none;stroke:rgba(var(--g2rgb),.8);stroke-width:1.4;stroke-linecap:round;transform:rotate(-90deg);transform-origin:60px 60px}
.stage.live .ring{opacity:1}

.cue{position:absolute;left:50%;transform:translateX(-50%);bottom:13%;z-index:4;min-height:1.5em;
  font-family:var(--serif);font-weight:300;font-size:clamp(1rem,3.6vw,1.3rem);letter-spacing:.02em;color:var(--ink);
  background:rgba(8,13,23,.88);border-radius:999px;padding:.18em .95em;opacity:0;pointer-events:none;transition:opacity .55s ease;white-space:nowrap}
.cue.on{opacity:1}
html.rm .cue,html:not(.js) .cue{position:static;transform:none;margin:1rem auto 0;text-align:center;width:fit-content}
.hint{position:absolute;left:50%;transform:translateX(-50%);bottom:5%;z-index:4;pointer-events:none;font-size:.63rem;letter-spacing:.24em;text-transform:uppercase;color:var(--faint);background:rgba(8,13,23,.88);border-radius:999px;padding:.35em .8em;transition:opacity .8s ease}
.hint.gone{opacity:0}
html.rm .hint,html:not(.js) .hint{display:none}
.scap{position:absolute;right:var(--pad);bottom:5%;z-index:4;pointer-events:none;font-size:.63rem;letter-spacing:.2em;text-transform:uppercase;color:var(--dim);background:rgba(8,13,23,.88);border-radius:999px;padding:.35em .8em;opacity:0;transition:opacity .7s ease;max-width:46vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.scap.on{opacity:1}
html.rm .scap,html:not(.js) .scap{display:none}
.takeone{position:fixed;left:12px;bottom:12px;z-index:44}
html.rm .takeone,html:not(.js) .takeone{position:static;margin:1.2rem auto 0;width:fit-content}
html:not(.js) .takeone{display:none}

.chip{font:inherit;font-size:.66rem;letter-spacing:.13em;text-transform:uppercase;color:var(--ink);background:rgba(9,14,24,.88);border:1px solid var(--edge);border-radius:999px;padding:.62em 1.05em;min-height:36px;cursor:pointer;transition:border-color .35s,color .35s}
.chip:hover{border-color:var(--ink)}
.chip[aria-pressed="true"]{border-color:var(--g2);color:var(--g2)}
.chip[hidden]{display:none}

/* ---------- copy column ---------- */
.copy{position:relative;z-index:2;padding:0 var(--pad)}
.ch{padding:8svh 0 6svh}
.chin{max-width:40rem;margin:0 auto}
.pane{position:relative;background:var(--pane);border-radius:22px;padding:1.3rem 1rem 1.45rem;margin:0 -.45rem;box-shadow:0 0 70px 42px var(--pane)}
.kick{font-size:.64rem;letter-spacing:.32em;text-transform:uppercase;color:var(--g2);display:flex;gap:.75rem;align-items:center}
.kick::before{content:"";width:1.8rem;height:1px;background:currentColor;opacity:.6;flex:none}
h1{font-family:var(--serif);font-weight:200;font-size:clamp(2.05rem,7.2vw,3.45rem);line-height:1.11;letter-spacing:-.008em;color:var(--ink);margin:.95rem 0 1rem;text-wrap:balance}
h2{font-family:var(--serif);font-weight:200;font-size:clamp(1.7rem,5.6vw,2.65rem);line-height:1.14;letter-spacing:-.006em;color:var(--ink);margin:.85rem 0 .85rem;text-wrap:balance}
h3{font-family:var(--serif);font-weight:300;font-size:1.08rem;color:var(--ink);letter-spacing:.005em}
.sub{color:var(--dim);max-width:46ch;font-size:clamp(1rem,3.2vw,1.1rem)}
.lead{color:var(--dim);max-width:46ch;margin-top:.5rem}
.trust{margin-top:1.5rem;color:var(--dim);font-size:.78rem;letter-spacing:.14em}
.btnrow{margin-top:1.7rem;display:flex;gap:1.1rem 1.3rem;align-items:center;flex-wrap:wrap}
.btn{display:inline-flex;align-items:center;min-height:44px;background:linear-gradient(120deg,var(--g1),var(--g2));color:#0b1220;padding:.8em 1.5em;border-radius:999px;font-size:.93rem;font-weight:600;letter-spacing:.01em;box-shadow:0 14px 34px rgba(var(--g1rgb),.26);transition:transform .35s var(--ease),box-shadow .35s ease}
.quiet{font-size:.92rem;color:var(--text);border-bottom:1px solid var(--line2);padding-bottom:2px;min-height:24px;display:inline-flex;align-items:center}
.quiet:hover{color:var(--ink)}
@media (hover:hover) and (pointer:fine){.btn:hover{transform:translateY(-2px);box-shadow:0 18px 40px rgba(var(--g1rgb),.34)}}
.earlyline{margin-top:1.5rem;display:inline-flex;align-items:center;gap:.6rem;flex-wrap:wrap;font-size:.86rem;color:var(--dim);border:1px solid var(--line);background:rgba(10,16,27,.7);border-radius:999px;padding:.55em 1.05em;min-height:38px}
.earlyline .dot{width:8px;height:8px;border-radius:50%;flex:none;background:linear-gradient(120deg,var(--g1),var(--g2))}
.earlyline .cta{color:var(--ink);font-weight:600;white-space:nowrap}
.scrollhint{margin-top:1.8rem;font-size:.62rem;letter-spacing:.3em;text-transform:uppercase;color:var(--faint);display:flex;align-items:center;gap:.6rem}
.scrollhint i{display:block;width:1px;height:2.2rem;background:linear-gradient(180deg,var(--faint),transparent)}
html.rm .scrollhint{display:none}

/* ---------- the field guide: twelve rhythms ---------- */
.guide{list-style:none;margin:1.9rem 0 0;display:grid;gap:0}
.guide li{position:relative;padding:.95rem 0 .95rem 1.15rem;border-top:1px solid var(--line)}
.guide li:last-child{border-bottom:1px solid var(--line)}
.guide li::before{content:"";position:absolute;left:0;top:.95rem;bottom:.95rem;width:1px;background:var(--line2);opacity:.5;transition:opacity .6s ease,background .6s ease}
.guide li.near::before{opacity:1;background:linear-gradient(180deg,var(--g1),var(--g2))}
.guide h3{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;color:var(--text);transition:color .6s ease}
.guide li.near h3{color:var(--ink)}
.guide p{font-size:.93rem;color:var(--dim);margin-top:.2rem;max-width:44ch}
.free{font-size:.58rem;letter-spacing:.16em;font-weight:700;color:var(--free);background:var(--freebg);border-radius:999px;padding:.3em .7em;line-height:1}

/* ---------- three ways to follow ---------- */
.ways{display:grid;gap:1rem;margin-top:1.8rem}
.way{background:rgba(14,21,35,.72);border:1px solid var(--line);border-radius:18px;padding:1.15rem 1.05rem}
.way h3{margin-bottom:.5rem}
.way p{font-size:.93rem;color:var(--dim)}
.wayart{height:58px;margin:-.2rem 0 .7rem;position:relative;overflow:hidden}
.wayart svg{width:100%;height:100%;overflow:visible}
.wayorb{position:absolute;left:0;top:50%;transform:translateY(-50%);width:46px;height:46px;border-radius:50%;
  background:radial-gradient(circle at 38% 32%, rgba(240,248,255,.85), rgba(var(--g2rgb),.6) 44%, rgba(var(--g1rgb),.18) 76%, transparent 100%);
  animation:wbreathe 11s ease-in-out infinite}
@keyframes wbreathe{0%,100%{transform:translateY(-50%) scale(.78);opacity:.7}50%{transform:translateY(-50%) scale(1.02);opacity:1}}
.wayart .rip{fill:none;stroke:rgba(var(--g2rgb),.7);stroke-width:1.2;transform-origin:29px 29px;animation:wrip 4.2s ease-out infinite}
.wayart .rip:nth-child(2){animation-delay:1.4s}
.wayart .rip:nth-child(3){animation-delay:2.8s}
@keyframes wrip{0%{transform:scale(.24);opacity:0}18%{opacity:.9}100%{transform:scale(1);opacity:0}}
.wayart .wave{fill:none;stroke:rgba(var(--g2rgb),.75);stroke-width:1.4;stroke-linecap:round;animation:wwave 7s linear infinite}
@keyframes wwave{0%{transform:translateX(0)}100%{transform:translateX(-60px)}}
.waybtn{margin-top:.9rem;display:flex;align-items:center;gap:.7rem;flex-wrap:wrap}
.waynote{font-size:.74rem;line-height:1.5;color:var(--faint);margin-top:.6rem;max-width:42ch}
html.paused .wayorb,html.paused .rip,html.paused .wave,html.rm .wayorb,html.rm .rip,html.rm .wave{animation:none}

/* ---------- checklist ---------- */
.checklist{list-style:none;margin-top:1.7rem;display:grid;gap:1rem;max-width:44rem}
.checklist li{position:relative;padding-left:2.3rem;color:var(--dim);font-size:.98rem}
.checklist li::before{content:"";position:absolute;left:0;top:.15em;width:22px;height:22px;border-radius:50%;opacity:.55;
  background:linear-gradient(135deg,var(--aqua),var(--lav));border:1px solid var(--line2)}
.checklist li::after{content:"";position:absolute;left:7px;top:.55em;width:8px;height:4px;border-left:1.5px solid var(--ink);border-bottom:1.5px solid var(--ink);transform:rotate(-45deg)}
.checklist strong{color:var(--ink);font-weight:600}

/* ---------- pro ---------- */
.pro-card{margin-top:1.7rem;background:linear-gradient(158deg, rgba(26,34,54,.92), rgba(16,22,38,.92));border:1px solid var(--line);border-radius:22px;padding:1.5rem 1.25rem;max-width:34rem;box-shadow:0 24px 60px rgba(5,9,18,.5)}
.payline{font-family:var(--serif);font-size:1.9rem;font-weight:200;color:var(--ink);line-height:1.2}
.payline small{display:block;font-family:var(--sans);font-size:.76rem;letter-spacing:.1em;text-transform:uppercase;color:var(--dim);margin-top:.35rem}
.pro-card ul{list-style:none;margin:1.2rem 0 .4rem;display:grid;gap:.65rem}
.pro-card li{position:relative;padding-left:1.5rem;font-size:.95rem;color:var(--text)}
.pro-card li::before{content:"";position:absolute;left:.15rem;top:.62em;width:6px;height:6px;border-radius:50%;background:var(--g2)}
.pro-card .btn{margin-top:1.2rem}
.fine{font-size:.82rem;line-height:1.55;color:var(--faint);margin-top:1rem}
.tints{margin-top:1.9rem;border:0;padding:0}
.tints legend{font-size:.64rem;letter-spacing:.28em;text-transform:uppercase;color:var(--dim);padding:0 0 .7rem}
.swrow{display:flex;flex-wrap:wrap;gap:.5rem}
.sw{display:inline-flex;align-items:center;gap:.5rem;min-height:38px;padding:.45em .95em .45em .55em;border:1px solid var(--line);border-radius:999px;background:rgba(12,18,31,.72);color:var(--dim);font-size:.76rem;cursor:pointer}
.sw input{position:absolute;opacity:0;width:1px;height:1px}
.sw .dot{width:16px;height:16px;border-radius:50%;flex:none;box-shadow:inset 0 0 0 1px rgba(255,255,255,.18)}
.sw.is-on{border-color:var(--edge);color:var(--ink);background:rgba(20,28,46,.85)}
.sw:focus-within{outline:2px solid var(--ink);outline-offset:2px}
.sw-classic .dot{background:linear-gradient(120deg,#6f9fd0,#9b8fd6)}
.sw-moss .dot{background:linear-gradient(120deg,#6fae86,#a9cf9c)}
.sw-rose .dot{background:linear-gradient(120deg,#d18fa2,#e6b2bd)}
.sw-gold .dot{background:linear-gradient(120deg,#d0a765,#e7cb8d)}
.sw-violet .dot{background:linear-gradient(120deg,#9b8fd6,#c2b3ea)}
.sw-lagoon .dot{background:linear-gradient(120deg,#5aa9bb,#8fd3da)}

/* ---------- calm band, video, download ---------- */
.calm{margin-top:1.6rem;border-left:1px solid var(--line2);padding-left:1.1rem}
.calm p{max-width:44rem}
.calm .fine{margin-top:.6rem}
.calm a{color:var(--g2);border-bottom:1px solid rgba(var(--g2rgb),.4)}
.promo{margin-top:1.7rem;max-width:44rem}
/* The real player lives in a clipping frame: the desktop GSAP scrub scales the <video>, and
   with no overflow:hidden wrapper the scale would spill past the rounded border and scale the
   border with it. The frame carries the radius, the hairline, the shadow and the clip. */
.promo .frame{position:relative;border-radius:18px;overflow:hidden;border:1px solid var(--line);box-shadow:0 24px 60px rgba(5,9,18,.55);background:#070c16}
.promo video{width:100%;height:auto;aspect-ratio:16/9;background:#070c16}
.promonote{margin-top:.9rem;font-size:.84rem;color:var(--faint)}
.promonote a{color:var(--g2);border-bottom:1px solid rgba(var(--g2rgb),.4)}
.store-row{display:flex;align-items:center;flex-wrap:wrap;gap:1rem;margin-top:1.7rem}
.play-badge{height:72px;width:auto;margin:2px 0}
.playlink{display:inline-block;border-radius:12px;transition:transform .4s var(--ease)}
@media (hover:hover) and (pointer:fine){.playlink:hover{transform:translateY(-3px)}}
.app-store-badge{display:block;height:48px;width:auto;margin:4px 0}
/* Apple's badge matches the VISIBLE plate of the Play badge: the Play PNG is 646x250 with a
   41px transparent border (visible 564x168), so Apple = Play x 168/250 (72px gives 48px,
   64px gives 43px, 60px gives 40px). The hero row must hold BOTH badges on one line on a
   phone: 72 + 48 needs 186 + 16 + 144 = 346px, more than the hero pane gives below about
   399px (340px at 393); 64 + 43 needs 310px, more than it gives below about 363px (307px
   at 360). */
@media (max-width:420px){.store-row .play-badge{height:64px}.store-row .app-store-badge{height:43px}}
@media (max-width:374px){.store-row .play-badge{height:60px}.store-row .app-store-badge{height:40px}}
.note{margin-top:1.2rem;font-size:.86rem;color:var(--faint);max-width:44ch}

/* ---------- footer ---------- */
.foot{position:relative;z-index:2;margin:2rem auto 0;max-width:44rem;padding:1.5rem 1rem 4.6rem;font-size:.82rem;color:var(--faint);background:var(--pane);border-radius:22px;box-shadow:0 0 70px 42px var(--pane)}
.foot > div{margin-bottom:.55rem}
.foot a{color:var(--dim);border-bottom:1px solid transparent}
/* The 1.1rem gap belongs to the footer's LINK ROW only. On every .foot a it also landed
   on the "Zone7 Studios" link inside the studio SENTENCE and pushed the word "app"
   17.6px away, which is what the retired light stylesheet scoped away too. */
.foot div:first-child a{display:inline-flex;align-items:center;min-height:24px;margin-right:1.1rem}
.foot a:hover{color:var(--ink)}
/* site refresh 2026-09-27 (axe, WCAG 1.4.1 link-in-text-block): the studio link INSIDE the footer sentence was
   told apart by colour alone (1.36:1 against the words around it); its border now takes the link's own colour,
   like the .calm and .promonote links. The link row above keeps its transparent edge. */
.foot div:nth-child(2) a{border-bottom-color:currentColor}
.foot div:last-child{margin-bottom:0}
.foot .legal-note{font-size:.74rem;line-height:1.5}
.footwrap{padding:0 var(--pad)}

/* ---------- reveals ---------- */
html.js.enh:not(.failsafe) .rv{opacity:0;translate:0 20px;transition:opacity .9s ease,translate .95s var(--ease);transition-delay:var(--d,0s)}
html.js.enh:not(.failsafe) .rv.on{opacity:1;translate:none}
.d1{--d:.08s}.d2{--d:.16s}.d3{--d:.24s}.d4{--d:.32s}.d5{--d:.4s}
html.failsafe .rv{opacity:1;translate:none}
/* site refresh 2026-09-27: the hero store row is never held back by the reveal. On a short phone (320x640)
   it starts below the phone reveal line, and the store badges are the one thing a visitor must never wait
   for (fleet rule: both badges visible near the top without hunting). Its neighbours still fade in. */
html.js.enh:not(.failsafe) .store-row[data-store="hero"]{opacity:1;translate:none}

/* ---------- desktop: sky column on the left, copy on the right ---------- */
@media (min-width:900px){
  :root{--stageh:100svh;--orbw:min(30vw,360px)}
  .stagegrid{display:grid;grid-template-columns:minmax(0,52fr) minmax(0,48fr);align-items:start;max-width:1660px;margin:0 auto}
  /* two columns: nothing scrolls under the sky panel, so it drops its own gradient and lets
     the page's fixed sky show through. No seam at the column edge, one less paint layer. */
  html.enh .stage{align-self:start;background:none;box-shadow:none}
  html.enh .stage::after{display:none}
  .copy{padding:0 clamp(1.6rem,3.4vw,3.6rem) 0 clamp(1.1rem,2.2vw,2.4rem)}
  .ch{min-height:100svh;padding:14svh 0 10svh;display:flex;align-items:center}
  .chin{max-width:34rem}
  .pane{padding:1.6rem 1.5rem 1.75rem;margin:0 -.6rem}
  .ways{grid-template-columns:1fr}
  .footwrap{padding:0 clamp(1.6rem,3.4vw,3.6rem)}
  .foot{max-width:1660px;margin-inline:auto}
  html.rm .stagegrid{display:block}
  .takeone{position:absolute;left:var(--pad);bottom:6%;z-index:5}
  .cue{bottom:13%}
  .hint{bottom:6%}
  .scap{bottom:6%;right:var(--pad);left:auto;max-width:40%}
}
@media (min-width:1280px){
  .ch{padding:16svh 0 12svh}
}
@media (max-height:700px) and (max-width:899px){
  :root{--orbw:min(34vw,112px)}
}
/* A landscape phone under 900px wide leaves a 32svh panel only ~115px tall; at min(34vw,112px)
   the sphere would be clipped by the panel's own overflow. Proven by geom.py at 740x360. */
@media (max-height:480px) and (max-width:899px){
  :root{--orbw:min(26vw,86px)}
}
@media (max-width:899px){
  html.enh [id]{scroll-margin-top:calc(var(--stageh) + 16px)}
  .stagegrid{display:block}
  .foot{margin-top:1.4rem;padding-bottom:calc(3.2rem + 56px)}
  .cue{bottom:8px;font-size:1rem;padding:.14em .8em}
  .hint{bottom:9px}
  .scap{bottom:9px;left:var(--pad);right:auto;max-width:30vw}
  .ch-hero{padding:5svh 0 0}
  .ch-hero .pane{padding-bottom:calc(1.45rem + 60px)}
  .ch{padding:7svh 0 5svh}
}
html.rm .stage{position:relative}
html.rm .ch{min-height:0;padding:5svh 0 3svh}

/* ---------- cards chapter (site refresh wave 2026-09-27, held.css v134) ----------
   "06 . At a glance": the three owner-approved store story cards (shots/cards/*.webp at 540w and
   1080w, made by the fleet site kit from the 2026-09-21 Play frames), just before #download. Each
   card carries its own headline and sub in the picture, so the page never repeats them as text
   (the alt does), and ONE honest caption sits under the set. Every class starts with "cards".
   PHONE (< 900 px): an ordinary pane chapter that scrolls under the sky panel like every other one.
   The cards are a horizontal scroll-snap strip with the next card peeking in; a card is at most
   78vw wide and never taller than the copy band left under the 32svh panel. The strip is a
   focusable, labelled region (tabindex 0, role region, aria-label), so a keyboard can scroll it.
   The three cards rise in turn when the strip is revealed, under the usual .rv guards.
   DESKTOP (>= 900 px): the copy column is too narrow for three cards of 200 px, so this ONE
   chapter becomes a full-bleed band across the stage grid (percentage arithmetic on the copy
   column, see the note below) with its pane running edge to edge and the usual feather above and
   below, on the denser GALLERY surface rgba(11,17,29,.96) so the sphere and motes never ghost
   through it. It has to paint OVER the sticky sky panel (z-index 3), so at >= 900 px .copy is no longer
   a stacking context (z-index:auto) and this chapter alone takes z-index 4: every other chapter
   still paints under the panel, as tools/contrast.py assumes. The band itself crosses the mote
   canvas, so its text is proven there against PURE WHITE as well as the sky. From 1200 px the
   heading sits left of the cards like a gallery label. The tint rail above the cards is
   decoration, like the .prog hairline. */
.cards-head{max-width:36rem}
.cards-strip{display:flex;gap:.9rem;margin:1.5rem -1rem 0;padding:.35rem 1rem 1rem;overflow-x:auto;scroll-snap-type:x mandatory;scroll-padding-inline:1rem;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;scrollbar-width:thin}
.cards-fig{flex:0 0 auto;width:min(78vw,340px,calc((100svh - var(--stageh) - 56px)*.5625));scroll-snap-align:start}
.cards-fig img{width:100%;height:auto;border-radius:18px;border:1px solid var(--line);box-shadow:0 20px 44px rgba(5,9,18,.55)}
.cards-cap{margin-top:.35rem;font-size:.78rem;line-height:1.5;color:var(--dim)}
html.js.enh:not(.failsafe) .cards-strip.rv .cards-fig{opacity:0;translate:0 24px;transition:opacity .9s ease,translate .95s var(--ease);transition-delay:var(--d,0s)}
html.js.enh:not(.failsafe) .cards-strip.rv .cards-fig:nth-child(2){transition-delay:calc(var(--d,0s) + .14s)}
html.js.enh:not(.failsafe) .cards-strip.rv .cards-fig:nth-child(3){transition-delay:calc(var(--d,0s) + .28s)}
html.js.enh:not(.failsafe) .cards-strip.rv.on .cards-fig{opacity:1;translate:none}
@media (min-width:900px){
  .copy{z-index:auto}
  /* The stage grid is minmax(0,52fr) minmax(0,48fr) with no gap, so the copy column is exactly .48
     of the grid width S, and a percentage on this box is of the copy column's CONTENT width
     C = .48 S - PL - PR, PL and PR being the column's own left and right padding (repeated verbatim
     from the desktop .copy rule). So S = (C + PL + PR) / .48 = 208.33333% + 2.08333 (PL + PR), and
     the grid's left edge lies .52 S + PL to the left of where this box would start. */
  .cards{position:relative;z-index:4;min-height:0;padding:12svh 0;width:calc(208.33333% + 2.08333*(clamp(1.1rem,2.2vw,2.4rem) + clamp(1.6rem,3.4vw,3.6rem)));margin-left:calc(-108.33333% - 1.08333*(clamp(1.1rem,2.2vw,2.4rem) + clamp(1.6rem,3.4vw,3.6rem)) - clamp(1.1rem,2.2vw,2.4rem))}
  .cards-in{max-width:none;margin:0;border-radius:0;background:rgba(11,17,29,.96);box-shadow:0 0 70px 42px rgba(11,17,29,.96);padding:3rem max(var(--pad),calc((100% - 86rem)/2));display:grid;grid-template-columns:minmax(0,1fr);gap:1.6rem 2.5rem;align-items:center}
  .cards-wall::before{content:"";display:block;height:1px;margin-bottom:1.4rem;background:linear-gradient(90deg,var(--g1),var(--g2) 45%,transparent)}
  .cards-strip{display:grid;grid-template-columns:repeat(3,minmax(0,340px));gap:1.5rem;margin:0;padding:0;overflow:visible;scroll-snap-type:none}
  .cards-fig{width:auto}
  .cards-cap{margin-top:1.1rem}
  /* reduced motion: the grid is one column, so the band is the grid width: the copy box plus its
     own two paddings, starting one left padding to the left. */
  html.rm .cards{width:calc(100% + clamp(1.1rem,2.2vw,2.4rem) + clamp(1.6rem,3.4vw,3.6rem));margin-left:calc(-1*clamp(1.1rem,2.2vw,2.4rem))}
}
@media (min-width:1200px){
  .cards-in{grid-template-columns:minmax(0,16rem) minmax(0,1fr)}
}
