/* ============ THEME TOKENS ============
     MONOCHROME, warm-grey. No hue anywhere: --accent, --live and --ink resolve
     to the same near-black (near-white in the dark theme), and what colour used
     to carry is carried by form instead — filled against outlined, solid against
     dashed. The app settled the same way ("Vorm draagt de boodschap, niet enkel
     kleur", bose-soundtouch public/index.html:355) and retired its own accent
     for the same reason.

     Deliberately WARM (red above blue) where the app's neutrals are cool (blue
     above red, which its docs protect as brand character). Owner's decision,
     taken with that documented conflict in front of it — see
     docs/monochrome-plan.md §1. Visible consequence: the app screenshots on the
     page read cooler than the page around them.

     The three accent tokens are kept even though they now coincide, so the CSS
     still says what a value MEANS rather than which grey it is, and so a palette
     with hue could diverge them again without touching every call site:
       --accent       fills and graphics that carry no text
       --accent-text  accent-coloured TEXT on a light ground
       --accent-deep  filled surfaces that DO carry text */
  :root {
    /* LIGHT — the default (also the no-JS fallback) */
    --bg:          #F2F0EC;
    --bg-alt:      #E7E4DE;
    --surface:     #FAF9F6;   /* paper, not white */
    --surface-2:   #EDEAE4;
    --ink:         #1C1A17;
    --ink-dim:     #45413A;
    --muted:       #67635C;   /*  4.7:1 on --bg-alt — the floor in this theme */
    --line:        rgba(28, 26, 23, 0.12);
    --line-2:      rgba(28, 26, 23, 0.20);
    --accent:      #2E2A25;
    --accent-text: #3B372F;
    --accent-deep: #2E2A25;
    --accent-ink:  #FAF9F6;
    --accent-soft: #E4E1DA;
    --accent-line: rgba(46, 42, 37, 0.28);
    --live:        #1C1A17;   /* = --ink. "Works now" is carried by form now */
    --live-soft:   #E4E1DA;
    /* Sits close to --muted now — in a monochrome palette it has to: both are
       mid-greys on the same grounds. That is exactly why the "gone" states
       stopped leaning on this token. Shape carries them (outlined against
       filled, dashed against solid) and --dead only tints what shape already
       said. Painted on --surface-2 (4.74:1) and --surface (5.41:1), never on
       --bg-alt. */
    --dead:        #6B665E;
    /* Shallow and close, not floating: printed matter lying on paper. The
       hairline --line borders carry most of the separation now. */
    --shadow-sm:   0 1px 2px rgba(28, 26, 23, 0.10);
    --shadow:      0 3px 10px -3px rgba(28, 26, 23, 0.18);
    --shadow-lg:   0 14px 34px -14px rgba(28, 26, 23, 0.32);
  }
  [data-theme="dark"] {
    /* DARK — the same warm greys inverted. Monochrome in both themes; the
       identity no longer carries a hue through either. */
    --bg:          #141311;
    --bg-alt:      #1B1917;
    --surface:     #221F1C;
    --surface-2:   #2B2723;
    --ink:         #EDEAE4;
    --ink-dim:     #C9C4BC;
    --muted:       #948E85;   /*  4.6:1 on --surface-2 — the floor in this theme */
    --line:        rgba(237, 234, 228, 0.14);
    --line-2:      rgba(237, 234, 228, 0.24);
    --accent:      #EDEAE4;
    --accent-text: #DCD7CF;
    --accent-deep: #EDEAE4;
    --accent-ink:  #141311;
    --accent-soft: rgba(237, 234, 228, 0.10);
    --accent-line: rgba(237, 234, 228, 0.30);
    --live:        #EDEAE4;   /* = --ink, as in the light theme */
    --live-soft:   rgba(237, 234, 228, 0.10);
    --dead:        #A29C93;
    --shadow-sm:   0 1px 2px rgba(0, 0, 0, 0.45);
    --shadow:      0 3px 10px -3px rgba(0, 0, 0, 0.60);
    --shadow-lg:   0 14px 34px -14px rgba(0, 0, 0, 0.75);
  }

  :root {
    --sans: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    /* Georgia ships everywhere and needs no webfont — the CSP forbids one.
       Used only for the section catchphrases. */
    --serif: Georgia, "Iowan Old Style", "Times New Roman", serif;
    --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
    --wrap: 1160px;
    --prose: 60ch;
    /* Squarer than the old soft-card look — vintage panels have corners.
       999px pills stay on interactive controls (.icon-btn, .lang-select,
       nav.links a, .badge, .back-link): the roundness is what makes them read
       as pressable, and they are the 44px tap targets. Only static surfaces
       tighten. */
    --r-sm: 8px; --r: 12px; --r-lg: 16px;

    /* type scale — 19px base. Nothing that carries meaning is set below
       --fs-cap; the old design put most of its body copy at ~15px. */
    --fs-cap:   clamp(1rem, 0.97rem + 0.15vw, 1.08rem);
    --fs-body:  clamp(1.1875rem, 1.13rem + 0.25vw, 1.25rem);
    --fs-lead:  clamp(1.28rem, 1.16rem + 0.6vw, 1.55rem);
    --fs-h3:    clamp(1.3rem, 1.18rem + 0.5vw, 1.5rem);
    --fs-h2:    clamp(1.95rem, 1.5rem + 2.2vw, 3.1rem);
    --fs-h1:    clamp(2.5rem, 1.8rem + 3.6vw, 4.4rem);
    --fs-quote: clamp(1.7rem, 1.2rem + 2.4vw, 3rem);
  }

  * { box-sizing: border-box; }
  html { -webkit-text-size-adjust: 100%; }
  @media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
  /* header.top is sticky; without this every in-page anchor — the six nav
     links, the footer links, the #compat link inside faq.a5, the skip link —
     parks its heading underneath it */
  html { scroll-padding-top: 88px; }
  @media (max-width: 1100px) { html { scroll-padding-top: 136px; } }

  body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: var(--sans);
    font-size: var(--fs-body);
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    overflow-x: hidden;
    transition: background-color .3s ease, color .3s ease;
  }
  ::selection { background: var(--accent-deep); color: var(--accent-ink); }
  a { color: inherit; }
  img, svg { max-width: 100%; display: block; }
  h1, h2, h3, h4 { margin: 0; text-wrap: balance; }
  p { margin: 0; text-wrap: pretty; }

  .wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: clamp(1.2rem, 4vw, 2.5rem); }
  .pad  { padding-block: clamp(3.6rem, 8vw, 6.5rem); }

  :where(a, button, summary, select, [tabindex]):focus-visible {
    outline: 3px solid var(--accent); outline-offset: 3px; border-radius: 8px;
  }
  .skip {
    position: absolute; left: 1rem; top: -100px; z-index: 100;
    background: var(--accent-deep); color: var(--accent-ink);
    padding: .85rem 1.3rem; border-radius: 999px; text-decoration: none; font-weight: 650;
  }
  .skip:focus { top: 1rem; }

  /* ============ TYPE UTILITIES ============ */
  /* Letterspaced caps — the vintage eyebrow. This deliberately reverses the
     earlier "no uppercase micro-labels" rule (owner's decision); the tracking
     and the bump from 0.98rem to the --fs-cap floor are what pay for the lost
     word-shape. Only the section eyebrows: .eyebrow-chip carries a sentence,
     not a label, and sentences do not go into caps. */
  .label {
    display: inline-flex; align-items: center; gap: .6rem;
    font-size: var(--fs-cap); font-weight: 650; color: var(--accent-text);
    text-transform: uppercase; letter-spacing: 0.1em;
    background: var(--accent-soft); border-radius: 999px;
    padding: .45rem 1.1rem .45rem 1.2rem;   /* the tracking adds a gap after the last letter */
    margin-bottom: 1.4rem;
  }
  /* Georgia on the section heads, not just the catchphrases. It carries the
     period better than the system sans, and it is already loaded — the CSP
     forbids a webfont, so this costs nothing. Lighter weight and less negative
     tracking than the sans it replaces: Georgia is wider and needs neither. */
  h2.h { font-family: var(--serif); font-weight: 700; font-size: var(--fs-h2); line-height: 1.08; letter-spacing: -0.015em; }
  /* …except a heading that carries figures. Georgia sets OLD-STYLE figures and
     ships no `lnum` feature, so `font-variant-numeric: lining-nums` cannot fix
     it: the shutdown date would render with text figures in the heading while
     the same date renders lining in the sans timeline a few rem below. One date,
     two shapes, one screen. This heading therefore keeps the sans — and with it
     the weight and tracking the sans was tuned to. There is exactly one such
     heading today (why.title, dated in all five languages); the test in
     tests/heading-figures.test.mjs fails if a translation adds a digit to
     another one. */
  h2.h--figures { font-family: var(--sans); font-weight: 740; line-height: 1.06; letter-spacing: -0.03em; }
  h3 { font-weight: 690; font-size: var(--fs-h3); letter-spacing: -0.015em; }
  .lead { color: var(--ink-dim); font-size: var(--fs-lead); line-height: 1.5; max-width: var(--prose); }
  .prose { max-width: var(--prose); }
  .prose p { color: var(--ink-dim); }
  .prose p + p { margin-top: 1.1rem; }
  .num { font-variant-numeric: tabular-nums; }

  /* the section catchphrase — italic serif, so it reads spoken rather than shouted */
  .quote {
    font-family: var(--serif); font-size: var(--fs-quote); font-weight: 400; font-style: italic;
    line-height: 1.14; letter-spacing: -0.01em; max-width: 22ch; margin: 0 0 1.5rem; color: var(--ink);
  }
  /* Roman inside the italic — the classic serif way to stress a word, and the
     one that survives a palette with no hue. It used to be copper on italic;
     as a grey it would have been 1.47:1 against the surrounding ink, and
     *lighter*, so the stressed words read as the quiet ones. */
  .quote em { font-style: normal; color: var(--ink); }

  /* ============ HEADER ============ */
  header.top {
    position: sticky; top: 0; z-index: 40;
    background: var(--bg); /* fallback: Safari < 16.2 (iOS 15) has no color-mix() */
    background: color-mix(in srgb, var(--bg) 86%, transparent);
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--line);
  }
  .progress { position: absolute; left: 0; bottom: -1px; height: 3px; width: 0; background: var(--accent); border-radius: 0 3px 3px 0; }
  .top-in { display: flex; align-items: center; gap: 1.3rem; min-height: 72px; }
  .brand { display: flex; align-items: center; gap: 0.65rem; text-decoration: none; }
  .brand .mast { width: 40px; height: 40px; border-radius: 10px; background: var(--accent); display: grid; place-items: center; flex: none; }
  /* the mark is a filled silhouette with stroked signal arcs, so it is driven by
     `color` rather than a fill/stroke pair — one property, both halves. The M is
     masked out, not painted, so the badge tint can change without touching
     the drawing. Geometry is shared with the app: bose-soundtouch/assets/logo. */
  .brand .mast svg { width: 30px; height: 30px; color: var(--accent-ink); }
  .brand b { font-weight: 750; font-size: 1.45rem; letter-spacing: -0.03em; }
  .brand .sub { font-size: 0.88rem; color: var(--muted); white-space: nowrap; }
  /* the sub-label is the most expendable thing in the header and the widest
     variable: "pour les systèmes Bose SoundTouch" is 238px. Dropping it early
     is what lets every language hold one row down to ~1100px — Spanish needs
     a 1280px viewport with it, English only 1070px. */
  @media (max-width: 1300px) { .brand .sub { display: none; } }

  nav.links { margin-left: auto; display: flex; gap: 0.2rem; }
  /* declared before the ≤940px block below: same specificity, so source order
     decides, and the wrapped-nav rule there has to come last to take effect */
  nav.links + .controls { margin-left: 1.1rem; }
  nav.links a {
    font-size: 1rem; color: var(--ink-dim); text-decoration: none;
    padding: 0.55rem 0.85rem; border-radius: 999px;
    min-height: 44px; display: inline-flex; align-items: center;
    /* flex items shrink below their content by default: without this the
       longer languages wrap "Comment ça marche" onto two lines and the
       header grows to 90px instead of moving the nav to its own row */
    flex: none; white-space: nowrap;
  }
  nav.links a:hover { background: var(--surface-2); color: var(--ink); }
  nav.links a.active { background: var(--accent-soft); color: var(--accent-text); font-weight: 640; }
  /* ≤1100px: keep the section nav as a compact scrollable anchor row on a
     second header line instead of dropping it entirely. 1100 not 940: Spanish
     needs 989px for brand + nav + controls once the sub-label is gone. */
  @media (max-width: 1100px) {
    .top-in { flex-wrap: wrap; row-gap: 0; padding-top: 0.5rem; }
    nav.links {
      order: 3; width: 100%; margin-left: 0;
      overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none;
      padding-bottom: 0.5rem;
    }
    nav.links::-webkit-scrollbar { display: none; }
    nav.links + .controls { margin-left: auto; } /* nav sits on row 2, so re-anchor the controls right */
  }

  .controls { margin-left: auto; display: flex; align-items: center; gap: 0.5rem; }
  /* 44px+ tap targets on every pointer, not only coarse ones */
  .icon-btn, .lang-select {
    min-width: 46px; height: 46px; border: 1px solid var(--line-2); border-radius: 999px;
    background: var(--surface); color: var(--ink); cursor: pointer;
  }
  .icon-btn { display: grid; place-items: center; padding: 0; }
  .icon-btn:hover, .lang-select:hover { background: var(--surface-2); }
  .icon-btn svg { width: 21px; height: 21px; stroke: currentColor; fill: none; stroke-width: 1.8; }
  .icon-btn .moon { display: none; }
  [data-theme="dark"] .icon-btn .sun { display: none; }
  [data-theme="dark"] .icon-btn .moon { display: block; }
  .lang-wrap { position: relative; display: flex; align-items: center; }
  .lang-select { appearance: none; -webkit-appearance: none; font: inherit; font-size: 0.95rem; padding: 0 2.1rem 0 1rem; }
  .lang-wrap::after {
    content: ""; position: absolute; right: 0.85rem; top: 50%; width: 7px; height: 7px;
    border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
    transform: translateY(-70%) rotate(45deg); pointer-events: none;
  }
  .lang-select option { color: initial; }

  /* ============ BADGES ============ */
  .badges { display: flex; flex-wrap: wrap; gap: 0.8rem; }
  .badge {
    display: inline-flex; align-items: center; gap: 0.75rem; padding: 0.85rem 1.4rem;
    background: var(--ink); color: var(--bg); border-radius: 999px; min-height: 58px;
    text-decoration: none; transition: transform .15s ease, box-shadow .15s ease;
  }
  .badge:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
  .badge svg { width: 25px; height: 25px; fill: var(--bg); flex: none; }
  .badge .bt { display: flex; flex-direction: column; line-height: 1.1; text-align: left; }
  .badge .bt small { font-size: 0.76rem; opacity: 0.8; }
  .badge .bt span { font-size: 1.1rem; font-weight: 700; letter-spacing: -0.015em; }
  /* 0.75, not lower: opacity composites the whole badge over the page ground,
     and the label is --bg — the exact ground — so the text does not move and
     only the diluted --ink fill carries the contrast. The nested .bt small
     (opacity .8) is the binding constraint, not the main label: at 0.6 it lands
     at 3.39:1 and at 0.7 still 4.47:1. This is the hero CTA — keep it at AA. */
  .badge--soon { cursor: default; opacity: 0.75; }
  .badge--soon:hover { transform: none; box-shadow: none; }
  .soon-note { margin-top: 0.9rem; font-size: var(--fs-cap); font-weight: 620; color: var(--ink-dim); }

  /* ============ SECTIONS ============ */
  .band-alt { background: var(--bg-alt); }

  /* ============ HERO ============ */
  .hero .pad { padding-top: clamp(2.6rem, 5vw, 4.4rem); }
  .hero-grid { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: clamp(2rem, 5vw, 4rem); align-items: center; }
  @media (max-width: 900px) { .hero-grid { grid-template-columns: 1fr; } }
  /* Outlined, where .label is filled. Both used to be a tinted pill telling
     themselves apart by hue — green against copper — and in monochrome that
     leaves two identical chips on one page. */
  .eyebrow-chip {
    display: inline-flex; align-items: center; gap: 0.6rem; border-radius: 999px; padding: 0.5rem 1.1rem;
    background: none; border: 1px solid var(--line-2); color: var(--ink-dim); font-size: 0.98rem; font-weight: 640;
  }
  .eyebrow-chip .dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex: none; }
  .hero h1 {
    font-weight: 780; font-size: var(--fs-h1); line-height: 1.02; letter-spacing: -0.04em;
    max-width: 15ch; margin-top: 1.4rem;
  }
  /* weight, not hue: the headline is already 780, so 900 is a real step up.
     The rest of the headline drops to --ink-dim so the stressed words are the
     darkest thing in it — emphasis has to run toward the ink, not away. */
  .hero h1 { color: var(--ink-dim); }
  .hero h1 em { font-style: normal; font-weight: 900; color: var(--ink); }
  .hero .tagline { margin-top: 1.2rem; font-family: var(--serif); font-style: italic; font-size: var(--fs-lead); color: var(--ink); }
  .hero .lead { margin-top: 1.1rem; }
  .hero .cta { margin-top: 2rem; }

  .hero-art { position: relative; display: grid; place-items: center; }
  .hero-art .glow {
    position: absolute; inset: 8% 12%; border-radius: 50%;
    background: radial-gradient(circle, var(--accent-soft), transparent 68%); filter: blur(12px);
  }
  /* height:auto is load-bearing — the img carries width/height attributes
     (640×1422), and setting only width in CSS leaves height pinned to the
     attribute, making the hero row 1422px tall with the copy floating in
     the middle of it */
  .hero-art img {
    position: relative; width: min(100%, 300px); height: auto; border-radius: 16px;
    box-shadow: var(--shadow-lg); border: 1px solid var(--line); transform: rotate(-2.5deg);
  }
  @media (prefers-reduced-motion: no-preference) {
    .hero-art img { transition: transform .5s cubic-bezier(.2,.7,.3,1); }
    .hero-art:hover img { transform: rotate(0deg) translateY(-6px); }
  }

  .trust-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-top: 2.6rem; }
  @media (max-width: 900px) { .trust-cards { grid-template-columns: 1fr 1fr; } }
  .tc { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); padding: 1.3rem 1.2rem; box-shadow: var(--shadow-sm); }
  .tc .ic { width: 46px; height: 46px; border-radius: 10px; background: var(--accent-soft); display: grid; place-items: center; margin-bottom: 0.9rem; }
  .tc .ic svg { width: 24px; height: 24px; stroke: var(--accent); fill: none; stroke-width: 1.8; }
  .tc b { display: block; font-weight: 690; font-size: 1.06rem; }
  .tc span { color: var(--ink-dim); font-size: var(--fs-cap); }

  .note {
    background: var(--surface); border: 1px solid var(--accent-line); border-left: 5px solid var(--accent);
    border-radius: var(--r); padding: 1.2rem 1.4rem; margin-top: 2rem; max-width: 62ch;
    display: flex; gap: 0.95rem; font-size: var(--fs-cap); color: var(--ink-dim); box-shadow: var(--shadow-sm);
  }
  .note svg { width: 24px; height: 24px; fill: var(--accent); flex: none; margin-top: 0.15rem; }
  .note b { color: var(--ink); }

  /* ============ TIMELINE ============ */
  .timeline { margin-top: 2.4rem; display: grid; gap: 1rem; position: relative; }
  .timeline::before { content: ""; position: absolute; left: 21px; top: 2rem; bottom: 2rem; width: 3px; background: var(--line-2); border-radius: 3px; }
  /* drawn in as the section scrolls into view (mast.js adds .drawn) */
  .timeline::after { content: ""; position: absolute; left: 21px; top: 2rem; width: 3px; height: 0; background: var(--accent); border-radius: 3px; transition: height 1.2s cubic-bezier(.4,0,.2,1); }
  .timeline.drawn::after { height: calc(100% - 4rem); }
  .tl { display: grid; grid-template-columns: 46px 1fr; gap: 1.2rem; align-items: start; position: relative; }
  .tl .pip { width: 46px; height: 46px; border-radius: 50%; background: var(--surface); border: 3px solid var(--line-2); display: grid; place-items: center; color: var(--muted); font-weight: 700; z-index: 1; }
  .tl.key .pip { border-color: var(--accent); color: var(--accent-text); background: var(--accent-soft); }
  .tl .card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); padding: 1.1rem 1.3rem; box-shadow: var(--shadow-sm); }
  .tl .date { font-size: var(--fs-cap); color: var(--muted); font-weight: 600; }
  .tl.key .date { color: var(--accent-text); }
  .tl b { display: block; font-weight: 690; margin-top: 0.1rem; }
  .tl .desc { color: var(--ink-dim); font-size: var(--fs-cap); }

  /* ============ PATHS DIAGRAM ============ */
  .paths { display: grid; grid-template-columns: 1fr 1fr; gap: 1.4rem; margin-top: 2.4rem; }
  @media (max-width: 860px) { .paths { grid-template-columns: 1fr; } }
  /* The whole point of this section is one card reading as over and the other as
     current, and in monochrome a tinted gradient cannot say that. The live card
     is drawn with a solid double-weight rule, the dead one dashed — the same
     device the app uses for an unreachable speaker. */
  .path { border: 1px solid var(--line); border-radius: var(--r-lg); padding: 1.8rem 1.6rem; background: var(--surface); box-shadow: var(--shadow-sm); }
  .path.then { border-style: dashed; border-color: var(--line-2); background: none; box-shadow: none; }
  .path.now { border-width: 2px; border-color: var(--live); }
  .path .tag { display: inline-block; font-size: 0.95rem; font-weight: 650; border-radius: 999px; padding: 0.3rem 0.85rem; }
  .path.then .tag { background: none; border: 1px dashed var(--dead); color: var(--dead); }
  .path.now .tag { background: var(--live); color: var(--bg); }
  .path h3 { margin: 0.8rem 0 1.4rem; }
  .path p { color: var(--ink-dim); font-size: var(--fs-cap); }
  .path .verdict { margin-top: 1.1rem; font-weight: 680; font-size: var(--fs-cap); }
  .path.then .verdict { color: var(--muted); }
  .path.now .verdict { color: var(--live); }

  .diagram { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 1.4rem; }
  .node { display: flex; flex-direction: column; align-items: center; gap: 0.5rem; font-size: 0.88rem; color: var(--ink-dim); text-align: center; }
  .node .ic { width: 58px; height: 58px; border-radius: 50%; display: grid; place-items: center; border: 2px solid var(--line-2); background: var(--surface-2); }
  .node .ic svg { width: 27px; height: 27px; fill: none; stroke-width: 1.8; }
  .then .node .ic { border-style: dashed; border-color: var(--dead); background: none; }
  .then .node .ic svg { stroke: var(--dead); }
  .now .node .ic { border-color: var(--live); background: var(--surface-2); }
  .now .node .ic svg { stroke: var(--live); }
  .link { flex: 1; min-width: 24px; height: 4px; border-radius: 4px; position: relative; margin-bottom: 1.6rem; }
  .then .link { background: repeating-linear-gradient(90deg, var(--dead) 0 7px, transparent 7px 14px); opacity: 0.6; }
  /* solid and full-strength against the dead link's dashes: the contrast is
     continuity against interruption, which survives greyscale */
  .now .link { background: var(--live); }
  /* the travelling packet — only runs while the section is on screen */
  .link::after {
    content: ""; position: absolute; top: 50%; left: 0; width: 11px; height: 11px; border-radius: 50%;
    background: var(--live); transform: translate(-50%, -50%); opacity: 0;
  }
  .anim .now .link::after { animation: travel 1.9s linear infinite; }
  /* seg1 = phone→cloud. Not :first-of-type: every child of .diagram is a
     <span>, so :first-of-type matches the first .node and never a .link. */
  .anim .then .link.seg1::after { background: var(--dead); animation: travel-die 2.6s linear infinite; }
  @keyframes travel { 0% { left: 0; opacity: 0; } 12% { opacity: 1; } 88% { opacity: 1; } 100% { left: 100%; opacity: 0; } }
  @keyframes travel-die { 0% { left: 0; opacity: 0; } 15% { opacity: .9; } 70% { left: 100%; opacity: .9; } 78%, 100% { left: 100%; opacity: 0; } }
  .link .x {
    position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
    width: 28px; height: 28px; border-radius: 50%; background: var(--surface);
    border: 2px solid var(--dead); color: var(--dead); display: grid; place-items: center;
    font-size: 0.85rem; font-weight: 700;
  }

  /* the "then" card holds three 58px nodes plus two links: ~260px minimum
     against ~230px of content box at a 320px viewport */
  @media (max-width: 380px) {
    .node .ic { width: 44px; height: 44px; }
    .node .ic svg { width: 22px; height: 22px; }
    .link { min-width: 12px; }
    .diagram { gap: 0.4rem; }
  }

  /* ============ FEATURES ============ */
  .features { display: grid; grid-template-columns: 1fr 1fr; gap: 1.3rem; margin-top: 2.4rem; }
  @media (max-width: 760px) { .features { grid-template-columns: 1fr; } }
  .feat {
    display: grid; grid-template-columns: 64px 1fr; gap: 1.3rem; align-items: start;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
    padding: 1.6rem; box-shadow: var(--shadow-sm);
    transition: transform .2s ease, box-shadow .2s ease;
  }
  .feat:hover { transform: translateY(-3px); box-shadow: var(--shadow); }
  @media (max-width: 460px) { .feat { grid-template-columns: 1fr; gap: 0.9rem; } }
  .feat .fi { width: 64px; height: 64px; border-radius: 12px; background: var(--accent-soft); display: grid; place-items: center; }
  .feat .fi svg { width: 30px; height: 30px; fill: none; stroke: var(--accent); stroke-width: 1.7; }
  .feat h3 { margin-bottom: 0.35rem; }
  .feat .benefit { font-weight: 660; color: var(--ink); margin-bottom: 0.5rem; font-size: var(--fs-cap); }
  .feat p { color: var(--ink-dim); font-size: var(--fs-cap); }
  .feat .tiny { display: block; margin-top: 0.8rem; font-size: 0.95rem; color: var(--muted); }

  /* ============ SCREENSHOTS ============ */
  .shots { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem; margin-top: 2.6rem; align-items: end; }
  .shot-fig { margin: 0; }
  /* a real button, not a scroll container with tabindex: keyboard users get
     the same enlarge affordance as everyone else */
  .shot-btn { display: block; width: 100%; padding: 0; border: 0; background: none; cursor: zoom-in; border-radius: 16px; }
  .shot { width: 100%; height: auto; border-radius: 16px; box-shadow: var(--shadow); border: 1px solid var(--line); }
  .shot-cap { margin-top: 1rem; font-size: var(--fs-cap); color: var(--ink-dim); }
  @media (max-width: 680px) { .shots { grid-template-columns: 1fr; max-width: 21rem; margin-inline: auto; gap: 2.4rem; } }

  /* Safari 15.0–15.3 doesn't know <dialog> and would render it as a plain
     block — a stray ✕ and a duplicate screenshot at the foot of the page */
  dialog.lb:not([open]) { display: none; }
  dialog.lb { border: 0; padding: 0; background: transparent; max-width: 92vw; max-height: 92vh; }
  /* hardcoded on purpose: ::backdrop did not inherit custom properties before
     Chrome 122, so var(--ink) here would fall back to transparent. Tracks the
     monochrome --ink #1C1A17 by hand. */
  dialog.lb::backdrop { background: rgba(28, 26, 23, 0.85); backdrop-filter: blur(4px); }
  dialog.lb img { max-height: 86vh; width: auto; border-radius: 16px; box-shadow: var(--shadow-lg); }
  dialog.lb .lb-in { position: relative; }
  dialog.lb .close {
    position: absolute; top: -0.5rem; right: -0.5rem; width: 46px; height: 46px; border-radius: 50%;
    /* the light tokens' literal values, fixed in both themes: this sits on the
       dark backdrop, not on --surface, so a var(--surface) circle would vanish
       in the dark theme. Was the last pure #FFF/#000 pair on the site. */
    border: 0; background: #FAF9F6; color: #1C1A17; font-size: 1.3rem; cursor: pointer;
  }

  /* ============ STEPS ============ */
  .steps { display: grid; gap: 1.3rem; margin-top: 2.4rem; }
  .step { display: grid; grid-template-columns: 72px 1fr; gap: 1.4rem; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 1.8rem 1.7rem; box-shadow: var(--shadow-sm); }
  .step .no { width: 72px; height: 72px; border-radius: 50%; background: var(--accent-deep); color: var(--accent-ink); display: grid; place-items: center; font-size: 1.9rem; font-weight: 740; }
  .step h3 { margin-bottom: 0.5rem; }
  .step p { color: var(--ink-dim); }
  .step .hint { margin-top: 1rem; padding: 0.95rem 1.15rem; border-radius: var(--r-sm); background: var(--surface-2); font-size: var(--fs-cap); color: var(--ink-dim); }
  .step .hint b { color: var(--ink); }
  @media (max-width: 560px) { .step { grid-template-columns: 1fr; gap: 1rem; } }

  .troubleshoot { margin-top: 1.6rem; background: var(--surface); border: 2px dashed var(--accent-line); border-radius: var(--r-lg); padding: 1.7rem 1.8rem; }
  .troubleshoot h3 { margin-bottom: 1rem; }
  .troubleshoot ul { margin: 0; padding-left: 1.4rem; color: var(--ink-dim); display: grid; gap: 0.6rem; font-size: var(--fs-cap); }
  .troubleshoot b { color: var(--ink); }

  /* ============ PANELS: COMPAT / CAN-CANNOT ============ */
  .two { display: grid; grid-template-columns: 1fr 1fr; gap: 1.4rem; margin-top: 2.4rem; }
  @media (max-width: 860px) { .two { grid-template-columns: 1fr; } }
  .panel { border: 1px solid var(--line); border-radius: var(--r-lg); padding: 1.8rem; background: var(--surface); box-shadow: var(--shadow-sm); }
  .panel h3 { margin-bottom: 1rem; }
  .panel > p { color: var(--ink-dim); font-size: var(--fs-cap); }
  .panel > p + p { margin-top: 0.9rem; }
  .req { display: grid; gap: 0.9rem; }
  .req div { display: flex; justify-content: space-between; gap: 1rem; padding-bottom: 0.9rem; border-bottom: 1px solid var(--line); font-size: var(--fs-cap); }
  .req div:last-child { border-bottom: 0; padding-bottom: 0; }
  .req span { color: var(--muted); }
  .req b { text-align: right; }

  .cando ul { list-style: none; margin: 0.4rem 0 0; padding: 0; }
  .cando li { display: flex; gap: 0.85rem; padding: 0.75rem 0; border-top: 1px solid var(--line); font-size: var(--fs-cap); }
  .cando li:first-child { border-top: 0; }
  /* Filled against outlined, not one tint against another. In the monochrome
     palette --live-soft and --surface-2 are nine levels apart — invisible — so
     the fill itself has to be the signal: "can" is solid ink with the glyph
     knocked out of it, "cannot" is an empty ring. Colour is now the last thing
     carrying this, not the first. */
  .mk { flex: none; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; font-weight: 800; font-size: 0.9rem; }
  .can .mk { background: var(--live); color: var(--bg); }
  .cant .mk { background: none; border: 1.5px solid var(--dead); color: var(--dead); }
  .cant li { color: var(--ink-dim); }

  /* ============ FAQ ============ */
  .faq { margin-top: 2.4rem; display: grid; gap: 0.9rem; max-width: 80ch; }
  .faq details { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow-sm); overflow: hidden; }
  .faq details[open] { border-color: var(--accent-line); }
  .faq summary { cursor: pointer; list-style: none; padding: 1.25rem 3.4rem 1.25rem 1.5rem; position: relative; font-weight: 680; font-size: 1.16rem; min-height: 44px; }
  .faq summary::-webkit-details-marker { display: none; }
  .faq summary::after {
    content: "+"; position: absolute; right: 1.1rem; top: 50%; transform: translateY(-50%);
    width: 32px; height: 32px; border-radius: 50%; background: var(--accent-soft); color: var(--accent-text);
    display: grid; place-items: center; font-size: 1.35rem; font-weight: 600; line-height: 1;
  }
  .faq details[open] summary::after { content: "\2212"; background: var(--accent-deep); color: var(--accent-ink); }
  .faq .ans { padding: 0 1.5rem 1.4rem; color: var(--ink-dim); font-size: var(--fs-cap); max-width: var(--prose); }
  /* Underlined, always. A link in running prose used to be told apart by being
     copper; as a grey it sits at ~1.2:1 against the paragraph around it, which
     is no distinction at all and fails WCAG 1.4.1 — colour must not be the only
     means. The underline is now the signal and the colour is decoration. */
  .faq .ans a { color: var(--accent-text); text-decoration: underline; text-underline-offset: 0.15em; }

  /* ============ FINAL ============ */
  .final-panel {
    background: var(--accent-deep); color: var(--accent-ink); border-radius: var(--r-lg);
    padding: clamp(2.6rem, 6vw, 4.6rem) clamp(1.5rem, 5vw, 4rem); text-align: center;
    margin-block: clamp(3rem, 7vw, 5.5rem);
  }
  .final-panel .label { background: var(--accent-ink); color: var(--accent-text); }
  .final-panel .quote { color: inherit; margin-inline: auto; max-width: 20ch; }
  .final-panel .lead { color: inherit; opacity: 0.94; margin-inline: auto; }
  .final-panel .badges { justify-content: center; margin-top: 1.8rem; }
  .final-panel .badge { background: var(--accent-ink); color: var(--accent-text); }
  .final-panel .badge svg { fill: currentColor; }
  .final-panel .soon-note { color: inherit; opacity: 0.94; }
  .final-panel .about-h { margin-top: 2.2rem; font-size: var(--fs-cap); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; opacity: 0.8; }
  .final-panel .about-note { margin: 0.5rem auto 0; max-width: 62ch; font-size: var(--fs-cap); line-height: 1.55; opacity: 0.94; }

  /* ============ FOOTER ============ */
  footer { border-top: 1px solid var(--line); background: var(--bg-alt); }
  .foot-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr; gap: 2.4rem; padding-block: clamp(3rem, 5vw, 4rem); }
  @media (max-width: 760px) { .foot-grid { grid-template-columns: 1fr; gap: 2rem; } }
  .foot-tag { color: var(--ink-dim); font-size: var(--fs-cap); margin-top: 1rem; max-width: 34ch; }
  footer h4 { font-size: 1rem; font-weight: 700; margin: 0 0 1rem; }
  footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.75rem; }
  footer ul a { color: var(--ink-dim); text-decoration: none; font-size: var(--fs-cap); }
  footer ul a:hover { color: var(--accent-text); text-decoration: underline; }
  .legal { border-top: 1px solid var(--line); padding-block: 1.8rem 2.6rem; display: grid; gap: 1.1rem; }
  .legal .mark { font-size: 0.98rem; line-height: 1.6; color: var(--ink-dim); max-width: 82ch; }
  .legal .mark .req-en { color: var(--ink); }
  .legal .meta { font-size: 0.95rem; color: var(--muted); display: flex; flex-wrap: wrap; gap: 0.4rem 1.4rem; }
  .legal .meta b { color: var(--ink-dim); font-weight: 500; }
  .ph { color: var(--accent-text); font-family: var(--mono); font-size: 0.92em; }

  /* ============ REVEAL ============ */
  .reveal { opacity: 0; transform: translateY(20px); }
  .reveal.in { opacity: 1; transform: none; transition: opacity .7s ease, transform .7s cubic-bezier(.2,.7,.3,1); }
  @media (prefers-reduced-motion: reduce) {
    .reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
    .timeline::after { transition: none; }
    .anim .link::after { animation: none !important; opacity: 0 !important; }
    .badge, .feat, body { transition: none !important; }
    .badge:hover, .feat:hover { transform: none !important; }
    html { scroll-behavior: auto; }
  }
  @media (prefers-contrast: more) {
    :root { --muted: var(--ink-dim); --line: rgba(28, 26, 23, 0.32); --line-2: rgba(28, 26, 23, 0.5); }
    [data-theme="dark"] { --muted: var(--ink-dim); --line: rgba(237, 234, 228, 0.34); --line-2: rgba(237, 234, 228, 0.56); }
  }

  /* ============ DOCUMENT / LEGAL PAGES ============
     Inherits the landing tokens (parta.html). Same readability floor: body
     copy at --fs-body, captions no smaller than --fs-cap. The floor's old
     "no uppercase micro-labels" clause was lifted for the vintage restyle
     (owner's decision) — but only for the landing's section eyebrows (.label,
     parta.html). Nothing on these pages is set in caps: they are dense legal
     prose, where word-shape matters more than period flavour. The document
     headings likewise stay in the sans, with the serif reserved for .intro. */
  .doc-main { padding-block: clamp(2.4rem, 6vw, 4.2rem); }
  .back-link {
    display: inline-flex; align-items: center; gap: 0.5rem;
    font-size: var(--fs-cap); font-weight: 620; color: var(--accent-text);
    background: var(--accent-soft); border-radius: 999px; padding: 0.55rem 1.1rem 0.55rem 0.9rem;
    text-decoration: none; margin-bottom: 1.8rem; min-height: 44px;
  }
  .back-link:hover { background: var(--accent-deep); color: var(--accent-ink); }
  .back-link svg { width: 16px; height: 16px; stroke: currentColor; fill: none; stroke-width: 2.2; }
  .doc-head { margin-bottom: 2.4rem; }
  .doc-head h1 { font-weight: 780; font-size: clamp(2.1rem, 4.6vw, 3.1rem); letter-spacing: -0.035em; line-height: 1.04; }
  .doc-updated { margin-top: 0.8rem; font-size: var(--fs-cap); color: var(--muted); }
  .doc { max-width: 68ch; }
  .doc > .intro { color: var(--ink); font-family: var(--serif); font-style: italic; font-size: var(--fs-lead); line-height: 1.5; margin-bottom: 1.8rem; }
  .doc h2 { font-weight: 720; font-size: 1.42rem; letter-spacing: -0.02em; margin: 2.5rem 0 0.8rem; }
  .doc h2:first-of-type { margin-top: 0.5rem; }
  .doc h3 { font-weight: 680; font-size: 1.14rem; margin: 1.7rem 0 0.5rem; }
  .doc p { color: var(--ink-dim); margin-bottom: 1rem; }
  .doc ul { color: var(--ink-dim); padding-left: 1.25rem; margin: 0 0 1.1rem; display: grid; gap: 0.6rem; }
  /* underlined for the same reason as .faq .ans a — with no hue in the palette
     the colour alone no longer marks a link (WCAG 1.4.1) */
  .doc a { color: var(--accent-text); text-decoration: underline; text-underline-offset: 0.15em; }
  .doc .verbatim { color: var(--ink); font-weight: 500; }
  .notice {
    border: 1px solid var(--accent-line); border-left: 5px solid var(--accent); background: var(--surface);
    border-radius: var(--r); padding: 1.1rem 1.3rem; font-size: var(--fs-cap); margin-bottom: 2rem;
    display: flex; gap: 0.8rem; color: var(--ink-dim); max-width: 68ch; box-shadow: var(--shadow-sm);
  }
  .notice svg { width: 22px; height: 22px; fill: var(--accent); flex: none; margin-top: 0.15rem; }
  .notice b { color: var(--ink); }
  .dl { display: grid; gap: 0; margin: 0.4rem 0 1.2rem; }
  .dl div { display: flex; gap: 1rem; justify-content: space-between; border-bottom: 1px solid var(--line); padding: 0.7rem 0; font-size: var(--fs-cap); flex-wrap: wrap; }
  .dl div:last-child { border-bottom: 0; }
  .dl dt { color: var(--muted); margin: 0; }
  .dl dd { margin: 0; text-align: right; color: var(--ink); }
  .cl-date { font-weight: 500; color: var(--muted); font-size: 0.72em; letter-spacing: 0; }
  .doc-links { display: flex; flex-wrap: wrap; gap: 0.7rem; margin-top: 0.5rem; }
  .doc-links a {
    display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.65rem 1.15rem;
    border: 1px solid var(--line-2); border-radius: 999px; text-decoration: none;
    color: var(--ink); font-size: var(--fs-cap); min-height: 44px; background: var(--surface);
  }
  .doc-links a:hover { background: var(--surface-2); border-color: var(--accent-line); }
  .eula-body { max-width: 72ch; }
  .eula-body h2 { font-size: 1.2rem; margin-top: 2rem; }
  .eula-body p, .eula-body li { color: var(--ink-dim); font-size: var(--fs-cap); }
  .eula-body ol { color: var(--ink-dim); padding-left: 1.3rem; display: grid; gap: 0.5rem; margin: 0 0 1.1rem; }
  .eula-body .ph { color: var(--accent-text); }

