/* Shared by index.html, pricing.html, docs.html and 404.html.
   download.html deliberately keeps its own inlined copy: it is linked to
   directly and should never wait on a second request.

   No JavaScript anywhere on this site. Everything below that moves does so
   with CSS only, and every one of those effects degrades to "no motion"
   rather than "broken layout" in a browser that lacks it. */

/* ── Type ─────────────────────────────────────────────────────────────────
   The brand kit's three faces, all OFL-1.1 (licence texts in fonts/), as the
   unmodified Google Fonts latin and latin-ext subsets that @fontsource ships:
     Outfit        display and headings, variable 100-900, 32 KB for latin
     IBM Plex Sans body and UI, variable 100-700, 46 KB for latin
     IBM Plex Mono code, 400 only, 15 KB for latin
   unicode-range means a latin-ext file is only fetched when a page actually
   uses one of its characters, and a face only when something is set in it.
   The system stacks stay as the fallback so a failed font request costs
   nothing but character. */

@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url(fonts/outfit-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Outfit';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url(fonts/outfit-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 100 700;
  font-display: swap;
  src: url(fonts/ibm-plex-sans-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 100 700;
  font-display: swap;
  src: url(fonts/ibm-plex-sans-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/ibm-plex-mono-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/ibm-plex-mono-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  color-scheme: light dark;

  --display: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
    Helvetica, Arial, sans-serif;
  --sans: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
    Helvetica, Arial, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Brand kit v1 palette (handbook/brand/README.md). One accent, and one
     gray family tinted toward it, so nothing clashes: the ground is flux
     cream, cards are silkscreen white, text is graphite, and the grays sit
     between them.

     PCB teal #00878F itself is only 4.32:1 against white and 3.82:1 against
     cream, so it fails AA for body-size text and for white button labels.
     --primary is therefore the kit's own deeper teal, #00727A: white on it
     is 5.69:1, and it is 5.04:1 on cream and 5.01:1 on --primary-soft.
     #00878F stays where the kit puts it, in the logo. Every text pair clears
     4.5:1: --muted is 6.22:1 on cream and 5.68:1 on --surface-2; in dark
     mode the lowest is --muted on --surface-2 at 5.07:1. */
  --bg: #f3f1ea;
  --fg: #142322;
  --muted: #4c5c5b;
  --border: #e2ddce;
  --surface: #ffffff;
  --surface-2: #eae7de;
  --primary: #00727a;
  --primary-fg: #ffffff;
  --primary-soft: rgba(0, 135, 143, 0.1);
  /* Solder gold, the kit's single accent. Decorative only (rules, selection):
     at 1.96:1 on cream it never carries text. #D4A84A is the kit's cut for
     light grounds. */
  --gold: #d4a84a;

  /* The lockup's wordmark and trace, per lockup-teal / lockup-white. */
  --logo-word: #00878f;
  --logo-trace: #9fcfd2;

  /* Shadows carry the text colour's hue instead of neutral black. */
  --shadow-sm: 0 1px 2px rgba(20, 35, 34, 0.06);
  --shadow-lg: 0 1px 2px rgba(20, 35, 34, 0.05), 0 18px 44px -12px rgba(20, 35, 34, 0.18);

  --radius-lg: 18px;
  --radius-md: 12px;
  --radius-sm: 8px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --z-header: 50;
  --z-skip: 100;
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Board ink, never #000 — the kit's dark UI ground, with cards and
       rules stepped up from it as on the launch-page design. Links and
       fills switch to trace cyan ("links on dark"), with board ink on it. */
    --bg: #06363a;
    --fg: #e8f2f2;
    --muted: #9dc1c3;
    --border: #1a565a;
    --surface: #0a4246;
    --surface-2: #0f4b4f;
    --primary: #6fd6db;
    --primary-fg: #06363a;
    --primary-soft: rgba(111, 214, 219, 0.12);
    --gold: #e0b95c;
    --logo-word: #ffffff;
    --logo-trace: #2f6e72;
    --shadow-sm: 0 1px 2px rgba(2, 20, 22, 0.4);
    --shadow-lg: 0 1px 2px rgba(2, 20, 22, 0.35), 0 18px 44px -12px rgba(2, 20, 22, 0.65);
  }
}

* { box-sizing: border-box; }

html {
  scroll-padding-top: 92px;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}
@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(--sans);
  font-size: 16px;
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* A single fixed grain layer. Flat vector surfaces read as sterile; this is
   below the noise floor individually but stops large areas looking like dead
   fills. pointer-events:none so it never eats a click. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.02;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
@media (prefers-color-scheme: dark) { body::before { opacity: 0.035; } }

.wrap { max-width: 1180px; margin: 0 auto; padding: 0 28px; position: relative; z-index: 2; }
.narrow { max-width: 760px; }

a { color: var(--primary); text-decoration-thickness: 1px; text-underline-offset: 2px; }

/* Outfit at 600-700 with -2% to -2.5% tracking, per the brand kit. */
h1, h2, h3 {
  font-family: var(--display);
  letter-spacing: -0.025em;
  line-height: 1.1;
  font-weight: 600;
  text-wrap: balance;
}
h2 { font-size: clamp(1.6rem, 3vw, 2.05rem); margin: 0 0 14px; }
h3 { font-size: 1.08rem; margin: 0 0 6px; letter-spacing: -0.02em; font-weight: 600; }
p { margin: 0 0 16px; text-wrap: pretty; }

code, pre { font-family: var(--mono); font-size: 0.85em; }

::selection { background: color-mix(in srgb, var(--gold) 38%, transparent); color: var(--fg); }

/* Keyboard focus must always be visible; mouse users never see it. */
:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

.skip {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: var(--z-skip);
  padding: 10px 18px;
  border-radius: var(--radius-sm);
  background: var(--primary);
  color: var(--primary-fg);
  font-weight: 600;
  text-decoration: none;
  transition: top 0.18s var(--ease);
}
.skip:focus { top: 12px; }

/* ── Header ──────────────────────────────────────────────────────────────── */

header.site {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  border-bottom: 1px solid transparent;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  /* An inner hairline reads as refraction rather than a drawn border. */
  box-shadow: inset 0 -1px 0 var(--border);
}
header.site .wrap { display: flex; align-items: center; gap: 26px; height: 66px; }

/* The brand kit's lockup, inlined so it costs no request and can follow the
   theme. The wordmark is outlined, so it renders the same whether or not the
   fonts load. Its presentation attributes are the light (lockup-teal) colours,
   so it is still correct with CSS off; dark mode swaps in lockup-white's
   wordmark and trace. The icon tile is the same in both. */
.brand {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  text-decoration: none;
  border-radius: var(--radius-sm);
}
.brand .lockup { display: block; width: auto; height: 32px; }
.brand .lw { fill: var(--logo-word); }
.brand .lt { stroke: var(--logo-trace); }

nav.site { margin-left: auto; display: flex; align-items: center; gap: 4px; }
nav.site a {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.93rem;
  font-weight: 500;
  padding: 7px 11px;
  border-radius: var(--radius-sm);
  transition: color 0.18s var(--ease), background-color 0.18s var(--ease);
}
nav.site a:hover { color: var(--fg); background: var(--surface-2); }
/* Where am I. Marked with aria-current in the markup, so it is announced too. */
nav.site a[aria-current="page"] { color: var(--fg); background: var(--primary-soft); }
/* `color` has to be restated here, not just inherited from .btn.
   `nav.site a` (0,1,2) outranks `.btn` (0,1,0), so the header CTA was being
   painted --muted on the --primary fill: grey-on-teal, near-unreadable. This
   selector is (0,2,1) and wins. The same trap applies to any future .btn
   placed inside a scoped `nav x a` rule. */
nav.site .btn {
  margin-left: 10px;
  color: var(--primary-fg);
}
nav.site .btn:hover { background: var(--primary); color: var(--primary-fg); }
@media (max-width: 780px) { nav.site a.hide-sm { display: none; } }

/* ── Buttons ─────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 13px 24px;
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--primary-fg);
  font-weight: 600;
  font-size: 0.97rem;
  letter-spacing: -0.01em;
  text-decoration: none;
  border: 1px solid transparent;
  white-space: nowrap;
  box-shadow: var(--shadow-sm);
  transition: transform 0.18s var(--ease), box-shadow 0.18s var(--ease),
    background-color 0.18s var(--ease), border-color 0.18s var(--ease);
}
.btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-lg); }
/* Pressing something should feel like pressing something. */
.btn:active { transform: translateY(0) scale(0.985); box-shadow: var(--shadow-sm); }
.btn.ghost { background: transparent; color: var(--fg); border-color: var(--border); box-shadow: none; }
.btn.ghost:hover { background: var(--surface); border-color: var(--muted); }
.btn.sm { padding: 8px 15px; font-size: 0.9rem; }

/* ── Hero ────────────────────────────────────────────────────────────────── */

/* The screenshot is the hero, with the copy over its lower half.

   The scrim is the whole trick. It goes fully opaque --bg at the bottom and
   clears to transparent before the top, so the headline sits on solid page
   background — genuinely readable, not text-over-busy-image with a shadow
   bolted on — while the circuit stays clean where it is worth looking at.
   Because every stop is derived from --bg, it inverts with the theme for
   free, and the light/dark <picture> variants keep the image underneath in
   step. */
.hero {
  position: relative;
  isolation: isolate;
  display: grid;
  align-items: end;
  min-height: min(92svh, 940px);
  padding: 0;
  overflow: hidden;
}

/* The same box as .wrap — identical max-width and side padding — so the
   screenshot's left and right edges land exactly on the nav's content edges
   rather than near them. A vw-based inset looked close at one width and drifted
   at every other.

   Inset rather than edge-to-edge for a second reason: stretched full-bleed the
   1400px source was upscaled past 1:1 on a wide display, so the app's own UI
   rendered larger and softer than it looks in the app. */
.hero-media {
  position: absolute;
  inset: 0;
  z-index: -2;
  max-width: 1180px;
  margin-inline: auto;
  padding: 0 28px;
}
.hero-media picture { display: block; }
/* width:100% with height:auto, not object-fit. `contain` centres the image
   inside its box whenever the box is the limiting dimension, which on a short
   hero would pull the edges inward and break the alignment this exists for.
   At natural aspect the width is always the container's, so the edges hold at
   every viewport; the hero's overflow:hidden trims any excess height, and that
   trim happens under the opaque part of the scrim. */
.hero-media img {
  display: block;
  width: 100%;
  height: auto;
}
/* The screenshots have the app's own white (light) and charcoal (dark)
   grounds, which no longer match the cream and board-ink page. Rather than
   let a pale rectangle float on the page, frame it as the window it is; the
   scrim below still dissolves its lower edge into the page. */
.hero-media { padding-top: 28px; }
.hero-media picture {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Stops in px, not %. The copy block is a roughly fixed height whatever the
     viewport is, while the hero's height varies — so percentage stops put the
     headline on a half-transparent scrim on a short screen and waste opacity
     on a tall one. Anchoring to the bottom edge means the plateau always
     covers the text and the fade always happens above it.
     Retuned down from 400px when the note and caption came out of the copy. */
  background: linear-gradient(
    to top,
    var(--bg) 0,
    var(--bg) 345px,
    color-mix(in srgb, var(--bg) 45%, transparent) 400px,
    color-mix(in srgb, var(--bg) 12%, transparent) 450px,
    transparent 500px
  );
}

/* No top padding. `align-items: end` already pins this to the bottom, so a
   large padding-top only inflates the copy block and eats the image: at 220px
   it took 87% of the hero and left a sliver of screenshot above it. */
.hero-copy { padding: 0 0 30px; text-align: center; }


/* On a short or narrow screen a cover-cropped 2.08:1 screenshot shows very
   little, and 220px of scrim padding wastes what is left. Shrink both. */
@media (max-width: 760px), (max-height: 620px) {
  .hero { min-height: min(80svh, 660px); }
  .hero-copy { padding: 0 0 24px; }
}

.hero h1 {
  font-size: clamp(2.2rem, 5.4vw, 3.5rem);
  font-weight: 650;
  margin: 0 auto 14px;
  /* 22ch keeps "Design, code and simulate" on one line, so the headline is two
     lines and not three. The third line cost ~70px that the screenshot needs. */
  max-width: 22ch;
  letter-spacing: -0.025em;
}
.hero .lede {
  font-size: clamp(1.03rem, 1.5vw, 1.18rem);
  color: var(--muted);
  /* Plex Sans sets wider than Geist did; 51ch keeps this to two lines. */
  max-width: 51ch;
  margin: 0 auto 22px;
}
/* A text-only page header (pricing) reuses .hero for its type, but has no
   screenshot: without this the full-height grid pushed the lede ~250px below
   the headline and painted the scrim over nothing. */
.hero.wrap {
  display: block;
  min-height: 0;
  overflow: visible;
  padding-top: 88px;
  padding-bottom: 0;
  text-align: center;
}
.hero.wrap::before { content: none; }
.hero.wrap .lede { margin-bottom: 0; }
.cta-row { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 0; }
.hero .cta-row { justify-content: center; }



/* ── Screenshots ─────────────────────────────────────────────────────────── */

figure.shot {
  margin: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}
figure.shot img { display: block; width: 100%; height: auto; }
figure.shot figcaption {
  padding: 13px 18px;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.85rem;
}

/* ── Sections ────────────────────────────────────────────────────────────── */

section { padding: 104px 0; }
section + section { padding-top: 0; }
.section-head { max-width: 34ch; margin: 0 0 40px; }
.section-head p { color: var(--muted); margin: 0; max-width: 52ch; }

/* Cards carry background and radius, no border in light mode — a border plus a
   shadow plus a fill is three ways of saying the same thing. */
.card {
  padding: 26px;
  border-radius: var(--radius-md);
  background: var(--surface);
  border: 1px solid transparent;
  transition: transform 0.22s var(--ease), border-color 0.22s var(--ease),
    background-color 0.22s var(--ease);
}
@media (prefers-color-scheme: dark) { .card { border-color: var(--border); } }
.card:hover { transform: translateY(-2px); border-color: var(--primary-soft); }
.card p { color: var(--muted); margin: 0; font-size: 0.95rem; }
.card h3 { margin-bottom: 8px; }

.grid { display: grid; gap: 18px; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

/* Two deliberate breaks from the three-equal-columns row.
   .grid.lead — one wide statement card, then the supporting pair beneath it.
   .grid.duo  — two columns, so each card gets room to be a sentence rather
                than a fragment. */
@media (min-width: 900px) {
  .grid.lead { grid-template-columns: repeat(2, 1fr); }
  .grid.lead > :first-child {
    grid-column: 1 / -1;
    background: var(--primary-soft);
    padding: 34px;
  }
  .grid.lead > :first-child h3 { font-size: 1.2rem; }
  .grid.lead > :first-child p { max-width: 62ch; font-size: 1rem; }

  .grid.duo { grid-template-columns: repeat(2, 1fr); gap: 20px; }
  /* Staggered, so the two columns do not read as a table. */
  .grid.duo > :nth-child(even) { transform: translateY(22px); }
  .grid.duo > :nth-child(even):hover { transform: translateY(20px); }
}

/* ── Examples ────────────────────────────────────────────────────────────── */

.examples {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
}
.examples a {
  display: block;
  padding: 15px 17px;
  border-radius: var(--radius-md);
  background: var(--surface);
  text-decoration: none;
  color: inherit;
  border: 1px solid transparent;
  transition: transform 0.18s var(--ease), border-color 0.18s var(--ease),
    background-color 0.18s var(--ease);
}
.examples a:hover { border-color: var(--primary); background: var(--primary-soft); transform: translateY(-2px); }
.examples a:active { transform: translateY(0); }
.examples strong { display: block; font-weight: 600; letter-spacing: -0.015em; }
.examples span { color: var(--muted); font-size: 0.86rem; }

/* ── Tables ──────────────────────────────────────────────────────────────── */

.table-scroll { overflow-x: auto; border-radius: var(--radius-md); }
table { border-collapse: collapse; width: 100%; min-width: 460px; font-size: 0.94rem; }
th, td { text-align: left; padding: 12px 15px; border-bottom: 1px solid var(--border); vertical-align: top; }
th { font-weight: 600; }
thead th { color: var(--muted); font-size: 0.8rem; letter-spacing: 0.04em; text-transform: uppercase; }
tbody tr:last-child td { border-bottom: 0; }
tbody td:first-child { color: var(--muted); }

.parts { color: var(--muted); line-height: 2.2; max-width: none; }
.parts code {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 4px 9px;
  color: var(--fg);
  white-space: nowrap;
  font-size: 0.8rem;
}

/* ── Closing ─────────────────────────────────────────────────────────────── */

.closing {
  border-radius: var(--radius-lg);
  /* A soft radial rather than a flat fill or a 45-degree gradient. */
  background:
    radial-gradient(120% 140% at 50% 0%, var(--primary-soft) 0%, transparent 62%),
    var(--surface);
  border: 1px solid var(--border);
  padding: 76px 32px;
  text-align: center;
}
.closing h2 { margin-bottom: 12px; }
.closing p { color: var(--muted); max-width: 46ch; margin: 0 auto 28px; }

/* ── Footer ──────────────────────────────────────────────────────────────── */

footer.site {
  border-top: 1px solid var(--border);
  margin-top: 104px;
  padding: 44px 0 72px;
  color: var(--muted);
  font-size: 0.9rem;
}
footer.site .links { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 24px; }
footer.site .links a {
  text-decoration: none;
  padding: 6px 12px 6px 0;
  margin-right: 8px;
  transition: color 0.18s var(--ease);
}
footer.site .links a:hover { color: var(--fg); }
footer.site .fine { max-width: 64ch; margin: 0; font-size: 0.85rem; }
footer.site .fine + .fine { margin-top: 10px; }

/* ── Pricing ─────────────────────────────────────────────────────────────── */

.tiers { display: grid; gap: 20px; grid-template-columns: repeat(auto-fit, minmax(285px, 1fr)); }

.tier {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  padding: 30px;
  /* Every tier is the same grid, so titles, prices, feature lists and buttons
     line up across columns however long the copy is. */
  display: grid;
  grid-template-rows: auto auto auto 1fr auto;
  gap: 0;
}
.tier.featured {
  border-color: var(--primary);
  background:
    radial-gradient(120% 100% at 50% 0%, var(--primary-soft) 0%, transparent 58%),
    var(--surface);
  box-shadow: var(--shadow-lg);
}
.tier h3 { font-size: 1.05rem; margin: 0 0 4px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tier .price {
  font-family: var(--display);
  font-size: 2.3rem;
  font-weight: 650;
  letter-spacing: -0.025em;
  margin: 12px 0 2px;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.tier .price small {
  font-size: 0.88rem;
  font-weight: 400;
  color: var(--muted);
  letter-spacing: 0;
}
.tier .price.text { font-size: 1.4rem; letter-spacing: -0.02em; }
.tier .terms { color: var(--muted); font-size: 0.88rem; margin: 0 0 22px; }
.tier ul { list-style: none; margin: 0 0 26px; padding: 0; }
.tier li { position: relative; padding: 0 0 0 26px; margin-bottom: 10px; font-size: 0.94rem; }
.tier li::before {
  content: "";
  position: absolute;
  left: 4px; top: 8px;
  width: 9px; height: 5px;
  border-left: 2px solid var(--primary);
  border-bottom: 2px solid var(--primary);
  border-radius: 1px;
  transform: rotate(-45deg);
}
.tier li.no { color: var(--muted); }
.tier li.no::before {
  border: 0; border-radius: 0;
  left: 5px; top: 11px;
  width: 10px; height: 2px;
  background: var(--muted);
  transform: none;
}
.tier .btn { justify-content: center; align-self: end; }

/* A tier nobody can buy must look unbuyable, not merely say so. */
.tier.planned { background: transparent; border-style: dashed; box-shadow: none; }

/* Square, not a pill — every generated page uses pill badges. */
.badge {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 4px;
  border: 1px solid var(--border);
  color: var(--muted);
  white-space: nowrap;
}
.badge.now { border-color: transparent; background: var(--primary-soft); color: var(--primary); }

/* The one place the gold accent shows up as a rule: like a pad on a trace. */
.note {
  border-left: 2px solid var(--gold);
  background: var(--surface);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  padding: 20px 24px;
  margin: 0 0 20px;
}
.note p { margin: 0; max-width: 62ch; }
.note p + p { margin-top: 12px; }

/* ── Docs ────────────────────────────────────────────────────────────────── */

.docs-layout { display: grid; gap: 56px; grid-template-columns: 210px minmax(0, 1fr); }
@media (max-width: 900px) { .docs-layout { grid-template-columns: 1fr; gap: 28px; } }

.toc { position: sticky; top: 100px; align-self: start; font-size: 0.91rem; }
@media (max-width: 900px) {
  .toc { position: static; border-radius: var(--radius-md); padding: 20px 22px; background: var(--surface); }
}
.toc ol { list-style: none; margin: 0; padding: 0; }
.toc li { margin-bottom: 2px; }
.toc a {
  color: var(--muted);
  text-decoration: none;
  display: block;
  padding: 5px 12px;
  border-radius: var(--radius-sm);
  border-left: 2px solid transparent;
  transition: color 0.18s var(--ease), border-color 0.18s var(--ease), background-color 0.18s var(--ease);
}
.toc a:hover { color: var(--fg); background: var(--surface-2); border-left-color: var(--primary); }
.toc .toc-head {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--muted);
  margin: 0 0 14px 12px;
  font-weight: 600;
}

.prose { max-width: 68ch; }
.prose h2 { margin: 0 0 16px; font-size: clamp(1.4rem, 2.4vw, 1.7rem); }
.prose h3 { margin: 34px 0 10px; font-size: 1.02rem; }
.prose section { margin-bottom: 76px; scroll-margin-top: 100px; }
.prose section:last-child { margin-bottom: 0; }
.prose ul, .prose ol { padding-left: 22px; margin: 0 0 18px; }
.prose li { margin-bottom: 8px; }
.prose li::marker { color: var(--muted); }
.prose code {
  background: var(--surface-2);
  border-radius: 5px;
  padding: 2px 6px;
  font-size: 0.86em;
}
.prose pre {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 20px 22px;
  overflow-x: auto;
  margin: 0 0 20px;
  line-height: 1.6;
}
.prose pre code { background: none; padding: 0; }
kbd {
  font-family: var(--sans);
  font-size: 0.82em;
  font-weight: 500;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: 6px;
  padding: 2px 7px;
  white-space: nowrap;
}

/* ── Entrance ────────────────────────────────────────────────────────────── */

/* Scroll-driven, CSS-only. Browsers without animation-timeline simply show the
   content — the @supports guard means nothing is ever left invisible. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .reveal {
      animation: rise linear both;
      animation-timeline: view();
      animation-range: entry 8% cover 26%;
    }
    @keyframes rise {
      from { opacity: 0; transform: translateY(14px); }
      to { opacity: 1; transform: translateY(0); }
    }
    /* The stagger: each card in a row starts fractionally later. */
    .grid > *:nth-child(2) { animation-delay: 60ms; }
    .grid > *:nth-child(3) { animation-delay: 120ms; }
  }
}

/* ── 404 ─────────────────────────────────────────────────────────────────── */

.notfound { padding: 120px 0 40px; max-width: 46ch; }
.notfound .code {
  font-family: var(--mono);
  font-size: 0.85rem;
  color: var(--primary);
  letter-spacing: 0.08em;
  margin: 0 0 14px;
}
