/* ============================================================
   n.css — SC4SAP landing page (index.html)

   Black ground, Pretendard set tight, and glass that only reads as
   glass because there is warm light behind it: every stage that holds
   a glass surface also holds an .aura of blurred amber and ember.

   Rules this file keeps:
   - Nothing is positioned with a fixed pixel offset. Measures are rem,
     offsets are % / em / svh. The only px left are hairlines and blur.
   - One accent hue (brand amber). Ember and rose exist only as light
     inside .aura, never as text or UI colour.
   - Every tunable is a custom property, at the top of its block.
   ============================================================ */

:root {
  color-scheme: dark;

  /* ---- Ground and ink ----
     Contrast on #000: ink 19.4:1 · ink-2 10.6:1 · ink-3 6.1:1 · accent-text 10.6:1 */
  --bg:      #000000;
  --ink:     #F4F4F5;
  --ink-2:   #B4B4B9;
  --ink-3:   #8B8B91;
  --ink-dim: #34343A;        /* statement words before they light; a passing state only */
  --line:    rgb(255 255 255 / 0.08);
  --line-2:  rgb(255 255 255 / 0.14);

  --accent:      #F0A030;
  --accent-text: #F5AE45;
  --accent-ink:  #140C00;
  --teal:        #2CC9B4;   /* the notice label only: 9.7:1 on #000 */
  --ok-text:     #7DD3A0;
  --bad-text:    #FF9C84;

  /* ---- Light inside the auras ---- */
  --light-amber: 240 160 48;
  --light-ember: 236 84 44;
  --light-rose:  190 70 110;

  /* ---- Glass ---- */
  --glass-top:    rgb(255 255 255 / 0.10);
  --glass-bottom: rgb(255 255 255 / 0.035);
  --glass-edge:   rgb(255 255 255 / 0.12);
  --glass-shine:  rgb(255 255 255 / 0.22);
  --glass-blur:   22px;

  /* ---- Type ---- */
  --sans: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, system-ui, 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', 'Cascadia Mono', Consolas, monospace;

  /* Tight like a product page: body pulled in a little, headlines a lot. */
  --track-body:    -0.02em;
  --track-head:    -0.04em;
  --track-display: -0.05em;

  --fs-display: clamp(2.2rem, 1.1rem + 4.2vw, 4.4rem);
  --fs-h2:      clamp(1.8rem, 1.2rem + 2.3vw, 3.1rem);
  --fs-h3:      clamp(1.2rem, 1.05rem + 0.6vw, 1.5rem);
  --fs-sub:     clamp(0.98rem, 0.94rem + 0.25vw, 1.12rem);

  /* ---- Rhythm ---- */
  --wrap:   70rem;
  --gutter: clamp(1.25rem, 5vw, 3rem);
  --band:   clamp(5rem, 11vw, 9rem);
  --band-tight: clamp(2.5rem, 4.5vw, 4rem);   /* platform and every section after it */
  --r-sm:   0.75rem;
  --r-md:   1.25rem;
  --r-lg:   1.75rem;
  --r-card: 1rem;      /* the analyze windows' 16px: product pictures that read as screens */
  --r-pill: 999em;

  /* ---- Fixed top: the notice strip, then the floating nav below it ---- */
  --notice-h: 0rem;   /* the strip is hidden; 3rem when it shows */
  --nav-w: 68rem;          /* the capsule's measure */
  --nav-inset: 1.4rem;    /* where the wordmark starts inside it */
  --nav-pad: 0.35rem;     /* capsule padding; the CTA keeps this gap on top, bottom and right */
  --nav-item-h: 2.3rem;   /* menu links and the CTA share one height */

  /* ---- Motion: generous, the way this site has always settled ---- */
  --ease:    cubic-bezier(0.16, 1, 0.3, 1);
  --ease-io: cubic-bezier(0.65, 0, 0.35, 1);
  --t-hover: 600ms;
  --t-swap:  900ms;
}

html[lang="ja"] {
  --sans: 'Pretendard JP Variable', 'Pretendard JP', 'Pretendard Variable', -apple-system, 'Hiragino Sans', 'Noto Sans JP', sans-serif;
}

/* ============================================================
   Base
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: calc(var(--notice-h) + 6rem); -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 0.96rem;
  line-height: 1.65;
  letter-spacing: var(--track-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

h1, h2, h3, p, ol, ul, dl, dd, figure { margin: 0; }
ol, ul { padding: 0; list-style: none; }
img { display: block; max-width: 100%; height: auto; }
button { font: inherit; color: inherit; letter-spacing: inherit; }

/* Scrollbar: a rounded pill on a clear track, no arrows. The transparent
   border insets the pill from the edge. Chrome and Safari only; browsers
   without ::-webkit-scrollbar get the thin standard one in the same tones.
   (Never set scrollbar-width or scrollbar-color where the webkit rules
   should apply: Chrome then ignores ::-webkit-scrollbar.) */
::-webkit-scrollbar { width: 10px; height: 10px; background: transparent; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgb(255 255 255 / 0.2);
  border: 2px solid transparent;
  border-radius: 999px;
  background-clip: padding-box;
  min-height: 3rem;
}
::-webkit-scrollbar-thumb:hover  { background-color: rgb(255 255 255 / 0.42); }
::-webkit-scrollbar-thumb:active { background-color: rgb(255 255 255 / 0.6); }
::-webkit-scrollbar-button, ::-webkit-scrollbar-corner { display: none; background: transparent; }
@supports not selector(::-webkit-scrollbar) {
  html { scrollbar-width: thin; scrollbar-color: rgb(255 255 255 / 0.25) transparent; }
}
a { color: inherit; }
code { font-family: var(--mono); font-size: 0.88em; letter-spacing: 0; }

html[lang="ko"] :is(h1, h2, h3, p, li, dt, dd, span) { word-break: keep-all; overflow-wrap: anywhere; }
/* Japanese has no spaces to break on; let the browser find phrase
   boundaries so a headline never splits inside a word. */
html[lang="ja"] :is(.display, .h2, .item-h, .statement, .sec-sub, .hero-sub, .launch-title, .launch-sub, .join-sub, .foot-brand p, .cost-note) { word-break: auto-phrase; overflow-wrap: anywhere; }
html[lang="ja"] .hero .display { max-width: 18ch; }

::selection { background: rgb(255 255 255 / 0.22); color: #fff; }   /* one fixed grey, not a token some sections re-point */

:where(a, button):focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

[hidden] { display: none !important; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip {
  position: fixed; left: 50%; top: 0.75rem; z-index: 200;
  transform: translate(-50%, -200%);
  padding: 0.6em 1.2em; border-radius: var(--r-pill);
  background: var(--ink); color: #000; text-decoration: none; font-weight: 600;
  transition: transform 300ms var(--ease);
}
.skip:focus { transform: translate(-50%, 0); }

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }

/* ---- Type roles ---- */

.display {
  font-size: var(--fs-display);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: var(--track-display);
  text-wrap: balance;
}
.display em { font-style: normal; color: var(--accent-text); }
@media (min-width: 30rem) { .display em { white-space: nowrap; } }

.h2 {
  font-size: var(--fs-h2);
  font-weight: 800;
  line-height: 1.16;
  letter-spacing: var(--track-head);
  text-wrap: balance;
}

.eyebrow {
  display: inline-block;
  font-family: var(--mono);
  font-size: 0.74rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  color: var(--accent-text);
}

.sec-head { max-width: 48rem; margin-inline: auto; text-align: center; display: grid; justify-items: center; gap: 1.1rem; }
.sec-sub { font-size: var(--fs-sub); color: var(--ink-3); max-width: 38ch; line-height: 1.6; text-wrap: balance; }

/* ============================================================
   Glass — the one surface recipe
   ============================================================ */

.glass {
  position: relative;
  background: linear-gradient(180deg, var(--glass-top), var(--glass-bottom));
  border: 1px solid var(--glass-edge);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.6);
          backdrop-filter: blur(var(--glass-blur)) saturate(1.6);
  box-shadow:
    inset 0 1px 0 var(--glass-shine),               /* lit top edge */
    inset 0 -1px 0 rgb(255 255 255 / 0.03),
    0 1.5rem 4rem -1.5rem rgb(0 0 0 / 0.7);
}

/* Browsers without backdrop-filter get a solid that still reads as a panel. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass { background: #141416; }
}

/* ---- Aura: the light glass needs behind it ---- */

.aura { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.orb {
  position: absolute;
  width: var(--size, 40%);
  aspect-ratio: 1;
  border-radius: 50%;
  filter: blur(64px);
  opacity: var(--alpha, 0.55);
  animation: drift var(--drift, 22s) var(--ease-io) infinite alternate;
}
.orb.o1 { --size: 38%; left: 8%;  top: 18%; background: radial-gradient(circle, rgb(var(--light-amber)) 0%, transparent 68%); }
.orb.o2 { --size: 34%; right: 6%; top: 34%; --drift: 26s; --alpha: 0.42; background: radial-gradient(circle, rgb(var(--light-ember)) 0%, transparent 68%); }
.orb.o3 { --size: 30%; left: 38%; bottom: 2%; --drift: 30s; --alpha: 0.34; background: radial-gradient(circle, rgb(var(--light-rose)) 0%, transparent 68%); }

.aura.is-idle .orb { animation-play-state: paused; }

@keyframes drift {
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(8%, -6%) scale(1.12); }
}

/* ============================================================
   Buttons
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  padding: 0.85em 1.4em;
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  font-size: 0.92rem;
  font-weight: 650;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-hover) var(--ease), color var(--t-hover) var(--ease),
              border-color var(--t-hover) var(--ease), transform 160ms var(--ease);
}
.btn:active { transform: scale(0.98); }
.btn .ph { font-size: 1.1em; }
.btn .ph-arrow-right { transition: transform var(--t-hover) var(--ease); }
.btn:hover .ph-arrow-right { transform: translateX(0.2em); }

.btn-light { background: var(--ink); color: #000; }
.btn-light:hover { background: #C9C9CE; color: #000; }

.btn-glass { color: var(--ink); }
.btn-glass:hover { border-color: rgb(255 255 255 / 0.28); }

.btn-sm { padding: 0.5em 1em; font-size: 0.84rem; }

.stars { font-family: var(--mono); font-size: 0.8em; color: var(--ink-3); letter-spacing: 0; }
.stars::before { content: '★ '; color: var(--accent-text); }

.actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.75rem; }

/* ============================================================
   NOTICE — the strip above the nav
   ============================================================ */

.notice {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 110;
  height: var(--notice-h);
  display: flex;
  align-items: center;
  padding-inline: var(--gutter);
  background: #000;
  border-bottom: 1px solid var(--line);
}
.notice[hidden] { display: none; }
/* Same measure as the nav capsule, so the label starts at the capsule's
   left edge. */
.notice-inner {
  width: 100%;
  max-width: var(--nav-w);
  margin-inline: auto;
  min-width: 0;
  display: flex;
}
.notice-link {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  min-width: 0;
  color: var(--ink);
  text-decoration: none;
  font-size: 0.82rem;
  font-weight: 600;
  white-space: nowrap;
}
.notice-label {
  flex: none;
  display: inline-flex;
  align-items: center;
  padding: 0.5em 0.75em;
  border: 1px solid var(--teal);
  border-radius: var(--r-pill);
  color: var(--teal);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  line-height: 1;
}
.notice-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; line-height: 1.2; }
.notice-sep { margin-inline: 0.55em; color: var(--ink-3); font-weight: 400; }
.notice-chev {
  flex: none;
  width: 0.82em; height: 0.82em;      /* matches the ink height of the Hangul beside it */
  fill: none; stroke: var(--ink-2); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
  transition: transform var(--t-hover) var(--ease), stroke var(--t-hover) var(--ease);
}
.notice-link:hover .notice-chev { transform: translateX(0.2em); stroke: var(--ink); }

/* Text boxes trimmed to cap height and baseline wherever a word sits
   inside a pill or beside an icon. Without it Pretendard's taller ascender
   leaves every label riding low. Browsers without text-box keep the
   line-height: 1 fallbacks above. */
@supports (text-box: trim-both cap alphabetic) {
  .notice-label, .notice-text, .brand-text, .nav-top > span, .btn > span {
    text-box: trim-both cap alphabetic;
  }
  .notice-label { padding: 0.55em 0.8em; }
  .notice-text { line-height: 1; padding-block: 0.25em; }
}

/* ============================================================
   NAV — floating glass capsule
   ============================================================ */

.nav {
  --nav-top: 0.85rem;
  position: fixed;
  inset: calc(var(--notice-h) + var(--nav-top)) 0 auto 0;
  z-index: 100;
  padding-inline: var(--gutter);
  pointer-events: none;
}

/* The capsule darkens when it opens by changing these two stops. A gradient
   cannot be transitioned, but registered colours can, so the fill fades
   with the height instead of snapping on the way back. */
@property --glass-top    { syntax: '<color>'; inherits: true; initial-value: rgb(255 255 255 / 0.10); }
@property --glass-bottom { syntax: '<color>'; inherits: true; initial-value: rgb(255 255 255 / 0.035); }

.nav-capsule {
  pointer-events: auto;
  max-width: var(--nav-w);
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 1rem;
  padding: var(--nav-pad) var(--nav-pad) var(--nav-pad) var(--nav-inset);
  /* A pill when closed, and the same corners when it grows, so the change
     of height never snaps the radius. */
  border-radius: calc(var(--nav-item-h) / 2 + var(--nav-pad));
  transition: background 420ms var(--ease), --glass-top 420ms var(--ease), --glass-bottom 420ms var(--ease);
  --glass-top: rgb(22 22 24 / 0.55);
  --glass-bottom: rgb(22 22 24 / 0.4);
}
.nav.is-scrolled .nav-capsule { --glass-top: rgb(16 16 18 / 0.8); --glass-bottom: rgb(16 16 18 / 0.68); }

.brand { display: inline-flex; align-items: center; gap: 0.55rem; text-decoration: none; flex: none; }
.brand-mark { width: 1.35rem; height: 1.35rem; }
.brand-text { font-size: 0.86rem; letter-spacing: -0.03em; font-weight: 500; line-height: 1; color: var(--ink); }
.brand-text b { font-weight: 800; }

.nav-menu { display: flex; gap: 0.15rem; margin-inline: auto; }
.nav-top {
  position: relative;
  z-index: 1;
  appearance: none;
  border: 0;
  background: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  height: var(--nav-item-h);
  padding: 0 0.95em;
  border-radius: var(--r-pill);
  color: var(--ink);
  font-size: 0.84rem;
  font-weight: 550;
  line-height: 1;
}
/* One highlight that slides between links instead of each link lighting
   on its own. It covers the whole menu and is clipped to the hovered link,
   so the move animates clip-path only, never layout. Script sets the
   inset; without script each link falls back to its own background. */
.nav-menu { position: relative; }
.nav-glow {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: var(--r-pill);
  background: rgb(255 255 255 / 0.12);
  clip-path: inset(0 100% 0 0 round 999px);
  opacity: 0;
  pointer-events: none;
  transition: clip-path 520ms var(--ease), opacity 700ms ease-in-out;
}
.nav-glow.is-snap { transition: opacity 500ms ease-in-out; }
html:not(.js) .nav-top:hover { background: rgb(255 255 255 / 0.12); }

/* ---- The capsule's second row ----
   Height opens on grid-template-rows (0fr to 1fr), the group inside fades.
   Groups share one cell, so moving from one to the next cross-fades in a
   row that is already open instead of closing and reopening. */
.nav-panel {
  flex-basis: 100%;
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 560ms var(--ease);
}
@media (min-width: 881px) {
  /* Always fully laid out here; the clip does the hiding. */
  .nav-panel { display: block; transition: none; }
  .nav-panel-in { overflow: visible; }
  .nav-capsule {
    --cut: 0px;                       /* set by script: height of the panel row */
    --cap-r: calc(var(--nav-item-h) / 2 + var(--nav-pad));
    --open-dur: 560ms;
    clip-path: inset(0 0 var(--cut) 0 round var(--cap-r));
    transition: clip-path var(--open-dur) var(--ease), background 420ms var(--ease),
      --glass-top var(--open-dur) var(--ease), --glass-bottom var(--open-dur) var(--ease);
    border-color: transparent;        /* the edge is drawn by ::after, which follows the cut */
  }
  .nav-capsule::after {
    content: '';
    position: absolute;
    inset: 0 0 var(--cut) 0;
    border: 1px solid var(--glass-edge);
    border-radius: var(--cap-r);
    pointer-events: none;
    transition: bottom var(--open-dur) var(--ease);
  }
  /* Brand and tools take equal shares, so the menu sits at the capsule's
     centre rather than the centre of whatever space they leave. The shift
     cancels the wider left padding that holds the wordmark in. */
  .brand, .nav-tools { flex: 1 1 0; }
  .nav-tools { justify-content: flex-end; }
  .nav-menu { left: calc((var(--nav-pad) - var(--nav-inset)) / 2); }
  .nav-capsule.is-expanded { --cut: 0px !important; --glass-top: rgb(18 18 20 / 0.9); --glass-bottom: rgb(18 18 20 / 0.84); }
  /* Before script has measured, keep the row out of sight. */
  html:not(.js) .nav-panel, .nav-capsule:not(.is-measured) .nav-panel { display: none; }
}
.nav-panel-in { min-height: 0; overflow: hidden; display: grid; }
.nav-group {
  grid-area: 1 / 1;
  margin-top: var(--nav-pad);
  padding: 0.85rem 0 0.5rem;
  border-top: 1px solid var(--line);
  opacity: 0;
  visibility: hidden;
  transition: opacity 360ms var(--ease), visibility 0s linear 360ms;
}
.nav-group.is-on { opacity: 1; visibility: visible; transition: opacity 460ms var(--ease) 80ms, visibility 0s; }
.nav-group-h { display: none; }
.nav-group-links { display: grid; grid-template-columns: repeat(3, minmax(0, 15rem)); gap: 0.25rem; }
.nav-group.is-four .nav-group-links { grid-template-columns: repeat(4, minmax(0, 13rem)); }
.nav-group-links a {
  display: grid;
  gap: 0.35rem;
  align-content: center;
  padding: 0.75rem 0.9rem;
  border-radius: var(--r-sm);
  color: var(--ink);
  text-decoration: none;
  transition: background 360ms var(--ease);
}
.nav-group-links a:hover, .nav-group-links a:focus-visible { background: rgb(255 255 255 / 0.08); }
.nav-group-links b { font-size: 0.86rem; font-weight: 650; letter-spacing: -0.02em; line-height: 1.2; }
.nav-group-links b em {
  margin-left: 0.3em; padding: 0.15em 0.45em; border-radius: 0.35rem;
  background: rgb(255 255 255 / 0.1); color: var(--ink-2);
  font-style: normal; font-size: 0.66rem; font-weight: 600; letter-spacing: 0.04em; vertical-align: 0.1em;
}
.pl-desc { font-size: 0.76rem; color: var(--ink-3); line-height: 1.3; }

/* The nav's one button, white text like every other label in the bar. */
.nav-cta.btn {
  height: var(--nav-item-h);
  padding: 0 1.15em;
  background: rgb(255 255 255 / 0.14);
  color: var(--ink);
  font-size: 0.82rem;
  line-height: 1;
}
.nav-cta.btn:hover { background: rgb(255 255 255 / 0.26); color: var(--ink); }

.nav-tools { display: flex; align-items: center; gap: 0.5rem; }

.lang { display: inline-flex; padding: 0.2rem; border-radius: var(--r-pill); background: rgb(255 255 255 / 0.05); }
.lang button {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  min-width: 2.2rem; min-height: 1.9rem;   /* clears the 24px target floor */
  padding: 0.35em 0.7em; border-radius: var(--r-pill);
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--ink-3);
  transition: color var(--t-hover) var(--ease), background var(--t-hover) var(--ease);
}
.lang button:hover { color: var(--ink); }
.lang button[aria-pressed="true"] { background: rgb(255 255 255 / 0.14); color: var(--ink); }

.nav-toggle {
  display: none;
  appearance: none; border: 0; padding: 0; cursor: pointer;
  width: 1.95rem; height: 1.95rem; border-radius: 50%;
  background: rgb(255 255 255 / 0.08);
  place-items: center;
  color: var(--ink);
  transition: background 360ms var(--ease);
}
.nav-toggle:hover { background: rgb(255 255 255 / 0.14); }
.nav-burger {
  display: block;
  width: 0.95rem; height: 0.95rem;
  fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round;
  overflow: visible;
}
/* Both strokes meet in the middle and turn: one icon, two states. */
.nav-burger path { transform-box: view-box; transform-origin: 8px 8px; transition: transform 420ms var(--ease); }
.nav-toggle[aria-expanded="true"] .b1 { transform: rotate(45deg) translateY(2.5px); }   /* meet at the centre, then turn */
.nav-toggle[aria-expanded="true"] .b2 { transform: rotate(-45deg) translateY(-2.5px); }

/* The phone list's scroll edges fade only where there is more to see. */
@property --fade-top { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --fade-bot { syntax: '<length>'; inherits: false; initial-value: 0px; }

@media (max-width: 880px) {
  .nav-toggle { display: grid; }
  .nav-cta { display: none; }
  .nav-capsule { border-radius: var(--r-md); }
  .nav-tools { margin-left: auto; }
  /* Phone: the menu button grows the capsule and lists all three groups. */
  .nav-menu { display: none; }
  .nav-capsule.is-open .nav-panel { grid-template-rows: 1fr; }
  .nav-capsule.is-open { --glass-top: rgb(16 16 18 / 0.96); --glass-bottom: rgb(16 16 18 / 0.94); }
  .nav-panel-in {
    display: block;
    /* Ten entries outgrow a phone screen: the list scrolls inside the bar,
       with no scrollbar; the faded edge says there is more. */
    max-height: calc(100svh - var(--notice-h) - 6rem);
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 var(--fade-top), #000 calc(100% - var(--fade-bot)), transparent);
            mask-image: linear-gradient(to bottom, transparent, #000 var(--fade-top), #000 calc(100% - var(--fade-bot)), transparent);
    transition: --fade-top 300ms var(--ease), --fade-bot 300ms var(--ease);
  }
  .nav-panel-in::-webkit-scrollbar { display: none; }
  .nav-panel-in.can-up   { --fade-top: 1.75rem; }
  .nav-panel-in.can-down { --fade-bot: 2.25rem; }

  .nav-group, .nav-group.is-on { opacity: 1; visibility: visible; transition: none; padding: 0.35rem 0 0.4rem; }
  .nav-group + .nav-group { margin-top: 0; }
  .nav-group:first-child { border-top-color: transparent; }
  .nav-group-h {
    display: block;
    padding: 0.55rem calc(var(--nav-inset) - var(--nav-pad)) 0.3rem;
    color: var(--ink-3);
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: -0.01em;
  }
  .nav-group-links, .nav-group.is-four .nav-group-links { grid-template-columns: minmax(0, 1fr); gap: 0.1rem; }
  /* The list spans the capsule edge to edge with the same gap on both
     sides (--nav-pad), and the words inside still start where the
     wordmark starts (--nav-inset). */
  .nav-panel {
    margin-left: calc(var(--nav-pad) - var(--nav-inset));
    flex-basis: calc(100% + var(--nav-inset) - var(--nav-pad));
  }
  .nav-group-links a { padding: 0.6rem calc(var(--nav-inset) - var(--nav-pad)); gap: 0.25rem; }
  .nav-group-links b { font-size: 0.9rem; }
  .pl-desc { font-size: 0.74rem; }

}


/* ============================================================
   Rail — chapter markers on the right edge
   ============================================================ */

.rail {
  position: fixed;
  right: max(1rem, 1.5vw);
  top: 50%;
  z-index: 90;
  transform: translateY(-50%);
  display: grid;
  gap: 0.15rem;
  justify-items: end;
}
.rail a {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.3rem 0;
  text-decoration: none;
  color: var(--ink-3);
  font-size: 0.78rem;
}
.rail a::after {
  content: '';
  width: 1.6rem;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  opacity: 0.45;
  transform: scaleX(0.55);
  transform-origin: right;
  /* Kept on its own layer for good: otherwise the browser lifts it onto one
     only while it animates, smooths its edges there, then repaints it sharp
     when the transition ends, and the line visibly shrinks a hair. */
  will-change: transform;
  transition: transform var(--t-hover) var(--ease), opacity var(--t-hover) var(--ease), background var(--t-hover) var(--ease);
}
.rail span {
  opacity: 0;
  transform: translateX(0.4rem);
  transition: opacity var(--t-hover) var(--ease), transform var(--t-hover) var(--ease);
}
.rail:hover span, .rail a[aria-current="true"] span { opacity: 1; transform: none; }
.rail a[aria-current="true"] { color: var(--ink); }
.rail a[aria-current="true"]::after { transform: none; opacity: 1; background: var(--ink); }

@media (max-width: 1320px) { .rail { display: none; } }

/* ============================================================
   HERO
   ============================================================ */

.hero {
  /* The photograph is bright in places (cream, sky blue), so it always sits
     under two scrims: a vignette behind the copy and a fade into the black
     page at the bottom. Raise --hero-dim if a lighter image comes in. */
  --hero-image: url(../img/hero-bg-2400.jpg);
  --hero-dim: 0.32;              /* overall darkening; 0.32 keeps the colour and still clears contrast */
  --hero-vignette: 0.58;         /* extra darkness behind the copy: amber h1 3.4:1 worst case (large-text 3:1) */
  position: relative;
  isolation: isolate;
  min-height: 92svh;
  display: grid;
  align-content: center;
  padding-top: calc(var(--notice-h) + clamp(5.5rem, 13vh, 7.5rem));
  padding-bottom: clamp(3rem, 7vh, 5rem);
  text-align: center;
  overflow: hidden;
}
/* The photograph replaces the drawn auras here. */
.hero .aura { display: none; }

.hero-bg {
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(ellipse 55% 45% at 50% 48%, rgb(0 0 0 / var(--hero-vignette)), transparent 100%),
    linear-gradient(rgb(0 0 0 / var(--hero-dim)), rgb(0 0 0 / var(--hero-dim))),
    var(--hero-image) center / cover no-repeat,
    var(--bg);
  /* A slow drift so the light feels alive; transform only. */
  transform-origin: 60% 40%;
  animation: hero-drift 28s var(--ease-io) infinite alternate;
}
/* The fade into the next section lives here, not on .hero-bg: the drift
   scales that layer past the hero's edge and would crop the black end off.
   Eased stops, so the photograph thins out with no visible line. */
.hero::after {
  content: '';
  position: absolute; inset: auto 0 0; z-index: -1;
  height: 55%;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgb(0 0 0 / 0) 0%,
    rgb(0 0 0 / 0.08) 18%,
    rgb(0 0 0 / 0.25) 36%,
    rgb(0 0 0 / 0.5) 54%,
    rgb(0 0 0 / 0.75) 72%,
    rgb(0 0 0 / 0.92) 88%,
    var(--bg) 100%);
}
@keyframes hero-drift {
  from { transform: scale(1.04); }
  to   { transform: scale(1.12) translate(-2%, 1%); }
}
/* Phones get the smaller file. */
@media (max-width: 760px) {
  .hero { --hero-image: url(../img/hero-bg-1280.jpg); }
}

.hero-copy { display: grid; justify-items: center; gap: 2rem; }

/* The prompt bar: questions typed out one after another, after flex.team's
   hero input. Darker than the shared glass so the white type sits on it, a
   heavier blur, and a soft inner light instead of a hard top edge.
   Each round: the empty bar opens out to its full width, the question types
   in, the words fade, the bar eases back to its minimum. Phones keep the
   bar full width, left aligned, and let the words wrap downward. */
.ask-wrap { display: grid; justify-items: center; width: 100%; margin-top: 1.4rem; }
.ask {
  --ask-min: min(14rem, 100%);   /* empty, between questions */
  --ask-full: min(42em, 100%);   /* open: the longest question (about 34em) fits; em, so it scales with the type */
  --open: 650ms;          /* min to full: quick growth, then a small spring at full width */
  /* A damped spring (damping 0.67): about 6% past full width, a hair back, then it settles. */
  --spring: linear(0, 0.039, 0.136, 0.264, 0.403, 0.541, 0.666, 0.775, 0.864, 0.934, 0.985, 1.021, 1.043, 1.055, 1.059, 1.057, 1.052, 1.044, 1.036, 1.028, 1.021, 1.014, 1.009, 1.004, 1.001, 0.999, 0.998, 0.997, 0.997, 0.997, 0.997, 0.997, 0.998, 0.998, 0.999, 0.999, 1);
  --fade: 800ms;          /* the next round's bar fades in, eased at both ends so it reads as a fade, not a pop */
  --fade-out: 500ms;      /* a finished round eases away */
  --soft: cubic-bezier(0.22, 1, 0.36, 1);
  --send: 1.2em;          /* the enter-key icon's column */
  --ask-r: var(--r-pill);
  --metal-w: 2px;         /* liquid-metal rim thickness */
  position: relative;
  display: grid;
  grid-template-columns: var(--send) minmax(0, 1fr) var(--send);   /* empty first column keeps the line truly centred */
  align-items: center;
  column-gap: 0.9em;
  box-sizing: border-box;
  width: var(--ask-min);
  max-width: 100%;
  padding: 1.15em 1.4em;
  border-radius: var(--ask-r);
  overflow: hidden;
  font-size: clamp(0.95rem, 0.86rem + 0.42vw, 1.18rem);
  font-weight: 650;
  line-height: 1.5;
  color: var(--ink);
  background: rgb(0 0 0 / 0.26);
  -webkit-backdrop-filter: blur(32px) saturate(1.4);
          backdrop-filter: blur(32px) saturate(1.4);
  box-shadow:
    inset 0 -0.25rem 1.1rem rgb(255 255 255 / 0.07),
    inset 0 0.25rem 1.1rem rgb(0 0 0 / 0.08),
    0 2rem 2.5rem rgb(0 0 0 / 0.1);
  transition: width var(--open) var(--spring), opacity var(--fade) var(--ease-io);
}
.ask.is-open { width: var(--ask-full); }
/* Between rounds: the whole bar fades; the reset to the minimum happens unseen. */
.ask.is-out { opacity: 0; transition: opacity var(--fade-out) var(--ease-io); }
.ask.is-reset { transition: opacity var(--fade) var(--soft); }

.ask-line {
  grid-column: 2;
  position: relative; z-index: 1;
  white-space: nowrap;
  overflow-x: clip;       /* while the bar is still narrow; never clip vertically, the line box is trimmed to the caps */
  text-align: center;
  text-box: trim-both cap alphabetic;   /* centres the ink, not the line box */
}
.ask-caret {
  display: inline-block;
  width: 0.08em; height: 1.15em;
  margin: -0.5em 0 -0.5em 0.1em;        /* tall stroke, but it never sets the line height */
  vertical-align: 0.28em;
  background: currentColor;
  animation: ask-blink 1s steps(1) infinite;
}
@keyframes ask-blink { 50% { opacity: 0; } }
.ask-send {
  grid-column: 3;
  position: relative; z-index: 1;
  display: grid; place-items: center;
  color: var(--ink-3);
  font-size: 0.85em;
  line-height: 1;
}

/* Liquid-metal rim: the @paper-design/shaders liquid-metal shader (the one
   behind the LiquidMetalButton component) drawn on a canvas under the
   element, with a ring mask so only the rim shows. Used on the hero prompt
   bar and the spec badge; the module script at the end of index.html
   mounts a canvas in every .metal-rim. The host needs position and
   border-radius; --metal-w sets the thickness. */
.metal-rim {
  position: absolute; inset: 0;
  border-radius: inherit;
  padding: var(--metal-w, 2px);
  pointer-events: none;
  opacity: 0;
  transition: opacity 900ms var(--soft);
  -webkit-mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
.metal-rim.is-on { opacity: 0.85; }
.metal-rim canvas {
  position: absolute !important; inset: 0;
  width: 100% !important; height: 100% !important;
  display: block;
}

/* Below this the open bar would be cut short of the longest question. */
@media (max-width: 56rem) {
  .ask, .ask.is-open {
    --ask-r: 1.6em;
    grid-template-columns: minmax(0, 1fr) var(--send);
    width: 100%;
  }
  .ask-line {
    grid-column: 1;
    white-space: normal;
    overflow: visible;
    text-align: left;
    word-break: keep-all;
    min-height: calc(1lh + 1cap);       /* two lines reserved, so nothing below jumps */
    align-content: center;
  }
  .ask-send { grid-column: 2; }
}

.hero .display {
  /* One line at every width. The headline measures 9.3em, so the viewport
     cap (8.6vw) keeps it inside a 320px phone's gutters. */
  max-width: none;
  white-space: nowrap;
  font-size: min(calc(var(--fs-display) * 0.86), 8.6vw);
}
/* The English headline is longer (11.6em), so its viewport cap is lower. */
html[lang="en"] .hero .display { font-size: min(calc(var(--fs-display) * 0.86), 7.2vw); }
.hero-sub { max-width: 40rem;   /* rem, not ch: ch is a Latin digit and wraps Hangul early */ font-size: var(--fs-sub); color: var(--ink-2); text-wrap: balance; }
.hero .actions { margin-top: 1.2rem; }
@media (max-width: 26rem) {
  .hero .actions { flex-wrap: nowrap; gap: 0.5rem; }
  .hero .actions .btn { padding: 0.75em 1.05em; font-size: 0.84rem; }
}

.hero-stage { margin-top: clamp(3rem, 7vh, 4.5rem); }

/* ---- Window chrome, shared by every product picture ---- */

.win-bar {
  display: flex;
  align-items: center;
  gap: 0.42rem;
  padding: 0.8rem 1rem;
  border-bottom: 1px solid var(--line);
}
.win-bar span { flex: none; width: 0.62rem; height: 0.62rem; border-radius: 50%; background: rgb(255 255 255 / 0.16); }
.win-bar b {
  min-width: 0;
  margin-left: 0.6rem;
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.74rem;
  letter-spacing: 0;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- Entry ---- */

.enter { opacity: 0; transform: translateY(1.1rem); animation: enter 1000ms var(--ease) forwards; animation-delay: var(--d, 0ms); }
@keyframes enter { from { opacity: 0; transform: translateY(1.1rem); } to { opacity: 1; transform: none; } }

/* ============================================================
   PROBLEM — the statement that lights as you read it
   ============================================================ */

.problem { padding-block: var(--band); }

.statement {
  /* The copy sets its own four lines with <br>; the wrap only bounds it. */
  max-width: none;
  margin-inline: auto;
  text-align: center;
  font-size: clamp(1.6rem, 1rem + 2.4vw, 2.8rem);
  font-weight: 750;
  line-height: 1.34;
  letter-spacing: var(--track-head);
  text-wrap: balance;
}
.br-m { display: none; }   /* a line break for phones only */
@media (max-width: 760px) {
  .br-m { display: inline; }
  .statement { font-size: clamp(1.2rem, 0.9rem + 1.6vw, 1.45rem); }
}
.statement .w { color: var(--ink-dim); transition: color 500ms var(--ease); }
.statement .w.lit { color: var(--ink); }
.statement .w.key.lit { color: var(--ink); }

/* ---- Before -> After ----
   Stacked by default: the meter, the manual steps, then the generated
   spec, all at their final state. On wide, tall screens with script the
   stage pins and the scroll walks it through --steps states (see n.js). */

.shift {
  /* This stage runs on the teal, not the page's amber: every accent token
     inside it is re-pointed here. */
  --accent: var(--teal);
  --accent-text: var(--teal);
  --light-amber: 44 201 180;
  --shift-step: 34svh;            /* scroll length each state holds */
  --steps: 9;                     /* 0 untouched, 1-5 steps struck, 6 spec up, 7-8 wide */
  --left: 0.006;                  /* the SC4SAP bar against the manual one; script sets it */
  position: relative;
  margin-top: clamp(4rem, 9vw, 6.5rem);
}
.shift-pin { position: relative; isolation: isolate; }
.shift-pin .aura { z-index: -1; }
/* The hero photograph's two lights, steel teal and amber, kept faint. */
.shift .orb.o1 { left: auto; right: 14%; top: 14%; --size: 42%; --alpha: 0.3; background: radial-gradient(circle, rgb(70 120 136) 0%, transparent 68%); }
.shift .orb.o2 { right: 2%; top: 44%; --size: 30%; --alpha: 0.2; background: radial-gradient(circle, rgb(216 135 34) 0%, transparent 68%); }

.shift-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(2.5rem, 5vw, 3.5rem); }   /* no-wrap text in the window must not widen the track */

/* -- Meter -- */
.shift-meter { display: grid; justify-items: start; align-content: center; gap: 0.9rem; }
.shift-kicker {
  display: inline-flex; align-items: center; gap: 0.6rem;
  font-size: 0.78rem; font-weight: 600; letter-spacing: 0.08em; color: var(--ink-3);
}
/* The side being shown is lit: BEFORE while the steps are struck, AFTER
   from the moment the time lands (.is-fast). Stacked, AFTER. */
.shift-kicker span { transition: color 600ms var(--ease); }
.shift-kicker span:last-child, .shift:not(.is-fast) .shift-kicker span:first-child { color: var(--ink); }   /* white, not the stage's teal */
.shift:not(.is-fast) .shift-kicker span:last-child { color: var(--ink-3); }
.shift-kicker .ph { font-size: 0.85rem; }
.shift-k { color: var(--ink-2); font-size: var(--fs-sub); font-weight: 550; letter-spacing: -0.02em; }
.shift-num {
  font-size: clamp(3rem, 1.7rem + 4.8vw, 5.8rem);
  font-weight: 800;
  line-height: 0.95;
  letter-spacing: var(--track-display);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
/* The display tracking pulls the unit into the last digit at this size,
   so the unit (일, 분) gets a little air back. */
.shift-num .u { margin-left: 0.07em; }
.shift-num.is-swap, .bar-val.is-swap { animation: num-swap 700ms var(--ease); }
@keyframes num-swap { from { opacity: 0.2; transform: translateY(0.12em); filter: blur(6px); } to { opacity: 1; transform: none; filter: none; } }

.shift-bars { width: 100%; max-width: 30rem; display: grid; gap: 0.7rem; margin-top: 0.6rem; }
.bar { display: grid; grid-template-columns: 6.5rem minmax(0, 1fr) 4.5rem; align-items: center; gap: 0.9rem; }
.bar-name { font-size: 0.8rem; font-weight: 600; color: var(--ink-3); }
.bar.is-after .bar-name { color: var(--ink); }
.bar-track { height: 0.5rem; border-radius: var(--r-pill); background: rgb(255 255 255 / 0.06); overflow: hidden; }
.bar-track i {
  display: block; height: 100%; border-radius: inherit;
  transform-origin: left center;
  transition: transform 1100ms var(--ease);
}
.bar.is-before .bar-track i {
  /* The stripes live in a square tile one band-pair wide. At 45 degrees a
     square's gradient line is exactly two band-pairs long, so tiles meet
     without a seam. The bar's own box as the tile (the default) left a
     seam that showed at the left edge once the stripes moved. */
  --tile: 0.75rem;
  background: repeating-linear-gradient(-45deg,
      rgb(255 255 255 / 0.28) 0 calc(var(--tile) * 0.35355),
      rgb(255 255 255 / 0.16) calc(var(--tile) * 0.35355) calc(var(--tile) * 0.70711));
  background-size: var(--tile) var(--tile);
  /* The bands crawl sideways, slowly: work still grinding on. One loop is
     exactly one tile, so it never jumps. */
  animation: bar-crawl 1.4s linear infinite;
}
@keyframes bar-crawl { to { background-position: var(--tile) 0; } }
.bar.is-after .bar-track i {
  position: relative;
  background: rgb(255 255 255 / 0.22);
  /* Slid out of the track rather than scaled or clipped: a transform runs on
     the compositor, so the bar stays smooth even when the page's shaders
     keep the main thread busy. Never shorter than a sliver. */
  transform: translateX(calc((max(var(--left), 0.02) - 1) * 100%));
  transition: transform 1100ms var(--ease);
}
/* The moving bar wears the spec badge's liquid-metal rim (.metal-rim, mounted
   by the module script); it slides with the bar, so its end stays ringed. */
.bar.is-after .bar-track { height: 0.6rem; }
.bar.is-after .bar-track i .metal-rim { --metal-w: 1.5px; }
.bar-val { font-size: 0.8rem; font-weight: 650; text-align: right; font-variant-numeric: tabular-nums; color: var(--ink-3); }
.bar.is-after .bar-val { color: var(--accent-text); visibility: hidden; }   /* the big number says it; the column stays so both bars end together */
.shift-ratio { margin-top: 0.4rem; font-size: 0.9rem; color: var(--ink-2); transition: opacity 900ms var(--ease), transform 900ms var(--ease); }
.shift-ratio b {
  font-size: 1.12em; font-weight: 750; color: var(--ink);
  /* An underline that draws itself, left to right, once the time lands. */
  padding-bottom: 0.08em;
  background: linear-gradient(currentColor, currentColor) left bottom / 0% 1px no-repeat;
  transition: background-size 700ms var(--ease) 350ms;
}
.shift.is-fast .shift-ratio b { background-size: 100% 1px; }
@media (prefers-reduced-motion: reduce) { .shift-ratio b { transition: none; } }
.shift-eco { margin-top: 0.3rem; font-size: 0.76rem; color: var(--ink-3); }

/* -- Stage: the manual list and the spec share one cell when pinned -- */
.shift-stage { position: relative; display: grid; grid-template-columns: minmax(0, 1fr); gap: 2rem; }

.shift-before {
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  border-radius: var(--r-card);
  border: 1px dashed var(--line-2);
  background: rgb(255 255 255 / 0.025);
  transition: opacity 1000ms var(--ease), transform 1000ms var(--ease), filter 1000ms var(--ease);
}
.shift-label {
  display: flex; align-items: baseline; gap: 0.75rem; margin-bottom: 0.9rem;
  font-size: 0.86rem; font-weight: 650; color: var(--ink-2);
}
.shift-label span:first-child { font-size: 0.74rem; font-weight: 600; letter-spacing: 0.08em; color: var(--ink-3); }

.task-list { list-style: none; margin: 0; padding: 0; }
.task {
  display: grid;
  grid-template-columns: 2.2rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.9rem;
  padding: 0.85rem 0;
  border-top: 1px solid var(--line);
}
.task-n { font-size: 0.8rem; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--ink); }
.task-t { display: grid; gap: 0.2rem; min-width: 0; }
.task-t b { font-size: 0.95rem; font-weight: 650; letter-spacing: -0.02em; color: var(--ink); }
.task-t small { font-size: 0.72rem; font-weight: 500; letter-spacing: 0; color: var(--ink-3); }   /* Pretendard: the mono face spaces Hangul apart */
.task-time {
  padding: 0.3em 0.75em; border-radius: var(--r-pill);
  background: rgb(255 255 255 / 0.06);
  font-size: 0.78rem; font-weight: 600; color: var(--ink-2); white-space: nowrap;
}
/* A struck step: crossed out; its number stays white. */
.task-t b, .task-time {
  text-decoration: line-through 1px transparent;
  transition: color 700ms var(--ease), text-decoration-color 700ms var(--ease), opacity 700ms var(--ease);
}
.task.is-done .task-t b { color: var(--ink-3); text-decoration-color: rgb(255 255 255 / 0.4); }
.task.is-done .task-time { opacity: 0.35; text-decoration-color: currentColor; }

.task-sum {
  display: flex; justify-content: space-between; align-items: baseline;
  padding-top: 0.9rem; border-top: 1px solid var(--line-2);
  font-size: 0.86rem; color: var(--ink-3);
}
.task-sum b { font-size: 1.05rem; color: var(--ink); font-weight: 750; }
.task-sum { transition: opacity 700ms var(--ease), transform 700ms var(--ease); }

/* -- The generated spec: the app's Program -> Spec screen, after the demo
   (motion/spec_b.html), in this page's dark glass. -- */
.shift-after { position: relative; }
/* The spec demo and its finish badge run in white, not the stage's teal:
   every accent token inside them is re-pointed to the ink. */
.spec-win, .shift-done {
  --teal: var(--ink);
  --accent: var(--ink);
  --accent-text: var(--ink);
  --light-amber: 244 244 245;
}
.spec-win, .spec-win.win { --doc-h: 22rem; border-radius: var(--r-card); overflow: hidden; display: flex; flex-direction: column; }
/* The analyze windows' edge (flex.team's): a hairline, a lit top, a deep fall-off */
/* flex.team draws a 0.5px line at 20% white. One device pixel at that strength
   on a 2x screen; on a 1x screen the same line averages out to a full pixel
   at half the strength, so that is what it gets. */
:root { --edge-hair: rgb(255 255 255 / 0.1); }
@media (min-resolution: 2dppx) {
  :root { --edge-hair: rgb(255 255 255 / 0.2); }
  .spec-win.glass, .cw-stage .cw { border-width: 0.5px; }
}
.spec-win.glass {
  border: 1px solid var(--edge-hair);
  background: linear-gradient(165deg, rgb(255 255 255 / 0.075), rgb(255 255 255 / 0.02) 55%, rgb(255 255 255 / 0.035));
  box-shadow: inset 0 1px 1px rgb(255 255 255 / 0.12), 0 10px 120px #000;
}
.spec-win.win > :not(.win-bar) { padding: 0; }   /* outranks the shared .win > * padding */
/* The bar carries only the skill's name, as a teal label like the notice's. */
.win-label {
  display: inline-flex; align-items: center;
  padding: 0.3em 0.8em;
  border: 1px solid var(--teal); border-radius: var(--r-pill);
  font-style: normal; font-size: 0.7rem; font-weight: 600; letter-spacing: 0.01em; line-height: 1.2;
  color: var(--teal);
}

.dx-view { position: relative; flex: 1; min-height: 0; overflow: hidden; font-size: 0.8rem; line-height: 1.5; }
.dx-page { padding: 1.2rem 1.4rem 1.4rem; transition: transform 800ms var(--ease); }
.dx-chip {
  display: inline-block; padding: 0.2em 0.75em;
  border: 1px solid var(--line-2); border-radius: var(--r-pill);
  font-family: var(--mono); font-size: 0.66rem; color: var(--ink-3);
}
.dx-h { margin-top: 0.6rem; display: flex; align-items: center; gap: 0.55rem; font-size: 1.1rem; font-weight: 700; letter-spacing: -0.02em; }
.dx-h .ph { color: var(--ink-3); font-size: 1.15rem; }
.dx-desc { margin-top: 0.3rem; font-size: 0.74rem; color: var(--ink-3); }

.dx-result {
  margin-top: 1.1rem; padding: 0.95rem 1.05rem 1.05rem;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: rgb(255 255 255 / 0.02);
}
.dx-label { font-size: 0.72rem; font-weight: 700; color: var(--ink-2); }
.dx-work { display: flex; align-items: center; gap: 0.6rem; margin: 1.6rem 0 0.7rem; font-size: 0.78rem; color: var(--ink-3); }
.dx-orb { display: none; width: 1.25rem; height: 1.25rem; flex: none; }
.spec-win.has-orb .dx-orb { display: block; }
.spec-win.has-orb .dx-spin { display: none; }
.dx-spin { width: 1rem; height: 1rem; border-radius: 50%; border: 2.5px dotted var(--ink); animation: dx-spin 1.6s linear infinite; }
@keyframes dx-spin { to { transform: rotate(360deg); } }
.dx-out { display: none; }
.spec-win.is-done .dx-work { display: none; }
.spec-win.is-done .dx-out { display: block; animation: dx-rise 600ms var(--ease) both; }
@keyframes dx-rise { from { opacity: 0; transform: translateY(0.75rem); } to { opacity: 1; transform: none; } }

.dx-panel { margin-top: 0.75rem; border: 1px solid var(--line-2); border-radius: 0.65rem; overflow: hidden; background: rgb(255 255 255 / 0.03); }
.dx-head {
  height: 2.6rem; padding: 0 0.9rem; display: flex; align-items: center; gap: 0.5rem;
  background: rgb(255 255 255 / 0.04); border-bottom: 1px solid var(--line-2);
  font-size: 0.72rem; font-weight: 700; color: var(--ink-2); white-space: nowrap;
}
.dx-head > .ph { font-size: 0.9rem; color: var(--ink-3); }
.dx-tools { margin-left: auto; display: flex; align-items: center; gap: 0.65rem; font-weight: 500; color: var(--ink-3); }
.dx-toggle { width: 1.9rem; height: 1.05rem; padding: 0.16rem; border-radius: var(--r-pill); background: var(--ink); display: flex; justify-content: flex-end; }
.dx-toggle::after { content: ''; width: 0.73rem; aspect-ratio: 1; border-radius: 50%; background: #000; }
.dx-zoom { position: relative; width: 6rem; height: 3px; border-radius: 2px; background: linear-gradient(90deg, var(--ink-3) 45%, var(--line-2) 45%); }
.dx-zoom::after {
  content: ''; position: absolute; left: 45%; top: 50%; width: 0.7rem; aspect-ratio: 1;
  border-radius: 50%; background: #18181b; border: 1.5px solid var(--ink-3); transform: translate(-50%, -50%);
}
.dx-dl { height: 1.7rem; padding: 0 0.7rem; display: flex; align-items: center; gap: 0.4rem; border: 1px solid var(--line-2); border-radius: 0.45rem; font-weight: 600; color: var(--ink-2); }

.dx-sum { padding: 0.9rem 1.1rem 0.4rem; }
.dx-sum p { margin: 0 0 0.55rem; font-size: 0.78rem; line-height: 1.7; color: var(--ink-2); }
.dx-sum code {
  padding: 0.05em 0.35em; border: 1px solid var(--line); border-radius: 0.25rem; background: rgb(255 255 255 / 0.05);
  font-family: var(--mono); font-size: 0.86em;
}

.dx-doc { background: rgb(255 255 255 / 0.025); }
.dx-doc-bar {
  height: 3rem; padding: 0 1.5rem; display: flex; align-items: center; gap: 1rem;
  border-bottom: 1px solid var(--line); font-size: 0.8rem; font-weight: 600; white-space: nowrap;
}
.dx-doc-tools { margin-left: auto; display: flex; align-items: center; gap: 1rem; font-size: 0.74rem; font-weight: 500; color: var(--ink-3); }
.dx-edit { height: 1.85rem; padding: 0 0.8rem; display: flex; align-items: center; border-radius: 0.5rem; background: var(--ink); color: #000; font-weight: 700; }
.dx-edit > span { text-box: trim-both cap alphabetic; }   /* centres the ink; needs a real element, trim skips anonymous flex text */
.dx-doc-body {
  position: relative; height: var(--doc-h); overflow: hidden;
  display: grid; grid-template-columns: 11rem minmax(0, 1fr); column-gap: 3rem; padding: 0 3rem 0 3.5rem;
}
.dx-toc { padding-top: 2.4rem; font-size: 0.76rem; color: var(--ink-3); }
.dx-toc > b { display: block; margin-bottom: 0.6rem; font-size: 0.68rem; font-weight: 500; }
.dx-toc ol { margin: 0; padding: 0; list-style: none; border-left: 1px solid var(--line-2); }
.dx-toc li {
  margin-left: -1px; padding: 0.38rem 0.65rem; border-left: 2px solid transparent;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: color 250ms, border-color 250ms;
}
.dx-toc li.is-active { color: var(--ink); font-weight: 600; border-left-color: var(--accent); }
.dx-scroll { padding: 2.4rem 0 3.5rem; transition: transform 600ms var(--ease); }
.dx-scroll h3 { margin: 0 0 1.2rem; font-size: 1.6rem; line-height: 1.3; font-weight: 700; letter-spacing: -0.02em; }
.dx-k { display: block; font-size: 0.68rem; color: var(--ink-3); }
.dx-lead { margin: 0.25rem 0 1.5rem; font-size: 0.92rem; line-height: 1.75; }
.dx-meta { display: grid; gap: 0.8rem; padding: 1.1rem 1.35rem; border: 1px solid var(--line); border-radius: 0.6rem; background: rgb(255 255 255 / 0.03); }
.dx-meta span:last-child { display: block; margin-top: 0.1rem; font-size: 0.8rem; font-weight: 500; }
.dx-scroll h4 { margin: 2.1rem 0 0.75rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--line); font-size: 1.1rem; font-weight: 700; letter-spacing: -0.015em; }
.dx-p { font-size: 0.8rem; line-height: 1.75; color: var(--ink-2); }
.dx-steps { margin: 0 0 0.9rem; padding-left: 1.25rem; font-size: 0.8rem; line-height: 1.9; color: var(--ink-2); }
.dx-table { width: 100%; border: 1px solid var(--line); border-radius: 0.5rem; border-spacing: 0; font-size: 0.74rem; overflow: hidden; }
.dx-table th { padding: 0.45rem 0.7rem; text-align: left; background: rgb(255 255 255 / 0.04); color: var(--ink-3); font-weight: 600; }
.dx-table td { padding: 0.45rem 0.7rem; border-top: 1px solid var(--line); color: var(--ink-2); }
.dx-table td:first-child { font-family: var(--mono); font-size: 0.7rem; color: var(--ink); white-space: nowrap; }
/* Main logic as a flowchart: four steps on a dotted canvas, each with an
   amber icon tile. When the cursor lands on section 4 the chart runs once,
   step by step (.is-live, set in n.js). */
.dx-flow {
  --step: 380ms;
  display: flex; align-items: center;
  padding: 1.6rem 1.25rem 1.35rem;
  border: 1px solid var(--line); border-radius: 0.7rem;
  background:
    radial-gradient(circle, rgb(255 255 255 / 0.07) 1px, transparent 1.2px) 0 0 / 1rem 1rem,
    rgb(255 255 255 / 0.02);
}
.dx-node {
  position: relative; flex: 1 1 0; min-width: 0;
  display: grid; grid-template-columns: minmax(0, 1fr); row-gap: 0.15rem; justify-items: start; align-content: start; align-self: stretch;
  padding: 0.95rem 0.75rem 0.75rem;
  border: 1px solid var(--line-2); border-radius: 0.65rem;
  background: linear-gradient(180deg, rgb(255 255 255 / 0.08), rgb(255 255 255 / 0.03));
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
  box-shadow: inset 0 1px 1px rgb(255 255 255 / 0.1), 0 0.6rem 1.4rem -0.8rem rgb(0 0 0 / 0.8);
  transition: border-color 500ms var(--ease), box-shadow 500ms var(--ease);
  transition-delay: calc(var(--i, 0) * var(--step));
}
.dx-node > .ph {
  margin-bottom: 0.4rem;
  display: grid; place-items: center; width: 1.75rem; aspect-ratio: 1;
  border-radius: 0.45rem; background: rgb(var(--light-amber) / 0.14);
  font-size: 0.92rem; color: var(--accent-text);
}
.dx-node b, .dx-node small { max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dx-node b { font-size: 0.76rem; font-weight: 650; line-height: 1.3; letter-spacing: -0.02em; }
.dx-node small { font-size: 0.68rem; font-weight: 500; color: var(--ink-3); }
.dx-node-n {
  position: absolute; top: -0.55rem; left: 0.7rem;
  padding: 0 0.4rem; border-radius: var(--r-pill);
  background: rgb(38 38 42 / 0.92); box-shadow: 0 0 0 1px var(--line-2);   /* near-opaque: it sits across the node's edge */
  font-size: 0.58rem; font-weight: 700; line-height: 1.1rem; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  transition: color 500ms var(--ease), box-shadow 500ms var(--ease);
  transition-delay: inherit;
}
.dx-node:nth-child(1) { --i: 0; }
.dx-node:nth-child(3) { --i: 1; }
.dx-node:nth-child(5) { --i: 2; }
.dx-node:nth-child(7) { --i: 3; }

/* An edge: a plain line joining two steps, the same colour as the steps'
   borders. A lit line in the lit border colour runs along it. */
.dx-flow { --node-edge: var(--line-2); --node-edge-on: rgb(var(--light-amber) / 0.45); }
.dx-edge {
  position: relative; flex: 0 1 2.4rem; min-width: 1.1rem; align-self: center;
  height: 1px;
  background: var(--node-edge);
}
.dx-edge::before {
  content: ''; position: absolute; inset: 0;
  background: var(--node-edge-on);
  transform: scaleX(0); transform-origin: left center;
  transition: transform 420ms var(--ease);
}
.dx-edge:nth-child(2) { --i: 0; }
.dx-edge:nth-child(4) { --i: 1; }
.dx-edge:nth-child(6) { --i: 2; }
.dx-edge::before { transition-delay: calc(var(--i) * var(--step) + var(--step) * 0.55); }

/* Lit: the teal border plus a wide, soft glow around each step. */
.dx-flow.is-live .dx-node {
  border-color: var(--node-edge-on);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.06),
    0 0 0 3px rgb(var(--light-amber) / 0.05),
    0 0 1.6rem 0.2rem rgb(var(--light-amber) / 0.07),
    0 0.6rem 1.4rem -0.8rem rgb(0 0 0 / 0.8);
}
.dx-flow.is-live .dx-node-n { color: var(--accent-text); box-shadow: 0 0 0 1px var(--node-edge-on); }
.dx-flow.is-live .dx-edge::before { transform: scaleX(1); }

/* The demo's cursor: it walks the contents and clicks. */
.dx-cursor {
  position: absolute; top: 0; left: 0; z-index: 5; width: 1.25rem; aspect-ratio: 1;
  opacity: 0; transition: transform 380ms var(--ease), opacity 300ms;
}
.dx-cursor.is-on { opacity: 1; }
.dx-cursor svg { display: block; width: 100%; height: 100%; filter: drop-shadow(0 2px 3px rgb(0 0 0 / 0.5)); }
.dx-cursor path { fill: #fff; stroke: #000; }
.dx-cursor::after {
  content: ''; position: absolute; left: -45%; top: -50%; width: 120%; aspect-ratio: 1;
  border-radius: 50%; border: 1.5px solid var(--ink); opacity: 0;
}
.dx-cursor.is-click::after { animation: dx-click 450ms ease-out; }
@keyframes dx-click { from { opacity: 0.9; transform: scale(0.4); } to { opacity: 0; transform: scale(1.5); } }

/* The finish badge hangs off the window's lower corner. */
.shift-done {
  position: absolute; right: -3%; bottom: -7%;
  display: inline-flex; align-items: center; gap: 0.55rem;
  padding: 0.75rem 1.1rem;
  border-radius: var(--r-pill);
  font-size: 0.9rem; font-weight: 700; color: var(--ink);
  overflow: hidden;
  background: rgb(10 12 14 / 0.62);
  -webkit-backdrop-filter: blur(32px) saturate(1.4);
          backdrop-filter: blur(32px) saturate(1.4);
  box-shadow:
    inset 0 -0.25rem 1.1rem rgb(255 255 255 / 0.07),
    0 1.2rem 2.5rem -0.6rem rgb(0 0 0 / 0.6);
  transition: opacity 900ms var(--ease), transform 900ms var(--ease);
}
.shift-done .ph { color: var(--accent-text); font-size: 1.15rem; }
.shift-done-t { font-weight: 600; font-size: 0.78rem; color: var(--ink-2); }

@media (max-width: 760px) {
  /* Phones get the meter over one cell that holds the task list, struck
     in step with it (meterLoop in n.js), then the spec window. */
  /* inside the window, the HTML preview straight away, without the summary above it */
  .dx-out > .dx-panel:not([data-dx-prev]) { display: none; }
  .dx-doc-body { grid-template-columns: minmax(0, 1fr); padding: 0 1rem; }
  .dx-toc, .dx-x, .dx-zoom, .dx-doc-tools, .dx-tools > :not(.dx-dl) { display: none; }
  .dx-flow { flex-direction: column; align-items: stretch; padding-top: 1.3rem; }
  .dx-node { flex: none; grid-template-columns: auto minmax(0, 1fr); column-gap: 0.6rem; align-items: center; }
  .dx-node > .ph { grid-row: span 2; margin-bottom: 0; }
  .dx-edge { flex: none; align-self: start; width: 1px; height: 1.6rem; min-width: 0; margin: 0.2rem 0 0.75rem 1.6rem; }
  .dx-edge::before { transform: scaleY(0); transform-origin: center top; }
  .dx-flow.is-live .dx-edge::before { transform: scaleY(1); }
}
/* Stacked, the screen shows its summary and the top of the preview, then
   fades out rather than running the whole document down the page. */
@media (max-width: 999px), (max-height: 679px) {
  .dx-view {
    max-height: 34rem;
    -webkit-mask-image: linear-gradient(180deg, #000 82%, transparent);
            mask-image: linear-gradient(180deg, #000 82%, transparent);
  }
}
@media (max-width: 760px) {
  /* the phone loop (meterLoop in n.js) steps faster than scrolling does */
  .bar.is-after .bar-track i { transition: transform 700ms cubic-bezier(0.45, 0, 0.2, 1); }
  .shift-num.is-swap, .bar-val.is-swap { animation-duration: 650ms; }
  .task-t b, .task-time { transition-duration: 450ms; }
  /* As on the pinned layout, the total and the ratio wait for the last step. */
  .shift.is-looping:not(.is-fast) .task-sum { opacity: 0; transform: translateY(0.4rem); }
  .shift.is-looping:not(.is-fast) .shift-ratio { opacity: 0; transform: translateY(0.5rem); }

  /* The task list and the spec share one cell: the list while the time
     counts down and the last step is struck, then the spec (.is-spec). As when pinned,
     the window fades itself so its backdrop blur holds through the fade. */
  .js .shift.is-looping .shift-stage { gap: 0; }
  .js .shift.is-looping .shift-before,
  .js .shift.is-looping .shift-after { grid-area: 1 / 1; align-self: start; }
  .js .shift.is-looping .shift-before { transition: opacity 600ms var(--ease) 450ms, transform 600ms var(--ease) 450ms; }   /* back in once the window is gone */
  .js .shift.is-looping.is-spec .shift-before { transition-delay: 0ms; }
  .js .shift.is-looping .shift-after { transform: translateY(1.5rem); pointer-events: none; transition: transform 900ms var(--ease); }
  .js .shift.is-looping .spec-win,
  .js .shift.is-looping .shift-done { opacity: 0; transition: opacity 500ms var(--ease); }
  .js .shift.is-looping.is-spec .shift-before { opacity: 0; transform: scale(0.96); pointer-events: none; }
  .js .shift.is-looping.is-spec .shift-after { transform: none; pointer-events: auto; }
  .js .shift.is-looping.is-spec .spec-win,
  .js .shift.is-looping.is-spec .shift-done { opacity: 1; transition: opacity 800ms var(--ease) 200ms; }

  /* Tighter, so the meter and its cell fit one phone screen together. */
  .shift-grid { gap: 1.25rem; }
  .shift-meter { gap: 0.5rem; }
  .shift-num { font-size: clamp(2.4rem, 1.6rem + 4vw, 3rem); }
  .shift-bars { gap: 0.5rem; margin-top: 0.3rem; }
  .shift-ratio { margin-top: 0.15rem; font-size: 0.84rem; }
  .shift-eco { margin-top: 0.15rem; }
  .shift-before { padding: 0.9rem 1rem; }
  .shift-label { margin-bottom: 0.4rem; }
  .task { gap: 0.7rem; padding: 0.55rem 0; }
  .task-t { gap: 0.1rem; }
  .task-t b { font-size: 0.88rem; }
  .task-sum { padding-top: 0.6rem; }
  .dx-view { max-height: 24rem; }
}
@media (max-width: 640px) {
  .shift-done { right: 4%; }
  .bar { grid-template-columns: 5.2rem minmax(0, 1fr) 3.8rem; gap: 0.6rem; }
}

/* ---- Pinned: wide and tall enough, script running ----
   States (n.js): .is-up raises the window, still working, in the right
   column; .is-wide widens it over the meter, the result arrives and the
   cursor walks the document. Going back, the window empties first, then
   narrows, and the meter returns. */
@media (min-width: 1000px) and (min-height: 680px) {
  .js .shift { height: calc(100svh + (var(--steps) - 1) * var(--shift-step)); }
  .js .shift-pin {
    position: sticky; top: 0; height: 100svh;
    padding-top: calc(var(--notice-h) + 4.5rem);
    display: grid; align-items: center;
  }
  .js .shift-grid {
    --gap: clamp(2.5rem, 5vw, 3.5rem);
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    column-gap: var(--gap);
    align-items: center;
    transition: grid-template-columns 1000ms var(--ease-io) 350ms, column-gap 1000ms var(--ease-io) 350ms;
  }
  .js .shift.is-wide .shift-grid {
    grid-template-columns: minmax(0, 0fr) minmax(0, 1fr);
    column-gap: 0;
    transition-delay: 0ms;
  }
  /* The meter keeps its own width while its column closes, clipped
     sideways only, so nothing rewraps on the way out. */
  .js .shift-meter { overflow-x: clip; transition: opacity 700ms var(--ease) 1200ms, transform 700ms var(--ease) 1200ms; }
  .js .shift-meter > * { min-width: 22rem; }
  .js .shift.is-wide .shift-meter { opacity: 0; transform: translateX(-1.5rem); transition-duration: 450ms; transition-delay: 0ms; }

  .js .shift-stage { gap: 0; }
  .js .shift-before, .js .shift-after { grid-area: 1 / 1; }
  .js .shift-before, .js .shift-after { align-self: center; }   /* the card keeps its own height, not the window's */

  /* Until the spec is up it waits below, unseen. The wrapper only moves:
     opacity or filter on an ancestor of the glass switches its backdrop
     blur off until the fade ends, then on again in one frame, and whatever
     sits behind snaps. So the window fades itself, and the manual card is
     fully gone before the window settles, leaving nothing behind to snap. */
  .js .shift-after {
    transform: translateY(8%) scale(0.97); pointer-events: none;
    transition: transform 1100ms var(--ease);
  }
  .js .spec-win {
    opacity: 0;
    /* One height in both states: the width changes, the height never does. */
    --win-h: min(36rem, calc(100svh - var(--notice-h) - 8.5rem));
    --doc-h: calc(var(--win-h) - 10.2rem);
    height: var(--win-h);
    transition: opacity 900ms var(--ease) 150ms;
  }
  .js .shift.is-up .shift-after { transform: none; pointer-events: auto; }
  .js .shift.is-up .spec-win { opacity: 1; }
  .js .shift.is-up .shift-before {
    opacity: 0; transform: scale(0.94); filter: blur(6px);
    transition-duration: 600ms;
  }

  .js .shift-done { opacity: 0; transform: translateY(40%) scale(0.9); transition-duration: 300ms; }
  .js .shift-done.is-on { opacity: 1; transform: none; transition-duration: 900ms; }
  .js .shift:not(.is-fast) .shift-ratio { opacity: 0; transform: translateY(0.5rem); }
  /* The total shows once all five manual steps are struck. Space stays reserved. */
  .js .shift:not(.is-fast) .task-sum { opacity: 0; transform: translateY(0.4rem); }
}

@media (prefers-reduced-motion: reduce) {
  .shift-grid, .shift-meter, .shift-before, .shift-after, .spec-win, .shift-done, .shift-ratio, .task-sum, .dx-page, .dx-scroll, .dx-cursor, .dx-node, .dx-node-n, .dx-edge::before,
  .bar-track i, .task-n, .task-t b, .task-time, .dx-toc li { transition: none !important; }
  .bar.is-before .bar-track i { animation: none; }
  .shift-num.is-swap, .bar-val.is-swap, .dx-spin, .spec-win.is-done .dx-out { animation: none; }
}

/* ============================================================
   BELOW THE PLATFORM — centred, no colour washes, placeholders
   The split sections (analyze, build, graph) are a heading over a
   placeholder box until their content is decided. Every section from
   here down is centred and carries no gradient glow.
   ============================================================ */

.ph-sec { position: relative; padding-block: var(--band); }
.ph-box {
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  aspect-ratio: 16 / 7;
  display: grid; place-items: center;
  border: 1px dashed var(--line-2);
  border-radius: var(--r-lg);
  background: rgb(255 255 255 / 0.015);
  font-size: 0.78rem; font-weight: 600; letter-spacing: 0.04em; color: var(--ink-3);
}
@media (max-width: 760px) { .ph-box { aspect-ratio: 4 / 3; } }

/* Analyze: one heading a step below the section title, then its picture */
.ana-list {
  --ana-gap: calc(clamp(4.5rem, 9vw, 7.5rem) + 1.25rem);   /* the same air above every subheading, the first included */
  list-style: none; margin: var(--ana-gap) 0 0; padding: 0; display: grid; gap: var(--ana-gap);
}
/* The bg2 box above is a solid, bright edge with a glow under it, where the
   other pictures fade or sit on black, so the same gap reads tighter there.
   It gets a little more to look the same. */
.ana-item.after-box { margin-top: 2rem; }
.ana-item { display: grid; justify-items: center; }
.ana-h {
  font-size: clamp(1.3rem, 0.95rem + 1.3vw, 2rem);
  font-weight: 600;
  line-height: 1.22;
  letter-spacing: var(--track-head);
  text-align: center;
  text-wrap: balance;
}
.ana-item .ph-box { justify-self: stretch; }
.ana-sub { margin-top: 0.9rem; text-align: center; max-width: none; }
/* Analyze 3: the Stardrift sphere (js/stardrift.js), straight on the page
   with no box: the edges fade out so the streaks seem to come from nowhere
   and gather into the sphere. */
.ana-sphere {
  position: relative;
  justify-self: center; width: min(100%, 64rem); aspect-ratio: 1024 / 700;
  margin-top: clamp(1.5rem, 3vw, 2.5rem);
  -webkit-mask-image: radial-gradient(closest-side, #000 55%, transparent);
          mask-image: radial-gradient(closest-side, #000 55%, transparent);
}
.ana-sphere canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* Analyze 4: the two run modes as glass cards, the liquid-metal rim
   taking turns between them. */
.cost-stage {
  position: relative; isolation: isolate;
  justify-self: stretch; width: min(100%, 56rem); margin-inline: auto;
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  padding: clamp(0.5rem, 2vw, 1.5rem) 0 0;
}
.cost-grid { position: relative; z-index: 1; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(0.9rem, 2vw, 1.25rem); }
.cost-card { position: relative; isolation: isolate; display: flex; flex-direction: column; gap: 1.4rem; padding: clamp(1.4rem, 3vw, 1.9rem); border-radius: var(--r-lg); text-align: left; }
/* With nothing behind them to blur, the cards carry the glass themselves:
   a sheen falling from the top-left corner, a frosted fill, lit inner
   edges, and a rim that catches the light on the top and left only. */
.cost-card.glass {
  background:
    radial-gradient(120% 70% at 0% 0%, rgb(255 255 255 / 0.13), transparent 55%),
    radial-gradient(90% 60% at 100% 100%, rgb(255 255 255 / 0.04), transparent 60%),
    linear-gradient(160deg, rgb(255 255 255 / 0.085), rgb(255 255 255 / 0.025) 55%, rgb(255 255 255 / 0.05));
  border-color: rgb(255 255 255 / 0.1);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.22),
    inset 1px 0 0 rgb(255 255 255 / 0.08),
    inset 0 -1px 0 rgb(255 255 255 / 0.04),
    inset 0 0 2.5rem rgb(255 255 255 / 0.025),
    0 2rem 4rem -1.5rem rgb(0 0 0 / 0.8);
}
.cost-card.glass::before {
  content: ''; position: absolute; inset: -1px; z-index: -1; border-radius: inherit; padding: 1px; pointer-events: none;
  background: linear-gradient(145deg, rgb(255 255 255 / 0.45), rgb(255 255 255 / 0.08) 30%, transparent 55%, rgb(255 255 255 / 0.12));
  -webkit-mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
/* Fine grain, the frosting itself. */
.cost-card.glass::after {
  content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit; pointer-events: none; opacity: 0.06; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.cost-card .cost-ic { background: rgb(255 255 255 / 0.08); box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.18); }
.cost-card .cost-ex { background: rgb(255 255 255 / 0.035); border-color: rgb(255 255 255 / 0.08); box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.06); }
.cost-card { --metal-w: 1.5px; }
/* Over the card's own 1px edge, so the ring follows the outer curve. */
.cost-card .metal-rim { inset: -1px; }
/* Both modes earn the rim: it passes from one card to the other (n.js),
   the lit one shown, the other faded out. */
.cost-card .metal-rim.is-on { opacity: 0; transition-duration: 1200ms; }
.cost-card.is-lit .metal-rim.is-on { opacity: 0.85; }
.cost-head { display: grid; justify-items: start; }
.cost-ic {
  display: grid; place-items: center; width: 2.6rem; height: 2.6rem; margin-bottom: 1.1rem;
  border-radius: 0.8rem; background: rgb(255 255 255 / 0.06); border: 1px solid var(--line-2);
  font-size: 1.2rem; color: var(--ink);
}
.cost-mode { font-size: 0.72rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
.cost-head h4 { margin: 0.3rem 0 0; font-size: clamp(1.3rem, 1.1rem + 0.7vw, 1.6rem); font-weight: 700; letter-spacing: var(--track-head); }
.cost-tag { margin-top: 0.35rem; font-size: 0.92rem; color: var(--ink-2); }
.cost-spec { display: grid; gap: 0.85rem; margin: 0; padding-top: 1.2rem; border-top: 1px solid var(--line); }
.cost-spec div { display: grid; gap: 0.2rem; }
.cost-spec dt { font-size: 0.74rem; font-weight: 600; color: var(--ink-3); }
.cost-spec dd { margin: 0; font-size: 0.92rem; line-height: 1.55; color: var(--ink); }
.cost-ex {
  margin-top: auto; display: grid; gap: 0.35rem;
  padding: 0.9rem 1rem; border-radius: var(--r-sm, 0.85rem);
  background: rgb(0 0 0 / 0.22); border: 1px solid rgb(255 255 255 / 0.06);
}
.cost-ex-k { font-size: 0.74rem; font-weight: 600; color: var(--ink-3); }
.cost-ex-v { display: flex; align-items: center; flex-wrap: wrap; gap: 0.2rem 0; font-size: 1.02rem; font-variant-numeric: tabular-nums; }
.cost-ex-v b { font-weight: 700; color: var(--ink); }
.cost-ex-v small { margin-left: 0.35rem; font-size: 0.8rem; font-weight: 500; color: var(--ink-3); }
.cost-ex-v i { width: 1px; height: 0.8em; margin-inline: 0.7rem; background: var(--line-2); }
.cost-note { position: relative; z-index: 1; margin-top: 1.25rem; text-align: center; font-size: 0.8rem; color: var(--ink-3); text-wrap: balance; }
@media (max-width: 760px) {
  .cost-grid { grid-template-columns: minmax(0, 1fr); }
  /* While the modes take turns (n.js), a phone keeps one card: the grid
     draws the glass once, both cards sit bare in one cell over it, and
     their contents cross-fade together. Without the turns, they stack. */
  .cost-grid.is-cycling { isolation: isolate; border-radius: var(--r-lg); }
  .cost-grid.is-cycling > .cost-card { grid-area: 1 / 1; }
  .cost-grid.is-cycling > .cost-card.glass {
    background: none; border-color: transparent; box-shadow: none;
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  .cost-grid.is-cycling > .cost-card.glass::before,
  .cost-grid.is-cycling > .cost-card.glass::after { content: none; }
  .cost-grid.is-cycling::before {
    content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit;
    border: 1px solid rgb(255 255 255 / 0.1);
    background:
      radial-gradient(120% 70% at 0% 0%, rgb(255 255 255 / 0.13), transparent 55%),
      radial-gradient(90% 60% at 100% 100%, rgb(255 255 255 / 0.04), transparent 60%),
      linear-gradient(160deg, rgb(255 255 255 / 0.085), rgb(255 255 255 / 0.025) 55%, rgb(255 255 255 / 0.05));
    box-shadow:
      inset 0 1px 0 rgb(255 255 255 / 0.22),
      inset 1px 0 0 rgb(255 255 255 / 0.08),
      inset 0 0 2.5rem rgb(255 255 255 / 0.025),
      0 2rem 4rem -1.5rem rgb(0 0 0 / 0.8);
  }
  .cost-grid.is-cycling > .cost-card > :not(.metal-rim) { transition: opacity 900ms cubic-bezier(0.45, 0, 0.25, 1); }
  .cost-grid.is-cycling > .cost-card:not(.is-lit) { pointer-events: none; }
  .cost-grid.is-cycling > .cost-card:not(.is-lit) > :not(.metal-rim) { opacity: 0; }
}
@media (max-width: 760px) { .ana-sphere { aspect-ratio: 1; } }
/* The bg2 picture turned on its side (img/analyze-map-bg.jpg), filling the box whatever its shape */
.ana-bg { position: relative; overflow: hidden; border-radius: var(--r-card); justify-self: center; width: min(100%, 64rem); aspect-ratio: 1024 / 632; border: 0; background: none; }   /* 1024 x 632 at full width */
/* The picture on its own layer, eased back a little, so what goes on it later keeps full strength. */
.ana-bg::before { content: ""; position: absolute; inset: 0; z-index: -1; background: url(../img/analyze-map-bg.jpg) center / cover no-repeat; opacity: 0.7; }
.ana-bg {
  isolation: isolate;
  /* The page is black, so a dark shadow would not show: a faint grey glow
     under the box does the same job. */
  box-shadow: 0 1.5rem 5rem -1.5rem rgb(255 255 255 / 0.08), 0 0 0 1px rgb(255 255 255 / 0.03);
}
/* ---- Analyze 2: the PoC and plug-in at a glance, on bg2 ----
   Wide: a 1024 x 632 frame, the skills in a column off each end of the
   capsule. Phone: a 400 x 640 frame, a row above and below. --u is one
   frame unit; every position is the design's own number in it. */
.ana-bg { container-type: inline-size; }
.fx { --u: calc(100cqi / 1024); position: absolute; inset: 0; margin: 0; }
.fx-lines { position: absolute; inset: 0; width: 100%; height: 100%; }
.fx-lines.is-narrow { display: none; }
.fx-lines path { fill: none; stroke: rgb(255 255 255 / 0.55); stroke-width: 1; stroke-dasharray: 2 3; vector-effect: non-scaling-stroke; }

.fx-cap, .fx-nodes li {
  -webkit-backdrop-filter: blur(24px) saturate(1.2);
          backdrop-filter: blur(24px) saturate(1.2);
}
.fx-cap {
  position: absolute; left: calc(var(--u) * 512); top: calc(var(--u) * 316);
  width: calc(var(--u) * 506); height: calc(var(--u) * 112);
  transform: translate(-50%, -50%);
  display: flex; align-items: center; justify-content: center; gap: calc(var(--u) * 14);
  padding: 0 calc(var(--u) * 20) 0 calc(var(--u) * 30);
  border-radius: 999px;
  background: rgb(38 38 40 / 0.34);
  border: 1px solid rgb(255 255 255 / 0.16);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.14), 0 calc(var(--u) * 30) calc(var(--u) * 70) rgb(0 0 0 / 0.22);
}
.fx-mark { width: calc(var(--u) * 46); height: auto; margin-right: calc(var(--u) * 10); display: block; }
.fx-pill {
  display: flex; align-items: center;
  height: calc(var(--u) * 72); padding: 0 calc(var(--u) * 18);
  border-radius: 999px;
  background: rgb(0 0 0 / 0.26);
  border: 1px solid rgb(255 255 255 / 0.08);
}
.fx-pill i.ph, .fx-pill img, .fx-sep { flex: none; width: calc(var(--u) * 50); }
/* Icon glyphs as boxes exactly their size, so the cell centres them on both axes. */
.fx i.ph { display: grid; place-items: center; line-height: 1; color: rgb(255 255 255 / 0.78); }
.fx i.ph::before { display: block; line-height: 1; }
/* Some glyphs sit off the middle of their own em box (measured ink centre
   against box centre, in em); these pull them back so each reads centred. */
.fx .ph-book-open-text::before   { transform: translateY(-0.065em); }
.fx .ph-stethoscope::before      { transform: translate(-0.065em, -0.03em); }
.fx .ph-tree-structure::before   { transform: translateX(0.05em); }
.fx .ph-chat-teardrop-text::before { transform: translate(-0.015em, 0.015em); }
.fx .ph-graph::before            { transform: translateY(0.015em); }
.fx-pill i.ph { height: calc(var(--u) * 50); font-size: calc(var(--u) * 24); }
.fx-claude { flex: none; width: calc(var(--u) * 50); height: calc(var(--u) * 50); display: grid; place-items: center; }
/* img/logo-claude.png: the mark sits dead centre of its 96px canvas with a 6px
   margin, so 27 units here draws it at the other icons' 24. */
.fx-pill .fx-claude img { width: calc(var(--u) * 27); height: calc(var(--u) * 27); padding: 0; }
.fx-sep { align-self: stretch; margin: calc(var(--u) * 18) 0; background: linear-gradient(rgb(255 255 255 / 0.14), rgb(255 255 255 / 0.14)) center / 1px 100% no-repeat; }
.fx-pill img { height: calc(var(--u) * 24); padding: 0 calc(var(--u) * 13); box-sizing: border-box; object-fit: contain; display: block; }

.fx-nodes { position: absolute; inset: 0; margin: 0; padding: 0; list-style: none; }
.fx-nodes li {
  --d: 56;
  position: absolute;
  left: calc(var(--u) * (var(--x) - var(--d) / 2)); top: calc(var(--u) * (var(--y) - var(--d) / 2));
  width: calc(var(--u) * var(--d)); height: calc(var(--u) * var(--d));
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgb(38 38 40 / 0.36);
  border: 1px solid rgb(255 255 255 / 0.16);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.12);
}
.fx-nodes i.ph { width: 100%; height: 100%; font-size: calc(var(--u) * 18); }

@media (max-width: 760px) {
  /* The 400 x 640 drawing cropped 60 off the top and bottom (the SVG's
     viewBox starts at 60, so the --my numbers drop by 60), and the whole
     figure drawn a little smaller inside it, lines and pieces together. */
  .ana-bg { aspect-ratio: 400 / 520; }
  .fx { --u: calc(100cqi / 400); transform: scale(0.92); }
  .fx-lines.is-wide { display: none; }
  .fx-lines.is-narrow { display: block; }
  .fx-cap { left: calc(var(--u) * 200); top: calc(var(--u) * 260); transform: translate(-50%, -50%) scale(0.7); }
  .fx-nodes li { --d: 52; left: calc(var(--u) * (var(--mx) - var(--d) / 2)); top: calc(var(--u) * (var(--my) - 60 - var(--d) / 2)); }
  .fx-nodes i.ph { font-size: calc(var(--u) * 24 * 0.7); }   /* the capsule icons on a phone: 24 at its 0.7 scale */
}


/* ---- Analyze 1: two PoC screens laid over each other, as flex.team does ----
   The PoC's layout (web/src/app/globals.css), recoloured as glass: every
   surface is a veil of white over what is behind it, and the type is the
   site's own. */
.cw-stage {
  --p-panel:   rgb(255 255 255 / 0.045);
  --p-panel-2: rgb(255 255 255 / 0.03);
  --p-panel-3: rgb(255 255 255 / 0.08);
  --p-ink:    var(--ink);
  --p-ink-80: var(--ink-2);
  --p-ink-55: var(--ink-3);
  --p-ink-38: rgb(255 255 255 / 0.32);
  --p-line:   rgb(255 255 255 / 0.1);
  --p-line-soft:   rgb(255 255 255 / 0.06);
  --p-line-strong: rgb(255 255 255 / 0.16);
  --p-on-ink: #0a0a0b;
  position: relative;
  justify-self: stretch;
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  aspect-ratio: 1024 / 642;
}
.cw {
  container-type: inline-size;
  position: absolute;
  width: 66.4%;
  aspect-ratio: 680 / 520;
  overflow: hidden;
  border-radius: 2.35% / 3.08%;   /* 16px on a 680 x 520 window */
  /* flex.team's edge: a hairline, a lit top, and a deep black fall-off */
  border: 1px solid var(--edge-hair);
  background: linear-gradient(165deg, rgb(255 255 255 / 0.075), rgb(255 255 255 / 0.02) 55%, rgb(255 255 255 / 0.035));
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
          backdrop-filter: blur(var(--glass-blur)) saturate(1.4);
  box-shadow: inset 0 1px 1px rgb(255 255 255 / 0.12), 0 10px 120px #000;
  text-align: left;
}
.cw-back  { left: 0; top: 0; }
.cw-front { left: 33.6%; top: 14.6%; }
/* cqi resolves against the window from here down: 1 --u is 1/680 of it */
.cw-in {
  --u: calc(100cqi / 680);
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  font-size: calc(var(--u) * 12.5);
  font-family: var(--sans);
  line-height: 1.6;
  letter-spacing: var(--track-body);
  color: var(--p-ink-80);
}
.cw i.ph { font-size: 1.1em; line-height: 1; }

/* Markdown, as the PoC sets it */
.cw-md p, .cw-md blockquote { margin: 0 0 calc(var(--u) * 9); }
.cw-md b { font-weight: 600; color: var(--p-ink); }
.cw-md code {
  font-family: 'IBM Plex Mono', 'Pretendard Variable', Pretendard, monospace; font-size: 0.86em; letter-spacing: 0;
  padding: calc(var(--u) * 1) calc(var(--u) * 4);
  background: var(--p-panel-3); border: 1px solid var(--p-line-soft); border-radius: calc(var(--u) * 4); color: var(--p-ink);
}
.cw-md blockquote {
  padding: calc(var(--u) * 2) 0 calc(var(--u) * 2) calc(var(--u) * 11);
  border-left: 2px solid var(--p-line); color: var(--p-ink-55);
}
.cw-md h1, .cw-md h2, .cw-md h3 { margin: calc(var(--u) * 15) 0 calc(var(--u) * 7); line-height: 1.3; font-weight: 700; letter-spacing: -0.03em; color: var(--p-ink); }
.cw-md h1 { margin-top: 0; font-size: calc(var(--u) * 16); }
.cw-md h2 { font-size: calc(var(--u) * 14); }
.cw-md h3 { font-size: calc(var(--u) * 12.5); }

/* Chat */
.cw-transcript { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: calc(var(--u) * 24); padding: calc(var(--u) * 22) calc(var(--u) * 22) 0; overflow: hidden; }
.cw-msg { display: flex; flex-direction: column; align-items: flex-start; }
.cw-msg.is-user { align-self: flex-end; align-items: flex-end; max-width: 78%; }
.cw-who {
  margin-bottom: calc(var(--u) * 8);
  padding: calc(var(--u) * 3) calc(var(--u) * 8);
  border: 1px solid var(--p-line); border-radius: 999px;
  font-size: calc(var(--u) * 8.5); font-weight: 700; letter-spacing: 0.09em; line-height: 1;
  opacity: 0.66;
}
.is-user .cw-who  { background: var(--p-ink); border-color: var(--p-ink); color: var(--p-on-ink); opacity: 0.78; }
.is-agent .cw-who { border-color: var(--p-ink); color: var(--p-ink); }
.is-user .cw-text {
  padding: calc(var(--u) * 9) calc(var(--u) * 13);
  border: 1px solid var(--p-line); border-radius: calc(var(--u) * 12);
  background: var(--p-panel-3);
  color: var(--p-ink);
}
.cw-table { margin: 0 0 calc(var(--u) * 10); border: 1px solid var(--p-line); border-radius: calc(var(--u) * 8); overflow: hidden; background: var(--p-panel); }
.cw-table-bar {
  display: flex; justify-content: space-between; align-items: center;
  padding: calc(var(--u) * 5) calc(var(--u) * 10);
  border-bottom: 1px solid var(--p-line); background: var(--p-panel-2);
  font-size: calc(var(--u) * 9.5); color: var(--p-ink-55);
}
.cw-table-title { display: inline-flex; align-items: center; gap: calc(var(--u) * 5); font-weight: 600; letter-spacing: 0.04em; }
.cw-table table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: calc(var(--u) * 11); }
.cw-table th, .cw-table td {
  padding: calc(var(--u) * 4) calc(var(--u) * 9);
  border-bottom: 1px solid var(--p-line-soft); border-right: 1px solid var(--p-line);
  text-align: left; white-space: nowrap; line-height: 1.5;
}
.cw-table :is(th, td):last-child { border-right: 0; }
.cw-table tr:last-child td { border-bottom: 0; }
.cw-table th { background: var(--p-panel-3); border-bottom-color: var(--p-line-strong); font-weight: 600; color: var(--p-ink); }
.cw-table tbody tr:nth-child(even) td { background: var(--p-panel-2); }

.cw-composer {
  margin: calc(var(--u) * 8) calc(var(--u) * 18) calc(var(--u) * 16);
  padding: calc(var(--u) * 8) calc(var(--u) * 10) calc(var(--u) * 7);
  border: 1px solid var(--p-line); border-radius: calc(var(--u) * 14);
  background: var(--p-panel);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.06);
}
.cw-placeholder { display: block; padding: calc(var(--u) * 4) calc(var(--u) * 4) 0; color: var(--p-ink-38); }
.cw-composer-foot { display: flex; align-items: center; gap: calc(var(--u) * 4); margin-top: calc(var(--u) * 2); }
.cw-attach { display: grid; place-items: center; width: calc(var(--u) * 28); height: calc(var(--u) * 28); color: var(--p-ink-55); font-size: calc(var(--u) * 15); }
.cw-model { margin-left: auto; padding: 0 calc(var(--u) * 6); font-size: calc(var(--u) * 11); color: var(--p-ink-55); }
.cw-send {
  display: grid; place-items: center; flex: none;
  width: calc(var(--u) * 28); height: calc(var(--u) * 28); border-radius: 999px;
  background: var(--p-panel-3); color: var(--p-ink-38); font-size: calc(var(--u) * 13);
}
.cw-send.is-on { background: var(--p-ink); color: var(--p-on-ink); }

/* Skill result */
.cw-panel { padding: calc(var(--u) * 20); }
.cw-panel-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: calc(var(--u) * 14); }
.cw-panel-h { font-size: calc(var(--u) * 10); font-weight: 700; letter-spacing: 0.12em; color: var(--p-ink-80); }
.cw-ghost {
  display: inline-flex; align-items: center; gap: calc(var(--u) * 5); flex: none;
  padding: calc(var(--u) * 3) calc(var(--u) * 10);
  border: 1px solid var(--p-line-strong); border-radius: calc(var(--u) * 7);
  background: var(--p-panel);
  font-size: calc(var(--u) * 10.5); color: var(--p-ink);
}
.cw-doc-box { flex: 1; min-height: 0; display: flex; flex-direction: column; border: 1px solid var(--p-line); border-radius: calc(var(--u) * 10); overflow: hidden; background: var(--p-panel-2); }
.cw-doc-bar {
  display: flex; align-items: center; gap: calc(var(--u) * 8);
  padding: calc(var(--u) * 7) calc(var(--u) * 9) calc(var(--u) * 7) calc(var(--u) * 13);
  border-bottom: 1px solid var(--p-line);
}
.cw-doc-kind { display: inline-flex; align-items: center; gap: calc(var(--u) * 5); font-size: calc(var(--u) * 9.5); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--p-ink-55); }
.cw-switch { display: inline-flex; align-items: center; gap: calc(var(--u) * 7); margin-left: auto; margin-right: calc(var(--u) * 4); font-size: calc(var(--u) * 10.5); color: var(--p-ink); }
.cw-track { position: relative; width: calc(var(--u) * 26); height: calc(var(--u) * 15); border-radius: 999px; background: var(--p-ink); }
.cw-track span { position: absolute; top: 12%; right: 8%; width: calc(var(--u) * 11.5); aspect-ratio: 1; border-radius: 50%; background: var(--p-on-ink); }
.cw-doc-bar .cw-ghost { padding: calc(var(--u) * 3) calc(var(--u) * 9); font-size: calc(var(--u) * 10); }
.cw-doc {
  flex: 1; min-height: 0; overflow: hidden;
  padding: calc(var(--u) * 15) calc(var(--u) * 17) 0;
  background: var(--p-panel);
  font-size: calc(var(--u) * 11.5); line-height: 1.7;
  /* the report runs on below the fold */
  -webkit-mask-image: linear-gradient(180deg, #000 78%, transparent);
          mask-image: linear-gradient(180deg, #000 78%, transparent);
}
.cw-diff {
  margin: 0; padding: calc(var(--u) * 9) 0;
  border: 1px solid var(--p-line); border-radius: calc(var(--u) * 8);
  background: rgb(0 0 0 / 0.22);
  font-family: var(--mono); font-size: calc(var(--u) * 10.5); line-height: 1.55; letter-spacing: 0;
}
.cw-diff span { display: block; padding: 0 calc(var(--u) * 12); white-space: pre; color: var(--p-ink-80); }
.cw-diff .del { background: rgb(248 113 113 / 0.12); color: #fca5a5; }
.cw-diff .add { background: rgb(74 222 128 / 0.1); color: #86efac; }

.cw-reply { margin-top: calc(var(--u) * 12); padding-top: calc(var(--u) * 12); border-top: 1px solid var(--p-line-soft); }
.cw-reply-box {
  display: flex; align-items: flex-end; gap: calc(var(--u) * 8);
  padding: calc(var(--u) * 6) calc(var(--u) * 6) calc(var(--u) * 6) calc(var(--u) * 12);
  border: 1px solid var(--p-line-strong); border-radius: calc(var(--u) * 12);
  background: var(--p-panel);
}
.cw-typed { flex: 1; align-self: center; color: var(--p-ink); font-size: calc(var(--u) * 12); line-height: 1.5; }
.cw-typed::after {   /* the caret, still blinking after the last character */
  content: ""; display: inline-block; vertical-align: -0.15em;
  width: 1px; height: 1.1em; margin-left: 2px; background: var(--p-ink);
  animation: cw-caret 1.1s steps(1) infinite;
}
@keyframes cw-caret { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .cw-typed::after { animation: none; } }

/* Narrow: no room to overlap, and scaled down the type would be unreadable.
   One window at a time, at real size, cross-fading into the other. */
@media (max-width: 760px) {
  .cw-stage { aspect-ratio: auto; display: grid; }
  .cw {
    grid-area: 1 / 1;
    position: relative; left: auto; top: auto;
    width: 100%; aspect-ratio: 4 / 5;
    border-radius: var(--r-card);
    animation: cw-swap 8.7s ease-in-out infinite;
  }
  .cw-front { animation-delay: -4.35s; }
  .cw-in { --u: 1px; }
  /* what does not fit a phone's width */
  .cw-table :is(th, td):nth-child(4),
  .cw-doc-bar .cw-ghost:last-child,
  .cw-doc-bar .cw-switch { display: none; }
  .cw-doc-bar .cw-ghost { margin-left: auto; }
}
/* Half a cycle apart (8.7s): each window holds 4s, then a quick cross-fade
   of about 0.35s, the incoming window rising as the outgoing one goes. */
@keyframes cw-swap {
  0%, 45.9%  { opacity: 1; }
  50%, 95.9% { opacity: 0; }
  100%       { opacity: 1; }
}
@media (max-width: 760px) and (prefers-reduced-motion: reduce) {
  .cw-stage { gap: 1.25rem; }
  .cw { grid-area: auto; animation: none; }
}

.platform ~ section .aura { display: none; }

.platform ~ section { text-align: center; }
.platform ~ section .sec-head .sec-sub { margin-inline: auto; }
.platform ~ section :is(.num, .num dd) { justify-items: center; text-align: center; }

/* ============================================================
   CHAPTERS — pinned split, list on one side, glass picture on the other
   ============================================================ */

.chapter {
  --step: 80svh;                       /* scroll length each item holds */
  --copy-col: 0.9fr;                   /* list column against the picture's 1.1fr */
  position: relative;
  padding-block: var(--band);
}

.chapter-pin { position: relative; isolation: isolate; }
.chapter-pin .aura { z-index: -1; }
.chapter .orb.o1 { left: auto; right: 4%; top: 22%; --size: 36%; }
.chapter .orb.o3 { left: auto; right: 22%; bottom: 8%; --size: 28%; }
.chapter.flip .orb.o2 { right: auto; left: 8%; top: 22%; }
.chapter.flip .orb.o3 { right: auto; left: 26%; }

.chapter-head { display: grid; gap: 1rem; justify-items: start; }
.chapter .h2 { max-width: 12ch; }

/* ---- Stacked: narrow screens, short screens, no script ---- */

.chapter-grid { display: grid; grid-template-columns: minmax(0, 1fr); }   /* a long window title must not widen the column */
.chapter-head { margin-bottom: 3rem; }

.item { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.25rem; padding-bottom: 4rem; }
.item-tab {
  appearance: none; border: 0; background: none; padding: 0; text-align: left;
  display: flex; align-items: baseline; gap: 0.9rem; cursor: default;
}
.item-n { font-family: var(--mono); font-size: 0.78rem; color: var(--accent-text); letter-spacing: 0; }
.item-name { font-size: 0.95rem; font-weight: 650; color: var(--ink-3); letter-spacing: -0.02em; }
.item-h { font-size: var(--fs-h3); font-weight: 750; letter-spacing: -0.035em; line-height: 1.3; }
.item-copy-in { display: grid; gap: 0.9rem; justify-items: start; }
.item-copy p { color: var(--ink-2); max-width: 36ch; font-size: 0.96rem; }

.cmd {
  padding: 0.5em 1em;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-2);
  background: rgb(255 255 255 / 0.04);
  font-size: 0.82rem;
  color: var(--ink);
}

/* ---- Pinned: wide and tall enough, script running ---- */

@media (min-width: 1000px) and (min-height: 680px) {
  /* The pinned frame is only as tall as its content at its tallest item
     (--pin-h, measured by n.js), not a whole screen, so the chapter has no
     more empty space above and below than any other section. It sticks
     centred in the space under the nav. */
  .js .chapter {
    --pin-clear: calc(var(--notice-h) + 4.5rem);   /* clears the floating nav */
    --pin-h: 100svh;                               /* until measured */
    height: calc(var(--pin-h) + (var(--items) - 1) * var(--step) + 2 * var(--band));
  }
  .js .chapter-pin {
    position: sticky;
    top: max(var(--pin-clear), calc((100svh + var(--pin-clear) - var(--pin-h)) / 2));
    height: var(--pin-h);
    display: grid;
    align-items: center;
  }
  /* The whole list has to fit one screen, so the chapter headline sits
     a size below the page's other h2s. */
  .js .chapter .h2 { font-size: clamp(1.8rem, 1.15rem + 1.7vw, 2.6rem); }

  .js .chapter-grid {
    grid-template-columns: minmax(0, var(--copy-col)) minmax(0, 1.1fr);
    column-gap: clamp(3rem, 6vw, 6rem);
    align-items: start;
  }
  .js .chapter.flip .chapter-grid { grid-template-columns: minmax(0, 1.1fr) minmax(0, var(--copy-col)); }

  .js .chapter-head { grid-column: 1; grid-row: 1; margin-bottom: 1.75rem; }
  .js .chapter.flip .chapter-head { grid-column: 2; }

  .js .item { display: contents; }

  .js .item-tab, .js .item-copy { grid-column: 1; }
  .js .chapter.flip .item-tab, .js .chapter.flip .item-copy { grid-column: 2; }

  /* Tabs are the rows of a list, a hairline above each. */
  .js .item-tab {
    cursor: pointer;
    width: 100%;
    padding: 0.9rem 0;
    border-top: 1px solid var(--line);
    transition: border-color var(--t-hover) var(--ease);
  }
  .js .item-tab .item-name { font-size: 1.02rem; transition: color var(--t-hover) var(--ease); }
  .js .item-tab:hover .item-name { color: var(--ink-2); }
  .js .item-n { color: var(--ink-3); transition: color var(--t-hover) var(--ease); }

  .js .item.is-active .item-tab { border-top-color: var(--line-2); }
  .js .item.is-active .item-name { color: var(--ink); }
  .js .item.is-active .item-n { color: var(--accent-text); }

  /* Only the active item's copy is open. */
  .js .item-copy {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--t-swap) var(--ease);
  }
  .js .item-copy-in {
    overflow: hidden;
    min-height: 0;
    opacity: 0;
    transition: opacity 500ms var(--ease);
  }
  .js .item.is-active .item-copy { grid-template-rows: 1fr; }
  .js .item.is-active .item-copy-in { opacity: 1; transition-delay: 180ms; }
  .js .item-copy-in > :last-child { margin-bottom: 1.4rem; }
  .js .item-h { font-size: clamp(1.12rem, 1rem + 0.45vw, 1.35rem); }

  /* Every picture shares one cell; the active one comes forward. */
  .js .item-visual {
    grid-column: 2;
    grid-row: 1 / span calc(var(--items) * 2 + 1);
    align-self: center;
    opacity: 0;
    transform: translateY(6%) scale(0.97);
    transition: opacity var(--t-swap) var(--ease), transform var(--t-swap) var(--ease);
    pointer-events: none;
  }
  .js .chapter.flip .item-visual { grid-column: 1; }
  .js .item.is-active .item-visual { opacity: 1; transform: none; pointer-events: auto; }
  .js .item.is-past .item-visual { transform: translateY(-6%) scale(0.97); }
  /* While n.js measures the pin, every state lands at once. */
  .js .chapter.is-measuring * { transition: none !important; }
}

/* ============================================================
   Feature pictures — glass windows with believable contents
   ============================================================ */

.win { border-radius: var(--r-lg); overflow: hidden; }
.win > :not(.win-bar) { padding: 1.5rem; }

.v-label { font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.1em; color: var(--ink-3); }

/* maker */
.v-maker { display: grid; gap: 1rem; }
.objs { display: grid; gap: 0.45rem; }
.objs li {
  display: flex; justify-content: space-between; gap: 1rem;
  padding: 0.6rem 0.85rem; border-radius: var(--r-sm); background: rgb(255 255 255 / 0.05);
  font-family: var(--mono); font-size: 0.8rem; letter-spacing: 0;
}
.objs em { font-style: normal; color: var(--ink-3); }
.objs .pending { opacity: 0.45; }

/* reuse */
.v-reuse { display: grid; gap: 0.6rem; }
.search {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.85rem 1rem; border-radius: var(--r-pill);
  background: rgb(255 255 255 / 0.07); color: var(--ink);
  margin-bottom: 0.4rem;
}
.search .ph { color: var(--ink-3); }
.hit {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 0.9rem 1rem; border-radius: var(--r-sm);
  border: 1px solid var(--line);
}
.hit b { display: block; font-family: var(--mono); font-weight: 500; font-size: 0.86rem; letter-spacing: 0; }
.hit span { display: block; color: var(--ink-3); font-size: 0.82rem; }
.hit em {
  flex: none; font-style: normal; font-size: 0.78rem; font-weight: 700;
  padding: 0.35em 0.8em; border-radius: var(--r-pill);
  background: var(--accent); color: var(--accent-ink);
}
.hit em.soft { background: rgb(255 255 255 / 0.08); color: var(--ink-2); font-weight: 550; }
.hit.best { border-color: rgb(var(--light-amber) / 0.45); background: rgb(var(--light-amber) / 0.06); }

/* agents */
.v-agents { display: grid; gap: 0.7rem; }
.tags { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-bottom: 0.4rem; }
.tags span {
  padding: 0.4em 0.75em; border-radius: var(--r-pill);
  background: rgb(255 255 255 / 0.06);
  font-family: var(--mono); font-size: 0.76rem; letter-spacing: 0; color: var(--ink-2);
}
.tags span.on { background: rgb(var(--light-amber) / 0.18); color: var(--accent-text); }

/* severity */
.v-sev { display: grid; gap: 0.55rem; }
.v-sev li {
  display: grid; grid-template-columns: 5.4rem minmax(0, 1fr); gap: 0.9rem; align-items: start;
  padding: 0.85rem 1rem; border-radius: var(--r-sm); background: rgb(255 255 255 / 0.045);
}
.v-sev em {
  font-style: normal; font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.04em;
  padding: 0.35em 0.5em; border-radius: 0.4rem; text-align: center;
}
.v-sev .crit { background: rgb(var(--light-ember) / 0.22); color: var(--bad-text); }
.v-sev .maj  { background: rgb(var(--light-amber) / 0.2); color: var(--accent-text); }
.v-sev .min  { background: rgb(255 255 255 / 0.08); color: var(--ink-2); }
.v-sev b { display: block; font-weight: 650; font-size: 0.95rem; }
.v-sev span { display: block; color: var(--ink-3); font-size: 0.84rem; }

/* compare */
.v-cmp { width: calc(100% - 3rem); margin: 0.6rem 1.5rem 0; border-collapse: collapse; font-size: 0.9rem; }
.v-cmp th, .v-cmp td { padding: 0.7rem 0.6rem; border-bottom: 1px solid var(--line); }
.v-cmp thead th { font-family: var(--mono); font-weight: 500; font-size: 0.76rem; color: var(--ink-3); letter-spacing: 0; }
.v-cmp tbody th { text-align: left; font-weight: 550; color: var(--ink-2); }
.v-cmp td { text-align: center; font-family: var(--mono); font-size: 0.8rem; letter-spacing: 0; }
.v-cmp .same { color: var(--ok-text); }
.v-cmp .diff { color: var(--accent-text); }
.v-cmp .opp  { color: var(--bad-text); }
.win > .v-cmp { padding: 0; }
.win > .v-verdict {
  display: flex; gap: 0.8rem; align-items: baseline; flex-wrap: wrap;
  margin: 1rem 1.5rem 1.5rem; padding: 0.9rem 1rem;
  border-radius: var(--r-sm); background: rgb(var(--light-amber) / 0.1);
}
.v-verdict b { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.1em; color: var(--accent-text); font-weight: 500; }
.v-verdict span { font-weight: 600; }

/* diagnosis */
.v-diag li { display: grid; grid-template-columns: 2.2rem minmax(0, 1fr); gap: 0.9rem; position: relative; padding-bottom: 1.1rem; }
.v-diag li:last-child { padding-bottom: 0; }
.v-diag li:not(:last-child)::after {
  content: ''; position: absolute; left: 1.1rem; top: 2.4rem; bottom: 0.2rem; width: 1px; background: var(--line-2);
}
.v-diag li > span {
  width: 2.2rem; aspect-ratio: 1; border-radius: 50%; display: grid; place-items: center;
  font-family: var(--mono); font-size: 0.74rem; letter-spacing: 0;
  background: rgb(255 255 255 / 0.1);
}
.v-diag .now > span { background: var(--accent); color: var(--accent-ink); }
.v-diag b { display: block; font-weight: 650; }
.v-diag em, .v-diag code { display: block; font-style: normal; color: var(--ink-3); font-size: 0.84rem; }
.v-diag .now b { color: var(--accent-text); }

/* ============================================================
   JOIN
   ============================================================ */

.join { position: relative; padding-top: calc(var(--band) * 2.4); }   /* more air after the cost cards above */
.join-sub {
  margin-top: 0.2rem;
  font-size: var(--fs-sub);   /* the same size as the section subtitles */
  font-weight: 400;
  color: var(--ink-3);
}
/* The globe: square, centred, and pulled down so the footer (drawn over
   it, below) covers its lower part (--globe-hidden). The two sizes live on
   :root because the footer needs them too, to stay at least that tall. */
:root {
  --globe-size: min(44rem, 88vw);
  --globe-hidden: 0.6;    /* share of the globe's height the footer covers */
}
.join-globe {
  --globe-dot: var(--ink-2);
  width: var(--globe-size);
  aspect-ratio: 1;
  margin: clamp(2.5rem, 5vw, 3.5rem) auto calc(var(--globe-size) * var(--globe-hidden) * -1);
  touch-action: pan-y;
  cursor: grab;
}
.join-globe:active { cursor: grabbing; }
/* The disc the globe sits on, as on the landing page's dark theme: a
   raised dark sheet (#171A1F at 94%) fading out, and a faint light ring
   (#E6E9EE at 14%) just inside the rim. closest-side makes 100% half the
   block, so 88% lands just inside the sphere, which globe.js draws at
   0.92 of the half-size. */
.join-globe {
  position: relative;
  isolation: isolate;     /* keeps the disc behind the dots, in front of the page */
  --globe-halo: rgb(23 26 31 / 0.94);
  --globe-halo-edge: rgb(230 233 238 / 0.14);
}
.join-globe::before {
  content: '';
  position: absolute; inset: 0;
  z-index: -1;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle closest-side at 50% 50%,
    var(--globe-halo) 0%,
    color-mix(in srgb, var(--globe-halo) 55%, transparent) 64%,
    var(--globe-halo-edge) 88%,
    transparent 94%);
}
.join-globe canvas { display: block; width: 100%; height: 100%; }

/* ============================================================
   FOOTER
   ============================================================ */

.foot { position: relative; z-index: 1; min-height: calc(var(--globe-size) * var(--globe-hidden)); padding-block: 4.5rem 2.5rem; border-top: 1px solid var(--line); background: var(--bg); }   /* opaque and on top: it hides the globe's lower half */

/* Link columns: small grey headings over bold white entries. */
.foot-grid { display: grid; grid-template-columns: minmax(0, 1.6fr) repeat(4, minmax(0, 1fr)); gap: 2.5rem 2rem; }
.foot-brand .brand-text { font-size: 0.95rem; }
.foot-brand p { margin-top: 0.75rem; color: var(--ink-3); font-size: 0.86rem; max-width: 24ch; }
.foot-col { display: grid; gap: 0.7rem; align-content: start; justify-items: start; }
.foot-col h3 { margin-bottom: 0.2rem; font-size: 0.74rem; font-weight: 600; color: var(--ink-3); }
.foot-col a {
  display: inline-flex; align-items: center; gap: 0.45em;
  color: var(--ink); text-decoration: none; font-size: 0.88rem; font-weight: 600; letter-spacing: -0.02em;
  transition: color var(--t-hover) var(--ease);
}
.foot-col a:hover { color: var(--ink-3); }
.foot-col a em {
  padding: 0.3em 0.5em; border-radius: 0.35rem;
  background: rgb(255 255 255 / 0.1); color: var(--ink-2);
  font-style: normal; font-size: 0.62rem; font-weight: 600; letter-spacing: 0.04em; line-height: 1;
}
/* The badge and the word beside it are both trimmed to cap height, so the
   badge's text sits mid-box and the two share one centre line. */
@supports (text-box: trim-both cap alphabetic) {
  .foot-col a > span, .foot-col a em { text-box: trim-both cap alphabetic; }
  .foot-col a em { padding: 0.5em 0.55em; }
}

/* Business details: two lines of fields split by short rules. */
.foot-biz {
  margin-top: 3.5rem;
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1.5rem 3rem;
}
.foot-info { display: grid; gap: 0.35rem; font-style: normal; font-size: 0.76rem; line-height: 1.6; color: var(--ink-3); }
.foot-row { display: flex; flex-wrap: wrap; align-items: center; row-gap: 0.15rem; }
/* Wide, a pair is just two more fields in the row. */
.foot-pair { display: contents; }
.foot-row span:not(.foot-pair) { display: inline-flex; align-items: center; }
.foot-row span:not(.foot-pair)::before {
  content: ''; width: 1px; height: 0.7em; margin-inline: 0.6rem;
  background: var(--line-2);
}
.foot-row > span:first-child::before,
.foot-row > .foot-pair:first-child > span:first-child::before { display: none; }
.foot-info a { color: inherit; text-decoration: none; transition: color var(--t-hover) var(--ease); }
.foot-info a:hover { color: var(--ink); }

.foot-meta {
  margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid var(--line);
  display: grid; gap: 0.5rem;
  font-size: 0.76rem; color: var(--ink-3);
}
.foot-legal { display: flex; flex-wrap: wrap; align-items: center; }
.foot-legal a { color: var(--ink-3); text-decoration: none; transition: color var(--t-hover) var(--ease); }
.foot-legal a + a::before {
  content: ''; display: inline-block; width: 1px; height: 0.7em; margin-inline: 0.6rem;
  background: var(--line-2); vertical-align: -0.05em;
}
.foot-legal b { color: var(--ink-2); font-weight: 700; }
.foot-legal a:hover, .foot-legal a:hover b { color: var(--ink); }

@media (max-width: 900px) {
  .foot-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .foot-brand { grid-column: 1 / -1; }
  .foot-biz { flex-direction: column; }
}
/* Narrow, the fields wrap anyway: one line per pair or lone field, no
   rules to start a line. */
@media (max-width: 640px) {
  .foot-info { gap: 0.15rem; }
  .foot-row { display: grid; }
  .foot-pair { display: flex; flex-wrap: wrap; align-items: center; }
  .foot-row > span:not(.foot-pair)::before,
  .foot-pair > span:first-child::before { display: none; }
}
/* A phone cannot fit the long pair on one line: its two fields stack. */
@media (max-width: 30rem) {
  .foot-pair.is-long { display: grid; }
  .foot-pair.is-long > span::before { display: none; }
}

/* ============================================================
   Shared picture parts: ticks, sheets, flow, numbers
   ============================================================ */

.ticks { margin-top: 0.6rem; display: grid; gap: 0.65rem; }
.ticks li { display: flex; align-items: center; gap: 0.6rem; color: var(--ink-2); font-size: 0.9rem; }
.ticks .ph { color: var(--ok-text); font-size: 1.1rem; flex: none; }
.ticks .is-live { color: var(--ink); }
.ticks .is-live .ph { color: var(--accent-text); animation: spin 1.4s linear infinite; }
@keyframes spin { to { transform: rotate(1turn); } }

.flow { display: grid; justify-items: center; }

.num-grid { margin-top: clamp(3rem, 6vw, 4rem); display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.8rem; }
.num { padding: 1.5rem 1.3rem 1.4rem; border-radius: var(--r-md); display: grid; gap: 0.3rem; align-content: start; }
.num dt { order: 2; font-weight: 650; font-size: 0.92rem; }
.num dd { display: contents; }
.num b {
  order: 1;
  font-size: clamp(2.2rem, 1.6rem + 2vw, 3.3rem);
  font-weight: 800; letter-spacing: -0.05em; line-height: 1;
  font-variant-numeric: tabular-nums;
  margin-bottom: 0.5rem;
}
.num b .suf { color: var(--accent-text); }
.num dd span { order: 3; font-size: 0.78rem; color: var(--ink-3); line-height: 1.5; }
@media (max-width: 900px) { .num-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ============================================================
   Chat bubbles
   ============================================================ */

.msg { max-width: 86%; font-size: 0.9rem; line-height: 1.6; }
.msg.me {
  justify-self: end;
  padding: 0.7rem 1rem; border-radius: 1rem 1rem 0.3rem 1rem;
  background: rgb(255 255 255 / 0.1);
}
.msg.ai { display: grid; gap: 0.6rem; color: var(--ink-2); }
.msg.ai b { color: var(--ink); }
.msg.ai code { color: var(--accent-text); }
.who { display: inline-flex; align-items: center; gap: 0.4rem; font-family: var(--mono); font-size: 0.74rem; color: var(--accent-text); letter-spacing: 0; }
.tools { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.tools span {
  display: inline-flex; align-items: center; gap: 0.35em;
  padding: 0.3em 0.7em; border-radius: var(--r-pill);
  background: rgb(255 255 255 / 0.06); border: 1px solid var(--line);
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0; color: var(--ink-3);
}
.tools .ph { color: var(--ok-text); }
.tools .live { color: var(--ink-2); }
.tools .live .ph { color: var(--accent-text); animation: spin 1.4s linear infinite; }
@media (max-width: 640px) { .msg { max-width: 100%; } }

/* ============================================================
   PLATFORM — heading over the Fibre Arc picture
   ============================================================ */

/* From here down the sections sit closer together. */
.platform, .platform ~ section { --band: var(--band-tight); }
.platform { position: relative; padding-block: var(--band); }

.plat-visual {
  position: relative;
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  aspect-ratio: 16 / 7;
  /* Edges dissolve into the page black on all four sides, so the strands
     never end at a hard line. */
  --fade-x: 16%;
  --fade-y: 18%;
  -webkit-mask-image:
    linear-gradient(90deg, transparent, #000 var(--fade-x), #000 calc(100% - var(--fade-x)), transparent),
    linear-gradient(180deg, transparent, #000 var(--fade-y), #000 calc(100% - var(--fade-y)), transparent);
  -webkit-mask-composite: source-in;
          mask-image:
    linear-gradient(90deg, transparent, #000 var(--fade-x), #000 calc(100% - var(--fade-x)), transparent),
    linear-gradient(180deg, transparent, #000 var(--fade-y), #000 calc(100% - var(--fade-y)), transparent);
          mask-composite: intersect;
}
.plat-visual canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
@media (max-width: 760px) { .plat-visual { aspect-ratio: 4 / 3; } }
.tile { padding: 1.6rem; border-radius: var(--r-lg); display: grid; gap: 0.6rem; align-content: start; }
.tile h3, .tcard h3 { font-size: 1.1rem; font-weight: 750; letter-spacing: -0.03em; line-height: 1.35; }
.tile p, .tcard p { color: var(--ink-3); font-size: 0.9rem; }
.tile-icon {
  width: 2.4rem; aspect-ratio: 1; border-radius: 0.8rem;
  display: grid; place-items: center; margin-bottom: 0.5rem;
  background: rgb(var(--light-amber) / 0.14); color: var(--accent-text); font-size: 1.2rem;
}

/* chat picture inside the analyze chapter */
.v-chat { display: grid; gap: 1rem; }
.v-chat .msg { max-width: 92%; }

/* build: the approval stamp */
.approval {
  display: flex; align-items: center; gap: 0.8rem;
  padding: 0.85rem 1rem; border-radius: var(--r-sm);
  background: rgb(var(--light-amber) / 0.1); border: 1px solid rgb(var(--light-amber) / 0.35);
}
.approval .ph { font-size: 1.5rem; color: var(--accent-text); }
.approval b { display: block; font-weight: 700; }
.approval span { display: block; font-family: var(--mono); font-size: 0.74rem; color: var(--ink-3); letter-spacing: 0; }

/* ============================================================
   Reveal on scroll, and the language swap
   ============================================================ */

.js .reveal { opacity: 0; transform: translateY(1.5rem); transition: opacity 1000ms var(--ease), transform 1000ms var(--ease); transition-delay: var(--rd, 0ms); }
.js .reveal.in { opacity: 1; transform: none; }

main, .foot, .rail { transition: opacity 260ms var(--ease); }
body.is-swapping :is(main, .foot, .rail) { opacity: 0; }

/* ============================================================
   Reduced motion: everything arrives at once, nothing drifts
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .orb, .ticks .is-live .ph, .tools .live .ph, .hero-bg { animation: none; }
  .ask-caret { animation: none; }
  .ask { transition: none; }
  .nav-glow, .nav-panel, .nav-group, .nav-burger path, .nav-panel-in { transition: none; }
  .enter { opacity: 1; transform: none; animation: none; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .statement .w { color: var(--ink); transition: none; }
  .js .item-visual, .js .item-copy, .js .item-copy-in { transition: none; }
  body.is-swapping :is(main, .foot, .rail) { opacity: 1; }
}

/* ============================================================
   LAUNCH NOTICE — what the workspace buttons open before the
   closed test starts (index.html <dialog data-launch>)
   ============================================================ */

.launch {
  --launch-dur: 640ms;
  position: fixed;   /* .glass sets relative, which would let the panel scroll away */
  inset: 0;
  width: min(30rem, 100% - 2 * var(--gutter));
  max-width: none;
  max-height: calc(100% - 2 * var(--gutter));
  margin: auto;
  padding: clamp(1.75rem, 1.2rem + 2.4vw, 2.6rem) clamp(1.4rem, 1rem + 2vw, 2.4rem);
  border-radius: var(--r-lg);
  color: var(--ink);
  text-align: center;
  overflow: auto;
  --glass-top: rgb(26 26 28 / 0.72);
  --glass-bottom: rgb(18 18 20 / 0.62);
  /* The panel fades itself; never an ancestor of the glass (that drops
     the backdrop blur until the fade ends). */
  opacity: 0;
  transform: translateY(1.2rem) scale(0.97);
  /* Keeps the panel on its own layer after the open transition. Without it
     the layer is rebuilt when the transition ends, and the buttons, still
     painted at the old sub-pixel offset, jump about 1px on the first hover. */
  will-change: opacity, transform;
  transition: opacity var(--launch-dur) var(--ease), transform var(--launch-dur) var(--ease),
              overlay var(--launch-dur) allow-discrete, display var(--launch-dur) allow-discrete;
}
.launch[open] { opacity: 1; transform: none; }
@starting-style {
  .launch[open] { opacity: 0; transform: translateY(1.2rem) scale(0.97); }
}

.launch::backdrop {
  background: rgb(0 0 0 / 0);
  -webkit-backdrop-filter: blur(0);
          backdrop-filter: blur(0);
  transition: background var(--launch-dur) var(--ease), backdrop-filter var(--launch-dur) var(--ease),
              overlay var(--launch-dur) allow-discrete, display var(--launch-dur) allow-discrete;
}
.launch[open]::backdrop {
  background: rgb(0 0 0 / 0.6);
  -webkit-backdrop-filter: blur(0.4rem);
          backdrop-filter: blur(0.4rem);
}
@starting-style {
  .launch[open]::backdrop { background: rgb(0 0 0 / 0); backdrop-filter: blur(0); }
}

/* The notice label's pill, in white, with digits that hold their width. */
.launch-dday {
  margin-inline: auto;
  border-color: rgb(255 255 255 / 0.7);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.launch-title {
  margin: 1.4rem 0 0;
  font-size: clamp(1.25rem, 1.05rem + 0.9vw, 1.6rem);
  font-weight: 700;
  letter-spacing: var(--track-head);
  line-height: 1.4;
  text-wrap: balance;
}
.launch-title em { font-style: normal; color: var(--accent-text); white-space: nowrap; }   /* the date never splits */

.launch-sub {
  margin: 1rem 0 0;
  font-size: 0.9rem;
  color: var(--ink-3);
  line-height: 1.7;
  text-wrap: balance;
}

.launch-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem;
  margin-top: 1.9rem;
}

@media (max-width: 30rem) {
  .launch-actions .btn { flex: 1 1 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .launch, .launch::backdrop { transition: none; }
}
