/* ═══════════════════════════════════════════════════════════════════════════
   YPReno marketing site — the whole stylesheet.

   ⚠️ EXTRACTED VERBATIM from site/index.html's inline <style> when the site
   grew past one page. Every rule below the "additions" fence is byte-identical
   to what shipped, because the migration onto Eleventy was a REFACTOR: the home
   page had to render the same text at the same sizes afterwards. New rules are
   fenced at the bottom so the diff stays honest.

   Tokens — copied from docs/BRAND.md §1, values unchanged.
   ═══════════════════════════════════════════════════════════════════════════ */
/* ⚠️⚠️ GOLD IS NEVER TEXT ON A LIGHT BACKGROUND, AND THE SPEC'S OWN NUMBER IS
   OPTIMISTIC. docs/BRAND.md §5 says "#C49A47 on #FAFAF9 is approximately 3:1"
   and permits gold for display text at 24px and up on that basis. Computed
   properly (WCAG relative luminance) it is 2.495:1 on ivory and 2.605:1 on
   white — BELOW the 3:1 large-text threshold, so that permission rests on a
   figure that does not hold. Gold display text was built here on 2026-07-29,
   measured, and removed.

   Gold on this site is therefore ONLY non-text: rules, dividers, borders and
   decorative shapes, none of which carry information. The one place it may be
   text is CHARCOAL #1C1917, where it measures 6.713:1 — comfortably AA even at
   body size. That is what the dark section and the footer are for. */
:root {
  --color-accent: #c49a47;
  --color-text-primary: #1c1917;
  --color-text-secondary: #78716c;
  --color-text-inverse: #ffffff;
  --color-background-page: #fafaf9;
  --color-background-surface: #ffffff;
  --color-background-dark: #1c1917;
  --color-border-subtle: #e7e5e4;
  --color-dark-text-secondary: #e7e5e4;
  --color-dark-border-subtle: #44403c;

  --font-family-ui: "Inter", ui-sans-serif, system-ui, -apple-system,
    BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-family-display: "Montserrat", "Inter", ui-sans-serif, system-ui,
    sans-serif;

  --font-size-display: clamp(2.5rem, 6vw, 4.5rem);
  --font-size-h2: clamp(1.75rem, 4vw, 3rem);
  --font-size-h3: clamp(1.25rem, 3vw, 1.75rem);

  --radius-medium: 0.625rem;
  --radius-card: 1rem;
  --radius-pill: 9999px;

  --container-max-width: 80rem;
  --shadow-card: 0 1px 2px rgba(28, 25, 23, 0.04),
    0 8px 24px rgba(28, 25, 23, 0.06);
}

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

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

body {
  margin: 0;
  min-width: 320px;
  background: var(--color-background-page);
  color: var(--color-text-primary);
  font-family: var(--font-family-ui);
  font-size: 1rem;
  line-height: 1.6;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

::selection {
  background: rgba(196, 154, 71, 0.25);
  color: var(--color-text-primary);
}

/* ⚠️ CHARCOAL, NOT docs/BRAND.md's gold ring — a deliberate deviation.
   §5 of that spec permits a gold tint only "when accompanied by a clearly
   visible outline"; gold at 45% opacity on ivory is ~3:1 and would be
   the only indicator here. A solid charcoal outline IS the clearly
   visible outline, and adding gold on top of it communicates nothing
   further. Matches the app's own rule, which BRAND.md protects for the
   same reason. */
:focus-visible {
  outline: 3px solid var(--color-text-primary);
  outline-offset: 2px;
}

img { max-width: 100%; }

h1, h2, h3 {
  font-family: var(--font-family-display);
  font-weight: 600;
  letter-spacing: -0.025em;
  margin: 0;
}

p { margin: 0; }

a { color: inherit; }

.container {
  width: 100%;
  max-width: var(--container-max-width);
  margin: 0 auto;
  padding: 0 1.25rem;
}

.section { padding: 4rem 0; }

.eyebrow {
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-text-secondary);
  margin: 0;
}

/* Gold is a decorative rule here — never a text colour. */
.accent-rule {
  width: 3rem;
  height: 1px;
  border: 0;
  background: var(--color-accent);
  margin: 1.5rem 0 0;
}

.lede {
  color: var(--color-text-secondary);
  max-width: 44rem;
  margin-top: 1.25rem;
}

/* ─── buttons: charcoal fill carries the contrast (BRAND.md §5) ─────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 3rem;
  padding: 0 1.5rem;
  border-radius: var(--radius-medium);
  font-family: var(--font-family-ui);
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: none;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.btn-primary {
  background: var(--color-text-primary);
  color: var(--color-text-inverse);
  border: 1px solid var(--color-text-primary);
}
.btn-primary:hover { background: #292524; }
/* The gold border is decorative; the charcoal label carries the contrast. */
.btn-secondary {
  background: transparent;
  color: var(--color-text-primary);
  border: 1px solid var(--color-accent);
}
.btn-secondary:hover { background: rgba(196, 154, 71, 0.08); }

/* ─── header ─────────────────────────────────────────────────────────── */
.site-header {
  border-bottom: 1px solid var(--color-border-subtle);
  background: var(--color-background-page);
}
.site-header .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 4.5rem;
  flex-wrap: wrap;
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
}
/* ⚠️ WIDTH ONLY, HEIGHT AUTO. The four lockups are four different ratios
   and setting both dimensions distorts the mark, which BRAND.md's
   forbidden-use list prohibits. 180px on YPReno_Text.svg is the approved
   ~18px cap height (BRAND.md §4).
   ⚠️ EACH FILE CARRIES ITS OWN WIDTH — 88px on YP_reno_narrow gives the SAME
   18.1px cap. Do not merge these into one rule; the widths are not
   interchangeable because the artwork is not the same (see header.njk). */
.brand-lockup { height: auto; display: block; }
.brand-lockup-full { width: 180px; }
.brand-lockup-narrow { width: 88px; }
/* 480px is BRAND.md's measured threshold for the app's identical swap, not a
   Tailwind default: below it the full lockup cannot fit beside the header's
   right-hand group. Exactly one of the two is ever displayed. */
.brand-lockup-narrow { display: block; }
.brand-lockup-full { display: none; }
@media (min-width: 480px) {
  .brand-lockup-narrow { display: none; }
  .brand-lockup-full { display: block; }
}

/* ─── header actions: a secondary text link beside the primary button ──── */
.header-actions {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
/* ⚠️ 44px OF HIT AREA FROM PADDING, same rule the nav and footer links hold.
   The gap above is deliberately tight (0.25rem) because this padding already
   separates the two controls optically. */
.header-signin {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 0.75rem;
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: none;
  color: var(--color-text-primary);
  border-bottom: 2px solid transparent;
  border-radius: var(--radius-medium);
}
.header-signin:hover { border-bottom-color: var(--color-accent); }

/* ─── hero ───────────────────────────────────────────────────────────── */
.hero { padding: 3.5rem 0 4rem; }
.hero h1 {
  font-size: var(--font-size-display);
  line-height: 1.02;
  letter-spacing: -0.04em;
  margin-top: 1.25rem;
  max-width: 20ch;
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 2rem;
}
.hero-note {
  margin-top: 1rem;
  font-size: 0.875rem;
  color: var(--color-text-secondary);
}

/* ─── generic section heading ────────────────────────────────────────── */
.section h2 {
  font-size: var(--font-size-h2);
  line-height: 1.1;
  max-width: 24ch;
}

/* ─── card grids ─────────────────────────────────────────────────────── */
.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  margin-top: 2.5rem;
}
.card {
  background: var(--color-background-surface);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-card);
  padding: 1.75rem;
  transition: transform 0.18s ease, box-shadow 0.18s ease;
}
/* ⚠️ ONLY LINKED CARDS LIFT. A hover motion on a plain text card implies an
   interaction that is not there; .card-linked is the class that means "this
   whole card is a link", so it is the class that moves.
   ⚠️ !important IS LOAD-BEARING, not styling laziness: the scroll-driven
   rise-in animation fills forwards, and the animations cascade origin beats a
   normal author declaration — so without it the hover transform silently
   never applies in engines that support view(), while working everywhere
   else. Important author declarations are the one origin above animations. */
.card-linked:hover {
  transform: translateY(-2px) !important;
  box-shadow: var(--shadow-card);
}
/* ⚠️ h2 AND h3. A card's heading level depends on what is above it, not on how
   it looks: on the home page and the product pages the cards sit under a
   section h2, so they are h3; on /product/ they sit directly under the page h1,
   so they are h2. Both must render identically, and this rule sits AFTER
   `.section h2` so it is the one that sets the size. */
.card h2,
.card h3 {
  font-size: 1.25rem;
  line-height: 1.3;
  letter-spacing: -0.015em;
  max-width: none;
}
/* A card whose heading is a link. The hit area is widened to the whole card by
   `.card-linked` at the bottom of this file — see the warning there for when
   that is safe. */
.card h2 a { text-decoration: none; }
.card h2 a:hover { border-bottom: 1px solid var(--color-accent); }
.card p {
  margin-top: 0.75rem;
  color: var(--color-text-secondary);
  font-size: 0.9375rem;
}

.band {
  background: var(--color-background-surface);
  border-top: 1px solid var(--color-border-subtle);
  border-bottom: 1px solid var(--color-border-subtle);
  /* ⚠️ A GOLD HAIRLINE ON THE TOP EDGE, and it is decoration in the WCAG sense:
     it carries no information, nothing is identified by it, and removing it
     changes nothing a reader needs. That is why gold is allowed here at 2.5:1
     when it is not allowed as text (see the note at the top of this file). 2px
     over the sand border, inset to the container's own gutter so it reads as a
     deliberate rule rather than a full-width stripe. */
  position: relative;
}
.band::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 1.25rem;
  width: 4rem;
  height: 2px;
  background: var(--color-accent);
}
@media (min-width: 640px) {
  .band::before { left: 2rem; }
}
@media (min-width: 80rem) {
  /* Aligned to the container's left edge once it stops touching the gutter. */
  .band::before { left: calc((100% - var(--container-max-width)) / 2 + 2rem); }
}
.band .card {
  border: 0;
  padding: 0;
  background: transparent;
}

/* ─── pricing ────────────────────────────────────────────────────────── */
.price-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  margin-top: 2.5rem;
  align-items: start;
}
.plan {
  background: var(--color-background-surface);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-card);
  padding: 1.75rem;
  box-shadow: var(--shadow-card);
}
/* A featured plan carries a visible LABEL, never a gold border alone —
   BRAND.md §7: colour must not be the only signal. */
.plan-featured { border-color: var(--color-accent); border-width: 2px; }
.plan-flag {
  display: inline-block;
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-pill);
  padding: 0.125rem 0.75rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: 1rem;
}
/* ⚠️ h2, NOT h3 (2026-07-28). The plan cards moved to /pricing, where the
   approved headline is the page's h1 — so the plan names are the level below it
   and skipping to h3 would leave a hole in the outline. This rule sits after
   `.section h2`, so it is the one that sets the size; the size itself is
   unchanged. */
.plan h2 { font-size: var(--font-size-h3); }
.price {
  font-family: var(--font-family-display);
  /* 2.75rem since 2026-07-29 — the price is the page's one number, and scale
     contrast against the 14px interval text is what a card row cannot give. */
  font-size: 2.75rem;
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.1;
  margin-top: 1.25rem;
}
.price small {
  font-family: var(--font-family-ui);
  font-size: 0.875rem;
  font-weight: 400;
  color: var(--color-text-secondary);
  letter-spacing: 0;
}
.plan-blurb {
  margin-top: 0.5rem;
  color: var(--color-text-secondary);
  font-size: 0.875rem;
}
.plan ul {
  margin: 1.5rem 0 0;
  padding: 1.5rem 0 0;
  border-top: 1px solid var(--color-border-subtle);
  list-style: none;
  font-size: 0.9375rem;
  color: var(--color-text-secondary);
}
.plan li { padding-left: 1.25rem; position: relative; margin-top: 0.5rem; }
.plan li:first-child { margin-top: 0; }
.plan li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.7em;
  width: 0.5rem;
  height: 1px;
  background: var(--color-accent);
}
.pricing-note {
  margin-top: 2rem;
  font-size: 0.875rem;
  color: var(--color-text-secondary);
  max-width: 46rem;
}

/* ─── footer ─────────────────────────────────────────────────────────── */
/* ⚠️ CUT DOWN 2026-07-29 — it was 697px tall at 1440×900 (77% of the
   viewport) and 1116px at 375×812, a second navigation under two labelled
   columns. Now two lines: brand + the top-level pages, then the base line
   with legal links. The old .footer-grid/.footer-col/.footer-child rules
   went with the markup that used them — no dead selectors kept. */
.site-footer {
  background: var(--color-background-dark);
  color: var(--color-text-inverse);
  padding: 3rem 0 2rem;
}
.footer-top {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 1.5rem 3rem;
}
.footer-brand {
  display: flex;
  align-items: center;
  gap: 1.125rem;
}
/* The mark is 40px; the padding is what claims the 44px tap target, and the
   negative margin gives the space back so the row's rhythm does not change.
   ⚠️ flex-shrink: 0 IS MEASURED, NOT DEFENSIVE: without it the 375w flex row
   squeezed the monogram to 15×15px — under BRAND.md's 32px minimum — because
   a flex item shrinks below its width before its sibling's TEXT wraps. The
   tagline is the flexible one. */
.footer-home-link { display: inline-flex; flex-shrink: 0; padding: 0.25rem; margin: -0.25rem; }
.footer-mark { width: 40px; height: auto; display: block; }
.footer-tagline {
  margin: 0;
  color: var(--color-dark-text-secondary);
  font-size: 0.9375rem;
  max-width: 26rem;
}
/* ⚠️ 44px OF HIT AREA, NOT 20px OF TEXT — same rule the old columns held. */
.footer-nav ul,
.footer-base-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 1.75rem;
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 0.9375rem;
}
.footer-nav a,
.footer-base-links a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  color: var(--color-text-inverse);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.footer-nav a:hover,
.footer-base-links a:hover { border-bottom-color: var(--color-accent); }
.footer-nav a[aria-current="page"] { border-bottom-color: var(--color-accent); }
.footer-base {
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--color-dark-border-subtle);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0.25rem 3rem;
}
.footer-legal {
  margin: 0;
  color: var(--color-dark-text-secondary);
  font-size: 0.8125rem;
}
/* Sand on charcoal is 13.93:1 — the muted register keeps its AA headroom. */
.footer-base-links { font-size: 0.875rem; }
.footer-base-links a { color: var(--color-dark-text-secondary); }
.footer-base-links a:hover { color: var(--color-text-inverse); }
.site-footer :focus-visible { outline-color: var(--color-text-inverse); }

/* ─── responsive ─────────────────────────────────────────────────────── */
@media (min-width: 640px) {
  .container { padding: 0 2rem; }
  .grid { grid-template-columns: repeat(2, 1fr); gap: 1.25rem; }
  .price-grid { grid-template-columns: repeat(3, 1fr); gap: 1.25rem; }
}
@media (min-width: 1024px) {
  .section { padding: 7rem 0; }
  /* .hero's desktop padding lives in the 64rem hero block below — a copy here
     was dead at the default root size and wrong under font scaling. */
  .grid-3 { grid-template-columns: repeat(3, 1fr); }
  .grid { gap: 1.5rem; }
}

/* ⚠️ Motion is limited to colour transitions, but the media query is here
   so a future addition inherits the right default rather than being
   retrofitted. */
@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ADDITIONS FOR THE MULTI-PAGE SITE — everything above this fence shipped with
   the single-page version and is unchanged. Everything below is new chrome:
   the header nav, the stub-page shell and markdown prose. Nothing below
   restyles anything above, so the home page renders as it did.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─── header nav ─────────────────────────────────────────────────────── */
/* The lockup and the CTA are the fixed ends; the nav takes the middle and is
   allowed to wrap under them on a narrow screen rather than squeezing. */
/* ⚠️ 44px OF HIT AREA, AND THIS IS A FIX, NOT A PRECAUTION. The full lockup is
   180×55, so the link cleared the tap-target floor by accident. The narrow
   mobile lockup is 88×26 — swapping it in dropped every page's brand link to
   26px tall, which the rule-23 sweep caught on 30 page×viewport combinations.
   The mark's size is unchanged; only the box around it grows, and it fits
   inside the row the 48px CTA already sets, so the header does not get taller. */
.brand-link {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
}
.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 1.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
/* ⚠️ 44px OF HIT AREA, same rule as the footer's — these are the links a phone
   user taps most, and 20px of text is under the floor the app holds itself to
   everywhere else. */
.site-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
  color: var(--color-text-secondary);
  border-bottom: 2px solid transparent;
}
.site-nav a:hover { color: var(--color-text-primary); }
/* ⚠️ The current page is marked by WEIGHT AND AN UNDERLINE, not by colour
   alone — and `aria-current` is what drives it, so the visual state and the
   accessible state cannot disagree (BRAND.md §5: never colour alone). */
.site-nav a[aria-current="page"] {
  color: var(--color-text-primary);
  font-weight: 600;
  border-bottom-color: var(--color-accent);
}

/* ⚠️ BELOW 640px THE NAV TAKES ITS OWN ROW, AND THIS IS A MEASURED FIX, NOT A
   precaution. Left to plain `flex-wrap`, the three header items wrapped onto
   THREE rows at 375w — lockup, then nav, then the CTA — for a 203px header and
   a hero starting 204px down a 812px screen. A quarter of the phone spent on
   chrome before a word of the page.

   `order: 3` puts the nav after the CTA in the flex order (it is second in the
   DOM, which is right for reading and for tab order), and `flex-basis: 100%`
   makes it claim a full row. Result: row 1 is lockup + CTA, row 2 is the nav.
   Measured 131px, and no JavaScript — the alternative is a hamburger, which
   needs a script this site does not have. */
@media (max-width: 639px) {
  .site-nav {
    order: 3;
    flex-basis: 100%;
  }
}

/* ─── page heads ─────────────────────────────────────────────────────── */
/* ⚠️ DARK SINCE 2026-07-29 — the owner's own reading of the site was that the
   charcoal statement band is its most striking register, so every interior
   page now OPENS in it: gold eyebrow (6.71:1 on charcoal — the one surface
   where gold text is legal), white display h1, sand lede. The home hero stays
   ivory; it has the screenshot treatment instead, and two dark openers in a
   row (header→hero) would drown the register that makes this work. */
.page-head {
  background: var(--color-background-dark);
  color: var(--color-text-inverse);
  padding: 3.5rem 0 4rem;
}
.page-head .eyebrow { color: var(--color-accent); }
.page-head h1 {
  font-size: clamp(2.25rem, 4.5vw, 3.5rem);
  line-height: 1.08;
  letter-spacing: -0.03em;
  margin-top: 1.25rem;
  max-width: 22ch;
}
.page-head .lede { color: var(--color-dark-text-secondary); max-width: 46rem; }
.page-head :focus-visible { outline-color: var(--color-text-inverse); }
/* The article eyebrow-link's light-surface hover colour would be charcoal on
   charcoal here. */
.page-head .eyebrow-link:hover { color: var(--color-text-inverse); }
.stub {
  padding: 3rem 0 5rem;
}
.stub p {
  color: var(--color-text-secondary);
  max-width: 44rem;
}
@media (min-width: 1024px) {
  .page-head { padding: 5rem 0 5.5rem; }
  .stub { padding: 3.5rem 0 7rem; }
}

/* ─── markdown prose (the help articles) ─────────────────────────────── */
/* Markdown is why this site has a generator rather than a hand-rolled
   assembler, so the elements it emits need styling once, here. */
.prose { max-width: 44rem; }
.prose h2 {
  font-size: var(--font-size-h3);
  line-height: 1.2;
  margin-top: 2.5rem;
}
.prose h3 {
  font-size: 1.125rem;
  line-height: 1.3;
  margin-top: 2rem;
}
.prose p,
.prose ul,
.prose ol { margin-top: 1rem; color: var(--color-text-secondary); }
.prose li { margin-top: 0.375rem; }
.prose a { text-decoration: underline; text-underline-offset: 2px; }
.prose code {
  font-size: 0.875em;
  background: var(--color-background-surface);
  border: 1px solid var(--color-border-subtle);
  border-radius: 0.25rem;
  padding: 0.1em 0.35em;
}

/* ─── screenshots ────────────────────────────────────────────────────── */
/* ⚠️ THE `width`/`height` ATTRIBUTES ARE THE POINT, and this rule is what lets
   them do their job: `height: auto` tells the browser to keep the declared
   aspect ratio while scaling the width down, so the box is reserved at the
   right shape before a byte of image arrives and nothing below it jumps. Drop
   `height: auto` and the attributes become a fixed, wrong size instead. */
.shot {
  margin: 2.5rem 0 0;
  max-width: 56rem;
}
.shot img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-card);
  background: var(--color-background-surface);
  /* The border is what defines the edge of a pale UI on a pale page; the
     shadow (added 2026-07-29, when depth became the brief) is what makes it
     an object sitting ON the page. Both, not either. */
  box-shadow: var(--shadow-card);
}
.shot figcaption {
  margin-top: 0.75rem;
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
  max-width: 44rem;
}
/* Inside a band the card treatment is flat, so the screenshot keeps its border
   but loses the surface fill it would otherwise sit invisibly against. */
.band .shot img { background: var(--color-background-page); }

/* ─── a card whose heading is its link ───────────────────────────────── */
/* ⚠️ THE WHOLE CARD IS THE TAP TARGET, and that is a fix rather than a flourish:
   measured, the heading link alone is 24px tall, well under the 44px minimum,
   and a card index is exactly where a phone user taps. The stretched
   pseudo-element makes the hit area the card without changing a pixel of what
   is drawn, and without wrapping anything in a second <a>.

   ⚠️ SAFE ONLY BECAUSE THESE CARDS CONTAIN EXACTLY ONE LINK. Add a second and
   the overlay swallows it — put the class back on the card only when the
   heading link is still the only one. */
.card-linked { position: relative; }
.card-linked h2 a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}

/* ═══════════════════════════════════════════════════════════════════════════
   HERO: TWO COLUMNS, AND A SCREENSHOT THAT LEAVES THE PAGE (2026-07-29)
   ═══════════════════════════════════════════════════════════════════════════
   Measured before: painted content stopped at x=1032 in a 1440px viewport, so
   408px sat empty to its right, and the content-to-whitespace ratio was
   25 : 75. The headline ran to three lines at 72px and a 112px gap followed it.
   The answer is to fill that space with the product, drop the display size a
   step so the headline sets in two lines, and let the image bleed off the edge
   so the page reads as wider than the screen. */

.hero-grid { display: block; }

/* ⚠️ THE BLEED IS CLIPPED, NEVER SCROLLED. The image is wider than its column
   on purpose; `overflow: hidden` here is what turns that into a bleed rather
   than a horizontal scrollbar, which would fail rule 23 at every width. Nothing
   in this section is sticky or position:fixed, so hiding overflow costs
   nothing. */
.hero { overflow: hidden; }

/* The screenshot's frame. A border and a real shadow rather than a bare
   rectangle — the page is pale on pale, so an edge is what makes it an object
   sitting ON the page instead of a hole cut into it. */
.hero-shot { position: relative; margin-top: 3rem; }
.hero-shot .shot { margin: 0; max-width: none; }
/* The frame itself (border, radius, shadow) is the base .shot img rule. */
/* ⚠️ A DECORATIVE GOLD EDGE, OFFSET BEHIND THE IMAGE — BRAND.md §5's "borders
   on large components where meaning does not depend on colour alone". It is
   `aria-hidden` by construction (a pseudo-element), carries no information, and
   is the only thing on the page that says "brand" in the hero.

   ⚠️ ANCHORED TO THE TOP-LEFT, AND THAT IS QA_LEDGER YQ-153. The pseudo is
   positioned against the grid column's box, but from 64rem the image is
   deliberately WIDER than that box (the bleed below) — a top-right bracket's
   vertical arm measured 116px INSIDE the painted image at 1440w, a stray gold
   line over the screenshot. The left edge is the side that never bleeds, so
   the offset geometry holds at every width. */
.hero-shot::before {
  content: "";
  position: absolute;
  inset: -0.75rem auto auto -0.75rem;
  width: 6rem;
  height: 6rem;
  border-top: 2px solid var(--color-accent);
  border-left: 2px solid var(--color-accent);
  border-top-left-radius: var(--radius-card);
  pointer-events: none;
}

@media (min-width: 64rem) {
  .hero { padding: 5rem 0 6rem; }
  /* 27rem of copy against the rest. The copy column is narrower than the old
     full-width one BY DESIGN: 20ch of 72px display text was three lines, and
     at 27rem the same string sets in two at a smaller step. */
  .hero-grid {
    display: grid;
    grid-template-columns: minmax(0, 34rem) minmax(0, 1fr);
    gap: 3.5rem;
    align-items: center;
  }
  .hero-copy > .lede { max-width: 34rem; }
  /* ⚠️ SIZED SO IT SETS IN THREE LINES, NOT FOUR — measured, not chosen. The
     old 72px display size ran to three lines across the FULL page width; the
     first attempt at 52px in a 30rem column ran to four in half of it, which is
     worse. 3.25rem in a 34rem column is 3 lines at 159px tall against the
     original 220px, and the space that saves now holds the image rather than a
     gap. */
  .hero h1 {
    font-size: clamp(2.5rem, 3.4vw, 3.25rem);
    max-width: 20ch;
  }
  .hero-shot { margin-top: 0; }
  /* ⚠️ THE BLEED. `width` past 100% pushes the image's right edge toward the
     viewport edge; the section clips whatever passes it. min() caps the reach
     so a very wide monitor does not push the image half off the screen. */
  .hero-shot .shot img { width: calc(100% + min(9vw, 8rem)); max-width: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION RHYTHM: THREE SHAPES, NOT ONE (2026-07-29)
   ═══════════════════════════════════════════════════════════════════════════
   Every section on this site was the same shape — eyebrow, heading, rule, lede,
   cards — so the page read as one long list regardless of what each part said.
   There are now three, and a page should use more than one:

     .section            the default. Heading and lede over a card grid.
     .section.split      image-led. Two columns from 64rem; the copy stays first
                         in the DOM, so reading order is unchanged on a phone.
     .section.statement  a single sentence on charcoal. No cards, centred.

   ⚠️ USE `.statement` SPARINGLY — once per page at most. Its whole value is
   being the thing that is not like the others; two of them on one page and the
   rhythm is flat again in a different colour. */

/* ─── split: copy beside an image ────────────────────────────────────── */
@media (min-width: 64rem) {
  .split > .container {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 4rem;
    align-items: center;
  }
  /* ⚠️ `order` PUTS THE IMAGE LEFT WITHOUT MOVING IT IN THE DOM. The copy stays
     first in the source, so a screen reader and a phone both get heading before
     picture; only the visual order flips. Mirrors the hero, which has its image
     on the right — alternating the side is what stops two image sections
     reading as the same section twice. */
  .split-media { order: -1; }
  .split-copy > .lede { max-width: none; }
  .split .shot { margin: 0; max-width: none; }
}
.split-media { margin-top: 2.5rem; }
@media (min-width: 64rem) { .split-media { margin-top: 0; } }

/* ─── statement: one sentence, on charcoal ───────────────────────────── */
/* ⚠️ THE ONE PLACE GOLD IS TEXT, AND IT IS LEGAL ONLY HERE. Measured on
   #1C1917: gold 6.713:1, white 17.488:1, sand 13.929:1 — all comfortably past
   AA for normal text, where the same gold on ivory is 2.495:1 and fails even
   the large-text threshold. Do not lift `.statement .eyebrow`'s colour out of
   this block. */
.statement {
  background: var(--color-background-dark);
  color: var(--color-text-inverse);
  border: 0;
}
.statement::before { content: none; }          /* no gold hairline; it has its own */
.statement > .container { text-align: center; }
.statement .eyebrow { color: var(--color-accent); }
.statement h2 { max-width: 22ch; margin-inline: auto; }
.statement .accent-rule { margin-inline: auto; }
.statement .lede {
  color: var(--color-dark-text-secondary);
  max-width: 46rem;
  margin-inline: auto;
  font-size: 1.0625rem;
}
/* ⚠️ FIGCAPTION RECOLOURED HERE — QA_LEDGER YQ-151. `.shot figcaption`
   hardcodes taupe, which measures 3.645:1 on charcoal — under AA for 13px
   text. Sand is 13.93:1. Every text colour a .shot can bring onto this dark
   surface must be re-declared in this block. */
.statement .shot figcaption { color: var(--color-dark-text-secondary); }
.statement :focus-visible { outline-color: var(--color-text-inverse); }
@media (min-width: 1024px) { .statement { padding: 6rem 0; } }

/* ═══════════════════════════════════════════════════════════════════════════
   HELP & ARTICLE NAVIGATION (2026-07-29)
   ═══════════════════════════════════════════════════════════════════════════
   An article was a dead end: no route to the other five except the back
   button. Three mechanisms, chosen over a lone breadcrumb because six articles
   is few enough that the full list IS the best navigation:

     .eyebrow-link    the article's eyebrow ("Help") links back to its index —
                      a return route that costs zero new words.
     .article-aside   every sibling, current marked by aria-current + weight +
                      a gold rail (never colour alone). Sticky from 64rem;
                      flows below the prose on a phone.
     .article-pager   previous/next under the prose, for the read-through path.

   All three live in article.njk, which serves the help articles. */

/* ⚠️ 44px OF HIT AREA FROM PADDING, HEIGHT GIVEN BACK BY NEGATIVE MARGINS —
   the eyebrow is a 12px line and its rhythm above the h1 must not change. */
.eyebrow-link {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  margin: -0.8125rem 0;
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.eyebrow-link:hover {
  color: var(--color-text-primary);
  border-bottom-color: var(--color-accent);
}

/* ⚠️ BASE RULE FIRST, MEDIA OVERRIDE AFTER — QA_LEDGER YQ-154. This block
   originally sat the other way round, and at equal specificity the later
   base rule won INSIDE the media query too, so the desktop overrides were
   dead and the sticky aside kept its mobile margin, border and padding. A
   media query is not "later"; only source order and specificity are. */
.article-aside {
  margin-top: 3.5rem;
  border-top: 1px solid var(--color-border-subtle);
  padding-top: 1.5rem;
}
@media (min-width: 64rem) {
  .article-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 15rem;
    gap: 5rem;
    align-items: start;
  }
  /* Sticky is safe here: nothing in the column is position:fixed, and the
     aside is shorter than any article beside it. */
  .article-aside {
    position: sticky;
    top: 2.5rem;
    margin-top: 0;
    border-top: 0;
    padding-top: 0;
  }
}
.aside-title {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-text-secondary);
  margin: 0;
}
.article-aside ul {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
  border-left: 1px solid var(--color-border-subtle);
}
.article-aside a {
  display: flex;
  align-items: center;
  min-height: 2.75rem;
  margin-left: -1px;
  padding-left: 0.875rem;
  border-left: 2px solid transparent;
  color: var(--color-text-secondary);
  font-size: 0.9375rem;
  line-height: 1.35;
  text-decoration: none;
}
.article-aside a:hover { color: var(--color-text-primary); }
/* Current article: weight + the gold rail + aria-current — never colour alone. */
.article-aside a[aria-current="page"] {
  color: var(--color-text-primary);
  font-weight: 600;
  border-left-color: var(--color-accent);
}

.article-pager {
  margin-top: 3.5rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--color-border-subtle);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  max-width: 44rem; /* aligns with the prose column */
}
.pager-link {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
  padding: 0.375rem 0;
  text-decoration: none;
}
.pager-label {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-text-secondary);
}
.pager-title {
  font-family: var(--font-family-display);
  font-weight: 600;
  font-size: 1.0625rem;
  line-height: 1.35;
  color: var(--color-text-primary);
  border-bottom: 1px solid transparent;
}
.pager-link:hover .pager-title { border-bottom-color: var(--color-accent); }
/* Next stays in the right column even when it is the only link (the first
   article has no previous), so "forward" is always on the same side. */
.pager-next { grid-column: 2; align-items: flex-end; text-align: right; }
.pager-prev { grid-column: 1; }

/* ─── the Help index: numbered editorial rows, not bare cards ───────────── */
/* ⚠️ THE NUMERALS ARE DECORATION AND SILENT. The <ol> carries the order
   semantically; the painted 01–06 use the `content: … / ""` alt-text syntax so
   assistive tech is not told each number twice. The first declaration is the
   fallback for engines without the syntax. Sand #E7E5E4 on ivory is 1.16:1 —
   legal only BECAUSE it is decoration: nothing is identified by it, and the
   ghost weight is the point. Do not promote it to an information carrier. */
.help-index {
  list-style: none;
  margin: 2.5rem 0 0;
  padding: 0;
  counter-reset: help-row;
  border-top: 1px solid var(--color-border-subtle);
}
.help-row {
  counter-increment: help-row;
  display: grid;
  grid-template-columns: 3.75rem minmax(0, 1fr) auto;
  gap: 1.25rem;
  align-items: center;
  padding: 1.625rem 0.75rem;
  margin: 0 -0.75rem;
  border-bottom: 1px solid var(--color-border-subtle);
  transition: background-color 0.15s ease;
}
.help-row:hover { background: var(--color-background-surface); }
.help-row::before {
  content: counter(help-row, decimal-leading-zero);
  content: counter(help-row, decimal-leading-zero) / "";
  font-family: var(--font-family-display);
  font-weight: 700;
  font-size: 2rem;
  line-height: 1;
  letter-spacing: -0.025em;
  color: var(--color-border-subtle);
}
/* After `.section h2` in the cascade on purpose — these are rows, not section
   headings, and must not take the display size. */
.help-row h2 {
  font-size: 1.375rem;
  line-height: 1.3;
  letter-spacing: -0.015em;
  max-width: none;
}
.help-row h2 a { text-decoration: none; }
.help-row:hover h2 a { border-bottom: 1px solid var(--color-accent); }
.help-row p {
  margin-top: 0.375rem;
  color: var(--color-text-secondary);
  font-size: 0.9375rem;
  max-width: 38rem;
}
.help-arrow {
  color: var(--color-text-secondary);
  transition: transform 0.15s ease, color 0.15s ease;
}
.help-row:hover .help-arrow {
  color: var(--color-text-primary);
  transform: translateX(4px);
}
@media (max-width: 639px) {
  .help-row { grid-template-columns: 2.5rem minmax(0, 1fr) auto; gap: 0.875rem; }
  .help-row::before { font-size: 1.375rem; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PRODUCT ROWS, PLACEHOLDER MEDIA, THE PHONE, MOTION (2026-07-29)
   ═══════════════════════════════════════════════════════════════════════════ */

/* Deep drop shadow for a hovered/featured object. Sits beside --shadow-card;
   never on the logo artwork (BRAND.md forbids effects on the mark itself). */
:root { --shadow-lift: 0 12px 32px rgba(28, 25, 23, 0.14); }

/* ─── /product/: image-led alternating rows ──────────────────────────── */
.product-rows {
  display: grid;
  gap: 3.5rem;
  margin-top: 0.5rem;
}
.product-row {
  display: grid;
  gap: 1.25rem;
  align-items: center;
}
@media (min-width: 64rem) {
  .product-rows { gap: 5.5rem; }
  .product-row { grid-template-columns: minmax(0, 26rem) minmax(0, 1fr); gap: 4.5rem; }
  /* Alternate the image side, hero-style: the copy stays first in the DOM, so
     reading order never flips — only the visual order does. */
  .product-row-flip .product-row-media { order: -1; }
}
/* After `.section h2` in the cascade on purpose — a row heading, not a section
   heading, and it must not take the display size. */
.product-row h2 {
  font-size: 1.75rem;
  line-height: 1.15;
  letter-spacing: -0.02em;
  max-width: none;
}
.product-row h2 a { text-decoration: none; }
.product-row:hover h2 a { border-bottom: 1px solid var(--color-accent); }
.product-row-copy p {
  margin-top: 0.75rem;
  color: var(--color-text-secondary);
  font-size: 1.0625rem;
  max-width: 26rem;
}
.product-row .shot { margin: 0; max-width: none; }
.product-row .shot img { transition: transform 0.18s ease, box-shadow 0.18s ease; }
.product-row:hover .shot img {
  transform: translateY(-3px);
  box-shadow: var(--shadow-lift);
}

/* ─── two figures side by side (a real shot beside its placeholder) ────── */
.media-duo {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2rem;
  margin-top: 2.5rem;
  align-items: start;
}
.media-duo .shot { margin: 0; max-width: none; }
@media (min-width: 64rem) {
  .media-duo { grid-template-columns: 1fr 1fr; }
}

/* The .placeholder-card frame that lived here went with the two greeked SVG
   sketches on 2026-07-29, when the owner supplied real screenshots for both.
   There are no placeholder graphics on this site. */

/* ─── the statement that carries the phone (home, #install) ─────────────── */
.statement-split .statement-media { margin-top: 1rem; }
@media (min-width: 64rem) {
  .statement-split > .container {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 5rem;
    align-items: center;
    text-align: left;
  }
  .statement-split h2,
  .statement-split .accent-rule,
  .statement-split .lede { margin-inline: 0; }
  .statement-split .statement-media { margin-top: 0; }
  .statement-split .phone { margin: 0; }
}

/* ⚠️ THE PHONE IS A CSS ILLUSTRATION — sharp at any size, no licensing
   question, and unmistakeably a sketch: every tile is a blank dark square
   except the app's own icon on ivory. It lives on the charcoal statement, so
   its greys are the dark-surface family; ratios are irrelevant to WCAG here
   (the whole device is aria-hidden decoration and carries no information the
   copy beside it does not state). No gradients — BRAND.md. */
.phone {
  width: 16rem;
  margin: 3rem auto 0;
  padding: 0.5rem;
  background: #0c0a09;
  border: 1px solid var(--color-dark-border-subtle);
  border-radius: 2.9rem;
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.4);
}
/* Proportions are measured against the real thing: a 1 : 1.95 face is what an
   iPhone actually has — the first build was 1 : 1.4 and read as a rounded
   card, not a phone. The min-height sets the face; the flex column pushes the
   dock to the bottom edge the way a real home screen holds it. Measured after:
   256 × 502, ratio 1.96. */
.phone-screen {
  position: relative;
  overflow: hidden;
  background: #292524;
  border-radius: 2.4rem;
  padding: 3.25rem 1rem 1.25rem;
  min-height: 30.25rem;
  display: flex;
  flex-direction: column;
}
.phone-notch {
  position: absolute;
  top: 0.8rem;
  left: 50%;
  transform: translateX(-50%);
  width: 5.5rem;
  height: 1.4rem;
  border-radius: 999px;
  background: #0c0a09;
}
.phone-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.25rem 0.75rem;
  margin-bottom: 1.25rem; /* the dock's minimum clearance when space is tight */
}
.phone-app {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.375rem;
}
.phone-app-icon {
  width: 100%;
  aspect-ratio: 1;
  border-radius: 26%;
  background: #44403c;
  display: flex;
  align-items: center;
  justify-content: center;
}
.phone-app-real .phone-app-icon { background: var(--color-background-page); }
/* ⚠️ HONEST MEASUREMENT, per BRAND.md's own ink method: 78% of the ~43px tile
   is a ~33px BOX, which clears the recorded "32px displayed" minimum as
   literally written — but the squared 1000×1000 artwork is padded (glyph =
   80.5% × 63% of its canvas), so the visible MARK is ~27×21px, the regime
   BRAND.md flags as nearer its old 16px failure than its old 32px pass. Kept
   because this is an aria-hidden ILLUSTRATION of a home-screen icon (the real
   installed icon renders ~180px), not the mark as identification — but that
   is a judgement for the person whose brand it is: OWNER, EYEBALL THIS RENDER
   before go-live, or the phone grows until the glyph itself clears 32px. */
.phone-app-real img { width: 78%; height: auto; display: block; }
.phone-app-label {
  font-size: 0.5625rem;
  line-height: 1;
  color: var(--color-dark-text-secondary);
  letter-spacing: 0.02em;
}
.phone-app-ghost {
  width: 60%;
  height: 0.25rem;
  border-radius: 999px;
  background: #3f3a36;
}
.phone-dock {
  margin-top: auto; /* pinned to the screen's bottom edge, like the real thing */
  padding: 0.6rem;
  border-radius: 1.4rem;
  background: rgba(255, 255, 255, 0.06);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.75rem;
}

/* ─── motion: scroll-driven, zero JS ─────────────────────────────────── */
/* ⚠️ DOUBLY GATED. Only engines with scroll-driven animations run it, and only
   for people who have not asked for reduced motion — the global kill switch
   above is belt, this gate is braces. Engines without view() (Firefox stable,
   2026) simply render everything static, which is the correct fallback.
   The rise is 14px and starts at 0.2 opacity, so an element caught mid-entry
   by a measurement or a print never vanishes entirely. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .card,
    .plan,
    .shot,
    .help-row,
    .product-row {
      animation: rise-in ease-out both;
      animation-timeline: view();
      animation-range: entry 0% entry 60%;
    }
    /* ⚠️ A .shot INSIDE an animated ancestor must not animate too — the
       opacities MULTIPLY (0.2 × 0.2 = 0.04 mid-entry, effectively invisible)
       and the translates compound to 28px. /product/'s rows are the case
       that exists today; the selector is written for the class pair so any
       future nesting inherits the guard. */
    .product-row .shot { animation: none; }
  }
}
@keyframes rise-in {
  from { opacity: 0.2; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}
/* ⚠️ PRINT: browsers omit backgrounds by default, so every dark surface would
   otherwise print its light text on white paper — including the gold eyebrow
   at 2.6:1, the exact on-light pairing this file's header forbids. Charcoal
   for everything is the print truth. The phone would print as an empty
   outline, so it does not print at all. */
@media print {
  .card, .plan, .shot, .help-row, .product-row { animation: none !important; }
  .page-head, .page-head .eyebrow, .page-head .lede,
  .statement, .statement .eyebrow, .statement .lede, .statement .shot figcaption,
  .site-footer, .footer-tagline, .footer-legal,
  .footer-nav a, .footer-base-links a { color: #1c1917 !important; }
  .phone { display: none; }
}
