/* ============================================================
   TestDossier — design system for marketing & public surfaces.
   Single source of truth for tokens, typography, components.
   ============================================================ */

/* Shared design foundation — the SAME tokens the app consumes (radius roles,
   motion, accent-ring, type scale). @import must precede all rules. The :root
   below keeps marketing's native values for any overlap; foundation only adds
   what marketing lacked. See docs/DESIGN-SYSTEM.md. */
@import "foundation.css";

:root {
  /* Cool slate neutrals and one indigo signal. */
  --bg: #f8fafb;
  --surface: #ffffff;
  --surface-2: #eeeff2;
  --surface-3: #e2e4e9;
  --border: #e2e4e9;
  --border-strong: #ced2d9;
  /* Border for interactive controls (ghost buttons, inputs). Distinct from
     --border-strong, which delimits STRUCTURE and may stay light. A control's
     boundary must clear 3:1 on every surface it lands on (page, card, band)
     per WCAG 1.4.11 — --border-strong measured 1.32:1. */
  --control-border: #7e8794;
  --text: #171c26;
  --text-2: #424955;
  --text-3: #5d6471;   /* was #616875 — 4.41:1 on --surface-3 */
  --text-4: #5f6672;   /* was #9298a3 — 2.77:1 on --bg; clears 4.5:1 on every light surface */

  /* Ink-button fill, split from --text so button glare can be tuned without
     touching typography. Hover/active shift VALUE toward the ground, never
     hue — indigo stays reserved for links and state. */
  --btn-ink: var(--text);
  --btn-ink-hover: color-mix(in srgb, var(--text) 85%, var(--bg));
  --btn-ink-active: color-mix(in srgb, var(--text) 76%, var(--bg));

  /* Indigo behaves like an annotation mark: action and state, not decor. */
  --accent: #4335de;
  --accent-text: #4335de;
  --accent-hover: #3a1ccf;
  --accent-active: #3201be;
  --accent-soft: #eceffe;
  --accent-ring: #4335de;
  --accent-glow: transparent;
  --accent-on: #ffffff;

  /* Semantic */
  --success: #247b52;
  --success-soft: #e8f7f0;
  --danger: #ce2222;
  --danger-soft: #fdeded;
  --warning: #a4590e;
  --warning-soft: #fdf1dd;

  /* Typography */
  --font-sans: "InterVariable", "Inter", -apple-system, BlinkMacSystemFont,
    "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --font-mono: "JetBrains Mono", "SF Mono", "Menlo", "Consolas",
    ui-monospace, monospace;
  --feat: "cv02", "cv03", "cv04", "cv11", "ss01";

  /* Type scale — modular, capped at 64 for h1 */
  --text-xs: 12px;
  --text-sm: 13px;
  --text-base: 15px;
  --text-md: 16px;
  --text-lg: 18px;
  --text-xl: 20px;
  --text-2xl: 24px;
  --text-3xl: 32px;
  --text-4xl: 40px;
  --text-5xl: 56px;
  --text-6xl: 64px;

  /* Line heights paired with sizes for vertical rhythm */
  --lh-tight: 1.1;
  --lh-snug: 1.25;
  --lh-base: 1.5;
  --lh-loose: 1.7;

  /* Spacing — 4px base, geometric */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 20px;
  --s-6: 24px;
  --s-8: 32px;
  --s-10: 40px;
  --s-12: 48px;
  --s-16: 64px;
  --s-20: 80px;
  --s-24: 96px;
  --s-32: 128px;

  /* Radii */
  --r-sm: 3px;
  --r: 5px;
  --r-md: 6px;
  --r-lg: 8px;
  --r-xl: 10px;
  --r-full: 999px;

  /* Shadows — layered for depth without heaviness */
  --shadow-xs: 0 1px 2px rgba(23, 28, 38, 0.05);
  --shadow-sm: 0 1px 2px rgba(23, 28, 38, 0.05), 0 1px 3px rgba(23, 28, 38, 0.04);
  --shadow: 0 2px 6px rgba(23, 28, 38, 0.07);
  --shadow-md: 0 4px 8px -2px rgba(23, 28, 38, 0.08), 0 2px 4px -2px rgba(23, 28, 38, 0.05);
  --shadow-lg: 0 12px 28px -6px rgba(23, 28, 38, 0.14), 0 6px 12px -6px rgba(23, 28, 38, 0.08);

  /* Transitions */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out: cubic-bezier(0.0, 0, 0.2, 1);
  --t-fast: 120ms;
  --t: 200ms;
  --t-slow: 320ms;

  /* Layout */
  --content-w: 1140px;
  --prose-w: 720px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #12151c;
    --surface: #1c1f27;
    --surface-2: #22262f;
    --surface-3: #303540;
    --border: #272c34;
    --border-strong: #393f4c;
  --control-border: #767e8c;
    --control-border: #767e8c;
    --text: #f3f4f7;
    --text-2: #c7cad1;
    --text-3: #929aaa;
    --text-4: #68707e;
    /* Same indigo the app (--primary) and the extension panel use in dark, so a
       CTA next to a screenshot of either reads as one product. Filled actions
       stay white; text takes --accent-text, the DARKEST value still clearing
       4.5:1 on --surface (the tightest ground it lands on). Kept close to
       --accent on purpose: a wider gap reads as a second purple. */
    /* Hue-locked to OKLCH 275.6deg — the hue of #4335de. The shipping ramp
       drifted 271.6->288.9deg across its five steps, which is why light and
       dark read as two different purples. Lightness and chroma move; hue does
       not. Changing these three values REQUIRES the same change in
       extension/assets/tokens.css — tests/e2e/design-system-consistency.spec.ts
       pins them together. */
    --accent: #727ffe;
    --accent-text: #8c9bff;
    --accent-hover: #8493ff;
    --accent-active: #97a6fe;
    --accent-soft: #1a1e46;
    --accent-ring: #727ffe;
    --accent-glow: transparent;
    --accent-on: #ffffff;
    --success: #40bf84;
    --success-soft: #1b372a;
    --danger: #e96363;
    --danger-soft: #431919;
    --warning: #f4a734;
    --warning-soft: #3d2d14;
    --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.4);
    --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.4),
                 0 1px 3px 0 rgba(0, 0, 0, 0.3);
    --shadow:    0 2px 4px -1px rgba(0, 0, 0, 0.45),
                 0 4px 6px -2px rgba(0, 0, 0, 0.3);
    --shadow-md: 0 4px 6px -2px rgba(0, 0, 0, 0.5),
                 0 10px 15px -3px rgba(0, 0, 0, 0.35);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.55),
                 0 20px 25px -5px rgba(0, 0, 0, 0.4);
  }
}

[data-theme="dark"] {
  --bg: #12151c;
  --surface: #1c1f27;
  --surface-2: #22262f;
  --surface-3: #303540;
  --border: #272c34;
  --border-strong: #393f4c;
  --control-border: #767e8c;
  --text: #f3f4f7;
  --text-2: #c7cad1;
  --text-3: #929aaa;
  --text-4: #68707e;
  /* Mirrors the prefers-color-scheme block above. */
  --accent: #727ffe;
  --accent-text: #8c9bff;
  --accent-hover: #8493ff;
  --accent-active: #97a6fe;
  --accent-soft: #1a1e46;
  --accent-ring: #727ffe;
  --accent-glow: transparent;
  --accent-on: #ffffff;
  --success: #40bf84;
  --success-soft: #1b372a;
  --danger: #e96363;
  --danger-soft: #431919;
  --warning: #f4a734;
  --warning-soft: #3d2d14;
  --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.4);
  --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.4),
               0 1px 3px 0 rgba(0, 0, 0, 0.3);
  --shadow:    0 2px 4px -1px rgba(0, 0, 0, 0.45),
               0 4px 6px -2px rgba(0, 0, 0, 0.3);
  --shadow-md: 0 4px 6px -2px rgba(0, 0, 0, 0.5),
               0 10px 15px -3px rgba(0, 0, 0, 0.35);
  --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.55),
               0 20px 25px -5px rgba(0, 0, 0, 0.4);
}

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-feature-settings: var(--feat);
  font-size: var(--text-base);
  line-height: var(--lh-base);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* Defense against any element accidentally overflowing the viewport
     (transforms, large mocks, long unbreakable strings). Triggers a
     hard stop at viewport width — content can't push horizontal scroll. */
  overflow-x: hidden;
}
*, *::before, *::after { box-sizing: border-box; }
img, svg { max-width: 100%; }

@supports (font-variation-settings: normal) {
  body { font-family: "InterVariable", var(--font-sans); }
}

::selection { background: var(--accent-soft); color: var(--text); }

a { color: var(--accent); text-decoration: none; transition: color var(--t-fast) var(--ease-out); }
a:hover { color: var(--accent-hover); }

p { margin: 0 0 var(--s-4); }
p:last-child { margin-bottom: 0; }

/* Inline code token — curl, add_run, X-CI-Run-Id etc. read as code,
   not body text. Matches the SF-Mono chip used inline elsewhere. */
code {
  font-family: var(--font-mono);
  font-size: 0.86em;
  background: var(--surface-2);
  color: var(--text-2);
  padding: 1px 6px;
  border-radius: 4px;
  border: 1px solid var(--border);
  white-space: nowrap;
}

h1, h2, h3, h4 {
  margin: 0 0 var(--s-4);
  font-weight: 700;
  letter-spacing: -0.022em;
  line-height: var(--lh-tight);
  color: var(--text);
}
/* Dynamic (fluid) heading typography — scales smoothly between mobile
   and desktop instead of stepping at static breakpoints. The static
   --text-* tokens stay available for body / micro / KPI use; headings
   use clamp() so the page feels right at every width without a media-
   query cascade. Min values are mobile-floor, max values match the old
   desktop tokens (5xl=56, 3xl=32, xl=20, md=16). */
h1 { font-size: clamp(28px, 4.6vw + 12px, 56px); letter-spacing: -0.034em; }
h2 { font-size: clamp(20px, 1.6vw + 14px, 32px); letter-spacing: -0.024em; }
h3 { font-size: clamp(15px, 0.6vw + 13px, 20px); letter-spacing: -0.014em; }
h4 { font-size: var(--text-md); letter-spacing: -0.01em; }

/* Container */
.container {
  width: 100%;
  max-width: var(--content-w);
  margin: 0 auto;
  padding: 0 var(--s-6);
}
.container--prose { max-width: var(--prose-w); }

/* ============================================================
   Header / nav
   ============================================================ */
.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: 1000;
  isolation: isolate;
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border-bottom: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
  box-shadow: 0 10px 30px color-mix(in srgb, var(--text) 4%, transparent);
}
/* Dark mode: near-opaque — the saturated accent wash on the share-page
   hero bleeds through aggressively. */
[data-theme="dark"] .site-header {
  background: color-mix(in srgb, var(--bg) 96%, transparent);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .site-header {
    background: color-mix(in srgb, var(--bg) 96%, transparent);
  }
}
.site-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 68px;
}
.site-logo {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.01em;
  color: var(--text);
}
.site-logo:hover { color: var(--text); }
.site-logo svg,
.site-logo img { display: block; flex: none; width: 28px; height: 28px; }
/* Joined wordmark: lighten "Test", keep "Dossier" heavy so the
   one-word "TestDossier" still parses as two at the camel-case seam. */
.brand-wordmark { font-weight: 500; }
.brand-wordmark b { font-weight: 800; }
.site-nav__links {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
.site-nav__links a {
  padding: var(--s-2) var(--s-3);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--text-2);
  border-radius: var(--r);
  transition: background var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out);
}
.site-nav__links a:hover { background: var(--surface-2); color: var(--text); }
.site-nav__links > a:is(.is-current, [aria-current="page"]):not(.is-cta) {
  color: var(--text);
  background: var(--surface-2);
}
.site-nav__links a.is-cta {
  background: var(--btn-ink, var(--text));
  color: var(--bg);
  padding: var(--s-2) var(--s-4);
  font-weight: 600;
}
.site-nav__links a.is-cta:hover {
  /* Follows the shared primary rule — this selector outranks it, so it must
     restate the same ink hover or it silently forks the contract. */
  background: var(--btn-ink-hover, var(--text));
  border-color: var(--btn-ink-hover, var(--text));
  color: var(--bg);
}
.marketing-language-shell {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 116px;
  height: 32px;
  padding: 0 25px 0 9px;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--text-2);
  font: 500 var(--text-xs)/1 var(--font-sans);
  cursor: pointer;
  transition: border-color var(--t-fast), background var(--t-fast), color var(--t-fast), box-shadow var(--t-fast);
}
.marketing-language-shell:hover { color: var(--text); background: var(--surface-2); }
.marketing-language-shell:focus-within {
  border-color: var(--primary);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 18%, transparent);
}
.marketing-language-shell__icon,
.marketing-language-shell__chevron { flex: none; pointer-events: none; }
.marketing-language-shell__current { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.marketing-language-shell__chevron { position: absolute; inset-inline-end: 8px; top: 50%; transform: translateY(-50%); }
.marketing-language {
  position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer;
}
.site-nav-more { display: none; position: relative; z-index: 1; }
.site-nav-more > summary {
  width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: var(--r); color: var(--text-2);
  background: var(--surface); cursor: pointer; list-style: none;
}
.site-nav-more > summary::-webkit-details-marker { display: none; }
.site-nav-more[open] > summary { background: var(--surface-2); color: var(--text); }
.site-nav-more__panel {
  position: absolute; inset-inline-end: 0; top: calc(100% + 10px); z-index: 3;
  width: min(272px, calc(100vw - 24px)); padding: 8px;
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: color-mix(in srgb, var(--surface) 96%, transparent);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  box-shadow: 0 18px 50px color-mix(in srgb, var(--text) 14%, transparent);
  max-height: calc(100dvh - 84px);
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  transform-origin: top right;
  animation: site-nav-menu-in 140ms var(--ease-out);
}
.site-nav-more__panel > a {
  display: flex; align-items: center; min-height: 42px; padding: 8px 10px;
  border-radius: var(--r); color: var(--text); font-size: var(--text-sm); font-weight: 600;
}
.site-nav-more__panel > a:hover { background: var(--surface-2); }
.site-nav-more__panel > a[aria-current="page"] {
  color: var(--accent-text);
  background: var(--accent-soft);
}
.site-nav-more__label {
  padding: 10px 10px 6px; border-top: 1px solid var(--border); margin-top: 4px;
  color: var(--text-3); font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
}
.site-nav-more__prefs { display: grid; grid-template-columns: minmax(0, 1fr) 38px; gap: 8px; padding: 4px; }
.site-nav-more__prefs .marketing-language-shell { width: 100%; height: 36px; }
.site-nav-more__prefs .theme-toggle { width: 36px; height: 36px; }

@keyframes site-nav-menu-in {
  from { opacity: 0; transform: translateY(-4px) scale(.985); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

/* Shared theme-toggle button (used in site-header across marketing,
   share, app surfaces). The <button> wraps two <svg> icons; theme.js
   shows the one that matches the OPPOSITE of the current theme so
   clicking flips to it. */
.theme-toggle {
  width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r);
  color: var(--text-2);
  cursor: pointer;
  transition: background var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out);
  padding: 0;
}
.theme-toggle:hover {
  background: var(--surface-2);
  color: var(--text);
  border-color: var(--border-strong);
}
.theme-toggle:focus-visible {
  outline: 2px solid var(--accent-ring);
  outline-offset: 2px;
}

@media (max-width: 540px) {
  .site-nav { height: 56px; }
  .site-nav__links { gap: 6px; }
  .site-nav__desktop-only { display: none !important; }
  .site-nav-more { display: block; }
  /* Primary mobile navigation controls need a real touch target, not merely a
     visually compact label. The 44px boxes still fit comfortably inside the
     56px header and meet the common touch-target floor. */
  .site-nav__links a.is-cta {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 14px;
    font-size: var(--text-xs);
  }
  .site-nav-more > summary {
    width: 44px;
    height: 44px;
  }
  .site-nav-more__panel > a { min-height: 44px; }
  .site-nav-more__prefs {
    grid-template-columns: minmax(0, 1fr) 44px;
  }
  .site-nav-more__prefs .marketing-language-shell,
  .site-nav-more__prefs .theme-toggle {
    height: 44px;
  }
  .site-nav-more__prefs .theme-toggle { width: 44px; }
  .site-nav-more__panel {
    position: fixed;
    inset: 64px 12px auto;
    width: auto;
    max-height: calc(100dvh - 76px);
  }
  .site-nav-more[open]::before {
    content: "";
    position: fixed;
    inset: 56px 0 0;
    z-index: 2;
    background: color-mix(in srgb, var(--bg) 48%, transparent);
    pointer-events: none;
  }
  .site-nav-more[open] > summary { position: relative; z-index: 4; }
}
@media (max-width: 360px) {
  .site-logo .brand-wordmark { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .site-nav-more__panel { animation: none; }
}

/* ============================================================
   Buttons
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  height: 40px;
  padding: 0 var(--s-5);
  border-radius: var(--radius-control);
  border: 1px solid transparent;
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: -0.005em;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition:
    background var(--t-fast) var(--ease-out),
    border-color var(--t-fast) var(--ease-out),
    color var(--t-fast) var(--ease-out),
    transform var(--t-fast) var(--ease-out),
    box-shadow var(--t-fast) var(--ease-out);
  white-space: nowrap;
  user-select: none;
}
/* Unified soft focus ring — identical to the app's .btn / .field ring. */
.btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--accent-ring); }
.btn--lg { height: 48px; padding: 0 var(--s-6); font-size: var(--text-md); }
.btn--sm { height: 32px; padding: 0 var(--s-3); font-size: var(--text-xs); }
.btn--block { width: 100%; }

/* Primary actions are INK, not indigo, on every surface.

   Calm is the goal. Three things were making the button loud: an accent fill
   competing with every other accent on the page, a two-layer inset sheen that
   reads as 2013 skeuomorphism, and a 1px hover lift that makes the page twitch
   under the cursor. All three are gone. Hover shifts value WITHIN the ink,
   never hue — an indigo hover on every primary is decoration through the back
   door, and the hue flip makes the page twitch as much as the old lift did. */
.btn--accent, .btn-primary {
  background: var(--btn-ink, var(--text));
  color: var(--bg);
  box-shadow: none;
}
.btn--accent:hover, .btn-primary:hover {
  background: var(--btn-ink-hover, var(--text));
  color: var(--bg);
  box-shadow: none;
}
.btn--accent:active, .btn-primary:active {
  background: var(--btn-ink-active, var(--text));
  box-shadow: none;
}

.btn--secondary, .btn-secondary {
  background: var(--surface);
  color: var(--text);
  border-color: var(--control-border);
}
.btn--secondary:hover, .btn-secondary:hover {
  background: var(--surface-2);
  border-color: var(--border-strong);
  color: var(--text);
}

.btn--ghost, .btn-ghost {
  background: transparent;
  color: var(--text-2);
}
.btn--ghost:hover, .btn-ghost:hover { background: var(--surface-2); color: var(--text); }

/* Danger — additive. Marketing CTAs don't use it, but shared/React components
   that emit .btn-danger must still resolve correctly on public pages. */
.btn--danger, .btn-danger { background: var(--danger); color: #fff; box-shadow: var(--shadow-sm); }
.btn--danger:hover, .btn-danger:hover { filter: brightness(0.93); }
/* Quiet destructive — destructive secondary actions, calm at rest. */
.btn-danger-soft { background: var(--danger-soft); color: var(--danger); border-color: transparent; }
.btn-danger-soft:hover { background: var(--danger); color: #fff; }

/* ============================================================
   Inputs
   ============================================================ */
.input,
.select,
.textarea {
  width: 100%;
  height: 40px;
  padding: 0 var(--s-3);
  border-radius: var(--r);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  font-family: inherit;
  font-size: var(--text-sm);
  line-height: 1.4;
  transition: border-color var(--t-fast) var(--ease-out),
              box-shadow var(--t-fast) var(--ease-out);
}
.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}
.textarea { padding: var(--s-2) var(--s-3); height: auto; min-height: 96px; resize: vertical; }
.input::placeholder, .textarea::placeholder { color: var(--text-3); }

/* ============================================================
   Cards / surfaces
   ============================================================ */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
}
.card--padded { padding: var(--s-6); }
.card--clickable { cursor: pointer; transition: border-color var(--t) var(--ease), box-shadow var(--t) var(--ease), transform var(--t) var(--ease); }
.card--clickable:hover { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }

.kicker {
  display: inline-flex;
  /* flex-start (not center) so the icon stays anchored to the first
     line of text when the label wraps to 2 lines on narrow viewports.
     The translateY nudge re-aligns it to the text's cap-height. */
  align-items: flex-start;
  gap: var(--s-2);
  padding: 4px 10px;
  border-radius: var(--r-full);
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--text-2);
  letter-spacing: 0;
  line-height: 1.4;
}
.kicker svg { flex: none; transform: translateY(2px); }
.kicker--accent {
  background: var(--accent-soft);
  border-color: transparent;
  color: var(--accent);
}
/* Three-stage flow kicker: Capture → Connect CI → Sign off. Reads as the
   product pipeline. Centered (overrides the base flex-start meant for a
   single wrapping label) and allowed to wrap segment-by-segment on narrow
   viewports rather than breaking mid-segment. */
.kicker--flow {
  align-items: center;
  flex-wrap: wrap;
  row-gap: var(--s-1);
  font-weight: 600;
}
.kicker--flow svg { transform: none; }
.kicker__step { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.kicker__sep { opacity: .45; font-weight: 400; }

/* ============================================================
   Pricing-card primitives
   ============================================================ */
.plan {
  display: flex;
  flex-direction: column;
  padding: var(--s-8);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
  /* Center the header zone (name + price + billed + toggle) and CTA. The
     feature list overrides this back to left-aligned so the checkmark
     column stays consistent. Standard pricing-card pattern. */
  text-align: center;
}
.plan--featured {
  border-color: var(--accent);
  background: var(--surface);
  box-shadow: var(--shadow);
  position: relative;
}
.plan--featured::after {
  content: "Most popular";
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--accent);
  color: white;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 4px 12px;
  border-radius: var(--r-full);
  white-space: nowrap;
  box-shadow: none;
}
.plan__name { font-size: var(--text-sm); text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-3); font-weight: 600; }
.plan__price { font-size: var(--text-5xl); font-weight: 700; letter-spacing: -0.026em; line-height: 1; margin-top: var(--s-3); }
.plan__price small { font-size: var(--text-md); color: var(--text-3); font-weight: 500; }
.plan__billed { font-size: var(--text-sm); color: var(--text-3); margin-top: var(--s-2); min-height: 20px; }
.plan__features { list-style: none; padding: 0; margin: var(--s-6) 0; flex: 1; display: block; text-align: left; }
/* Block layout with floated icon — content after the SVG is regular
   inline flow, so any number of <strong>s, <span>s, plain text, or
   <small>s all wrap as a single line of text without splitting into
   columns. Each li gets its own row via display:block + margin. */
.plan__features li { display: block; padding-left: 26px; position: relative; font-size: var(--text-sm); color: var(--text-2); line-height: 1.55; margin-bottom: var(--s-3); }
.plan__features li:last-child { margin-bottom: 0; }
.plan__features li.muted { color: var(--text-3); }
.plan__features li > svg { position: absolute; left: 0; top: 5px; color: var(--success); }
.plan__features li.muted > svg { color: var(--text-4); }

/* Post-CTA footer wrapper. Each tile's trust messaging (guarantee
   line + fineprint) lives in here; the min-height clamps every
   tile's footer to the tallest natural one, so all three CTA
   buttons land on the same row regardless of how much trust copy
   each tile carries. Without this, Team's 3-line wrapped fineprint
   would push its CTA higher than Free's and Pro's. */
.plan__footer {
  margin-top: var(--s-3);
  min-height: 64px;
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}
/* Children carry inline margin-top from the legacy (un-wrapped) layout —
   override since the flex `gap` now handles spacing inside the wrapper. */
.plan__footer > * {
  margin-top: 0 !important;
}

/* ============================================================
   Long-form documents
   ============================================================ */
.doc {
  padding: clamp(var(--s-10), 7vw, var(--s-16)) 0 var(--s-16);
}
.doc h1 {
  max-width: 16ch;
  margin-bottom: var(--s-3);
  font-size: clamp(32px, 5vw, 48px);
}
.doc__updated {
  margin-bottom: var(--s-6);
  color: var(--text-3);
  font-size: var(--text-sm);
}
.doc__summary {
  margin-bottom: var(--s-6);
  padding: var(--s-6);
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-card, var(--r-lg));
  background: var(--surface);
  box-shadow: none;
}
.doc__summary p {
  margin: 0;
  color: var(--text);
  font-size: var(--text-md);
  line-height: 1.65;
}
.doc__toc {
  margin-bottom: var(--s-12);
  padding: var(--s-5);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface-2);
}
.doc__toc-label {
  display: block;
  margin-bottom: var(--s-3);
  color: var(--text-3);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.doc__toc-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-2) var(--s-4);
}
.doc__toc a {
  min-width: 0;
  padding: 6px 8px;
  border-radius: var(--r);
  color: var(--text-2);
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1.4;
}
.doc__toc a:hover {
  color: var(--accent);
  background: var(--surface);
}
.doc__body h2 {
  scroll-margin-top: var(--s-6);
  margin-top: var(--s-12);
  margin-bottom: var(--s-3);
  padding-top: var(--s-6);
  border-top: 1px solid var(--border);
  font-size: var(--text-xl);
}
.doc__body h2:first-of-type {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
.doc__body p,
.doc__body ul {
  color: var(--text-2);
  font-size: var(--text-base);
  line-height: var(--lh-loose);
}
.doc__body p {
  margin-bottom: var(--s-4);
}
.doc__body ul {
  margin: 0 0 var(--s-5);
  padding-left: var(--s-5);
}
.doc__body li {
  margin-bottom: var(--s-2);
  padding-left: var(--s-1);
}
.doc__body a {
  font-weight: 600;
  text-underline-offset: 3px;
}

@media (max-width: 640px) {
  .doc {
    padding-top: var(--s-10);
  }
  .doc__summary {
    padding: var(--s-5);
    border-radius: var(--r-lg);
  }
  .doc__summary p {
    font-size: var(--text-base);
  }
  .doc__toc {
    margin-bottom: var(--s-10);
    padding: var(--s-4);
  }
  .doc__toc-list {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-1);
  }
  .doc__toc a {
    padding: 7px 8px;
  }
  .doc__body h2 {
    margin-top: var(--s-10);
    padding-top: var(--s-5);
  }
}

/* ============================================================
   Footer
   ============================================================ */
.site-footer {
  margin-top: var(--s-24);
  padding: var(--s-12) 0;
  border-top: 1px solid var(--border);
  background: var(--bg);
}
.site-footer__row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-4);
}
.site-footer__links { display: flex; gap: var(--s-5); }
.site-footer__links a { color: var(--text-2); font-size: var(--text-sm); font-weight: 550; }
.site-footer__links a:hover { color: var(--text); }

/* Invite-only promotion discovery. Hidden HTML becomes visible only after the
   public status endpoint confirms a campaign is currently accepting codes. */
/* The invite is a quiet action that points somewhere else, so it is the
   .link-arrow component — not a bespoke accent-filled pill. It was the last
   decorative accent fill on the page, and next to ink buttons and ink eyebrows
   a lavender lozenge read as left over from the old design. Only the spacing
   is local; everything visual comes from .link-arrow. */
.promotion-discovery { margin-top: var(--s-4); }
.site-footer__copy { color: var(--text-2); font-size: var(--text-sm); font-weight: 550; }
/* Mobile (≤640px): the footer row wraps from a justify-content:
   space-between row into stacked lines, but the items kept their
   left-aligned position from the wrap — looks like a layout bug
   even though it isn't. Center both halves explicitly so the
   stacked column reads as intentional. */
@media (max-width: 640px) {
  .site-footer__row {
    justify-content: center;
    text-align: center;
  }
  .site-footer__links {
    justify-content: center;
    flex-wrap: wrap;
    gap: var(--s-4);
  }
  .site-footer__links a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

/* ============================================================
   Utilities
   ============================================================ */
.muted { color: var(--text-3); }
.text-center { text-align: center; }
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}
.lead { font-size: var(--text-lg); color: var(--text-2); line-height: var(--lh-base); }
.eyebrow {
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: 650;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* Ink, not indigo. An eyebrow is a label, not a state — painting every one
     of them accent is what makes the accent read as decoration. */
  color: var(--text-3);
  margin-bottom: var(--s-4);
}

@media (max-width: 700px) {
  /* h1 + h2 sizing is now fluid via clamp() above — no override needed. */
  .container { padding: 0 var(--s-4); }
  .plan { padding: var(--s-6); }
}

/* Section rhythm — one value, used everywhere. Convention: top:0,
   bottom owns the gap. Sections with internal cards (.team) subtract
   the card's own bottom padding via calc() so the visual gap matches.
   First section on each page (.hero / .page-head) keeps a larger top
   for header breathing. Banners (.guarantee) use their own thin pad. */
:root {
  --section-pad: var(--s-20);
}
@media (max-width: 700px) {
  :root { --section-pad: var(--s-16); }
}
@media (max-width: 480px) {
  /* Desktop's 80px section rhythm leaves more empty space than content on a
     phone. Keep the same spacing token contract, but give narrow marketing
     surfaces a compact mobile value. */
  :root { --section-pad: var(--s-12); }
}
.features { padding: 0 0 var(--section-pad); }
.hero { padding: clamp(48px, 8vw, 80px) 0 var(--section-pad); }

/* Section head — shared rhythm for every title block on every section.
   Eyebrow → title 8px, title → subhead 12px, head → content 40px.
   Wrap eyebrow + h1/h2/h3 + optional <p> subhead in a div with this class.

   CENTRED by default, on every marketing surface, so a visitor moving between
   the home page and pricing sees one rhythm. .section-head--left is the opt-out
   for the two-column split sections that own their own layout. */
.section-head {
  text-align: center;
  margin-bottom: var(--s-10);
}
.section-head--left { text-align: left; }
.section-head--left p { margin-inline: 0; }
.section-head .eyebrow {
  margin-bottom: var(--s-2);
  display: inline-block;
}
.section-head h1,
.section-head h2,
.section-head h3 {
  margin: 0 0 var(--s-3);
  /* Even line lengths instead of a long first line and one orphaned word.
     The hero and the film head already balanced; four other section heads did
     not, giving splits like 663px / 126px. No-op where unsupported. */
  text-wrap: balance;
}
.section-head p {
  text-wrap: pretty;
}

/* Page heads (pricing, pro, legal) follow the same rule as section heads. */
.page-head h1,
.page-head h2 {
  text-wrap: balance;
}
.page-head p {
  text-wrap: pretty;
}
.section-head p {
  color: var(--text-3);
  font-size: var(--text-md);
  max-width: 560px;
  margin: 0 auto;
}

/* Restrained entrance motion for marketing and pricing. JavaScript adds the
   root opt-in class, so content remains fully visible when scripting is
   unavailable. Variants only change the starting pose; every element settles
   into its authored layout after one reveal. */
.reveal {
  --reveal-delay: 0ms;
  --reveal-distance: 10px;
  --reveal-scale: 1;
}
html.has-marketing-motion .reveal {
  opacity: 0;
  transform: translate3d(0, var(--reveal-distance), 0) scale(var(--reveal-scale));
  transition:
    opacity 480ms var(--ease),
    transform 560ms var(--ease);
  transition-delay: var(--reveal-delay);
  will-change: opacity, transform;
}
html.has-marketing-motion .reveal.reveal--scale {
  --reveal-distance: 8px;
  --reveal-scale: 0.992;
}
html.has-marketing-motion .reveal.reveal--fade {
  --reveal-distance: 0px;
}
html.has-marketing-motion .reveal.is-revealed {
  opacity: 1;
  transform: none;
  will-change: auto;
}

@media (prefers-reduced-motion: reduce) {
  html.has-marketing-motion .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* Printing suppresses backgrounds and never fires an IntersectionObserver, so
   without this every .reveal section prints as a blank band. */
@media print {
  html.has-marketing-motion .reveal {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }

}

/* Opt-in wider prose for dense positioning sections. The base .section-head
   stays narrow for ordinary one-line section intros across pricing/FAQ/etc. */
.section-head--capture p {
  max-width: 600px;
}

.section-head--capture p:not(:first-of-type) {
  max-width: 620px;
}

.section-head--versus {
  max-width: 780px;
  margin-left: auto;
  margin-right: auto;
}

.section-head--versus p {
  max-width: 720px;
  text-align: center;
  line-height: 1.55;
}

.section-head--versus p + p {
  margin-top: var(--s-3);
}

/* FAQ accordion — shared between landing and pricing. */
.faq__list {
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}
.faq-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--s-5) var(--s-6);
}
.faq-item > summary {
  cursor: pointer;
  font-weight: 600;
  font-size: var(--text-md);
  list-style: none;
}
.faq-item > summary::-webkit-details-marker { display: none; }
.faq-item__body {
  margin-top: var(--s-3);
  color: var(--text-2);
  font-size: var(--text-sm);
  line-height: 1.6;
}
.faq-item__body p { margin: 0; }
.faq-item__body p + p { margin-top: var(--s-2); }

/* Premium accordion treatment shared by the homepage and pricing page. Keep
   this in the design system so both surfaces retain one visual language. */
.faq--premium .faq__list {
  max-width: 820px;
  gap: var(--s-2);
}
.faq--premium .faq-item {
  box-shadow: 0 4px 18px color-mix(in srgb, var(--text) 3%, transparent);
  transition: border-color 160ms var(--ease), box-shadow 160ms var(--ease);
}
.faq--premium .faq-item[open] {
  border-color: color-mix(in srgb, var(--accent) 28%, var(--border));
  box-shadow: 0 12px 32px color-mix(in srgb, var(--text) 6%, transparent);
}
.faq--premium .faq-item > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
}
.faq--premium .faq-item > summary::after {
  content: "+";
  display: grid;
  width: 28px;
  height: 28px;
  flex: none;
  place-items: center;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--accent);
  font-size: 20px;
  font-weight: 500;
  line-height: 1;
}
.faq--premium .faq-item[open] > summary::after { content: "−"; }

/* Scrollbars — thin, reveal-on-hover. Applied site-wide via this stylesheet.
   Note: macOS "Always show scrollbars" overrides browser-styled scrollbars. */
html { scrollbar-width: thin; scrollbar-color: transparent transparent; }
html:hover { scrollbar-color: var(--border-strong) transparent; }
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background: transparent; border-radius: 4px;
  transition: background 0.15s ease; }
*:hover::-webkit-scrollbar-thumb { background: var(--border-strong); }
*::-webkit-scrollbar-thumb:hover { background: var(--text-3); }

/* ============================================================
   Arrow link — the one component for a quiet action that points
   somewhere else. Promoted from the one-off treatment that was living on
   .stack-fit__copy a, so every "go and look at this" link on every marketing
   surface is the same object.

   The arrow is part of the component, not the copy: it must not sit inside a
   translated string, or the direction is wrong in an RTL locale and the glyph
   is duplicated wherever the component is reused.
   ============================================================ */
.link-arrow {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-2);
  width: fit-content;
  padding-bottom: 2px;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 42%, transparent);
  color: var(--accent-text);
  font-size: var(--text-sm);
  font-weight: 600;
  text-decoration: none;
  transition: color var(--t) var(--ease-out), border-color var(--t) var(--ease-out);
}
.link-arrow::after {
  content: "\2192";
  transition: transform var(--t) var(--ease-out);
}
.link-arrow:hover {
  color: var(--accent-hover);
  border-bottom-color: currentColor;
}
.link-arrow:hover::after { transform: translateX(2px); }
.link-arrow:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}
[dir="rtl"] .link-arrow::after { content: "\2190"; }
[dir="rtl"] .link-arrow:hover::after { transform: translateX(-2px); }

@media (prefers-reduced-motion: reduce) {
  .link-arrow::after,
  .link-arrow:hover::after { transition: none; transform: none; }
}

/* Inline link inside running prose. The arrow component is for standalone
   actions; inside a sentence an arrow is wrong, so this is the sibling
   treatment: same colour, same underline weight, no glyph. Replaces the
   hardcoded style="color: var(--accent); font-weight: 600" that had been
   copy-pasted through the FAQ bodies. */
.link-inline {
  color: var(--accent-text);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent) 42%, transparent);
  text-underline-offset: 0.16em;
}
.link-inline:hover {
  color: var(--accent-hover);
  text-decoration-color: currentColor;
}

.guarantee__link { display: inline-flex; margin-top: var(--s-4); }
