/**
 * styles.css — the public site.
 *
 * One stylesheet for three pages: the landing page, the page Stripe returns a
 * buyer to, and the one it returns them to if they change their mind.
 *
 * ── The look, and the reasoning behind it ──────────────────────────────────
 *
 * The product's one idea is a *thread*: research is a line you follow, and the
 * thing ContextTab does is keep hold of it. So the site has a literal thread —
 * drawn down the page in SVG, drawn again in WebGL behind the hero, and used
 * as the accent on every heading. One idea, said three ways, is what a brand
 * is; a page of tastefully arranged grey boxes is not.
 *
 * Colour is a signature, not decoration. Three hues in a fixed order —
 * mint → violet → coral — always in that order, always the same gradient. The
 * demo's depth pips walk through them, so the palette teaches the hierarchy
 * rather than merely brightening it.
 *
 * Type carries the personality, because there is no webfont to carry it: a
 * very large, very tight system sans against one italic serif word. The serif
 * is doing all the work of looking like a person made this, and it costs
 * nothing to download.
 *
 * ── The constraints it is built inside ─────────────────────────────────────
 *
 * No inline styles anywhere: the CSP is `style-src 'self'`, which forbids them
 * outright. No webfont, no framework, no build step. Everything that moves
 * moves on `transform` and `opacity` only — never a property that triggers
 * layout — so the animation cannot cost a millisecond of Cumulative Layout
 * Shift, and the compositor can run it off the main thread.
 *
 * Dark by default, light when the machine asks for it.
 */

/* ══ Tokens ═══════════════════════════════════════════════════════════════ */

:root {
  /* The signature triad, always in this order. */
  --mint: #00e5a0;
  --violet: #7c5cff;
  --coral: #ff7a5a;
  --amber: #ffc24b;

  --thread: linear-gradient(104deg, var(--mint) 0%, var(--violet) 52%, var(--coral) 100%);

  --bg: #06080c;
  --bg-soft: #0d1117;
  --bg-lift: #141a22;
  --fg: #f2f5fa;
  --fg-dim: #a3adbe;
  --fg-faint: #6f7889;
  --line: rgba(255, 255, 255, 0.09);
  --line-strong: rgba(255, 255, 255, 0.18);

  --accent: var(--mint);
  --accent-ink: #05130b;
  --accent-soft: rgba(0, 229, 160, 0.13);
  --glow: 0 0 60px rgba(0, 229, 160, 0.22);

  --shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
  --radius: 16px;

  --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, system-ui, sans-serif;
  --serif: ui-serif, 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia, serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --ease: 260ms cubic-bezier(0.22, 0.61, 0.36, 1);

  color-scheme: dark;
}

@media (prefers-color-scheme: light) {
  :root {
    --mint: #00875a;
    --violet: #5b45cc;
    --coral: #d1503a;
    --amber: #a5730a;

    --bg: #fcfbf9;
    --bg-soft: #ffffff;
    --bg-lift: #f2f1ee;
    --fg: #0b0e14;
    --fg-dim: #4c5464;
    --fg-faint: #737b8a;
    --line: rgba(11, 14, 20, 0.11);
    --line-strong: rgba(11, 14, 20, 0.2);

    --accent: var(--mint);
    --accent-ink: #ffffff;
    --accent-soft: rgba(0, 135, 90, 0.10);
    --glow: 0 0 60px rgba(0, 135, 90, 0.14);

    --shadow: 0 24px 60px rgba(11, 14, 20, 0.13);
    color-scheme: light;
  }
}

* { box-sizing: border-box; }

/*
 * `hidden` has to win.
 *
 * The attribute is styled by the user agent as `display: none`, and any class
 * rule that sets `display` beats it — so `.eyebrow { display: inline-flex }`
 * silently made `<p class="eyebrow" hidden>` visible. That is exactly what
 * happened to "Nothing was charged" on the pricing page: the element's
 * `hidden` property was still true, so the test asserting it passed, while
 * every visitor saw a line about a payment they had not made.
 */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }

/*
 * Reduced motion is honoured as a *setting*, not as a stylistic afterthought.
 * The scripts check the same query and never start; this covers whatever CSS
 * would still have moved.
 */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: 16.5px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

a { color: inherit; }

.wrap { width: min(1120px, 100% - 44px); margin-inline: auto; }
.wrap.narrow { width: min(740px, 100% - 44px); }

.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;
}

/* ══ The layers ═══════════════════════════════════════════════════════════
   Four of them, back to front: the WebGL thread, a colour veil, a film of
   grain, and the page. Each is `position: fixed` and `pointer-events: none`
   so none of them can intercept a click or move anything in the document —
   which is what keeps a decorative background from costing layout shift. */

.layers {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}

/*
 * The canvas is sized entirely in CSS and never by the script, so its box
 * exists before WebGL does. A canvas that arrives late and sizes itself is a
 * layout shift on the largest element on the page.
 */
#threads {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  opacity: 0;
  transition: opacity 900ms ease;
}
#threads.on { opacity: 1; }

/*
 * The veil: the signature gradient, very dilute, pooled behind the hero.
 *
 * No `filter: blur()`. It had one, and it was the single most expensive thing
 * on the page — measured: a click in the demo went from 64 ms before the
 * redesign to 280 ms with it, and to 128 ms with the blur alone removed. A
 * blur filter over a 130vh fixed surface has to be re-rasterised whenever
 * anything above it repaints, and a radial gradient is already soft, so the
 * filter was paying a large cost for an effect that was almost invisible.
 * Wider, softer colour stops do the same job for nothing.
 *
 * `will-change: transform` is here for the other half of it: the parallax
 * writes a transform to this element, and promoting it to its own compositor
 * layer means the document repainting above it does not repaint this.
 */
.veil {
  position: absolute;
  inset: -20% -10% auto;
  height: 130vh;
  background:
    radial-gradient(62% 52% at 18% 10%, rgba(0, 229, 160, 0.19), rgba(0, 229, 160, 0.06) 46%, transparent 76%),
    radial-gradient(58% 48% at 80% 2%, rgba(124, 92, 255, 0.20), rgba(124, 92, 255, 0.06) 48%, transparent 78%),
    radial-gradient(52% 46% at 56% 48%, rgba(255, 122, 90, 0.13), rgba(255, 122, 90, 0.04) 50%, transparent 80%);
  will-change: transform;
}
@media (prefers-color-scheme: light) {
  .veil {
    background:
      radial-gradient(62% 52% at 18% 10%, rgba(0, 135, 90, 0.13), rgba(0, 135, 90, 0.04) 46%, transparent 76%),
      radial-gradient(58% 48% at 80% 2%, rgba(91, 69, 204, 0.13), rgba(91, 69, 204, 0.04) 48%, transparent 78%),
      radial-gradient(52% 46% at 56% 48%, rgba(209, 80, 58, 0.10), rgba(209, 80, 58, 0.03) 50%, transparent 80%);
  }
}

/*
 * Grain. A flat gradient reads as a rendering; a gradient with a film of noise
 * over it reads as a printed thing. Generated by the browser from a filter, so
 * it costs no request and no bytes beyond this rule.
 */
.grain {
  position: absolute;
  inset: -50%;
  opacity: 0.5;
  will-change: transform;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='0.36'/%3E%3C/svg%3E");
  mix-blend-mode: overlay;
}
@media (prefers-color-scheme: light) { .grain { opacity: 0.28; mix-blend-mode: multiply; } }

/* Everything the reader reads sits above all of it. */
.site-head, main, .site-foot { position: relative; z-index: 2; }

/* ══ Type ═════════════════════════════════════════════════════════════════ */

h1, h2, h3 { margin: 0; font-weight: 640; line-height: 1.08; letter-spacing: -0.035em; }
/*
 * The very large size belongs to the hero, not to `h1`. The pricing page's own
 * h1 inherited it and filled a screen on its own, which is a poster rather than
 * a heading.
 */
h1 { font-size: clamp(2.1rem, 5vw, 3.4rem); }
.hero h1 { font-size: clamp(2.9rem, 8.4vw, 6.2rem); }
h2 { font-size: clamp(1.9rem, 4.4vw, 3.1rem); letter-spacing: -0.032em; margin-bottom: 16px; }
h3 { font-size: 1.12rem; letter-spacing: -0.012em; line-height: 1.3; }
p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

/*
 * The one serif word.
 *
 * A single italic serif inside a wall of tight sans is the whole typographic
 * idea: it is the thread, and it is the thing that stops the page looking
 * generated. It carries the gradient too, which is why the gradient never has
 * to appear as a full-width band.
 */
.thread-word {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 500;
  letter-spacing: -0.02em;
  /*
   * A shallower angle than the site's `--thread`. At 104 degrees across a box
   * only as wide as one word, the ramp's far end falls outside the glyphs and
   * the coral never appears — the word reads mint-to-violet and the third hue
   * of the signature is simply missing.
   */
  background: linear-gradient(94deg, var(--mint) 2%, var(--violet) 48%, var(--coral) 96%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /*
   * The italic's overhang needs paint space or the gradient clips its tail —
   * but adding padding also pushes the full stop after it visibly away. The
   * negative margin gives the space back to the layout and keeps it for the
   * paint, so "thread." reads as one word.
   */
  padding-right: 0.07em;
  margin-right: -0.07em;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 0.76rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  font-weight: 620;
  color: var(--fg-dim);
  font-family: var(--mono);
  border: 1px solid var(--line);
  border-radius: 100px;
  padding: 6px 14px 6px 10px;
  background: color-mix(in srgb, var(--bg-soft) 70%, transparent);
}
.eyebrow .dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--mint);
  box-shadow: 0 0 0 3px var(--accent-soft);
  flex: none;
}

.lede { font-size: clamp(1.06rem, 1.6vw, 1.28rem); color: var(--fg-dim); max-width: 56ch; }
.small { font-size: 0.88rem; color: var(--fg-dim); }
.faint { color: var(--fg-faint); }

/* A section's number, set in mono and hung off the left the way a printed
   thing would hang it. */
.kicker {
  font-family: var(--mono);
  font-size: 0.74rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-faint);
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
}
.kicker::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--line-strong), transparent);
}

/* ══ Buttons ══════════════════════════════════════════════════════════════ */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 13px 22px;
  border-radius: 12px;
  border: 1px solid var(--line-strong);
  background: color-mix(in srgb, var(--bg-soft) 60%, transparent);
  color: var(--fg);
  font: inherit;
  font-size: 0.95rem;
  font-weight: 560;
  text-decoration: none;
  cursor: pointer;
  overflow: hidden;
  transition: border-color var(--ease), color var(--ease), background var(--ease);
}
.btn:hover { border-color: color-mix(in srgb, var(--mint) 60%, var(--line-strong)); }
.btn:focus-visible { outline: 2px solid var(--mint); outline-offset: 3px; }

/* The primary action carries the signature gradient, and is the only thing on
   the page that does at full strength. */
.btn.primary {
  border-color: transparent;
  background: var(--thread);
  background-size: 180% 100%;
  background-position: 0% 50%;
  color: var(--accent-ink);
  font-weight: 640;
  box-shadow: var(--glow);
  transition: background-position 600ms var(--ease), box-shadow var(--ease);
}
.btn.primary:hover { background-position: 100% 50%; }
@media (prefers-color-scheme: light) { .btn.primary { color: #fff; } }

.btn.ghost { border-color: transparent; background: transparent; color: var(--fg-dim); padding-inline: 12px; }
.btn.ghost:hover { color: var(--fg); }
.btn.small { padding: 8px 14px; font-size: 0.86rem; border-radius: 9px; }
.btn .arrow { transition: transform var(--ease); }
.btn:hover .arrow { transform: translateX(3px); }

/* ══ Header ═══════════════════════════════════════════════════════════════ */

.site-head {
  position: sticky;
  top: 0;
  z-index: 30;
  backdrop-filter: blur(16px) saturate(150%);
  background: color-mix(in srgb, var(--bg) 74%, transparent);
  border-bottom: 1px solid transparent;
  transition: border-color var(--ease), background var(--ease);
}
/* Set by the motion layer once the page has scrolled — a class, so the rule
   still lives here and nothing writes style attributes the CSP forbids. */
.site-head.lifted { border-bottom-color: var(--line); background: color-mix(in srgb, var(--bg) 90%, transparent); }
.site-head .wrap { display: flex; align-items: center; gap: 18px; height: 64px; }

.brand { display: flex; align-items: center; gap: 10px; font-weight: 660; letter-spacing: -0.03em; text-decoration: none; font-size: 1.02rem; }
.brand svg { display: block; color: var(--mint); }

.site-nav { margin-left: auto; display: flex; align-items: center; gap: 4px; }
.site-nav a { text-decoration: none; color: var(--fg-dim); font-size: 0.91rem; padding: 8px 12px; border-radius: 9px; transition: color var(--ease), background var(--ease); }
.site-nav a:hover { color: var(--fg); background: var(--bg-lift); }
.site-nav .btn { margin-left: 8px; }
@media (max-width: 720px) { .site-nav .hide-sm { display: none; } }

/* ══ Hero ═════════════════════════════════════════════════════════════════
   Deliberately asymmetric and deliberately not centred: a centred stack of
   headline, sub and two buttons is the shape every generated landing page
   has. The headline runs wide, the sub is inset under it, and the proof sits
   off to one side. */

.hero { padding: clamp(56px, 10vw, 104px) 0 clamp(30px, 5vw, 56px); }
.hero h1 { margin: 20px 0 0; max-width: 15ch; }
.hero .lede { margin-top: 26px; margin-left: clamp(0px, 4vw, 64px); }

.cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 34px; margin-left: clamp(0px, 4vw, 64px); }

/* The three claims, as a row of hairline-separated facts rather than a list of
   ticks. Ticks in a row is the most template-shaped element there is. */
.facts {
  margin: 34px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  border-top: 1px solid var(--line);
}
.facts li {
  flex: 1 1 190px;
  padding: 16px 20px 0 0;
  border-right: 1px solid var(--line);
  padding-left: 0;
}
.facts li:first-child { padding-left: 0; }
.facts li + li { padding-left: 20px; }
.facts li:last-child { border-right: 0; }
.facts b { display: block; font-size: 0.95rem; font-weight: 600; letter-spacing: -0.01em; }
.facts span { display: block; font-size: 0.85rem; color: var(--fg-faint); margin-top: 2px; }
.facts .n { font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.12em; color: var(--mint); display: block; margin-bottom: 7px; }
.facts li:nth-child(2) .n { color: var(--violet); }
.facts li:nth-child(3) .n { color: var(--coral); }
@media (max-width: 640px) {
  .facts li { border-right: 0; border-bottom: 1px solid var(--line); padding: 14px 0; flex-basis: 100%; }
  .facts li + li { padding-left: 0; }
  .facts li:last-child { border-bottom: 0; }
}

/* ══ The spine ════════════════════════════════════════════════════════════
   A single line running down the page, drawn as the reader scrolls. It is the
   product's own metaphor used as navigation furniture — and it is the element
   that makes the page feel like one continuous thing rather than a stack of
   sections. Purely decorative, so it is hidden from assistive technology and
   removed entirely on a narrow screen where there is no margin to hang it in. */

.spine {
  position: absolute;
  left: max(14px, calc(50% - 622px));
  top: 0;
  bottom: 0;
  width: 2px;
  pointer-events: none;
  z-index: 1;
  border-radius: 2px;
  background: var(--line);
  overflow: hidden;
}
/*
 * The drawn part is a second bar scaled from the top, not a stroke-dashoffset:
 * `scaleY` is a compositor property, so the whole length of the page can be
 * drawn on scroll without ever asking the main thread to repaint.
 */
.spine-live {
  position: absolute;
  inset: 0;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--mint) 0%, var(--violet) 55%, var(--coral) 100%);
  transform: scaleY(0);
  transform-origin: top center;
  will-change: transform;
}
@media (max-width: 1180px) { .spine { display: none; } }

/* ══ The demo ═════════════════════════════════════════════════════════════ */

.demo-shell { position: relative; margin-top: clamp(36px, 5vw, 58px); }

/* The stacked-paper effect: two offset sheets behind the real one. It is what
   makes the demo read as "a thing you can pick up" rather than a screenshot in
   a rounded rectangle. */
.demo-shell::before,
.demo-shell::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 20px;
  border: 1px solid var(--line);
  background: var(--bg-soft);
  z-index: -1;
}
.demo-shell::before { transform: translate(0, 14px) scale(0.985); opacity: 0.6; }
.demo-shell::after { transform: translate(0, 27px) scale(0.968); opacity: 0.3; }

/*
 * Opaque, and deliberately not backdrop-filtered. The demo is the one thing on
 * the page that repaints when somebody clicks, and a backdrop filter means
 * every one of those repaints re-blurs everything behind the card. The surface
 * is 92% opaque, so the blur was buying almost nothing.
 */
.demo {
  position: relative;
  border: 1px solid var(--line-strong);
  border-radius: 20px;
  background: var(--bg-soft);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.demo-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--bg-lift) 80%, transparent);
}
.dots { display: flex; gap: 6px; }
.dots i { width: 10px; height: 10px; border-radius: 50%; background: var(--line-strong); }
.dots i:first-child { background: color-mix(in srgb, var(--coral) 70%, transparent); }
.dots i:nth-child(2) { background: color-mix(in srgb, var(--amber) 60%, transparent); }
.dots i:nth-child(3) { background: color-mix(in srgb, var(--mint) 60%, transparent); }
.demo-title { font-size: 0.83rem; color: var(--fg-faint); font-family: var(--mono); }
.demo-hint { position: relative; margin-left: auto; font-size: 0.79rem; color: var(--fg-faint); display: inline-flex; align-items: center; gap: 7px; }
/* The live dot, and the ring that pulses out of it.
   The ring used to be an animated `box-shadow` on the dot itself. A box-shadow
   is a paint property: every frame of that loop repainted the element on the
   main thread, for ever, in every tab with this page open — including the ones
   nobody was looking at. Two elements instead, and the ring moves by transform
   and opacity alone, which the compositor runs on its own thread. */
.demo-hint::before {
  content: '';
  position: relative;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--mint);
}
.demo-hint::after {
  content: '';
  position: absolute;
  left: 0;
  width: 6px; height: 6px; border-radius: 50%;
  border: 1px solid var(--mint);
  transform: scale(1);
  opacity: 0.55;
  animation: pulse 2.4s ease-out infinite;
  will-change: transform, opacity;
}
@keyframes pulse {
  0% { transform: scale(1); opacity: 0.55; }
  70% { transform: scale(3.4); opacity: 0; }
  100% { transform: scale(3.4); opacity: 0; }
}

.demo-body { display: grid; grid-template-columns: minmax(0, 340px) minmax(0, 1fr); min-height: 432px; }
@media (max-width: 860px) { .demo-body { grid-template-columns: 1fr; } }

.demo-tree { border-right: 1px solid var(--line); padding: 14px 12px; display: flex; flex-direction: column; }
@media (max-width: 860px) { .demo-tree { border-right: 0; border-bottom: 1px solid var(--line); } }

.tree-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 0 6px 10px;
  font-size: 0.72rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--fg-faint);
  font-family: var(--mono);
}
.tree-head .count { margin-left: auto; text-transform: none; letter-spacing: 0.02em; }

.tree { list-style: none; margin: 0; padding: 0; flex: 1; overflow: auto; }
.node {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 0.9rem;
  text-align: left;
  cursor: pointer;
  transition: background var(--ease), opacity var(--ease), transform 120ms var(--ease);
}
.node:hover { background: var(--bg-lift); transform: translateX(2px); }
.node:focus-visible { outline: 2px solid var(--mint); outline-offset: -2px; }
.node[aria-current='true'] { background: var(--accent-soft); }

/* Depth walks the signature triad, so the colour is teaching the hierarchy
   rather than just brightening the page. */
.node .pip { width: 8px; height: 8px; border-radius: 50%; background: var(--mint); flex: none; transition: background var(--ease), box-shadow var(--ease); }
.node[data-depth='1'] .pip { background: var(--violet); }
.node[data-depth='2'] .pip { background: var(--coral); }
.node[data-depth='3'] .pip { background: var(--amber); }
.node .label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.node .tag {
  margin-left: auto;
  font-size: 0.68rem;
  font-family: var(--mono);
  color: var(--fg-faint);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 1px 6px;
  flex: none;
}
.node.frozen { opacity: 0.42; }
.node.frozen .pip { background: var(--fg-faint); }
.node.has-note .pip { box-shadow: 0 0 0 3px var(--accent-soft); }

.node[data-depth='1'] { padding-left: 28px; }
.node[data-depth='2'] { padding-left: 46px; }
.node[data-depth='3'] { padding-left: 64px; }
.tree li { position: relative; }
.tree li[data-depth]:not([data-depth='0'])::before {
  content: '';
  position: absolute;
  left: calc(10px + (var(--d) - 1) * 18px + 4px);
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--line);
}

.demo-panel { padding: 22px 24px; display: flex; flex-direction: column; gap: 15px; min-width: 0; }
.panel-kicker { font-size: 0.72rem; letter-spacing: 0.13em; text-transform: uppercase; color: var(--fg-faint); font-family: var(--mono); }
.panel-title { font-size: 1.24rem; font-weight: 640; letter-spacing: -0.028em; }
.panel-why {
  position: relative;
  padding: 3px 0 3px 14px;
  color: var(--fg-dim);
  font-size: 0.93rem;
}
.panel-why::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 2px;
  border-radius: 2px;
  background: var(--thread);
}
.panel-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: auto; padding-top: 12px; }

.note-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.note-list li {
  background: color-mix(in srgb, var(--bg-lift) 70%, transparent);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 10px 13px;
  font-size: 0.89rem;
  color: var(--fg-dim);
}
.note-list li b { color: var(--fg); font-weight: 570; }

.export {
  margin: 0;
  background: color-mix(in srgb, var(--bg-lift) 70%, transparent);
  border: 1px solid var(--line);
  border-radius: 11px;
  padding: 15px 17px;
  font-family: var(--mono);
  font-size: 0.78rem;
  line-height: 1.72;
  color: var(--fg-dim);
  overflow-x: auto;
  white-space: pre;
  max-height: 262px;
}
.export b { color: var(--mint); font-weight: 500; }

.demo-status {
  padding: 10px 16px;
  border-top: 1px solid var(--line);
  background: color-mix(in srgb, var(--bg-lift) 80%, transparent);
  font-size: 0.84rem;
  color: var(--fg-dim);
  min-height: 40px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.demo-status b { color: var(--mint); font-weight: 570; }

/* ══ Bands ════════════════════════════════════════════════════════════════
   The rhythm is deliberately uneven — a wide band, a narrow one, a split one.
   Three identical full-width sections of three identical cards is the shape
   this page is trying not to have.

   `content-visibility` lets the browser skip layout and paint for a section
   that is still far below the fold. `contain-intrinsic-size` gives it a
   stand-in height so skipping costs no layout shift when it scrolls in — the
   two go together, and using the first without the second is how this
   optimisation turns into a CLS problem. */

.band { padding: clamp(64px, 9vw, 108px) 0; position: relative; }
.band.deferred { content-visibility: auto; contain-intrinsic-size: auto 720px; }
.band.alt { background: color-mix(in srgb, var(--bg-soft) 60%, transparent); border-block: 1px solid var(--line); }

/* ── The three pillars, as a zigzag rather than a card row ──────────────── */

.pillars { margin-top: 46px; display: flex; flex-direction: column; gap: clamp(38px, 6vw, 76px); }
.pillar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(24px, 5vw, 64px);
  align-items: center;
}
.pillar:nth-child(even) .pillar-text { order: 2; }
@media (max-width: 820px) { .pillar { grid-template-columns: 1fr; } .pillar:nth-child(even) .pillar-text { order: 0; } }

.pillar-text h3 { font-size: clamp(1.35rem, 2.6vw, 1.9rem); letter-spacing: -0.028em; margin-bottom: 12px; }
.pillar-text p { color: var(--fg-dim); font-size: 1rem; max-width: 46ch; }
.pillar-n {
  font-family: var(--mono);
  font-size: 0.74rem;
  letter-spacing: 0.16em;
  color: var(--mint);
  display: block;
  margin-bottom: 14px;
}
.pillar:nth-child(2) .pillar-n { color: var(--violet); }
.pillar:nth-child(3) .pillar-n { color: var(--coral); }

/* Each pillar carries a small piece of the real interface rather than an icon.
   An icon says "there is a feature here"; this says what it looks like. */
.pillar-art {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--bg-soft) 80%, transparent);
  padding: 20px;
  min-height: 178px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  justify-content: center;
  font-size: 0.86rem;
  color: var(--fg-dim);
  overflow: hidden;
}
.art-row { display: flex; align-items: center; gap: 10px; }
.art-row .dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--mint); }
.art-row.d1 { padding-left: 18px; }
.art-row.d1 .dot { background: var(--violet); }
.art-row.d2 { padding-left: 36px; }
.art-row.d2 .dot { background: var(--coral); }
.art-row .why { font-size: 0.78rem; color: var(--fg-faint); font-style: italic; }
.art-row.dim { opacity: 0.4; }
.art-chip {
  align-self: flex-start;
  font-family: var(--mono);
  font-size: 0.72rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 2px 7px;
  color: var(--fg-faint);
}
.art-md { font-family: var(--mono); font-size: 0.76rem; line-height: 1.85; color: var(--fg-faint); white-space: pre; overflow: hidden; }
.art-md b { color: var(--mint); font-weight: 500; }

/* ── Privacy, as three short statements on hairlines ────────────────────── */

.statements { margin-top: 42px; display: grid; gap: 0; grid-template-columns: repeat(auto-fit, minmax(258px, 1fr)); }
.statement { padding: 26px 24px 26px 0; border-top: 2px solid var(--mint); }
.statement + .statement { padding-left: 24px; border-top-color: var(--violet); }
.statement + .statement + .statement { border-top-color: var(--coral); }
.statement h3 { margin-bottom: 10px; }
.statement p { color: var(--fg-dim); font-size: 0.93rem; margin: 0; }
@media (max-width: 820px) { .statement, .statement + .statement { padding-left: 0; padding-right: 0; } }

/* ══ Pricing ══════════════════════════════════════════════════════════════ */

.tiers { display: grid; gap: 20px; grid-template-columns: repeat(auto-fit, minmax(276px, 1fr)); margin-top: 40px; align-items: start; }
.tier {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 28px 26px;
  background: color-mix(in srgb, var(--bg-soft) 78%, transparent);
}
.tier.featured { border-color: transparent; }
/* The gradient border, drawn as a mask rather than a background so the card's
   own surface stays flat. */
.tier.featured::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
  padding: 1px;
  background: var(--thread);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
}
.tier .badge {
  position: absolute; top: -12px; left: 24px;
  background: var(--thread);
  color: var(--accent-ink);
  font-size: 0.71rem; font-weight: 680; letter-spacing: 0.04em;
  padding: 4px 11px; border-radius: 20px;
}
@media (prefers-color-scheme: light) { .tier .badge { color: #fff; } }
/* The tier name is an <h2>, because on the pricing page it is the second level
   of the document and an <h3> there skipped a level in the outline. It is still
   the size of a card heading — the outline is about structure, not type. */
.tier-name { font-size: 1.12rem; letter-spacing: -0.012em; line-height: 1.3; margin: 0; }

.price { font-size: 2.1rem; font-weight: 660; letter-spacing: -0.04em; margin: 8px 0 2px; }
.price small { font-size: 0.9rem; font-weight: 400; color: var(--fg-faint); letter-spacing: 0; }
.tier ul { list-style: none; margin: 20px 0 24px; padding: 0; display: flex; flex-direction: column; gap: 11px; }
.tier li { display: flex; gap: 11px; font-size: 0.93rem; color: var(--fg-dim); }
.tier li svg { flex: none; margin-top: 4px; color: var(--mint); }
.tier.featured li svg { color: var(--violet); }
.tier .btn { width: 100%; }

/* ══ Steps ════════════════════════════════════════════════════════════════ */

.steps { counter-reset: step; display: grid; gap: 28px; margin-top: 40px; grid-template-columns: repeat(auto-fit, minmax(236px, 1fr)); }
.step { counter-increment: step; position: relative; padding-top: 22px; border-top: 1px solid var(--line); }
.step::before {
  content: counter(step, decimal-leading-zero);
  font-family: var(--mono);
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  color: var(--mint);
  display: block;
  margin-bottom: 12px;
}
.step:nth-child(2)::before { color: var(--violet); }
.step:nth-child(3)::before { color: var(--coral); }
.step h3 { margin-bottom: 7px; }
.step p { color: var(--fg-dim); font-size: 0.93rem; margin: 0; }

/* ══ The closing line ═════════════════════════════════════════════════════ */

.closer { padding: clamp(72px, 11vw, 132px) 0; text-align: center; position: relative; }
.closer h2 { font-size: clamp(2.1rem, 6.4vw, 4.2rem); max-width: 14ch; margin-inline: auto; }
.closer .lede { margin: 22px auto 0; }
.closer .cta { justify-content: center; margin-left: 0; }

/* ══ FAQ ══════════════════════════════════════════════════════════════════ */

.faq { margin-top: 38px; display: grid; gap: 0; }
.faq details {
  border-top: 1px solid var(--line);
  padding: 18px 0;
}
.faq details:last-child { border-bottom: 1px solid var(--line); }
.faq summary {
  cursor: pointer;
  list-style: none;
  font-weight: 580;
  font-size: 1.02rem;
  letter-spacing: -0.015em;
  display: flex;
  align-items: center;
  gap: 12px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::before {
  content: '+';
  font-family: var(--mono);
  color: var(--mint);
  font-size: 1.1rem;
  line-height: 1;
  transition: transform var(--ease);
  flex: none;
}
.faq details[open] summary::before { content: '−'; }
.faq summary:focus-visible { outline: 2px solid var(--mint); outline-offset: 3px; border-radius: 6px; }
.faq p { color: var(--fg-dim); font-size: 0.95rem; margin: 12px 0 0 24px; max-width: 62ch; }

/* ══ Outcome pages ════════════════════════════════════════════════════════ */

.outcome { min-height: 76vh; display: grid; place-items: center; padding: 60px 0; }
.outcome-card {
  width: min(580px, 100% - 44px);
  text-align: center;
  background: color-mix(in srgb, var(--bg-soft) 88%, transparent);
  backdrop-filter: blur(10px);
  border: 1px solid var(--line-strong);
  border-radius: 20px;
  padding: clamp(32px, 5vw, 52px);
  box-shadow: var(--shadow);
}
.outcome-mark {
  width: 66px; height: 66px;
  margin: 0 auto 24px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--thread);
  color: var(--accent-ink);
  box-shadow: var(--glow);
}
@media (prefers-color-scheme: light) { .outcome-mark { color: #fff; } }
.outcome-card h1 { font-size: clamp(1.9rem, 4.4vw, 2.6rem); margin-bottom: 14px; }
.outcome-card .lede { margin-inline: auto; }
.outcome-card .cta { justify-content: center; margin-left: 0; }
.next {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
  text-align: left;
}
.next h2 { font-size: 0.75rem; letter-spacing: 0.13em; text-transform: uppercase; color: var(--fg-faint); margin-bottom: 14px; font-family: var(--mono); }
.next ol { margin: 0; padding-left: 20px; color: var(--fg-dim); font-size: 0.93rem; display: flex; flex-direction: column; gap: 8px; }
.ref { margin-top: 22px; font-family: var(--mono); font-size: 0.75rem; color: var(--fg-faint); word-break: break-all; }

/* ══ Footer ═══════════════════════════════════════════════════════════════ */

.site-foot { border-top: 1px solid var(--line); padding: 44px 0; }
.site-foot .wrap { display: flex; flex-wrap: wrap; gap: 14px 28px; align-items: center; }
.site-foot .small { margin: 0; }
.site-foot nav { margin-left: auto; display: flex; gap: 20px; }
.site-foot nav a { color: var(--fg-faint); font-size: 0.87rem; text-decoration: none; }
.site-foot nav a:hover { color: var(--fg); }

kbd {
  font-family: var(--mono);
  font-size: 0.86em;
  border: 1px solid var(--line-strong);
  border-bottom-width: 2px;
  border-radius: 5px;
  padding: 0 5px;
  color: var(--fg);
}

/* ══ The reveal ═══════════════════════════════════════════════════════════
   Elements marked `data-reveal` start slightly down and transparent, and the
   motion layer animates them in when they scroll into view. Two rules matter:

   The offset is a `transform`, so nothing reflows and the reveal cannot
   contribute to layout shift.

   The hidden state is applied by script, not by this stylesheet. A CSS-only
   `opacity: 0` here would leave the content invisible for anyone whose
   JavaScript never runs — a crawler, a reader-mode view, a failed request —
   which is the classic way an animated landing page becomes a blank one. */

[data-reveal].armed { opacity: 0; transform: translate3d(0, 18px, 0); }

/* ══ The legal pages ══════════════════════════════════════════════════════
   A privacy policy and a set of terms are the two pages on a site that people
   read under pressure — mid-purchase, or after something went wrong. So they
   get real typography rather than a wall: a measure that stops at 68
   characters, headings that separate without shouting, and a definition list
   for the data inventory so "what do you hold" is answered as a list of
   answers rather than as a paragraph to be waded through.

   They carry no motion, no WebGL and no reveal. Nothing here should wait on a
   script, and nobody wants a legal page that fades in at them. */
.legal h1 { font-size: clamp(2rem, 4.6vw, 3rem); letter-spacing: -0.03em; margin-bottom: 18px; }
.legal h2 {
  font-size: clamp(1.15rem, 1.9vw, 1.4rem);
  letter-spacing: -0.014em;
  margin: 52px 0 14px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
  color: var(--fg);
}
.legal p { color: var(--fg-dim); max-width: 68ch; margin: 0 0 14px; }
.legal .lede { color: var(--fg-dim); margin-bottom: 10px; }
.legal strong { color: var(--fg); font-weight: 620; }
.legal a { color: var(--mint); text-decoration: underline; text-underline-offset: 3px; }
.legal a:hover { color: var(--fg); }
.legal ul { color: var(--fg-dim); max-width: 68ch; padding-left: 20px; margin: 0 0 14px; }
.legal ul li { margin-bottom: 10px; }
.legal .mono { font-family: var(--mono); font-size: 0.94em; }

/* The data inventory. A <dl> because that is what it is: each field we hold,
   and why we hold it. The rule down the left makes it read as an itemised
   list of admissions rather than as prose that might be hiding something. */
.legal .inventory { margin: 0 0 18px; max-width: 68ch; }
.legal .inventory dt {
  color: var(--fg);
  font-weight: 620;
  margin-top: 18px;
}
.legal .inventory dd {
  color: var(--fg-dim);
  margin: 5px 0 0;
  padding-left: 14px;
  border-left: 2px solid var(--line-strong);
  font-size: 0.95rem;
}

/* ══ Per-platform instructions ════════════════════════════════════════════
   The shortcut is the same keystroke everywhere, but on a Mac it is printed on
   the key as Option, which is not a detail somebody should have to know to
   open the thing they just installed. */
/* A <dl>, and stacked rather than in two columns: the step sits in a third of
   the page, and a label wide enough for "Windows, Linux, ChromeOS" beside the
   keys pushed the last key onto its own line. Keeping the sentence that
   explains them out of this block matters too — as flex items, its words were
   laid out as keycaps' siblings and the sentence came apart. */
.platform { margin: 0 0 14px; }
.platform dt {
  color: var(--fg-faint);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-top: 12px;
}
.platform dd {
  margin: 5px 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
}
.platform .plus { color: var(--fg-faint); font-size: 0.8rem; }
.step em { color: var(--fg); font-style: normal; font-weight: 600; }
.step .mono { font-family: var(--mono); font-size: 0.86em; color: var(--fg); overflow-wrap: anywhere; }


/* Step two now says three separate things — the keys, why they are the same
   keys, and what to do if neither works — so its paragraphs need to read as
   three, not as one that ran on. */
.step p + p { margin-top: 11px; }

/* The price under the tier name. `price-alt` is the yearly option stated as a
   real comparison rather than as "save 20%!": $44.99 against twelve months at
   $3.99 is $2.89, and a page that rounds that up is a page that lies about a
   number somebody can check. */
.price-alt {
  margin: -8px 0 14px;
  font-size: 0.88rem;
  color: var(--fg-faint);
  font-variant-numeric: tabular-nums;
}

/* ══ The gestures ═════════════════════════════════════════════════════════
   Four small stages that play a gesture instead of describing it.

   Every stage is the same object: a stylised browser window, a cursor, and
   one thing that appears. Keeping the furniture identical across the four is
   what lets the differences between them read at a glance.

   The animation rules are the same as everywhere else on this page and are
   pinned by tests: transform and opacity only, so nothing can reflow and the
   compositor can run it off the main thread; nothing loops on its own, so an
   idle tab costs nothing; and `prefers-reduced-motion` gets the finished state
   with no movement at all. */

.platform-switch {
  margin: 30px 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}
.ps-label {
  font-size: 0.72rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--fg-faint);
}
.ps-buttons {
  display: inline-flex;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  padding: 3px;
  gap: 3px;
}
.ps-btn {
  font: inherit;
  font-size: 0.82rem;
  padding: 5px 14px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--fg-dim);
  cursor: pointer;
  transition: color var(--ease), background var(--ease);
}
.ps-btn:hover { color: var(--fg); }
.ps-btn[aria-checked="true"] { background: var(--accent); color: var(--accent-ink); font-weight: 600; }
.ps-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.gestures {
  margin-top: 26px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 16px;
}

.gesture {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--bg-soft) 74%, transparent);
  padding: 14px 16px 18px;
  transition: border-color var(--ease), transform var(--ease);
  cursor: default;
}
.gesture:hover, .gesture:focus-visible { border-color: var(--line-strong); transform: translate3d(0, -1px, 0); }
.gesture:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.gesture h3 { margin: 10px 0 4px; font-size: 1rem; line-height: 1.35; }
.gesture .gsub { margin: 0; color: var(--fg-faint); font-size: 0.86rem; }
.gesture .keys {
  margin: 12px 0 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
}
.gesture .keys kbd { font-size: 0.72rem; }
.gesture .keys .plus { color: var(--fg-faint); font-size: 0.76rem; }
.gesture .keys .verb {
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-faint);
}

/* ── The stage ───────────────────────────────────────────────────────────
   A fixed aspect ratio, so the section's height is known before anything is
   painted and the reveal cannot shift the page. */
.stage {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: 10px;
  overflow: hidden;
  background: var(--bg-lift);
  border: 1px solid var(--line);
}
.win { position: absolute; inset: 0; }
.win-bar {
  height: 16px;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0 8px;
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--bg) 55%, transparent);
}
.win-bar i { width: 5px; height: 5px; border-radius: 50%; background: var(--line-strong); }
.win-body { padding: 14px 12px; display: flex; flex-direction: column; gap: 8px; }

/* Grey bars standing in for text. Never real words: a stage full of lorem is
   something to read, and the point is to watch the gesture. */
.ln { height: 5px; border-radius: 3px; background: var(--line-strong); opacity: 0.55; }
.ln.w80 { width: 80%; }
.ln.w60 { width: 60%; }
.lnk {
  height: 5px;
  width: 52%;
  border-radius: 3px;
  background: var(--accent);
  opacity: 0.85;
  font-size: 0; /* the text is for a screen reader that will never see it */
}
.ln.sel {
  width: 46%;
  height: 9px;
  margin: -2px 0;
  border-radius: 2px;
  background: var(--violet);
  opacity: 0;
  font-size: 0;
  transform-origin: left center;
  transform: scaleX(0);
}

/* Where the pointer comes to rest, per stage: on the link it is hovering, on
   the words it has just selected, on the link it is about to Shift-click. A
   single shared position had it resting on empty page in three of the four. */
.gesture[data-gesture="hover"] .stage { --cx: 30%; --cy: 47%; }
.gesture[data-gesture="select"] .stage { --cx: 34%; --cy: 40%; }
.gesture[data-gesture="split"] .stage { --cx: 26%; --cy: 47%; }

.cursor {
  position: absolute;
  left: var(--cx, 20%); top: var(--cy, 60%);
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--fg);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--fg) 22%, transparent);
  opacity: 0;
  will-change: transform, opacity;
}

/* The link-preview card. */
.pop {
  position: absolute;
  left: 12%; top: 56%;
  width: 76%;
  padding: 7px 8px;
  border-radius: 7px;
  border: 1px solid var(--line-strong);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  gap: 3px;
  opacity: 0;
  transform: translate3d(0, 6px, 0) scale(0.97);
  transform-origin: top left;
  will-change: transform, opacity;
}
.pop-t { font-size: 0.6rem; font-weight: 640; color: var(--fg); }
.pop-u { font-size: 0.52rem; font-family: var(--mono); color: var(--fg-faint); overflow: hidden; white-space: nowrap; }
.pop-b {
  margin-top: 2px;
  align-self: flex-start;
  font-size: 0.55rem;
  font-weight: 600;
  padding: 3px 7px;
  border-radius: 5px;
  background: var(--accent);
  color: var(--accent-ink);
}

/* The selection arc. */
.arc { position: absolute; left: 34%; top: 40%; width: 0; height: 0; }
.arc-b {
  position: absolute;
  color: var(--fg);
  width: 20px; height: 20px;
  margin: -10px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: var(--bg);
  display: grid;
  place-items: center;
  font-size: 9px;
  opacity: 0;
  will-change: transform, opacity;
}
.arc-b.a1 { --x: -26px; --y: -18px; }
.arc-b.a2 { --x: 0px;   --y: -30px; }
.arc-b.a3 { --x: 26px;  --y: -18px; }

/* The split pane. */
.pane {
  position: absolute;
  right: 0; top: 16px; bottom: 0;
  width: 46%;
  padding: 12px 10px;
  border-left: 1px solid var(--line-strong);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  gap: 7px;
  transform: translate3d(100%, 0, 0);
  will-change: transform;
}
.pane-bar { height: 8px; display: flex; align-items: center; }
.pane-bar i { width: 22px; height: 3px; border-radius: 2px; background: var(--violet); }

/* The dock at the edge. */
.dock {
  position: absolute;
  right: 0; top: 16px; bottom: 0;
  width: 38%;
  padding: 10px 8px;
  border-left: 1px solid var(--line-strong);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  gap: 7px;
  transform: translate3d(100%, 0, 0);
  will-change: transform;
}
.dk { height: 5px; border-radius: 3px; opacity: 0.9; }
.dk.t1 { width: 86%; background: var(--mint); }
.dk.t2 { width: 66%; background: var(--violet); margin-left: 10%; }
.dk.t3 { width: 52%; background: var(--coral); margin-left: 10%; }
.dk.t4 { width: 74%; background: var(--amber); }

/* ── Playing ─────────────────────────────────────────────────────────────
   One class, added when the card comes into view and re-added on hover, focus
   or tap. Removing it resets every animation, which is what makes a replay a
   replay rather than a stutter. */
.gesture.play .cursor { animation: cursor-in 2.4s var(--ease) forwards; }
.gesture[data-gesture="hover"].play .pop { animation: pop-in 2.4s var(--ease) forwards; }
.gesture[data-gesture="select"].play .ln.sel { animation: select-in 2.4s var(--ease) forwards; }
.gesture[data-gesture="select"].play .arc-b { animation: arc-in 2.4s var(--ease) forwards; }
.gesture[data-gesture="select"].play .arc-b.a2 { animation-delay: 60ms; }
.gesture[data-gesture="select"].play .arc-b.a3 { animation-delay: 120ms; }
.gesture[data-gesture="split"].play .pane { animation: slide-in 2.4s var(--ease) forwards; }
.gesture[data-gesture="dock"].play .dock { animation: slide-in 2.4s var(--ease) forwards; }

@keyframes cursor-in {
  0%   { opacity: 0; transform: translate3d(0, 26px, 0); }
  18%  { opacity: 1; transform: translate3d(0, 14px, 0); }
  42%  { opacity: 1; transform: translate3d(6px, 0, 0); }
  86%  { opacity: 1; transform: translate3d(6px, 0, 0); }
  100% { opacity: 0; transform: translate3d(6px, 0, 0); }
}
@keyframes pop-in {
  0%, 40%  { opacity: 0; transform: translate3d(0, 6px, 0) scale(0.97); }
  56%      { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
  88%      { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
  100%     { opacity: 0; transform: translate3d(0, 2px, 0) scale(0.99); }
}
@keyframes select-in {
  0%, 24%  { opacity: 0; transform: scaleX(0); }
  44%      { opacity: 0.75; transform: scaleX(1); }
  92%      { opacity: 0.75; transform: scaleX(1); }
  100%     { opacity: 0; transform: scaleX(1); }
}
@keyframes arc-in {
  0%, 46%  { opacity: 0; transform: translate3d(0, 0, 0) scale(0.6); }
  62%      { opacity: 1; transform: translate3d(var(--x), var(--y), 0) scale(1); }
  88%      { opacity: 1; transform: translate3d(var(--x), var(--y), 0) scale(1); }
  100%     { opacity: 0; transform: translate3d(var(--x), var(--y), 0) scale(0.9); }
}
@keyframes slide-in {
  0%, 34%  { transform: translate3d(100%, 0, 0); }
  58%      { transform: translate3d(0, 0, 0); }
  90%      { transform: translate3d(0, 0, 0); }
  100%     { transform: translate3d(100%, 0, 0); }
}

/* With motion turned down, every stage simply shows its finished state. There
   is no animation to slow to nothing, because there is none running. */
@media (prefers-reduced-motion: reduce) {
  .gesture .pop, .gesture .arc-b { opacity: 1; transform: none; }
  .gesture .arc-b.a1 { transform: translate3d(-26px, -18px, 0); }
  .gesture .arc-b.a2 { transform: translate3d(0, -30px, 0); }
  .gesture .arc-b.a3 { transform: translate3d(26px, -18px, 0); }
  .gesture .ln.sel { opacity: 0.75; transform: scaleX(1); }
  .gesture .pane, .gesture .dock { transform: none; }
  .gesture .cursor { opacity: 1; transform: translate3d(6px, 0, 0); }
}

.gestures-more {
  margin-top: 30px;
  color: var(--fg-dim);
  font-size: 0.95rem;
  max-width: 60ch;
}
.gestures-more a { color: var(--accent); text-decoration: none; font-weight: 560; white-space: nowrap; }
.gestures-more a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* Breadcrumbs, on the pages deep enough to need them. */
.crumbs { font-size: 0.8rem; color: var(--fg-faint); margin: 0 0 14px; }
.crumbs a { color: var(--fg-dim); text-decoration: none; }
.crumbs a:hover { color: var(--fg); text-decoration: underline; text-underline-offset: 3px; }
.whatis-cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 40px; }
