/* ============================================================
   RestMap — shared marketing design system  ·  "Road atlas, hand-kept"
   v1 · 2026-07-04 · replaces per-page inline CSS on marketing pages.

   Direction: the visual language of American highway travel, kept with
   editorial care. Warm paper ground, highway-sign blue + brand teal
   accents, Fraunces display type, enamel grade badges, a dashed
   route-line motif. Light-first with a considered dark mode.

   Performance contract: no blocking JS, CSS-only motion, LCP is the H1.
   Cache note: css/js is cached 1 year immutable — bump the filename
   (site.v2.css) on any post-deploy change.
   ============================================================ */

/* ---------- tokens ---------- */
:root {
  /* ground */
  --paper: #F8F4EA;          /* warm cream — the page */
  --paper-deep: #EFE8D8;     /* deeper paper — alt sections */
  --card: #FFFDF7;           /* raised paper */
  --ink: #24313A;            /* deep blue-slate text  — 12.14 : 1 on paper */
  --ink-2: #4B5860;          /* secondary text        —  6.68 : 1 on paper, 6.01 on paper-deep */
  --muted: #5F686F;          /* tertiary text         —  5.17 : 1 on paper, 4.65 on paper-deep */
  --line: rgba(36, 49, 58, 0.16);
  --line-soft: rgba(36, 49, 58, 0.09);

  /* accents */
  --sign-blue: #1A4E86;      /* FHWA service-sign blue */
  --sign-blue-deep: #143C68;
  --brand: #30B0C7;          /* app teal (theme-color) */
  --brand-cta: #0E7A8B;      /* AA-contrast teal for links/CTAs on paper */
  --brand-cta-hover: #0A6573;
  /* Label colour for text sitting ON an accent FILL (not on paper). The accent
     tokens are tuned for their text-on-paper role; in dark they lighten, so a
     white label on that same fill drops to ~2:1. Flip the label instead. */
  --on-accent: #FFFFFF;
  --on-warm: #14181D;        /* amber/grade-b fills are too light for white in EITHER mode */
  --grade-a: #2E7D4F;        /* enamel green */
  --grade-b: #B97A1F;        /* amber */
  --stamp-red: #A94438;

  /* ---- TEXT role of the accents (the mirror image of --on-accent above) ----
     An accent token carries ONE value but serves THREE roles: fill, border, and
     text. The value that is right as a fill is not the value that is right as
     text — measured on the real render, --brand-cta and --grade-a as text on
     --paper-deep read 4.12 and 4.13, and --sign-blue as text in dark mode reads
     2.41. Fills keep the vivid token; TEXT uses these. Every pair below clears
     AA (4.5) on all three grounds — paper, card AND paper-deep.
     Rule for new components: an accent behind text needs --on-*; an accent AS
     text needs --*-ink. Never the raw token. */
  --brand-ink: #0B6675;      /* 6.03 / 6.51 / 5.42 */
  --brand-ink-hover: #073F49;/* the fill token's hover is a 3% step from --brand-ink — invisible */
  --sign-blue-ink: #1A4E86;  /* 7.72 / 8.33 / 6.94 */
  --grade-a-ink: #25663F;    /* 6.27 / 6.77 / 5.64 */
  --grade-b-ink: #8A5B16;    /* 5.33 / 5.75 / 4.79 — raw amber as text is 3.26, unusable */
  --stamp-red-ink: #93382D;  /* 6.72 / 7.26 / 6.05 */

  /* type */
  --font-display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --font-body: 'Schibsted Grotesk', -apple-system, 'Helvetica Neue', Arial, sans-serif;
  --font-mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, monospace;

  /* type scale. There was none: four separate clamp() triples produced four
     different sizes for headings at the SAME semantic level (section H2s at
     2.4 / 2.5 / 2.3 / 2.6rem), differing by 1-5px — too small to read as
     deliberate, too large to read as consistent. One token per level. */
  --t-card:  1.16rem;                          /* card + FAQ item titles      */
  --t-sub:   1.5rem;                           /* sub-section headings        */
  --t-sect:  clamp(1.75rem, 3.1vw, 2.45rem);   /* every section-level H2      */
  --t-page:  clamp(1.9rem, 3.8vw, 2.9rem);     /* page H1                     */
  --t-home:  clamp(2.35rem, 4.6vw, 3.7rem);    /* home + 404 H1               */

  /* shape */
  --r-s: 8px; --r-m: 14px; --r-l: 22px;
  --shadow-card: 0 1px 2px rgba(46, 38, 20, 0.06), 0 10px 30px -12px rgba(46, 38, 20, 0.18);
  --shadow-lift: 0 2px 4px rgba(46, 38, 20, 0.08), 0 18px 44px -14px rgba(46, 38, 20, 0.26);

  --maxw: 1120px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #14181D;
    --paper-deep: #10141a;
    --card: #1C222A;
    --ink: #ECE6D9;
    --ink-2: #ADB5BB;
    --muted: #8B959C;        /* was #7E888F — 4.43 on --card, just under AA */
    --line: rgba(236, 230, 217, 0.16);
    --line-soft: rgba(236, 230, 217, 0.08);
    --sign-blue: #24578F;
    --sign-blue-deep: #1B4272;
    --brand-cta: #4FC3D8;
    --brand-cta-hover: #6ED2E4;
    --on-accent: #14181D;    /* see the light-mode note: white on #4FC3D8 is 2.07:1 */
    --grade-a: #4CAE7B;
    --grade-b: #D89A3F;
    --stamp-red: #D06A5C;
    /* Text role in dark. The light values would be near-invisible here, and
       --sign-blue is the standout: as text it reads 2.41 on --paper and 2.16
       on --card, so .callout headings were failing across blog + glossary +
       iq-platform. The others are already legible as text once lightened. */
    --brand-ink: #4FC3D8;      /* 8.60 / 7.72 / 8.91 */
    --brand-ink-hover: #8CDCEC;
    --sign-blue-ink: #7FB0E6;  /* 7.86 / 7.06 / 8.14 */
    --grade-a-ink: #4CAE7B;    /* 6.49 / 5.83 / 6.73 */
    --grade-b-ink: #D89A3F;    /* 7.31 / 6.57 / 7.58 */
    --stamp-red-ink: #E08476;  /* lifted from #D06A5C, which was 4.50 on --card — exactly on the line */
    --shadow-card: 0 1px 2px rgba(0,0,0,0.4), 0 10px 30px -12px rgba(0,0,0,0.55);
    --shadow-lift: 0 2px 4px rgba(0,0,0,0.45), 0 18px 44px -14px rgba(0,0,0,0.65);
  }
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* the skip link is an accessibility escape hatch — animating it defeats the
   purpose, and focus can land before the scroll finishes */
:target, #main-content { scroll-behavior: auto; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* paper grain — one tiny inline SVG, fixed, ~3% */
body::before {
  content: "";
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  opacity: 0.035;
  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.9' numOctaves='2'/%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.05; } }

main, footer, .fixed-header { position: relative; z-index: 1; }

h1, h2, h3 { font-family: var(--font-display); font-weight: 700; line-height: 1.14; margin: 0 0 0.6em; letter-spacing: -0.012em; }
p { margin: 0 0 1em; }
a { color: var(--brand-ink); text-decoration-thickness: 1px; text-underline-offset: 3px; overflow-wrap: anywhere; }
a:hover { color: var(--brand-ink-hover); }
img { max-width: 100%; height: auto; }

.skip-to-content {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--sign-blue); color: #fff; padding: 0.6rem 1rem; border-radius: 0 0 var(--r-s) 0;
}
.skip-to-content:focus { left: 0; }

.shell { max-width: var(--maxw); margin: 0 auto; padding: 0 clamp(1.1rem, 4vw, 2rem); }

/* ---------- route-line motif ---------- */
.route-rule {
  height: 12px; margin: 0 auto; max-width: var(--maxw);
  background:
    radial-gradient(circle 3px at 8px 6px, var(--brand) 98%, transparent) 0 0 / 64px 12px repeat-x,
    repeating-linear-gradient(90deg, var(--line) 0 14px, transparent 14px 26px) 0 5.5px / 100% 1.5px no-repeat;
  opacity: 0.75;
}

/* mile-marker section headers */
.mile { display: flex; align-items: baseline; gap: 0.9rem; }
.mile .mm {
  font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.14em;
  color: #FDFBF4; background: var(--sign-blue); border-radius: 5px;
  padding: 0.28rem 0.5rem; transform: translateY(-2px);
  box-shadow: inset 0 0 0 1.5px rgba(255,255,255,0.35), 0 1px 2px rgba(0,0,0,0.18);
  white-space: nowrap;
}
.eyebrow {
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--brand-ink); margin-bottom: 0.65rem;
}

/* keyboard focus — branded ring; UA default is low-contrast on our accent fills */
:where(a, button, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--brand-cta);
  outline-offset: 2px;
  border-radius: var(--r-s);
}

/* ---------- nav ---------- */
.fixed-header { position: sticky; top: 0; z-index: 300; }
.site-nav {
  display: flex; align-items: center; justify-content: space-between;
  max-width: var(--maxw); margin: 0 auto; padding: 0.7rem clamp(1.1rem, 4vw, 2rem);
}
.fixed-header::after { content: ""; position: absolute; inset: 0; z-index: -1;
  background: color-mix(in srgb, var(--paper) 86%, transparent);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-soft);
}
.nav-logo { display: flex; align-items: center; gap: 0.55rem; text-decoration: none; color: var(--ink); }
.nav-logo img { border-radius: 7px; }
.nav-logo span { font-family: var(--font-display); font-weight: 700; font-size: 1.18rem; letter-spacing: -0.01em; }
.nav-links { display: flex; align-items: center; gap: 1.4rem; }
.nav-link { color: var(--ink-2); text-decoration: none; font-weight: 500; font-size: 0.95rem; }
.nav-link:hover { color: var(--ink); }
.nav-cta {
  background: var(--brand-cta); color: var(--on-accent) !important; text-decoration: none;
  font-weight: 600; font-size: 0.92rem; padding: 0.5rem 1.05rem; border-radius: 999px;
  transition: background 0.18s ease, transform 0.18s ease;
}
.nav-cta:hover { background: var(--brand-cta-hover); transform: translateY(-1px); }
@media (max-width: 768px) { .nav-links .nav-link { display: none; } }

/* ---------- hero ---------- */
.home-hero { padding: clamp(2.6rem, 7vw, 5.2rem) 0 clamp(2.2rem, 5vw, 3.6rem); overflow: hidden; }

/* atlas relief — the WebGL "driving through the atlas" scene
   (js/atlas-relief.js). Hosts carry data-atlas-relief; the canvas is
   injected as the host's first child and must never affect layout or
   intercept input. Content stacks above it; the ::after scrim keeps copy
   legible over the moving scene and fades the diorama into the page at
   the top and bottom edges. When the canvas is absent (no WebGL,
   reduced capability), the scrim blends paper-on-paper: invisible. */
[data-atlas-relief] { position: relative; }
[data-atlas-relief] > *:not(.atlas-relief) { position: relative; z-index: 1; }
.atlas-relief {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%;
  pointer-events: none;
}
[data-atlas-relief]::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    linear-gradient(94deg,
      var(--paper) 0%,
      color-mix(in srgb, var(--paper) 88%, transparent) 30%,
      color-mix(in srgb, var(--paper) 46%, transparent) 56%,
      color-mix(in srgb, var(--paper) 10%, transparent) 74%,
      transparent 92%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--paper) 70%, transparent) 0%,
      transparent 16%,
      transparent 78%,
      var(--paper) 100%);
}
/* centered narrow heroes (premium): the scene escapes the column to
   full viewport width; the host column itself is untouched */
[data-atlas-relief].pro-hero > .atlas-relief,
[data-atlas-relief].pro-hero > .atlas-pins,
[data-atlas-relief].pro-hero::after {
  left: 50%; right: auto; width: 100vw; transform: translateX(-50%);
}
/* centered heroes (premium) want a radial pocket, not a left wall */
[data-atlas-relief].pro-hero::after {
  background:
    radial-gradient(ellipse 78% 72% at 50% 42%,
      color-mix(in srgb, var(--paper) 82%, transparent) 0%,
      color-mix(in srgb, var(--paper) 55%, transparent) 48%,
      transparent 78%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--paper) 70%, transparent) 0%,
      transparent 18%,
      transparent 78%,
      var(--paper) 100%);
}
/* the phone drifts on the breeze over the moving map */
@media (prefers-reduced-motion: no-preference) {
  [data-atlas-relief] .hero-phone {
    animation: atlas-float 9s ease-in-out infinite;
  }
  @keyframes atlas-float {
    0%, 100% { transform: rotate(1.2deg) translateY(0); }
    50% { transform: rotate(0.6deg) translateY(-9px); }
  }
}
.hero-grid {
  max-width: var(--maxw); margin: 0 auto; padding: 0 clamp(1.1rem, 4vw, 2rem);
  display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: clamp(2rem, 5vw, 4.5rem); align-items: center;
}
.hero-kicker {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-size: 0.8rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-2); border: 1px solid var(--line); border-radius: 999px;
  padding: 0.36rem 0.85rem; margin-bottom: 1.3rem; background: var(--card);
}
.hero-kicker::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--grade-a); }
.home-hero h1 {
  font-size: var(--t-home); font-weight: 640;
  font-variation-settings: "opsz" 90; margin-bottom: 0.5em;
}
.hero-lede { font-size: clamp(1.05rem, 1.5vw, 1.2rem); color: var(--ink-2); max-width: 36em; }
.hero-actions { display: flex; align-items: center; gap: 1.3rem; margin: 1.7rem 0 1.4rem; flex-wrap: wrap; }
.app-store-badge img { display: block; height: 48px; width: auto; }
.app-store-badge { transition: transform 0.18s ease; display: inline-block; }
.app-store-badge:hover { transform: translateY(-2px); }
.secondary-link { font-weight: 600; }

.hero-desktop-download {
  display: flex; align-items: center; gap: 0.9rem; margin: 0.4rem 0 1.4rem;
  color: var(--ink-2); font-size: 0.9rem; max-width: 24rem;
}
.hero-desktop-download img { border-radius: var(--r-s); background: #fff; padding: 4px; border: 1px solid var(--line); }
.hero-desktop-download p { margin: 0; line-height: 1.45; }
.hero-desktop-download strong { display: block; color: var(--ink); }
@media (max-width: 900px) { .hero-desktop-download { display: none; } }

/* trust row — field data */
.trust-row {
  list-style: none; display: flex; flex-wrap: wrap; gap: 0.5rem 2rem;
  margin: 0; padding: 0.9rem 0 0; border-top: 1.5px dashed var(--line);
  font-size: 0.92rem; color: var(--ink-2);
}
.trust-row strong { color: var(--ink); font-family: var(--font-display); font-size: 1.15rem; font-weight: 700; margin-right: 0.3rem; }
.maker-line { margin-top: 1rem; font-size: 0.88rem; color: var(--muted); }
.maker-line a { color: inherit; }

/* hero visual — screenshot as pinned field photo */
.hero-visual { position: relative; justify-self: center; }
.hero-phone {
  background: var(--card); border: 1px solid var(--line); border-radius: 30px;
  padding: 10px; box-shadow: var(--shadow-lift);
  transform: rotate(1.6deg); max-width: 300px;
  transition: transform 0.35s ease;
}
.hero-phone:hover { transform: rotate(0.4deg) translateY(-4px); }
.hero-phone img { display: block; border-radius: 22px; }
.phone-badge {
  position: absolute; z-index: 2; left: -20%; bottom: -7%;
  max-width: 15rem; background: var(--card); border: 1px solid var(--line);
  border-left: 4px solid var(--brand); border-radius: var(--r-m);
  box-shadow: var(--shadow-card); padding: 0.65rem 0.85rem;
  font-size: 0.8rem; line-height: 1.45; color: var(--ink-2);
  transform: rotate(-0.8deg);
}
.phone-badge strong { display: block; color: var(--ink); margin-bottom: 0.15rem; }
/* The enamel grade badge pinned to the hero phone. It must agree with the
   screenshot underneath it: that screenshot's "YOUR BEST OPTION" card and its
   map pin both read B, so a green A here was contradicted twice inside 500px —
   the first quality claim a visitor sees, disproved by the evidence beside it.
   Badge is now B, in the B ink (amber), with the dark label amber requires. */
.hero-grade {
  position: absolute; z-index: 2; top: 6%; right: -7%;
  width: 62px; height: 62px; border-radius: 50%;
  background: var(--grade-b); color: var(--on-warm);
  display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 800; font-size: 1.7rem;
  box-shadow: inset 0 0 0 3px rgba(255,255,255,0.55), inset 0 0 0 6px var(--grade-b), 0 6px 18px -6px rgba(0,0,0,0.4);
  transform: rotate(6deg);
}
@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; }
  /* The illustration used to be force-ordered ABOVE the copy on phones, so the
     first screen of every page was a decorative image with no proposition and
     no CTA — the headline, lede and App Store button all started below the
     fold. Copy leads; the visual follows it. */
  /* the phone badge and grade disc overhang the column by ~9px; .home-hero
     has overflow:hidden for the atlas canvas, so give the box the room. */
  .hero-visual { margin: 0.8rem 0 0.6rem; padding: 0 10px; }
  .hero-phone { max-width: 210px; transform: rotate(1.2deg); }
  .phone-badge { left: auto; right: -4%; bottom: -6%; max-width: 13rem; }
  .hero-grade { right: auto; left: -4%; }
}

/* page-load stagger (hero only, cheap) */
@media (prefers-reduced-motion: no-preference) {
  .hero-copy > * { opacity: 0; transform: translateY(10px); animation: rise 0.6s cubic-bezier(0.2, 0.7, 0.2, 1) forwards; }
  .hero-copy > *:nth-child(1) { animation-delay: 0.02s; }
  .hero-copy > *:nth-child(2) { animation-delay: 0.08s; }
  .hero-copy > *:nth-child(3) { animation-delay: 0.16s; }
  .hero-copy > *:nth-child(4) { animation-delay: 0.24s; }
  .hero-copy > *:nth-child(5) { animation-delay: 0.30s; }
  .hero-copy > *:nth-child(6) { animation-delay: 0.36s; }
  .hero-copy > *:nth-child(7) { animation-delay: 0.42s; }
  .hero-visual { opacity: 0; transform: translateY(14px); animation: rise 0.7s 0.2s cubic-bezier(0.2, 0.7, 0.2, 1) forwards; }
  @keyframes rise { to { opacity: 1; transform: none; } }
}

/* scroll reveal (JS adds .in). Hiding is gated on html.js-anim, which only
   the reveal script sets — if JS is blocked, errors out, or never runs,
   .reveal content stays fully visible instead of leaving blank sections. */
@media (prefers-reduced-motion: no-preference) {
  html.js-anim .reveal { opacity: 0; transform: translateY(16px); transition: opacity 0.55s ease, transform 0.55s cubic-bezier(0.2, 0.7, 0.2, 1); }
  html.js-anim .reveal.in { opacity: 1; transform: none; }
}

/* ---------- daily strip — roadside marquee ---------- */
.daily-strip { padding: 0.4rem 0 0.8rem; }
.daily-strip-inner {
  max-width: var(--maxw); margin: 0 auto;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  background: var(--sign-blue); color: #F4F8FD; text-decoration: none;
  border-radius: var(--r-m); padding: 0.9rem 1.3rem;
  box-shadow: inset 0 0 0 2px rgba(255,255,255,0.28), inset 0 0 0 5px var(--sign-blue), var(--shadow-card);
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.daily-strip-inner:hover { transform: translateY(-2px); box-shadow: inset 0 0 0 2px rgba(255,255,255,0.38), inset 0 0 0 5px var(--sign-blue), var(--shadow-lift); }
@media (min-width: 1121px) { .daily-strip .daily-strip-inner { margin: 0 auto; } }
@media (max-width: 1160px) { .daily-strip { padding-left: 1.1rem; padding-right: 1.1rem; } }
.daily-strip-text { display: flex; align-items: center; gap: 0.95rem; }
.daily-strip-glyph { border-radius: 50%; border: 2px solid rgba(255,255,255,0.7); }
.daily-strip-label { margin: 0; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: #BCD3EC; }
.daily-strip-headline { margin: 0.1rem 0 0; font-family: var(--font-display); font-weight: 700; font-size: 1.12rem; color: #fff; }
.daily-strip-sub { margin: 0.15rem 0 0; font-size: 0.82rem; color: #C9DBEF; }
.daily-strip-cta { flex-shrink: 0; font-weight: 700; font-size: 0.95rem; color: #fff; border: 1.5px solid rgba(255,255,255,0.55); border-radius: 999px; padding: 0.45rem 1rem; }
/* Phone layout used to hide BOTH the explanatory sub AND the "Play now" CTA,
   leaving an unlabelled blue box on the viewport where most readers actually
   are. Keep the call to action; stack it under the copy and let the sub carry
   the short half of its sentence rather than vanish. */
@media (max-width: 700px) {
  .daily-strip-inner { flex-direction: column; align-items: flex-start; gap: 0.75rem; }
  .daily-strip-cta { align-self: stretch; text-align: center; }
  .daily-strip-sub { display: block; font-size: 0.78rem; }
}

/* ---------- showcase ---------- */
.screenshot-showcase { padding: clamp(3rem, 7vw, 5.5rem) 0; }
.showcase-container {
  max-width: var(--maxw); margin: 0 auto; padding: 0 clamp(1.1rem, 4vw, 2rem);
  display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 5fr); gap: clamp(2rem, 5vw, 4.5rem); align-items: center;
}
.showcase-text h2 { font-size: var(--t-sect); }
.showcase-text > p { color: var(--ink-2); max-width: 34em; }
.showcase-features { list-style: none; margin: 1.4rem 0 0; padding: 0; display: grid; gap: 0.75rem; }
.showcase-features li {
  display: flex; gap: 0.7rem; align-items: baseline;
  font-size: 0.98rem; color: var(--ink-2);
  padding-left: 0.1rem;
}
.showcase-dot { flex-shrink: 0; width: 9px; height: 9px; border-radius: 50%; background: var(--brand); transform: translateY(-1px); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 22%, transparent); }
.iphone-mockup { justify-self: center; text-align: center; width: 100%; max-width: 430px; }
.iphone-frame {
  background: var(--card); border: 1px solid var(--line); border-radius: 34px; padding: 11px;
  box-shadow: var(--shadow-lift); width: 100%; max-width: min(clamp(320px, 34vw, 430px), 40vh); margin: 0 auto;
}
.iphone-screen { border-radius: 25px; overflow: hidden; position: relative; aspect-ratio: 552 / 1200; }
.screenshot-carousel img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 0.5s ease; }
.screenshot-carousel img.active { opacity: 1; }
.carousel-dots { display: flex; gap: 0.1rem; justify-content: center; margin-top: 1.1rem; }
/* The visible dot stays 10px; the TAP TARGET is 24px (WCAG 2.2 AA 2.5.8).
   Padding plus content-box background-clip grows the hit area without
   growing the mark. */
.carousel-dot {
  width: 10px; height: 10px; box-sizing: content-box; padding: 7px;
  border-radius: 50%; border: 1.5px solid var(--muted);
  background: transparent; background-clip: content-box;
  cursor: pointer; transition: background 0.2s, border-color 0.2s, transform 0.2s;
}
.carousel-dot:hover { transform: scale(1.25); }
.carousel-dot.active { background: var(--brand-cta); background-clip: content-box; border-color: var(--brand-cta); }

/* Carousel pause control (WCAG 2.2.2 Pause, Stop, Hide — Level A). The carousel
   auto-advanced every 2.8s indefinitely and mouse hover was the only way to stop
   it, which is no mechanism at all for keyboard or touch. Sits with the dots so
   the whole control group reads as one unit. */
.carousel-toggle {
  display: inline-flex; align-items: center; gap: 0.35rem;
  margin-left: 0.5rem; padding: 5px 10px; min-height: 24px;
  font-family: var(--font-body); font-size: 0.72rem; font-weight: 600;
  letter-spacing: 0.04em; color: var(--ink-2);
  background: var(--card); border: 1px solid var(--line); border-radius: 999px;
  cursor: pointer; transition: color 0.2s, border-color 0.2s;
}
.carousel-toggle:hover { color: var(--ink); border-color: var(--brand-ink); }
.carousel-toggle-glyph {
  width: 8px; height: 9px; flex-shrink: 0;
  border-left: 3px solid currentColor; border-right: 3px solid currentColor;
}
/* pressed = paused, so the glyph becomes a play triangle */
.carousel-toggle[aria-pressed="true"] .carousel-toggle-glyph {
  width: 0; height: 0; border-left: 8px solid currentColor; border-right: 0;
  border-top: 5px solid transparent; border-bottom: 5px solid transparent;
}
@media (max-width: 900px) { .showcase-container { grid-template-columns: 1fr; } }

/* ---------- sections & cards ---------- */
.features, .mode-section, .faq, .maker-note { padding: clamp(2.8rem, 6.5vw, 5rem) 0; }
.section-band { background: var(--paper-deep); border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft); }
.section-header { max-width: 44rem; margin: 0 auto 2.6rem; text-align: center; padding: 0 1.1rem; }
.section-header h2 { font-size: var(--t-sect); }
.section-header > p:last-child { color: var(--ink-2); }
.section-shell { max-width: var(--maxw); margin: 0 auto; padding: 0 clamp(1.1rem, 4vw, 2rem); }

/* Card rows. auto-fit grid tracks always fill from the left, so a partial last
   row leaves an orphan hard against the left edge with dead columns beside it —
   index has 7 cards in a 3-up (3+3+1), about and compare each have a 4-card grid
   (3+1). Four separate sections therefore ENDED on a row that looks unfinished.
   Flex wrap + centred justification lets a short final row sit under the middle
   of the row above; align-items defaults to stretch, so cards on a line keep
   equal height exactly as the grid gave us. */
.features-grid, .mode-grid {
  max-width: var(--maxw); margin: 0 auto; padding: 0 clamp(1.1rem, 4vw, 2rem);
  display: flex; flex-wrap: wrap; justify-content: center; gap: 1.1rem;
}
.features-grid > *, .mode-grid > * {
  flex: 1 1 270px;
  max-width: 356px;
}
@media (max-width: 620px) { .features-grid > *, .mode-grid > * { max-width: none; } }
.mode-section .mode-grid { padding: 0; }
.feature-card, .mode-card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-m);
  padding: 1.5rem 1.4rem 1.4rem; box-shadow: var(--shadow-card);
  position: relative;
}
/* h4 carried NO rule, so 30 related-card titles rendered in the body face
   at UA default size while their siblings used the display face. */
.feature-card h2, .mode-card h2,
.feature-card h3, .mode-card h3,
.feature-card h4, .mode-card h4 { font-size: var(--t-card); margin: 0.9rem 0 0.45rem; }
.feature-card p, .mode-card p { font-size: 0.94rem; color: var(--ink-2); margin: 0; }
/* Multi-paragraph card copy ran together as one block: `.feature-card p` sets
   margin:0, so two <p> in a card sat one line apart — the same leading as
   inside a paragraph. */
.feature-card p + p, .mode-card p + p { margin-top: 0.8em; }
/* /premium is the one page carrying 200-word essays in a component built for a
   96px icon and a blurb, so its rows stretched to the tallest card and left up
   to ~250px of empty card beside it. Scoped to that page rather than applied to
   `.features-grid` globally, which would end equal-height cards on all 23 card
   grids sitewide — grids that render correctly today. */
body.pro-page .features-grid { align-items: flex-start; }
.feature-icon img, .mode-icon img { width: 60px; height: 60px; border-radius: var(--r-s); display: block; }
.mode-card { text-decoration: none; color: var(--ink); display: block; transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; }
.mode-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lift); border-color: color-mix(in srgb, var(--brand-cta) 45%, var(--line)); }
.mode-card .learn { display: inline-block; margin-top: 0.9rem; font-weight: 650; font-size: 0.9rem; color: var(--brand-ink); }
.mode-card .learn::after { content: " \2192"; transition: transform 0.2s; display: inline-block; }
.mode-card:hover .learn::after { transform: translateX(3px); }

/* ---------- FAQ — field notes ---------- */
.faq .section-title { text-align: center; font-size: var(--t-sect); margin-bottom: 2.2rem; }
.faq-container { max-width: 46rem; margin: 0 auto; padding: 0 1.1rem; counter-reset: faq; }
.faq-item {
  padding: 1.35rem 0 1.15rem 3.1rem; position: relative;
  border-bottom: 1.5px dashed var(--line);
}
.faq-item:first-child { border-top: 1.5px dashed var(--line); }
.faq-item::before {
  counter-increment: faq; content: counter(faq, decimal-leading-zero);
  position: absolute; left: 0; top: 1.5rem;
  font-family: var(--font-mono); font-size: 0.78rem; letter-spacing: 0.06em;
  color: var(--brand-ink); border: 1px solid var(--line); border-radius: 6px; padding: 0.2rem 0.4rem;
  background: var(--card);
}
.faq-item h3 { font-size: 1.14rem; margin-bottom: 0.4rem; }
.faq-item p { color: var(--ink-2); font-size: 0.97rem; margin: 0; }

/* ---------- maker note ---------- */
.maker-note .note-card {
  max-width: 46rem; margin: 0 auto; padding: clamp(1.6rem, 4vw, 2.6rem);
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-l);
  box-shadow: var(--shadow-card); position: relative;
  display: grid; grid-template-columns: 84px 1fr; gap: 1.4rem; align-items: start;
}
.maker-note img { border-radius: 50%; border: 3px solid var(--paper-deep); box-shadow: var(--shadow-card); }
.maker-note h2 { font-size: 1.45rem; margin-bottom: 0.5rem; }
.maker-note p { color: var(--ink-2); font-size: 0.98rem; }
.maker-note .signoff { font-family: var(--font-display); font-style: italic; color: var(--ink); font-size: 1.05rem; margin: 0.4rem 0 0; }
.maker-stamp {
  position: absolute; top: -14px; right: 18px; transform: rotate(4deg);
  font-family: var(--font-mono); font-size: 0.72rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--stamp-red-ink); border: 2px solid var(--stamp-red); border-radius: 6px;
  padding: 0.3rem 0.55rem; background: var(--card); opacity: 0.9;
}
@media (max-width: 640px) { .maker-note .note-card { grid-template-columns: 1fr; } .maker-note img { width: 64px; height: 64px; } }

/* ---------- final CTA ---------- */
.final-cta {
  text-align: center; padding: clamp(3rem, 7vw, 5rem) 1.1rem clamp(3.4rem, 7vw, 5.4rem);
}
.final-cta h2 { font-size: var(--t-sect); }
.final-cta p { color: var(--ink-2); max-width: 36em; margin: 0 auto 1.6rem; }

/* ---------- footer — the map legend ---------- */
footer {
  background: var(--paper-deep); border-top: 1px solid var(--line);
  padding: 2.4rem 1.1rem calc(2.6rem + env(safe-area-inset-bottom, 0px));
  font-size: 0.88rem; color: var(--ink-2); text-align: center;
}
/* footer links measured 14-18px tall on 31 pages — under the 24px WCAG 2.2 AA
   2.5.8 minimum. inline-block + vertical padding lifts the target without
   changing the type or the line rhythm. */
footer a { color: var(--ink-2); display: inline-block; padding: 3px 2px; }
footer a:hover { color: var(--ink); }
footer p { max-width: var(--maxw); margin: 0 auto 0.75rem; }
footer strong { color: var(--ink); }

/* ---------- pro page pieces (unlinked until launch) ---------- */
.pro-hero { text-align: center; max-width: 46rem; margin: 0 auto; padding: clamp(2.8rem, 7vw, 5rem) 1.1rem 1rem; }
.pro-badge {
  display: inline-block; font-family: var(--font-mono); font-size: 0.7rem; font-weight: 700;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--stamp-red-ink);
  border: 2px solid var(--stamp-red); border-radius: 6px; padding: 0.32rem 0.6rem;
  transform: rotate(-1.5deg); margin-bottom: 1.4rem; background: var(--card);
}
.price-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1.1rem; max-width: 52rem; margin: 2.2rem auto; padding: 0 1.1rem; }
.price-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-m); padding: 1.6rem 1.5rem; box-shadow: var(--shadow-card); text-align: left; position: relative; }
.price-card.hero-card { border: 2px solid var(--brand-cta); }
.price-card .tier { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase; color: var(--brand-ink); }
.price-card .price { font-family: var(--font-display); font-size: 2.3rem; font-weight: 700; margin: 0.35rem 0 0.1rem; color: var(--ink); }
.price-card .per { color: var(--muted); font-size: 0.9rem; margin-bottom: 0.7rem; }
.price-card p { font-size: 0.92rem; color: var(--ink-2); margin: 0; }
.founder-flag {
  position: absolute; top: -12px; right: 14px; background: var(--grade-b); color: var(--on-warm);
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.08em; padding: 0.28rem 0.6rem; border-radius: 6px;
}
.covenant {
  max-width: 46rem; margin: 2.4rem auto; padding: 1.4rem 1.6rem;
  border: 1.5px dashed var(--grade-a); border-radius: var(--r-m);
  background: color-mix(in srgb, var(--grade-a) 6%, var(--card));
}
.covenant h2 { font-size: 1.2rem; color: var(--grade-a-ink); margin-bottom: 0.4rem; }
.covenant p { font-size: 0.95rem; color: var(--ink-2); margin: 0; }

/* ---------- sticky mobile CTA (shared) ---------- */
.mobile-sticky-cta {
  display: none; position: fixed; bottom: 0; left: 0; right: 0; z-index: 200;
  padding: 0.6rem 1rem calc(0.6rem + env(safe-area-inset-bottom, 0px));
  background: var(--brand-cta); color: var(--on-accent); text-decoration: none;
  font-weight: 600; font-size: 0.92rem; text-align: center;
  box-shadow: 0 -2px 16px rgba(0, 0, 0, 0.22);
  align-items: center; justify-content: center; gap: 0.4rem;
  transition: background 0.2s, transform 0.25s ease, opacity 0.2s ease;
}
.mobile-sticky-cta:hover, .mobile-sticky-cta:active { background: var(--brand-cta-hover); }
.mobile-sticky-cta.hidden { transform: translateY(calc(100% + env(safe-area-inset-bottom, 0px))); opacity: 0; pointer-events: none; }
@media (max-width: 768px) { .mobile-sticky-cta { display: flex; } }

/* Waddles rides the route (js/atlas-relief.js places him each frame) */
.atlas-waddles {
  position: absolute; left: 0; top: 0; z-index: 1;
  pointer-events: none; will-change: transform;
  filter: drop-shadow(0 7px 12px rgba(10, 20, 24, 0.30));
}
/* On phone widths the route corridor sits under the hero copy — park the duck. */
@media (max-width: 719px) { .atlas-waddles { display: none; } }

/* Real app pins ride the route (js/atlas-relief.js places them each frame).
   One layer for the whole pool: the pins' inline z-indices depth-sort only
   against each other inside it, while the layer stacks with the duck at
   z-index 1 — behind the hero phone and copy, which occlude passing pins.
   The child selector out-ranks the host's *:not(.atlas-relief) reset so the
   cascade (not the JS stale-CSS guard) owns geometry — pro-hero hosts widen
   this layer to match the escaped canvas, keeping sprite coordinates in
   canvas space so every pin stands on its shader-drawn landing ring. */
[data-atlas-relief] > .atlas-pins {
  position: absolute; inset: 0; z-index: 1;
  pointer-events: none;
}
@media (max-width: 719px) { .atlas-pins { display: none; } }

/* The shared nav menu overlay (docs/js/nav-menu.js) can exceed narrow
   viewports via its hidden content; never let the page scroll sideways. */
html { overflow-x: clip; }

/* ============================================================
   SUBPAGE KIT — v3.0 sitewide sweep (2026-07-11)
   ------------------------------------------------------------
   Added 2026-07-20 (CDO refinement pass):
     .soon-tag      — the "arrives in a free Premium update" honesty pill
                      (was a repeated inline style= on premium.html)
     .figure-frame  — SVG figure wrapper (same, twice)
     :focus-visible — branded keyboard ring; the system had exactly one
                      focus rule (.skip-to-content) before this.
   Shared components for every non-home marketing page. Pages consume
   these classes; page files carry NO inline <style>. If a page needs
   something not here, it gets added HERE, once, by the design lead.
   ============================================================ */

/* --- per-page accent -------------------------------------------------
   Set on <body>. Only family pages carry an accent today: the green
   identity of the #1 organic page is deliberate (README §4.3). */
body.accent-green { --brand-cta: #2E7D4F; --brand-cta-hover: #256B43;
                    --brand-ink: #25663F; --brand-ink-hover: #1A4B2E; }
@media (prefers-color-scheme: dark) {
  body.accent-green { --brand-cta: #4CAE7B; --brand-cta-hover: #63C08F;
                      --brand-ink: #4CAE7B; --brand-ink-hover: #7ECBA0; }
}

/* --- breadcrumbs — the route so far --- */
.crumbs {
  max-width: var(--maxw); margin: 0 auto; padding: 0.55rem clamp(1.1rem, 4vw, 2rem) 0;
  font-family: var(--font-mono); font-size: 0.74rem; letter-spacing: 0.05em;
  color: var(--muted); display: flex; align-items: center; flex-wrap: wrap; gap: 0.55rem;
  list-style: none;
}
/* crumb links measured 14px tall - same 2.5.8 shortfall the footer had. */
.crumbs a { color: var(--muted); text-decoration: none; display: inline-block; padding: 5px 2px; }
.crumbs a:hover { color: var(--brand-ink); }
.crumbs li:not(:last-child)::after { content: "--"; margin-left: 0.55rem; color: var(--line); letter-spacing: -1px; }
.crumbs [aria-current] { color: var(--ink-2); }

/* --- page hero — compact, text-first --- */
.page-hero { max-width: var(--maxw); margin: 0 auto; padding: clamp(1.8rem, 5vw, 3.4rem) clamp(1.1rem, 4vw, 2rem) clamp(1.6rem, 4vw, 2.6rem); display: grid; grid-template-columns: minmax(0, 8fr) minmax(0, 4fr); gap: clamp(1.6rem, 4vw, 3.5rem); align-items: center; }
.page-hero.no-art { display: block; max-width: calc(46rem + 2 * clamp(1.1rem, 4vw, 2rem)); }
/* crumbs are capped at --maxw (1120px) but a no-art hero is capped at ~800px,
   so on those pages the breadcrumb started ~160px left of the H1 it belongs to. */
body:has(.page-hero.no-art) .crumbs { max-width: calc(46rem + 2 * clamp(1.1rem, 4vw, 2rem)); }
.page-hero h1 { font-size: var(--t-page); font-weight: 640; font-variation-settings: "opsz" 90; }
.page-hero .lede { font-size: clamp(1.02rem, 1.4vw, 1.14rem); color: var(--ink-2); max-width: 40em; }
/* the img is rotated 1.2deg inside this box, so its bounding rect is ~3px wider
   than its max-width — measured CLIPPED at 303-in-300 on 19 pages. Pad the box
   by the rotation's overshoot instead of shrinking the art. */
.hero-art { justify-self: center; max-width: 300px; padding: 6px; overflow: visible; }
.hero-art img {
  display: block; border-radius: var(--r-m); border: 1px solid var(--line);
  box-shadow: var(--shadow-card); transform: rotate(1.2deg);
  background: var(--card); padding: 8px;
}
/* same reasoning as .hero-visual above — on 19 page-hero pages the art was
   ordered ahead of the h1 and lede on phones. */
@media (max-width: 820px) { .page-hero { grid-template-columns: 1fr; } .hero-art { margin-top: 0.4rem; max-width: 226px; } }

/* freshness stamp — mono field-note date */
.updated-stamp {
  display: inline-block; font-family: var(--font-mono); font-size: 0.7rem;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted);
  border: 1px solid var(--line); border-radius: 6px; padding: 0.22rem 0.5rem;
  margin-top: 0.9rem; background: var(--card);
}

/* --- TL;DR / atomic-answer card (content byte-preserved from docs) --- */
.tldr-card {
  max-width: 46rem; margin: 0 auto 1.4rem; padding: 1.15rem 1.3rem 1.05rem;
  background: var(--card); border: 1px solid var(--line); border-left: 4px solid var(--brand);
  border-radius: var(--r-m); box-shadow: var(--shadow-card); position: relative;
}
.tldr-card .tldr-tag {
  font-family: var(--font-mono); font-size: 0.72rem; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--brand-ink);
  display: block; margin-bottom: 0.35rem;
}
.tldr-card p { margin: 0; font-size: 0.99rem; color: var(--ink); }

/* --- long-form prose (blog posts, glossary entries, privacy, about) --- */
.prose { max-width: 46rem; margin: 0 auto; padding: 0 1.1rem; }
.prose h2 { font-size: clamp(1.4rem, 2.4vw, 1.8rem); margin: 2.2em 0 0.55em; scroll-margin-top: 5rem; }
.prose h3 { font-size: 1.15rem; margin: 1.8em 0 0.45em; }
.prose p, .prose li { color: var(--ink-2); }
.prose ul, .prose ol { padding-left: 1.3rem; margin: 0 0 1.1em; }
.prose li { margin-bottom: 0.45em; }
.prose strong { color: var(--ink); }
.prose blockquote {
  margin: 1.4em 0; padding: 0.2em 0 0.2em 1.2em;
  border-left: 3px solid var(--brand); color: var(--ink); font-style: italic;
}
.prose hr { border: none; border-top: 1.5px dashed var(--line); margin: 2.4em 0; }
.prose img { border-radius: var(--r-m); border: 1px solid var(--line); }

/* The blog share row's "Copy link" was a bare UA <button>: 21px tall (under the
   24px WCAG 2.2 AA 2.5.8 minimum) and styled as a system control sitting in a
   row of text links, so it read as a different kind of thing than its siblings.
   Match it to the links around it and give it a real target. */
.prose button {
  font: inherit; color: var(--brand-ink); background: none; border: 0;
  padding: 5px 2px; display: inline-block; cursor: pointer;
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px;
}
.prose button:hover { color: var(--brand-ink-hover); }
/* the share row's own links get the same target height as the button */
/* one-glyph share labels ("X") measured 15px wide; min-width carries them to
   the 24px WCAG 2.2 AA 2.5.8 minimum without changing the type. */
.prose p:has(> button) a { display: inline-block; padding: 5px 4px; min-width: 24px; text-align: center; }

/* --- callouts --- */
.callout {
  max-width: 46rem; margin: 1.6rem auto; padding: 1.1rem 1.3rem;
  border: 1.5px dashed var(--sign-blue); border-radius: var(--r-m);
  background: color-mix(in srgb, var(--sign-blue) 6%, var(--card));
  font-size: 0.95rem; color: var(--ink-2);
}
.callout strong, .callout h2, .callout h3 { color: var(--sign-blue-ink); }
.callout.success { border-color: var(--grade-a); background: color-mix(in srgb, var(--grade-a) 6%, var(--card)); }
.callout.success strong, .callout.success h2, .callout.success h3 { color: var(--grade-a-ink); }

/* --- fact/stat strip (audience-page facts rows) --- */
.stat-strip {
  max-width: var(--maxw); margin: 0 auto; padding: 0.4rem clamp(1.1rem, 4vw, 2rem) 1.6rem;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 0.55rem 2.2rem; align-items: baseline;
  border: none; font-size: 0.92rem; color: var(--ink-2); list-style: none;
}
/* The <strong> label was a shrinkable flex item, so any multi-word term
   collapsed into a narrow column and wrapped 2-3 times at 1.2rem display
   serif ("Best for / route / planning"). Pin the label, let the description
   wrap to the next line only where there is genuinely no room — short labels
   like /press and / already fit on one line and are unchanged. */
.stat-strip li { display: flex; align-items: baseline; gap: 0.45rem; flex-wrap: wrap; }
.stat-strip strong { flex: 0 0 auto; }
.stat-strip strong { color: var(--ink); font-family: var(--font-display); font-size: 1.2rem; font-weight: 700; }

/* --- comparison table (compare page + any data table) --- */
/* Scroll affordance — the tables run 640-720px wide inside a 390px viewport, so
   without an edge hint the cut column reads as broken layout rather than
   "scroll me".

   The previous implementation painted two radial gradients as backgrounds OF the
   scroll box, which put the affordance in the wrong place in both directions.
   `.compare-table` carries an opaque `background: var(--card)`, so when the table
   overflows it paints straight over the right-hand gradient — exactly where the
   hint is needed — while on desktop, where nothing overflows, both gradients sat
   exposed in the padding as grey smudges outside the table's rounded corner.
   Paint order, not background-attachment, was the mechanism.

   The hint now lives ABOVE the table on a sticky pseudo-element, and is scheme-
   paired rather than hardcoded to light-mode literals. */
.table-scroll {
  max-width: var(--maxw); margin: 0 auto; padding: 0 clamp(1.1rem, 4vw, 2rem);
  overflow-x: auto; position: relative;
}
.table-scroll::after {
  content: ""; position: sticky; z-index: 2; float: right;
  top: 0; right: 0; width: 26px; height: 100%; margin-left: -26px;
  pointer-events: none;
  background: linear-gradient(to left,
    color-mix(in srgb, var(--paper) 92%, transparent),
    color-mix(in srgb, var(--paper) 55%, transparent) 45%,
    transparent);
  /* only meaningful where the table actually overflows */
  opacity: 0; transition: opacity 0.2s ease;
}
@media (max-width: 900px) { .table-scroll::after { opacity: 1; } }
.table-scroll:focus-visible { outline: 2px solid var(--brand-ink); outline-offset: 3px; }
@media (max-width: 700px) {
  .compare-table { min-width: 560px; font-size: 0.86rem; }
  .compare-table th, .compare-table td { padding: 0.6rem 0.65rem; }
}
.compare-table { border-collapse: collapse; width: 100%; min-width: 640px; font-size: 0.92rem; background: var(--card); border: 1px solid var(--line); border-radius: var(--r-m); overflow: hidden; box-shadow: var(--shadow-card); }
.compare-table th, .compare-table td { padding: 0.75rem 0.9rem; text-align: left; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
.compare-table thead th { font-family: var(--font-display); font-size: 0.98rem; background: var(--paper-deep); border-bottom: 1.5px solid var(--line); }
.compare-table tbody th { font-weight: 600; color: var(--ink); }
.compare-table td { color: var(--ink-2); }
.compare-table tr:last-child th, .compare-table tr:last-child td { border-bottom: none; }
.compare-table .yes { color: var(--grade-a-ink); font-weight: 700; }
.compare-table .no { color: var(--muted); }
.compare-table .col-us { background: color-mix(in srgb, var(--brand) 7%, transparent); }

/* --- changelog timeline — mile markers down the route --- */
.timeline { max-width: 46rem; margin: 0 auto; padding: 0 1.1rem; position: relative; }
.timeline::before {
  content: ""; position: absolute; top: 0.4rem; bottom: 0.4rem; left: calc(1.1rem + 2.1rem);
  border-left: 2px dashed var(--line);
}
.timeline-entry { position: relative; padding: 0 0 2.2rem 6rem; }
.timeline-entry:last-child { padding-bottom: 0.6rem; }
.timeline-version {
  position: absolute; left: 0; top: 0.1rem; width: 4.2rem; text-align: center;
  font-family: var(--font-mono); font-size: 0.74rem; font-weight: 700; letter-spacing: 0.04em;
  color: #FDFBF4; background: var(--sign-blue); border-radius: 5px; padding: 0.3rem 0.2rem;
  box-shadow: inset 0 0 0 1.5px rgba(255,255,255,0.35), 0 1px 2px rgba(0,0,0,0.18);
}
.timeline-entry.latest .timeline-version { background: var(--brand-cta); color: var(--on-accent); }
.timeline-entry h2, .timeline-entry h3 { font-size: 1.2rem; margin: 0.05rem 0 0.15rem; }
.timeline-date { font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.08em; color: var(--muted); text-transform: uppercase; }
.timeline-entry ul { padding-left: 1.15rem; margin: 0.6rem 0 0; }
.timeline-entry li { color: var(--ink-2); font-size: 0.95rem; margin-bottom: 0.35rem; }
@media (max-width: 560px) {
  .timeline::before { left: calc(1.1rem + 0.35rem); }
  .timeline-entry { padding-left: 2.2rem; }
  .timeline-version { position: static; display: inline-block; width: auto; padding: 0.28rem 0.5rem; margin-bottom: 0.3rem; }
}

/* --- sources / citations (glossary, data-sources) --- */
.sources { max-width: 46rem; margin: 1.4rem auto; padding: 0 1.1rem; }
.sources ol { list-style: none; counter-reset: src; padding: 0; margin: 0; }
.sources li {
  counter-increment: src; position: relative; padding: 0.5rem 0 0.5rem 2.6rem;
  border-bottom: 1px dashed var(--line-soft); font-size: 0.9rem; color: var(--ink-2);
}
.sources li::before {
  content: counter(src, decimal-leading-zero); position: absolute; left: 0; top: 0.62rem;
  font-family: var(--font-mono); font-size: 0.7rem; color: var(--brand-ink);
  border: 1px solid var(--line); border-radius: 5px; padding: 0.12rem 0.32rem; background: var(--card);
}

/* --- dot list — capability bullets outside the showcase --- */
.dot-list { list-style: none; padding: 0; margin: 1rem 0; display: grid; gap: 0.6rem; }
.dot-list li { position: relative; padding-left: 1.5rem; color: var(--ink-2); }
.dot-list li::before {
  content: ""; position: absolute; left: 0.15rem; top: 0.55em; width: 9px; height: 9px;
  border-radius: 50%; background: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 22%, transparent);
}

/* --- blog post header + meta --- */
.post-header { max-width: 46rem; margin: 0 auto; padding: clamp(1.8rem, 5vw, 3rem) 1.1rem 0.8rem; }
.post-header h1 { font-size: var(--t-page); font-weight: 640; }
.post-meta {
  display: flex; flex-wrap: wrap; gap: 0.4rem 1.2rem; align-items: center;
  font-family: var(--font-mono); font-size: 0.74rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 0.4rem;
}
.post-list { max-width: 46rem; margin: 0 auto; padding: 0 1.1rem; }
.post-card {
  display: block; text-decoration: none; color: var(--ink);
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-m);
  box-shadow: var(--shadow-card); padding: 1.4rem 1.5rem; margin-bottom: 1.1rem;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.post-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lift); border-color: color-mix(in srgb, var(--brand-cta) 45%, var(--line)); }
.post-card h2, .post-card h3 { font-size: 1.25rem; margin-bottom: 0.35rem; }
.post-card p { color: var(--ink-2); font-size: 0.95rem; margin: 0; }
.post-card .post-meta { margin: 0 0 0.4rem; }

/* --- premium cross-sell strip (LAUNCH-GATED; road-trip surfaces only,
       never on medical/dignity pages) --- */
.premium-strip { padding: 0 1.1rem clamp(2.2rem, 5vw, 3.4rem); }
.premium-strip-inner {
  max-width: 46rem; margin: 0 auto; display: flex; align-items: center; gap: 1.1rem;
  border: 1.5px dashed var(--line); border-radius: var(--r-m);
  padding: 1rem 1.25rem; background: var(--card);
}
.premium-strip .pro-badge { margin: 0; transform: rotate(-1deg); flex-shrink: 0; }
.premium-strip p { margin: 0; font-size: 0.93rem; color: var(--ink-2); }
@media (max-width: 560px) { .premium-strip-inner { flex-direction: column; align-items: flex-start; gap: 0.7rem; } }

/* --- section spacing helper for kit pages --- */
.band { padding: clamp(2.4rem, 6vw, 4.2rem) 0; }
.band-tight { padding: clamp(1.6rem, 4vw, 2.6rem) 0; }

/* --- post-fanout consolidation (agents' kit-gap reports, 2026-07-11) --- */
/* lede works anywhere, not only inside .page-hero (blog post subtitles) */
.lede { font-size: clamp(1.02rem, 1.4vw, 1.14rem); color: var(--ink-2); max-width: 40em; }
.post-card h4 { font-family: var(--font-display); font-size: 1.08rem; margin: 0 0 0.3rem; }
.tldr-card ul { margin: 0.45rem 0 0; padding-left: 1.2rem; color: var(--ink-2); font-size: 0.95rem; }
.tldr-card ul li { margin-bottom: 0.3rem; }
.tldr-card small { display: block; margin-top: 0.55rem; font-size: 0.78rem; color: var(--muted); }
.callout.warn { border-color: var(--grade-b); background: color-mix(in srgb, var(--grade-b) 7%, var(--card)); }
.callout.warn strong, .callout.warn h2, .callout.warn h3 { color: var(--grade-b-ink); }
.compare-table .partial { color: var(--grade-b-ink); font-weight: 700; }
.compare-table caption {
  caption-side: top; text-align: left; padding: 0 0 0.55rem;
  font-size: 0.85rem; color: var(--muted);
}
/* glossary spec-table citation chips + source annotations */
.cite {
  font-family: var(--font-mono); font-size: 0.7rem; white-space: nowrap;
  color: var(--brand-ink); border: 1px solid var(--line); border-radius: 5px;
  padding: 0.08rem 0.35rem; background: var(--card);
}
.sources .meta { display: inline-block; font-size: 0.8rem; color: var(--muted); margin-top: 0.15rem; }
/* glossary hub keeps H2s inside cards (AEO); size them like card titles */
/* (glossary hub keeps H2s inside cards for AEO — same size as any card title) */
/* updated-stamp doubles as an inline chip inside cards/cells — no top gap there */
.feature-card .updated-stamp, .compare-table .updated-stamp, .mode-card .updated-stamp,
.dot-list .updated-stamp, li .updated-stamp, td .updated-stamp { margin: 0 0.3rem 0.3rem 0; }
/* audience/feature card illustrations read better larger than icon size */
.feature-icon-art img { width: 84px; height: 84px; }

/* honesty pill: "arrives in a free Premium update" (premium.html) */
.soon-tag {
  display: inline-block; vertical-align: middle; white-space: nowrap;
  font-family: var(--font-body); font-size: 0.72rem; font-weight: 600;
  color: var(--muted); border: 1px solid var(--line);
  border-radius: 99px; padding: 0.15rem 0.55rem;
}

/* SVG figure wrapper (premium.html Trip Report / Inspector / glovebox card) */
.figure-frame { justify-self: center; width: 100%; max-width: 420px; }

/* --- 404 --- the only page a lost visitor lands on, so it carries the
       sitewide header and footer like every other page rather than being a
       dead end with no route back to the product. --- */
.notfound { min-height: 62vh; display: grid; place-items: center; text-align: center; padding: clamp(2.6rem, 7vw, 4.5rem) 1.1rem; }
.notfound h1 { font-size: var(--t-home); margin-top: 1.2rem; }
.notfound .hero-lede { margin: 0 auto 1.6rem; max-width: 28em; }
.notfound .nav-cta { display: inline-block; }
.notfound .maker-line { margin-top: 1.5rem; }

/* ============================================================
   PRINT
   Two reasons this exists. First, .reveal content is hidden until the
   IntersectionObserver fires, and printing never scrolls — measured with
   scripts enabled and no scroll, every .reveal element on / , /premium,
   /iq-platform, /compare, /data-sources and the audience pages sat at
   opacity 0, so a printed page came out with blank bands where the cards
   and section headers should be. (With JS OFF the page prints correctly,
   which is why this was easy to miss.) Second, a site that pitches a
   printable glovebox card should itself print like a considered document.
   ============================================================ */
@media print {
  /* the reveal rule is gated on html.js-anim; override it rather than
     depending on the observer having run */
  html.js-anim .reveal { opacity: 1 !important; transform: none !important; }

  :root {
    --paper: #FFFFFF; --paper-deep: #FFFFFF; --card: #FFFFFF;
    --ink: #000000; --ink-2: #1A1A1A; --muted: #3A3A3A;
    --line: #BBBBBB; --line-soft: #DDDDDD;
    --brand-ink: #000000; --brand-ink-hover: #000000;
    --sign-blue-ink: #000000; --grade-a-ink: #000000;
    --grade-b-ink: #000000; --stamp-red-ink: #000000;
    --shadow-card: none; --shadow-lift: none;
  }

  body { background: #fff; font-size: 11pt; line-height: 1.45; }
  body::before { display: none; }              /* paper grain wastes toner */

  /* screen furniture that means nothing on paper */
  .fixed-header, .mobile-sticky-cta, .atlas-relief, .atlas-pins, .atlas-waddles,
  .skip-to-content, .carousel-dots, .daily-strip, .hero-desktop-download,
  .premium-strip, .crumbs { display: none !important; }

  /* the screenshot carousel stacks every slide when only one is visible on screen */
  .screenshot-carousel img:not(.active) { display: none !important; }

  a { color: #000; text-decoration: underline; }
  /* a printed link is useless without its destination — but only for real
     off-page targets, not for every in-page anchor */
  main a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.85em; color: #333; word-break: break-all; }

  .feature-card, .mode-card, .post-card, .price-card, .callout, .tldr-card,
  .covenant, .note-card, .timeline-entry, .faq-item {
    break-inside: avoid; page-break-inside: avoid;
    border: 1px solid var(--line); box-shadow: none;
  }
  h1, h2, h3 { break-after: avoid; page-break-after: avoid; }
  .page-hero, .home-hero { padding-top: 0; }
  .section-band { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
  img { max-width: 100% !important; }
}
