/* ========================
   King AI · Shared SEO page styles — "The Contact Sheet", spoke edition

   Loaded after each page's inline <style> and after seo/theme.css. Those two
   files ARE the visual system for the ~83 hand-written pages: the markup
   carries component class names and nothing else.

   The design is the homepage's, tuned down for reading:
     canvas     near-black #080808 / paper #F4F5F7, from --c-base
     display    Bebas, uppercase — h1, h2, card and step titles, prices
     prose      Inter, one muted step, sane measure
     ledger     mono 11-13px / 0.18em / uppercase for every eyebrow, caption,
                counter, table head and frame number (see .slug, theme.css)
     structure  hairlines, not boxes. A card is a rule and some type; a frame
                is a 2px-cornered plate with sprockets and grain
     lime       the grease pencil. It marks the ONE primary CTA in view, the
                chosen plan, the current breadcrumb, the hovered card and the
                focus ring — nothing else. FILL is solid #D1FE17 with #14151A
                type in BOTH themes; INK is type/hairline only and darkens on
                paper (--accent-ink, theme.css).

   Two rules hold it together:
     1. No literal rgba(255,255,255,a) / rgba(20,21,26,a) for anything read.
        Colour goes through --c-fg / --c-muted / --c-line, so both themes come
        out of ONE declaration. That is why this file has no `:root.light`
        block: the ~120 light overrides it used to carry are gone.
     2. Nothing rests at opacity 0. Reveals are additive — shell.js marks only
        what is below the fold when it runs — so with JS off, or before
        shell.js runs, the page is already complete.
   ======================== */

/* ------------------------
   Layout & reset
   ------------------------ */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: 92px; }

body {
  margin: 0;
  background: rgb(var(--c-base));
  color: rgb(var(--c-fg));
  font-family: var(--font-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  /* `clip`, not `hidden`: `overflow-x: hidden` forces the other axis to
     `auto`, making this a scroll container — and a scroll container is what
     every `view()` timeline inside it resolves against, so one `hidden` here
     parks every reveal at its start state for ever. The pages' inline
     <style> still says `hidden`, the right fallback where `clip` is not. */
  overflow-x: clip;
}

a { color: inherit; text-decoration: none; }
img, video, svg { max-width: 100%; display: block; }
::selection { background: var(--accent-fill); color: var(--on-accent); }
:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 3px; }

/* The React landing's `max-w-shell` (100rem) and its gutters, so type starts
   on the same vertical crossing from the homepage. */
.wrap {
  width: 100%;
  max-width: 100rem;
  margin-left: auto;
  margin-right: auto;
  padding-left: 24px;
  padding-right: 24px;
}
@media (min-width: 640px) { .wrap { padding-left: 32px; padding-right: 32px; } }
@media (min-width: 1024px) { .wrap { padding-left: 40px; padding-right: 40px; } }

/* ------------------------
   Type roles
   ------------------------ */
.podium,
.page-hero h1,
section.page h2,
.band h2,
.card h3,
.benefit .bd h3,
.crosslink h3,
.post-card h3,
.step h3,
.frow .copy h3,
.faq summary,
.plan .plan-price .amt,
.pack .pack-credits,
.step .n,
.brand .name {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  text-wrap: balance;
}

.page-hero h1 {
  font-size: clamp(2.9rem, 6.8vw, 6.25rem);
  line-height: 0.86;
  letter-spacing: -0.018em;
  margin: 20px 0 0;
  max-width: 7.8em;
  color: rgb(var(--c-fg));
}

section.page h2 {
  font-size: clamp(2rem, 3.5vw, 3.1rem);
  line-height: 0.94;
  letter-spacing: -0.012em;
  margin: 14px 0 0;
  max-width: 8.6em;
}

/* The grease-pencil mark: the phrase the page is about, underlined once. It
   replaces `.grad`'s animated lime-white-lime gradient — a text shimmer, which
   the motion spec deleted in v1 and keeps deleted. An underline survives a
   wrap, costs no layout and, unlike a gradient fill, is legible. */
.grad {
  color: inherit;
  background: none;
  -webkit-text-fill-color: currentColor;
  text-decoration: underline;
  text-decoration-color: var(--accent-ink);
  text-decoration-thickness: 0.055em;
  text-underline-offset: 0.1em;
  text-decoration-skip-ink: none;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  color: rgb(var(--c-muted));
  margin: 0;
}

/* The chapter tick. Neutral, not lime — a page carries up to eight of these
   and lime that marks everything marks nothing. */
.eyebrow::before {
  content: "";
  flex: none;
  width: 18px;
  height: 2px;
  background: rgb(var(--c-fg) / 0.3);
}

.muted { color: rgb(var(--c-muted)); }

/* Measures are in `em`, never `ch`, throughout this file. A `ch` is the
   advance of "0" IN THE CURRENT FONT, so a ch-based max-width resizes when
   the webfont swaps in and re-wraps everything under it — on the h1 that was
   836px -> 783px, a whole 86px line out of the hero and 0.075 of layout
   shift, the largest on the site. These are the same measures the ch figures
   gave with the real faces (Inter: 1ch = 0.631em), in a unit swap cannot
   move. */
.page-hero .lede {
  margin: 22px 0 0;
  max-width: 39.1em;
  font-size: 1.06rem;
  color: rgb(var(--c-fg) / 0.78);
}

section.page .sub {
  margin: 18px 0 0;
  max-width: 41.6em;
  color: rgb(var(--c-fg) / 0.72);
}

/* ------------------------
   Buttons — a pill is the only round shape left on the page
   ------------------------ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: 999px;
  padding: 14px 24px;
  font-family: var(--font-body);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1.25;
  transition: transform 200ms var(--ease), background 200ms var(--ease),
    border-color 200ms var(--ease), box-shadow 200ms var(--ease);
  border: 1px solid rgb(var(--c-line) / 0.18);
  background: transparent;
  color: rgb(var(--c-fg));
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
}

.btn:hover { transform: translateY(-2px); border-color: rgb(var(--c-line) / 0.45); }

/* FILL, not ink: the plate stays lime on paper too, with near-black on it.
   Painting it with the ink value made an army-green button. The 1px inset
   keeps the edge from dissolving into a light page. */
.btn-primary {
  background: var(--accent-fill);
  color: var(--on-accent);
  border-color: var(--accent-fill);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1), var(--shadow-accent);
}
.btn-primary:hover {
  background: var(--accent-fill-hover);
  border-color: var(--accent-fill-hover);
}

/* ------------------------
   Header — a flat instrument bar, not a floating pill. The homepage masthead
   is 72px of near-black behind a hairline, edge to edge; the pages used to
   float a blurred rounded pill in a 16px inset, the loudest tell that they
   were a different site. 72px is pinned so `main`'s reserve is exact.
   ------------------------ */
header.site {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  padding: 0;
  background: rgb(var(--c-base) / 0.72);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-bottom: 1px solid rgb(var(--c-line) / 0.1);
  transition: background 200ms var(--ease), border-color 200ms var(--ease);
}

header.site .bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 72px;
  padding-top: 10px;
  padding-bottom: 10px;
  border-radius: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
}

/* shell.js adds `.scrolled` past 24px. The bar settles; nothing moves. */
header.site:has(.bar.scrolled),
header.site.scrolled { background: rgb(var(--c-base) / 0.94); border-bottom-color: rgb(var(--c-line) / 0.14); }

/* Reserve for the fixed bar. Exactly its height — anything else shows as a
   gap under the hairline or clips the first line of the breadcrumb. */
body.seo main { padding-top: 72px; }

.brand { display: inline-flex; align-items: center; gap: 12px; flex-shrink: 0; }
.brand .name {
  font-size: 1.32rem;
  letter-spacing: 0.06em;
  white-space: nowrap;
  line-height: 1;
  color: rgb(var(--c-fg));
}

/* ONE primary CTA per viewport. The hero owns the lime plate at the top of
   every page, so the header's App button is a hairline until the visitor has
   scrolled past it. With JS off `.scrolled` never lands and it stays a
   hairline — the correct resting answer, not a degraded one. */
header.site .bar:not(.scrolled) .btn-primary {
  background: transparent;
  color: rgb(var(--c-fg));
  border-color: rgb(var(--c-line) / 0.25);
  box-shadow: none;
}

/* Primary nav (desktop) */
.nav-desktop { display: none; align-items: center; gap: 2px; }
@media (min-width: 1160px) { .nav-desktop { display: inline-flex; } }

.nav-item { position: relative; }
.nav-trigger,
.nav-plain {
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgb(var(--c-fg) / 0.7);
  background: transparent;
  border: 1px solid transparent;
  cursor: pointer;
  transition: color 200ms var(--ease), background 200ms var(--ease);
}
.nav-trigger:hover,
.nav-plain:hover,
.nav-trigger[aria-expanded="true"] {
  color: rgb(var(--c-fg));
  background: rgb(var(--c-fg) / 0.06);
}

.nav-trigger .caret {
  width: 7px; height: 7px;
  border-right: 1.6px solid currentColor;
  border-bottom: 1.6px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  opacity: 0.6;
  transition: transform 200ms var(--ease);
}
.nav-trigger[aria-expanded="true"] .caret { transform: translateY(2px) rotate(225deg); opacity: 0.9; }

/* Dropdown panel (mega menu, built by shell.js) */
.nav-dropdown {
  position: absolute;
  top: calc(100% + 12px);
  left: 50%;
  transform: translateX(-50%) translateY(-6px);
  width: min(720px, calc(100vw - 32px));
  background: rgb(var(--c-base) / 0.97);
  border: 1px solid rgb(var(--c-line) / 0.12);
  border-radius: var(--r-frame);
  padding: 24px;
  box-shadow: var(--shadow-panel);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  opacity: 0;
  visibility: hidden;
  /* Grace period: the panel stays hit-testable for ~200ms after the pointer
     leaves so the user can cross the 12px gap. Mirrors the React header. */
  transition: opacity 200ms 200ms var(--ease), transform 200ms 200ms var(--ease),
    visibility 200ms linear 200ms;
  z-index: 60;
}
.nav-item:hover > .nav-dropdown,
.nav-item:focus-within > .nav-dropdown,
.nav-trigger[aria-expanded="true"] + .nav-dropdown {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  visibility: visible;
  transition: opacity 200ms var(--ease), transform 200ms var(--ease), visibility 200ms var(--ease);
}
/* Invisible hover bridge covering the gap between trigger and panel. */
.nav-dropdown::after {
  content: "";
  position: absolute;
  top: -14px; left: 0; right: 0;
  height: 14px;
}
.nav-dropdown .col-title {
  color: rgb(var(--c-muted));
  margin-bottom: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid rgb(var(--c-line) / 0.1);
}
.nav-dropdown .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
.nav-dropdown .items { display: flex; flex-direction: column; gap: 2px; }

.nav-link {
  display: flex;
  gap: 12px;
  padding: 9px 10px;
  border-radius: var(--r-frame);
  transition: background 200ms var(--ease);
  align-items: flex-start;
  text-decoration: none;
  color: inherit;
}
.nav-link:hover { background: rgb(var(--c-fg) / 0.06); }
.nav-link .icn {
  width: 34px; height: 34px;
  border-radius: var(--r-frame);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  color: rgb(var(--c-fg) / 0.72);
  flex-shrink: 0;
  border: 1px solid rgb(var(--c-line) / 0.16);
}
.nav-link .body { min-width: 0; display: flex; flex-direction: column; }
.nav-link .t { display: block; font-size: 0.86rem; font-weight: 600; color: rgb(var(--c-fg)); line-height: 1.25; }
.nav-link .d { display: block; font-size: 0.74rem; color: rgb(var(--c-muted)); margin-top: 2px; line-height: 1.4; }

.nav-dropdown .feature {
  position: relative;
  border-radius: var(--r-frame);
  overflow: clip;
  background: transparent;
  border: 1px solid rgb(var(--c-line) / 0.14);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 100%;
}
.nav-dropdown .feature .tag {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgb(var(--c-muted));
}
.nav-dropdown .feature h4 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  font-size: 1.14rem;
  letter-spacing: 0.01em;
  color: rgb(var(--c-fg));
  line-height: 1.05;
}
.nav-dropdown .feature p { margin: 0; font-size: 0.76rem; color: rgb(var(--c-muted)); line-height: 1.5; }
.nav-dropdown .feature .cta-link {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgb(var(--c-fg));
  margin-top: auto;
}
.nav-dropdown .feature .cta-link::after { content: " →"; }
.nav-dropdown .see-all {
  margin-top: 14px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgb(var(--c-fg));
}
.nav-dropdown .see-all::after { content: "→"; transition: transform 200ms var(--ease); }
.nav-dropdown .see-all:hover::after { transform: translateX(3px); }

/* Mobile menu */
.menu-toggle {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 40px; height: 40px;
  border-radius: var(--r-frame);
  border: 1px solid rgb(var(--c-line) / 0.18);
  background: transparent;
  cursor: pointer;
  color: rgb(var(--c-fg));
}
@media (min-width: 1024px) { .menu-toggle { display: none; } }
.menu-toggle span { display: block; width: 18px; height: 1.5px; background: currentColor; transition: transform 200ms var(--ease), opacity 200ms var(--ease); }
.menu-toggle span + span { margin-top: 4px; }
.menu-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.menu-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.menu-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: rgb(var(--c-base) / 0.98);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  overflow-y: auto;
  transform: translateX(100%);
  transition: transform 200ms var(--ease);
  display: flex;
  flex-direction: column;
}
.mobile-menu[data-open="true"] { transform: translateX(0); }
.mobile-menu .header-row {
  display: flex; align-items: center; justify-content: space-between;
  min-height: 72px; padding: 10px 20px;
  border-bottom: 1px solid rgb(var(--c-line) / 0.1);
}
.mobile-menu .menu-body { padding: 20px; flex: 1; }
.mobile-menu .menu-group { border-bottom: 1px solid rgb(var(--c-line) / 0.1); padding: 18px 0; }
.mobile-menu .menu-group h3 { color: rgb(var(--c-muted)); margin: 0 0 10px; }
.mobile-menu .menu-group a { display: block; padding: 8px 0; font-size: 1rem; color: rgb(var(--c-fg)); }
.mobile-menu .menu-cta { display: flex; flex-direction: column; gap: 10px; padding: 20px; border-top: 1px solid rgb(var(--c-line) / 0.1); }
.mobile-menu .menu-cta .btn { justify-content: center; }
.mobile-menu .menu-flat-link { display: block; padding: 14px 0; font-size: 1rem; font-weight: 600; color: rgb(var(--c-fg)); }
.mobile-menu .menu-prefs { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.mobile-menu .menu-prefs .seo-lang { display: flex; width: 100%; justify-content: center; }
.mobile-menu .menu-prefs .seo-lang select { width: 100%; text-align: center; text-align-last: center; }
.mobile-menu .menu-prefs .seo-theme-toggle { width: 100%; }

/* Header preference controls are desktop-only (xl+), like the React header;
   below that they live in the mobile menu. */
header.site .seo-lang,
header.site .seo-theme-toggle { display: none; }
@media (min-width: 1280px) {
  header.site .seo-lang { display: inline-flex; }
  header.site .seo-theme-toggle { display: inline-flex; }
}

/* Web Studio header button appears from md (768px), like the React header. */
.bar-actions .btn-webstudio { display: none; }
@media (min-width: 768px) { .bar-actions .btn-webstudio { display: inline-flex; } }

/* “Get the app” label collapses to “App” below sm (640px), like React. */
.bar-actions .btn .lbl-full { display: none; }
.bar-actions .btn .lbl-short { display: inline; }
@media (min-width: 640px) {
  .bar-actions .btn .lbl-full { display: inline; }
  .bar-actions .btn .lbl-short { display: none; }
}

/* Inline icons inside pill buttons (Apple / Globe). */
.btn > svg { width: 13px; height: 13px; flex-shrink: 0; }
.mobile-menu .menu-cta .btn > svg { width: 15px; height: 15px; }

/* ------------------------
   Breadcrumb — the ledger's "you are here", and the page's ONE lime tick
   above the fold besides the CTA.
   ------------------------ */
.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  /* 21px, not 26: the links below carry 5px of their own block padding to
     clear the 24px tap target, so the trail's first baseline lands where it
     did before. */
  padding-top: 21px;
  margin: 0 0 6px;
  color: rgb(var(--c-muted));
}
.breadcrumb::before {
  content: "";
  flex: none;
  width: 16px;
  height: 2px;
  background: var(--accent-ink);
}
/* WCAG 2.2 AA, Target Size (Minimum). A breadcrumb link's own text box is
   19px tall; 5px of block padding takes the hit area to 29px without moving
   a single glyph, because the row is `align-items: center`. */
.breadcrumb a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding-block: 5px;
  color: rgb(var(--c-muted));
  text-decoration: none;
  transition: color 200ms var(--ease);
}
.breadcrumb a:hover { color: rgb(var(--c-fg)); }
/* --c-muted, not an alpha of --c-fg: at 0.35 the chevron measured 2.22:1 on
   paper. It is decoration, but it is still a text node. */
.breadcrumb .sep { color: rgb(var(--c-muted)); }
.breadcrumb > span:last-child { color: rgb(var(--c-fg)); }

/* ------------------------
   Hero
   ------------------------ */
.page-hero {
  position: relative;
  padding: 26px 0 64px;
  /* clip, never hidden: an `overflow: hidden` hero is a scroll container and
     every reveal inside it would resolve `view()` against a box that never
     scrolls. */
  overflow: clip;
}
.page-hero .cta-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 32px; }

/* ————— The film edge —————
   A sprocket rail down the document's left margin, as the homepage's Slate
   carries one down the viewport edge: one repeating gradient, no markup, no
   request, and it is what makes a page of type read as a strip of film.
   Desktop only — below 1280px the gutter belongs to the copy. It scrolls with
   the page on purpose (a fixed rail reads as chrome, a scrolling one as
   stock), and it is `absolute`, never `fixed`, because `overflow: clip` on the
   body is not a containing block a fixed rail could be trusted inside. */
body.seo main { position: relative; }
@media (min-width: 1280px) {
  body.seo main::before {
    content: "";
    position: absolute;
    left: 10px;
    top: 8px;
    bottom: 8px;
    width: 6px;
    pointer-events: none;
    background-image: repeating-linear-gradient(
      to bottom,
      transparent 0 8px,
      rgb(var(--c-fg) / 0.13) 8px 19px,
      transparent 19px 27px
    );
  }
  body.legal main::before { left: -34px; }
}
.page-hero .trust { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 28px; }

.chip {
  display: inline-flex;
  align-items: center;
  border: 1px solid rgb(var(--c-line) / 0.16);
  background: transparent;
  border-radius: 999px;
  padding: 7px 13px;
  color: rgb(var(--c-muted));
}

/* A lime alpha wash over paper is a yellow stain, and over film it is the
   glow halo the motion spec deleted. The hero is type on canvas. */
.hero .glow { display: none; }

/* ------------------------
   Sections
   ------------------------ */
section.page {
  position: relative;
  padding: 76px 0;
  border-top: 0;
  /* Restart frame numbering at every section, so a card's number reads as
     its position in the set the visitor is looking at. */
  counter-reset: frame;
}

/* The section hairline, as a pseudo-element so scroll can DRAW it (see the
   reveal block at the foot of this file) instead of just fading it in. */
section.page::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: rgb(var(--c-line) / 0.12);
  transform-origin: left center;
}

.grid { display: grid; gap: 0 28px; margin-top: 40px; }
.cols-2 { grid-template-columns: 1fr; }
.cols-3 { grid-template-columns: 1fr; }
.cols-4 { grid-template-columns: 1fr 1fr; }
@media (min-width: 760px) {
  .cols-2 { grid-template-columns: 1fr 1fr; }
  .cols-3 { grid-template-columns: repeat(3, 1fr); }
  .cols-4 { grid-template-columns: repeat(4, 1fr); }
}

/* ————— A card is a rule and some type —————
   A contact sheet has no boxes, only frames and marks. These cards used to be
   20px-radius tinted panels with a lime hover fill — the look the homepage
   rebuild removed. What is left: the hairline they hang from, a frame number
   in the ledger voice, and a lime tick that draws along the rule under the
   pointer — the grease pencil marking the selected frame. */
.card {
  position: relative;
  counter-increment: frame;
  border: 0;
  border-top: 1px solid rgb(var(--c-line) / 0.14);
  border-radius: 0;
  background: transparent;
  padding: 22px 0 30px;
  scroll-margin-top: 92px;
  transition: border-color 200ms var(--ease);
  display: block;
  color: inherit;
}
.card::before {
  content: "";
  position: absolute;
  top: -1px; left: 0; right: 0;
  height: 1px;
  background: var(--accent-ink);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 320ms var(--ease);
}
.card::after {
  content: counter(frame, decimal-leading-zero);
  position: absolute;
  top: 22px;
  right: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  font-variant-numeric: tabular-nums;
  color: rgb(var(--c-muted));
}
a.card:hover::before, a.card:focus-visible::before { transform: scaleX(1); }
a.card:hover, a.card:focus-visible { border-top-color: rgb(var(--c-line) / 0.32); }

.card h3 { margin: 0 0 8px; font-size: 1.3rem; letter-spacing: 0.008em; line-height: 1.04; color: rgb(var(--c-fg)); max-width: 11em; }
.card p { margin: 0; font-size: 0.92rem; color: rgb(var(--c-muted)); max-width: 29em; }
.card .icn-lg {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px;
  border-radius: var(--r-frame);
  background: transparent;
  border: 1px solid rgb(var(--c-line) / 0.16);
  color: rgb(var(--c-fg) / 0.72);
  margin-bottom: 16px;
}

/* The step numeral is the page's typographic gasp: Bebas, big, outlined. The
   stroke is 0.55 of the foreground — 5.3:1 on film, 3.4:1 on paper, above the
   3:1 a glyph this size has to clear. */
/* Grids earn the full shell; a column of prose does not. Capping the
   linear blocks is what keeps a rule from running 1,360px past the last
   word on the line — the same reason the homepage's Notes chapter stops its
   rules at the index column. */
.steps, .faq > .wrap > div, .article, .toc { max-width: 1080px; }
.steps { margin-top: 36px; }
.step { display: flex; gap: 24px; padding: 26px 0; border-top: 1px solid rgb(var(--c-line) / 0.12); }
.step:first-child { border-top: 0; }
.step .n {
  font-size: clamp(2.6rem, 4.4vw, 3.6rem);
  line-height: 0.9;
  min-width: 1.05em;
  color: transparent;
  -webkit-text-stroke: 0.022em rgb(var(--c-fg) / 0.55);
  paint-order: stroke fill;
}
.step h3 { margin: 0 0 8px; font-size: 1.36rem; letter-spacing: 0.008em; line-height: 1.04; }
.step p { margin: 0; color: rgb(var(--c-muted)); max-width: 39.1em; }

/* ------------------------
   Alternating feature rows with a film plate
   ------------------------ */
.frow { display: grid; gap: 32px; grid-template-columns: 1fr; align-items: center; margin-top: 44px; }
@media (min-width: 900px) { .frow { grid-template-columns: 1fr 1fr; gap: 56px; } .frow + .frow { margin-top: 64px; } }
.frow .copy .eyebrow { margin-bottom: 14px; }
.frow .copy h3 { font-size: clamp(1.7rem, 2.8vw, 2.3rem); margin: 0 0 14px; line-height: 0.98; letter-spacing: 0.004em; }
.frow .copy p { margin: 0; color: rgb(var(--c-fg) / 0.74); font-size: 1rem; max-width: 32.8em; }
.frow .copy ul { list-style: none; padding: 0; margin: 20px 0 0; display: flex; flex-direction: column; gap: 10px; }
.frow .copy li { display: flex; align-items: flex-start; gap: 10px; font-size: 0.92rem; color: rgb(var(--c-fg) / 0.82); }
.frow .copy li svg { width: 16px; height: 16px; stroke: rgb(var(--c-fg) / 0.5); fill: none; flex-shrink: 0; margin-top: 3px; }
.frow.reverse .media { order: -1; }
@media (min-width: 900px) { .frow.reverse .media { order: 1; } .frow.reverse .copy { order: 2; } }

/* ————— The film plate —————
   An `.on-dark` island in BOTH themes: sprocket rails down each edge, the
   512px grain plate the homepage tiles, a vignette to the island's own
   near-black, and the caption in the ledger voice. */
.mock {
  position: relative;
  border-radius: var(--r-frame);
  overflow: clip;
  border: 1px solid rgb(var(--c-line) / 0.14);
  background: #0b0b0b;
  aspect-ratio: 16 / 9;
  box-shadow: var(--shadow-panel);
  --c-base: 8 8 8;
  --c-fg: 255 255 255;
  --c-muted: 160 160 160;
  --c-line: 255 255 255;
  color-scheme: dark;
}
/* Sprocket rails + vignette, one layer above the cells. Gradients, not the
   homepage's SVG pattern: no element, no request, and the hole count follows
   the plate's height for free. */
.mock::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(to bottom, transparent 0 8px, rgba(255, 255, 255, 0.22) 8px 19px, transparent 19px 27px),
    repeating-linear-gradient(to bottom, transparent 0 8px, rgba(255, 255, 255, 0.22) 8px 19px, transparent 19px 27px),
    radial-gradient(115% 92% at 50% 42%, transparent 52%, rgba(8, 8, 8, 0.78) 100%);
  background-size: 6px 100%, 6px 100%, cover;
  background-position: 8px 0, calc(100% - 8px) 0, 0 0;
  background-repeat: repeat-y, repeat-y, no-repeat;
}
/* Grain at the homepage's static register (0.045). Past about 0.08 it stops
   being film and starts being television snow. */
.mock::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: url("/film/grain-512.webp") repeat 0 0 / 512px 512px;
  opacity: var(--film-opacity-static, 0.045);
}
/* A real still in the same box the tile grid occupies. The frame's geometry
   belongs to the box, not the picture, so a page can swap one for the other
   without moving a pixel; absolute + inset so the img cannot size it. */
.mock .mock-img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--r-frame);
}

.mock .grid-tiles {
  position: absolute; inset: 0; padding: 22px 26px;
  display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: 1fr; gap: 7px;
}
/* Empty frames: a hairline cell, not a coloured plate. The old rule filled
   each with a lime gradient and ran a 6s `tilePulse` — decoration pretending
   to be content, and the loudest lime on the page. */
.mock .tile {
  border-radius: 1px;
  position: relative;
  overflow: clip;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.mock .tile:nth-child(3n + 1) { background: rgba(255, 255, 255, 0.055); }
.mock .tile:nth-child(4n) { background: rgba(255, 255, 255, 0.015); }
.mock .badge-lg {
  position: absolute; left: 16px; bottom: 16px; z-index: 5;
  padding: 7px 12px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  background: rgba(8, 8, 8, 0.86);
  color: #ffffff;
}

/* ------------------------
   Proof strip — a run of real frames off the sheet. Not a card grid: rails
   top and bottom, a frame number punched into each frame's corner, caption in
   the ledger voice. Equal columns collapsing 4→2→1; `minmax(0, 1fr)` is what
   stops a wide image pushing the row past 390px. Zero layout shift is
   structural, not careful — `aspect-ratio` + `width: 100%` reserve each box
   before a byte of the image arrives. A portrait strip sets `--proof-ar: 9/16`
   on `.proof`; the frames stay uniform either way, which is the point.
   ------------------------ */
.proof {
  position: relative;
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: 36px;
  padding-block: 20px;
  counter-reset: frame;
}
@media (max-width: 559.98px) { .proof { grid-template-columns: minmax(0, 1fr); } }
@media (min-width: 900px) { .proof { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); } }

/* The perforation rails. Absolutely positioned, so they are out of flow and
   never become grid items of the strip they frame. */
.proof::before,
.proof::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 6px;
  pointer-events: none;
  background-image: repeating-linear-gradient(
    to right,
    transparent 0 8px,
    rgb(var(--c-fg) / 0.14) 8px 19px,
    transparent 19px 27px
  );
}
.proof::before { top: 0; }
.proof::after { bottom: 0; }

.proof-item {
  position: relative;
  margin: 0;
  counter-increment: frame;
}

.proof-img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: var(--proof-ar, 16 / 9);
  object-fit: cover;
  border-radius: var(--r-frame);
  border: 1px solid rgb(var(--c-line) / 0.14);
  /* The plate the frame develops out of, so a slow or failed image is a
     black frame rather than a hole in the strip. */
  background: #0b0b0b;
}

/* The frame number, the way the homepage's contact sheet numbers its takes.
   White on its own near-black chip in both themes — the picture underneath is
   not a background contrast can be measured against. */
.proof-item::after {
  content: counter(frame, decimal-leading-zero);
  position: absolute;
  top: 9px;
  left: 9px;
  padding: 3px 7px;
  border-radius: 1px;
  background: rgba(8, 8, 8, 0.82);
  color: #ffffff;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  line-height: 1.3;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}

.proof-item figcaption {
  margin-top: 10px;
  color: rgb(var(--c-muted));
}

.proof-cap {
  margin: 14px 0 0;
  color: rgb(var(--c-muted));
  max-width: 46.7em;
}

/* ------------------------
   Benefit list (icon + text rows)
   ------------------------ */
.benefits { display: grid; grid-template-columns: 1fr; gap: 0 28px; margin-top: 36px; }
@media (min-width: 680px) { .benefits { grid-template-columns: 1fr 1fr; } }
@media (min-width: 980px) { .benefits.three { grid-template-columns: repeat(3, 1fr); } }
.benefit {
  display: flex; gap: 16px; align-items: flex-start;
  padding: 22px 0 26px;
  border: 0;
  border-top: 1px solid rgb(var(--c-line) / 0.12);
  background: transparent;
}
.benefit .ic {
  flex-shrink: 0; width: 36px; height: 36px;
  border-radius: var(--r-frame);
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent;
  color: rgb(var(--c-fg) / 0.72);
  border: 1px solid rgb(var(--c-line) / 0.16);
}
.benefit .bd h3 { margin: 0 0 5px; font-size: 1.14rem; letter-spacing: 0.008em; line-height: 1.06; }
.benefit .bd p { margin: 0; font-size: 0.88rem; color: rgb(var(--c-muted)); }

/* SVG icons inside the hairline squares */
.card .icn-lg svg, .nav-link .icn svg, .benefit .ic svg { stroke: currentColor; fill: none; }
.card .icn-lg svg { width: 19px; height: 19px; }
.nav-link .icn svg { width: 17px; height: 17px; }
.benefit .ic svg { width: 18px; height: 18px; }

/* ------------------------
   Crosslinks
   ------------------------ */
.crosslinks { display: grid; grid-template-columns: 1fr; gap: 0 28px; margin-top: 40px; counter-reset: frame; }
@media (min-width: 760px) { .crosslinks { grid-template-columns: repeat(3, 1fr); } }
.crosslink {
  position: relative;
  counter-increment: frame;
  border: 0;
  border-top: 1px solid rgb(var(--c-line) / 0.14);
  background: transparent;
  border-radius: 0;
  padding: 22px 0 28px;
  transition: border-color 200ms var(--ease);
  display: block;
  text-decoration: none;
  color: inherit;
}
.crosslink::before {
  content: "";
  position: absolute; top: -1px; left: 0; right: 0; height: 1px;
  background: var(--accent-ink);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 320ms var(--ease);
}
.crosslink::after {
  content: counter(frame, decimal-leading-zero);
  position: absolute; top: 22px; right: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  font-variant-numeric: tabular-nums;
  color: rgb(var(--c-muted));
}
.crosslink:hover::before, .crosslink:focus-visible::before { transform: scaleX(1); }
.crosslink:hover, .crosslink:focus-visible { border-top-color: rgb(var(--c-line) / 0.32); }
.crosslink .k { color: rgb(var(--c-muted)); display: block; }
.crosslink h3 { margin: 12px 0 6px; font-size: 1.24rem; letter-spacing: 0.008em; line-height: 1.04; max-width: 7em; }
.crosslink p { margin: 0; font-size: 0.9rem; color: rgb(var(--c-muted)); }
.crosslink .arrow {
  margin-top: 14px; display: block;
  font-family: var(--font-mono);
  font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase;
  color: rgb(var(--c-fg) / 0.72);
}
.crosslink .arrow::after { content: " →"; }
.crosslink:hover .arrow { color: rgb(var(--c-fg)); }

/* ------------------------
   FAQ — footnotes, not accordions in boxes
   ------------------------ */
.faq details {
  position: relative;
  border: 0;
  border-top: 1px solid rgb(var(--c-line) / 0.12);
  background: transparent;
  border-radius: 0;
  padding: 22px 0;
  margin: 0;
  counter-increment: frame;
}
@media (min-width: 860px) {
  .faq details { padding-left: 44px; }
  .faq details::before {
    content: counter(frame);
    position: absolute;
    left: 0;
    top: 26px;
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: 0.18em;
    font-variant-numeric: tabular-nums;
    color: rgb(var(--c-muted));
  }
}
.faq summary {
  cursor: pointer;
  font-size: clamp(1.24rem, 1.9vw, 1.55rem);
  line-height: 1.04;
  letter-spacing: 0.006em;
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: 20px;
  align-items: center;
  color: rgb(var(--c-fg));
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  font-family: var(--font-body);
  color: rgb(var(--c-fg) / 0.55);
  font-size: 1.3rem;
  line-height: 1;
  flex-shrink: 0;
}
.faq details[open] summary::after { content: "−"; }
.faq details p { margin: 14px 0 0; color: rgb(var(--c-fg) / 0.78); font-size: 0.96rem; max-width: 46.7em; }

/* ------------------------
   Comparison table
   ------------------------ */
.cmp {
  margin-top: 40px;
  border: 0;
  border-top: 1px solid rgb(var(--c-line) / 0.16);
  border-bottom: 1px solid rgb(var(--c-line) / 0.16);
  background: transparent;
  border-radius: 0;
  overflow: clip;
}
/* The comparison table is wider than a phone and always has been. What was
   missing was any sign of it: the classic four-gradient scroll shadow, two
   `local` covers that ride with the content and two `scroll` shadows pinned
   to the box, so an edge shadow appears exactly while there is more table
   past it and vanishes at either end. Pure CSS, no script, no measurement. */
.cmp-wrap {
  overflow-x: auto;
  background:
    linear-gradient(to right, rgb(var(--c-base)), rgb(var(--c-base) / 0)) left center / 32px 100% no-repeat local,
    linear-gradient(to left, rgb(var(--c-base)), rgb(var(--c-base) / 0)) right center / 32px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, rgb(var(--c-fg) / 0.22), rgb(var(--c-fg) / 0)) left center / 14px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgb(var(--c-fg) / 0.22), rgb(var(--c-fg) / 0)) right center / 14px 100% no-repeat scroll;
}
.cmp table { width: 100%; min-width: 720px; border-collapse: collapse; text-align: left; }
.cmp th, .cmp td { padding: 14px 18px 14px 0; font-size: 0.9rem; }
.cmp thead th { color: rgb(var(--c-muted)); border-bottom: 1px solid rgb(var(--c-line) / 0.14); padding-bottom: 12px; }
.cmp tbody tr { border-top: 1px solid rgb(var(--c-line) / 0.08); }
.cmp th[scope="row"] { font-weight: 600; color: rgb(var(--c-fg)); }
.cmp td { color: rgb(var(--c-fg) / 0.74); }

/* ------------------------
   Model chips
   ------------------------ */
.model-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 28px; }

/* ------------------------
   CTA band — the one dark island on the page, in BOTH themes. The homepage
   stages every media chapter on film whatever the theme, and the closing beat
   is the loudest of them: on paper a black slab dropped on the desk, on film
   continuous with the page. The token pins are what keep its captions,
   hairlines and vignette dark inside a light document.
   ------------------------ */
.band {
  position: relative;
  overflow: clip;
  text-align: center;
  border-radius: var(--r-frame);
  padding: 72px 28px;
  background: #080808;
  box-shadow: var(--shadow-panel);
  --c-base: 8 8 8;
  --c-surface: 20 20 20;
  --c-fg: 255 255 255;
  --c-muted: 160 160 160;
  --c-line: 255 255 255;
  --accent-ink: #d1fe17;
  color: rgb(var(--c-fg));
  color-scheme: dark;
}
.band::before {
  content: "";
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background-image:
    repeating-linear-gradient(to bottom, transparent 0 8px, rgba(255, 255, 255, 0.2) 8px 19px, transparent 19px 27px),
    repeating-linear-gradient(to bottom, transparent 0 8px, rgba(255, 255, 255, 0.2) 8px 19px, transparent 19px 27px),
    radial-gradient(115% 95% at 50% 40%, transparent 55%, rgba(8, 8, 8, 0.72) 100%);
  background-size: 6px 100%, 6px 100%, cover;
  background-position: 12px 0, calc(100% - 12px) 0, 0 0;
  background-repeat: repeat-y, repeat-y, no-repeat;
}
.band::after {
  content: "";
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: url("/film/grain-512.webp") repeat 0 0 / 512px 512px;
  opacity: var(--film-opacity-static, 0.045);
}
.band > * { position: relative; z-index: 2; }
.band .eyebrow { justify-content: center; }
/* `section.page h2` is (0,1,2) and would otherwise out-rank a plain
   `.band h2`, taking back the auto margins and leaving the headline
   left-of-centre inside a centred slab. */
section.page .band h2 { margin: 14px auto 0; max-width: 7.8em; }
.band p { margin: 18px auto 0; max-width: 34em; color: rgb(var(--c-muted)); }
.band .cta-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; margin-top: 30px; }

/* ------------------------
   Pricing — the instrument
   ------------------------ */
.pricing-grid { display: grid; gap: 20px; grid-template-columns: 1fr; margin-top: 44px; }
@media (min-width: 900px) { .pricing-grid { grid-template-columns: repeat(3, 1fr); } }
.plan {
  position: relative; display: flex; flex-direction: column; gap: 18px;
  border: 1px solid rgb(var(--c-line) / 0.14);
  background: transparent;
  border-radius: var(--r-frame);
  padding: 30px;
  transition: border-color 200ms var(--ease);
}
.plan:hover { border-color: rgb(var(--c-line) / 0.3); }
/* The chosen frame. This is the sanctioned lime border — one per page. */
.plan.featured { border-color: var(--accent-ink); }
.plan .plan-badge {
  position: absolute; top: -12px; left: 30px;
  background: var(--accent-fill); color: var(--on-accent);
  font-family: var(--font-mono);
  font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;
  padding: 6px 12px; border-radius: 999px;
}
.plan .plan-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.plan .plan-name { color: rgb(var(--c-muted)); }
.plan .plan-credits {
  border-radius: 999px; padding: 5px 11px;
  border: 1px solid rgb(var(--c-line) / 0.16);
  color: rgb(var(--c-muted));
}
.plan.featured .plan-credits { border-color: var(--accent-ink); color: var(--accent-ink); }
.plan .plan-tag { font-size: 0.9rem; color: rgb(var(--c-muted)); margin: 0; }
.plan .plan-price { display: flex; align-items: baseline; gap: 8px; }
.plan .plan-price .amt { font-size: 3rem; line-height: 0.9; color: rgb(var(--c-fg)); }
.plan .plan-price .per { font-size: 0.8rem; font-weight: 600; color: rgb(var(--c-muted)); }
.plan ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 11px; }
.plan li { display: flex; align-items: flex-start; gap: 10px; font-size: 0.9rem; color: rgb(var(--c-fg) / 0.82); }
.plan li svg { width: 15px; height: 15px; stroke: rgb(var(--c-fg) / 0.45); fill: none; flex-shrink: 0; margin-top: 3px; }
.plan.featured li svg { stroke: var(--accent-ink); }
.plan .plan-cta { margin-top: auto; }
.plan .plan-cta .btn { width: 100%; justify-content: center; }

.packs { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; margin-top: 36px; }
@media (min-width: 760px) { .packs { grid-template-columns: repeat(4, 1fr); } }
.pack {
  position: relative; text-align: center; padding: 26px 18px;
  border-radius: var(--r-frame);
  border: 1px solid rgb(var(--c-line) / 0.14);
  background: transparent;
  transition: border-color 200ms var(--ease);
}
.pack:hover { border-color: rgb(var(--c-line) / 0.3); }
.pack .pack-credits {
  font-size: 2.3rem; line-height: 0.9; color: rgb(var(--c-fg));
}
.pack .pack-label { color: rgb(var(--c-muted)); margin-top: 8px; display: block; }
.pack .pack-price { margin-top: 14px; font-size: 1.06rem; font-weight: 700; color: rgb(var(--c-fg)); }
.pack .pack-badge {
  position: absolute; top: -10px; left: 50%; transform: translateX(-50%);
  background: var(--accent-fill); color: var(--on-accent);
  font-family: var(--font-mono);
  font-size: 9px; letter-spacing: 0.18em; text-transform: uppercase;
  padding: 5px 10px; border-radius: 999px; white-space: nowrap;
}

/* ------------------------
   Blog — index cards + long-form article prose
   ------------------------ */
.posts { display: grid; grid-template-columns: 1fr; gap: 0 28px; margin-top: 44px; counter-reset: frame; }
@media (min-width: 760px) { .posts { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .posts { grid-template-columns: repeat(3, 1fr); } }
.post-card {
  position: relative;
  counter-increment: frame;
  display: flex; flex-direction: column; gap: 12px;
  padding: 22px 0 30px;
  border: 0;
  border-top: 1px solid rgb(var(--c-line) / 0.14);
  border-radius: 0;
  background: transparent;
  transition: border-color 200ms var(--ease);
}
.post-card::before {
  content: "";
  position: absolute; top: -1px; left: 0; right: 0; height: 1px;
  background: var(--accent-ink);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 320ms var(--ease);
}
.post-card::after {
  content: counter(frame, decimal-leading-zero);
  position: absolute; top: 22px; right: 0;
  font-family: var(--font-mono);
  font-size: 11px; letter-spacing: 0.18em;
  font-variant-numeric: tabular-nums;
  color: rgb(var(--c-muted));
}
.post-card:hover::before, .post-card:focus-within::before { transform: scaleX(1); }
.post-card:hover, .post-card:focus-within { border-top-color: rgb(var(--c-line) / 0.32); }
.post-card .k { color: rgb(var(--c-muted)); }
.post-card h3 { margin: 0; font-size: 1.28rem; letter-spacing: 0.006em; color: rgb(var(--c-fg)); line-height: 1.06; max-width: 8.6em; }
.post-card p { margin: 0; font-size: 0.9rem; color: rgb(var(--c-muted)); }
.post-card .post-meta { margin-top: auto; padding-top: 6px; color: rgb(var(--c-muted)); }

.article { max-width: min(48rem, 1080px); }
.article > p, .article > ul, .article > ol { color: rgb(var(--c-fg) / 0.82); font-size: 1.04rem; }
section.page .article h2 {
  margin: 56px 0 0;
  font-size: clamp(1.7rem, 2.6vw, 2.35rem);
  line-height: 0.98;
  letter-spacing: 0.002em;
  max-width: 10.2em;
  color: rgb(var(--c-fg));
}
section.page .article h3 {
  margin: 36px 0 0;
  font-family: var(--font-body);
  font-size: 1.12rem;
  font-weight: 700;
  letter-spacing: -0.005em;
  text-transform: none;
  color: rgb(var(--c-fg));
}
.article h2 + p, .article h3 + p { margin-top: 14px; }
.article ul, .article ol { padding-left: 20px; display: flex; flex-direction: column; gap: 8px; }
.article a {
  color: var(--accent-ink);
  font-weight: 500;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.article blockquote {
  margin: 30px 0; padding: 4px 0 4px 22px;
  border-left: 2px solid var(--accent-ink);
  border-radius: 0;
  background: transparent;
  color: rgb(var(--c-fg));
  font-size: 1.06rem;
}
.article .cmp { margin: 36px 0; }
.article .cmp table { min-width: 560px; }
.article-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px; margin-top: 24px;
  color: rgb(var(--c-muted));
}
.article-meta .dot { width: 3px; height: 3px; border-radius: 999px; background: currentColor; }
.article-meta a {
  display: inline-block;
  padding-block: 5px;
  color: rgb(var(--c-fg));
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Article hero: editorial scale, smaller than a marketing page's. */
.page-hero.article-hero h1 { font-size: clamp(2.3rem, 4.4vw, 3.5rem); line-height: 0.94; max-width: 10.2em; }
.page-hero.article-hero .lede { font-size: 1.1rem; }

/* Table of contents — a ledger index, not a panel. */
.toc {
  margin: 0 0 16px;
  padding: 20px 0;
  border-radius: 0;
  border: 0;
  border-top: 1px solid rgb(var(--c-line) / 0.14);
  border-bottom: 1px solid rgb(var(--c-line) / 0.14);
  background: transparent;
}
.toc .toc-title { margin: 0; color: rgb(var(--c-muted)); display: block; }
.toc ol { margin: 14px 0 0; padding-left: 20px; display: grid; gap: 7px; }
@media (min-width: 760px) { .toc ol { grid-template-columns: 1fr 1fr; column-gap: 32px; } }
.toc li { font-size: 0.92rem; color: rgb(var(--c-muted)); }
/* Listed links, not inline ones, so WCAG 2.2's inline exception does not
   apply: 4px of block padding takes an 18px line box to 26px. */
.toc a { display: inline-block; padding-block: 4px; color: rgb(var(--c-fg) / 0.82); font-weight: 500; text-decoration: none; }
.toc a:hover { color: rgb(var(--c-fg)); text-decoration: underline; text-underline-offset: 3px; }
.article h2[id] { scroll-margin-top: 92px; }

/* ------------------------
   Footer + colophon
   ------------------------ */
footer.site { position: relative; padding: 64px 0 36px; border-top: 1px solid rgb(var(--c-line) / 0.12); }
footer.site .row { display: grid; gap: 40px; grid-template-columns: 1fr; }
@media (min-width: 760px) { footer.site .row { grid-template-columns: 1.4fr 2fr; } }
footer.site .foot-brand p { font-size: 0.86rem; color: rgb(var(--c-muted)); margin: 16px 0 0; max-width: 24em; }
footer.site .foot-brand .btn { margin-top: 22px; }
footer.site .foot-cols { display: grid; grid-template-columns: repeat(2, 1fr); gap: 28px; }
@media (min-width: 760px) { footer.site .foot-cols { grid-template-columns: repeat(4, 1fr); } }
/* h3, not h4: these follow the page's <h2> sections, and an h2 -> h4 jump
   is a heading-order failure. They were h4 for as long as shell.js built
   them, where no static check could see it. */
footer.site .foot-cols h3 { color: rgb(var(--c-muted)); margin: 0 0 14px; font-size: 0.86rem; }
footer.site .foot-cols a { display: block; padding: 4px 0; font-size: 0.86rem; color: rgb(var(--c-fg) / 0.72); transition: color 200ms var(--ease); }
footer.site .foot-cols a:hover { color: rgb(var(--c-fg)); }
footer.site .meta {
  display: flex; flex-wrap: wrap; gap: 16px; justify-content: space-between; align-items: center;
  margin-top: 44px; padding-top: 22px;
  border-top: 1px solid rgb(var(--c-line) / 0.12);
  font-size: 0.78rem; color: rgb(var(--c-muted));
}
/* Same tap-target rule as the breadcrumb: Privacy / Terms / Support /
   Cookies were 44×21 to 48×21, all four under the 24px minimum. */
footer.site .meta .meta-links a {
  display: inline-block;
  padding-block: 4px;
}
footer.site .meta a:hover { color: rgb(var(--c-fg)); }
/* The legal pages' inline <style> carries a bare `p { color: rgba(248,250,252,.78) }`
   for their prose, and the footer's copyright line is a `p` too — near-white
   on paper, 1.03:1. Inheritance from `.meta` never reached it because that
   element-level rule wins over an inherited value. */
footer.site .meta p { margin: 0; color: rgb(var(--c-muted)); }
footer.site .meta .meta-links { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 20px; }
footer.site .meta .langs { display: inline-flex; align-items: center; gap: 8px; }
footer.site .meta .langs svg { width: 13px; height: 13px; flex-shrink: 0; }
/* The trademark line carries `opacity:.42` in every page's inline markup,
   which put it at 2.2:1 on film and 2.0:1 on paper — the quietest failing
   text on the site. Inline styles can only be beaten with `!important`, so
   this is the one place the file uses it: the alpha goes back to 1 and the
   quietness comes from --c-muted, which is AA in both themes. */
footer.site .meta .tm { opacity: 1 !important; color: rgb(var(--c-muted)); }

/* The colophon wordmark. shell.js appends it at the very end of the footer,
   below everything, so nothing that was already painted can move. Purely
   decorative and aria-hidden; its height is fixed in `em` of its own font
   size so the Bebas swap cannot resize the box. */
.colophon-mark {
  margin: 56px 0 0;
  padding: 0 24px;
  font-family: var(--font-display);
  font-size: clamp(4.5rem, 13vw, 11rem);
  line-height: 0.78;
  height: 0.78em;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: transparent;
  -webkit-text-stroke: 0.014em rgb(var(--c-fg) / 0.55);
  paint-order: stroke fill;
  user-select: none;
  overflow: clip;
}

/* ------------------------
   Legal pages. Their inline <style> predates the shell — navy #05070D canvas,
   its own measure, its own greys. These rules take them back onto the shared
   canvas without touching a page.
   ------------------------ */
body.legal { background: rgb(var(--c-base)); color: rgb(var(--c-fg)); }
/* 72px of that top padding is the fixed header's reserve: this rule sets
   the `padding` shorthand, so it also replaces the `body.seo main` value
   above at equal specificity. */
body.legal main {
  width: min(48rem, calc(100% - 48px));
  margin: 0 auto;
  padding: 116px 0 84px;
}
body.legal main h1 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.6rem, 6.4vw, 4.4rem);
  line-height: 0.88;
  letter-spacing: -0.012em;
  margin: 14px 0 0;
  text-transform: uppercase;
  color: rgb(var(--c-fg));
}
body.legal main h2 {
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  font-size: 1.6rem;
  line-height: 1;
  letter-spacing: 0.004em;
  margin: 44px 0 0;
  padding-top: 20px;
  border-top: 1px solid rgb(var(--c-line) / 0.12);
  color: rgb(var(--c-fg));
}
body.legal main p, body.legal main li { color: rgb(var(--c-fg) / 0.82); }
body.legal main a { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 3px; }
body.legal .eyebrow {
  color: rgb(var(--c-muted));
  font-family: var(--font-mono);
  font-size: clamp(11px, 0.625vw, 13px);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
body.legal .meta {
  border: 1px solid rgb(var(--c-line) / 0.16);
  background: transparent;
  border-radius: 999px;
  display: inline-flex;
  padding: 8px 14px;
  margin: 16px 0 30px;
  color: rgb(var(--c-muted));
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
/* support.html's own action pills. */
body.legal .actions { display: flex; flex-wrap: wrap; gap: 12px; margin: 30px 0; }
body.legal .button {
  border: 1px solid rgb(var(--c-line) / 0.18);
  border-radius: 999px;
  padding: 12px 18px;
  background: transparent;
  color: rgb(var(--c-fg));
  text-decoration: none;
}

/* ------------------------
   Template watch page. Google only treats a page as a video "watch page" when
   the video is primary content high on the page, so the player sits in the
   hero with real `controls`; `--watch-ar` is the clip's true pixel ratio,
   which sizes the box AND reserves it before metadata loads. Only the colours
   changed here — this behaviour took three Search Console rounds to clear.
   ------------------------ */
.page-hero .watch-figure { position: relative; margin: 32px 0 0; }

.page-hero .watch-video {
  display: block;
  margin: 0 auto;
  width: 100%;
  max-width: min(100%, calc(66vh * var(--watch-ar)));
  aspect-ratio: var(--watch-ar);
  height: auto;
  border-radius: var(--r-frame);
  border: 1px solid rgb(var(--c-line) / 0.14);
  background: #0b0b0b;
  box-shadow: var(--shadow-panel);
}

.page-hero .watch-figure figcaption {
  margin: 16px auto 0;
  max-width: 39.1em;
  text-align: center;
  font-size: 0.86rem;
  color: rgb(var(--c-muted));
}

/* ------------------------
   Reveal on scroll. Scoped THREE ways, and all three matter:

     html.seo-ready   only after shell.js has run, so the static page — what a
                      crawler and a no-JS visitor get — is the finished page.
     .reveal          shell.js adds it ONLY to elements below the fold when it
                      runs. Nothing already on screen is hidden and re-shown,
                      so there is no flash and nothing above the fold depends
                      on an observer firing.
     reduced motion   the block sits inside `prefers-reduced-motion:
                      no-preference`: stillness gets the resting state at once.

   Only `opacity` and `translate` move; neither affects layout, so the reveal
   cannot contribute to CLS.
   ------------------------ */
@keyframes seo-rise {
  from { opacity: 0; translate: 0 var(--reveal-y, 14px); }
  to { opacity: 1; translate: none; }
}
@keyframes seo-tick {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

@media (prefers-reduced-motion: no-preference) {
  /* Scroll-driven branch. `animation-fill-mode: both` is what makes the
     first paint correct: an element past its range sits at the END state,
     which is the resting state. */
  @supports (animation-timeline: view()) {
    html.seo-ready .reveal {
      animation: seo-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 58%;
    }
    html.seo-ready section.page.reveal-tick::before {
      animation: seo-tick linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 76%;
    }
  }

  /* IntersectionObserver branch (Firefox, Safari < 26). The element holds
     its START state until shell.js adds `.in-view`; the 3.5s delayed
     keyframe is the CSS watchdog that matches the observer's own, so
     nothing can stay hidden because an observer never fired. */
  @supports not (animation-timeline: view()) {
    html.seo-ready .reveal:not(.in-view) {
      opacity: 0;
      translate: 0 var(--reveal-y, 14px);
      animation: seo-rise 520ms var(--ease) 3.5s both;
    }
    html.seo-ready section.page.reveal-tick:not(.in-view)::before {
      transform: scaleX(0);
      animation: seo-tick 700ms var(--ease) 3.5s both;
    }
    /* The END state, reached by transition. Declared on the after-change
       state so an element that already carried `.in-view` does not replay. */
    html.seo-ready .reveal.in-view {
      opacity: 1;
      translate: none;
      animation: none;
      transition: opacity 520ms var(--ease), translate 520ms var(--ease);
    }
    html.seo-ready section.page.reveal-tick.in-view::before {
      transform: scaleX(1);
      animation: none;
      transition: transform 700ms var(--ease);
    }
  }
}

/* ------------------------
   Reduced motion
   ------------------------ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .btn:hover { transform: none !important; }
  .card::before, .crosslink::before, .post-card::before { transition: none !important; }
}

/* ————— Header fit (overrides, must stay last) —————
   Measured before this block: brand 106 + nav 730 + actions 522 in 1341px of
   bar, so `.bar-actions` overhung by 49px and the App CTA was clipped at EVERY
   desktop width. Three graduated reliefs, largest first. */
@media (min-width: 1160px) { .nav-desktop { display: inline-flex; } }

/* 1. Tighter nav labels on desktop: 0.18em is the eyebrow value, and a
      six-item nav bar is not an eyebrow. */
@media (min-width: 1160px) {
  .nav-trigger, .nav-plain { padding-left: 9px; padding-right: 9px; letter-spacing: 0.1em; }
}

/* 2. Web Studio is reachable from the footer and the mobile menu, so it is
      the first thing to go when the row is tight. */
@media (min-width: 1160px) and (max-width: 1439.98px) {
  .bar-actions .btn-webstudio { display: none; }
}

/* 3. Below xl the icon carries the brand on its own. */
@media (min-width: 1160px) and (max-width: 1279.98px) {
  .brand .name { display: none; }
}
