/* Skippr /blog — the v3 theme.
   ────────────────────────────────────────────────────────────────────────────
   The estate's design, on all 126 pages: its article furniture rendered in the
   language of the skippr.ai landing page (homepage-ai, `src/app/(home)/v3.css`
   + `_sections/*`). Started as a one-page test and Harry took it estate-wide on
   2026-08-11.

   This is an override layer on top of style.css rather than a replacement, and
   deliberately so. style.css is entirely token-driven, so most of the theme is
   just re-tokening: swap eleven custom properties and the whole page turns over
   with no risk of a component being missed. What follows the token block is the
   part re-tokening cannot do — the vocabulary that is v3's rather than the
   design system's.

   Everything is scoped under `html.v3`, which `PageShell` now puts on every
   page. The scope is kept rather than stripped for two reasons: it wins the
   specificity contest against style.css's own `:root` overrides without needing
   `!important`, and it is what makes reverting a one-attribute change.

   ── What v3's vocabulary actually is, as read off the landing page ──
   1. Dark editorial ground. Near-black, one flat surface, no page-level tints.
   2. Hairline architecture. Structure is drawn with 1px rules and grid gaps.
      No rounded cards, no drop shadows, no ring elevation. The one exception is
      the film card's 14px radius, which the hero illustration inherits here.
   3. Cyan is punctuation, not paint. It marks eyebrows, rules and links; it is
      never a large filled surface. Where the landing wants to feature something
      it tints at 5% and lays a solid 1-2px cyan rule across the top edge
      (`.v3price-card.is-featured`).
   4. Links carry a 2px rule that wipes in from the left rather than a box.
      No filled buttons anywhere on the landing page, so none here either.
   5. Archivo, set tight. Display weights 700-800 at -0.045em to -0.055em and
      line-heights under 1, which is what makes the headlines read as a wall.
   ──────────────────────────────────────────────────────────────────────────── */

/* ---------- Archivo, self-hosted ----------
   The landing page pulls Archivo through next/font, which self-hosts it at
   build. This estate has no build step for fonts and deliberately serves no
   Google Fonts (see the 2026-07-31 16:04 log entry), so the two variable
   subsets are vendored beside Inter. Inter stays loaded and stays the font for
   every other page. */

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

/* ---------- tokens ----------
   Copied value-for-value from the landing page's `.v3-root` block so the two
   surfaces cannot drift. The only additions are the two the estate needs and
   the landing page has no equivalent for: a `--card` variant quiet enough to
   sit under body copy, and the ring/shadow tokens neutralised, since v3 draws
   elevation with hairlines and this sheet must cancel style.css's rings rather
   than fight them component by component. */

html.v3 {
  --background: oklch(0.145 0.012 285);
  --foreground: oklch(0.975 0.004 285);
  --card: oklch(0.19 0.014 285);
  --card-foreground: oklch(0.975 0.004 285);
  --popover: oklch(0.19 0.014 285);
  --popover-foreground: oklch(0.975 0.004 285);
  --primary: oklch(0.86 0.155 191);
  --primary-foreground: oklch(0.16 0.012 285);
  --secondary: oklch(0.66 0.245 15);
  --secondary-foreground: oklch(0.98 0.004 285);
  --muted: oklch(0.24 0.014 285);
  --muted-foreground: oklch(0.7 0.012 285);
  --accent: oklch(0.24 0.014 285);
  --accent-foreground: oklch(0.975 0.004 285);
  --border: oklch(0.3 0.014 285);
  --input: oklch(0.3 0.014 285);
  --ring: oklch(0.86 0.155 191);

  --font-sans: "Archivo", ui-sans-serif, system-ui, -apple-system, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, sans-serif;

  /* v3 draws elevation with rules, so every ring in style.css resolves to
     nothing rather than needing to be unset at each call site. The focus ring
     is the exception and is re-declared below: it is an accessibility
     affordance, not decoration. */
  --ring-1: none;
  --shadow-sm: none;
  --shadow-md: none;
  --shadow-lg: none;

  /* The 5% tint and the rule that go together wherever the landing page marks
     something out. Named so the four blocks that use it cannot disagree. */
  --v3-tint: oklch(from var(--primary) l c h / 0.05);
  --v3-rule: 2px;
}

html.v3 body {
  background: var(--background);
  color: var(--foreground);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* The shell stays at the estate's 76rem and does NOT take the landing page's
   1400. Tried and reverted: the landing's sections are full-bleed compositions
   that use the width, whereas every block here is measure-bound, so the extra
   184px landed as void down the right of the whole page and pulled the related
   list into two columns a screen apart. The one thing that genuinely wanted the
   room was the headline, and giving it to the hero alone would break the shared
   left edge that the hero, article and footer are deliberately built on. */

/* ---------- the eyebrow ----------
   11px / 600 / 0.08em / uppercase / cyan. One rule for every labelled block on
   the landing page (`.v3price-eyebrow`, the footer column titles, the hero
   eyebrow) and therefore one rule for every labelled block here. */

html.v3 .eyebrow,
html.v3 .toc .label,
html.v3 .glance dt,
html.v3 .assessment dt,
html.v3 thead th,
html.v3 .skippr .bar {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
html.v3 .eyebrow,
html.v3 .toc .label {
  color: var(--primary);
}

/* ---------- masthead ----------
   The landing nav is transparent over the black rather than a tinted bar, and
   its items are the eyebrow at nav size. The blur stays: this masthead is
   sticky over scrolling copy, where the landing's sits over a video. */

html.v3 header.masthead {
  background: oklch(from var(--background) l c h / 0.72);
  border-bottom: 1px solid var(--border);
}
html.v3 .wordmark span,
html.v3 nav.crumbs {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
html.v3 nav.crumbs em {
  font-weight: 600;
}

/* ---------- hero ----------
   No tint band. The landing opens on flat black with the headline as the whole
   event, so the hero here stops being a panel and becomes the top of the page.
   The rule under the kicker turns cyan, which is the one place the estate
   already had a 2px accent rule waiting for a colour. */

html.v3 .hero {
  background: transparent;
  border-bottom: none;
}
html.v3 .kicker {
  border-top-color: var(--primary);
  font-size: 11px;
  letter-spacing: 0.08em;
}
html.v3 .kicker .what {
  color: var(--primary);
}

/* 800 at -0.055em with the line-height under 1 — the landing's headline spec
   exactly. `text-wrap: balance` stays from style.css; at this tracking an
   orphaned word is much more visible than it was in Inter. */
html.v3 h1 {
  font-size: clamp(2.5rem, 6.4vw, 4.75rem);
  font-weight: 800;
  letter-spacing: -0.055em;
  line-height: 0.96;
  max-width: 18ch;
}

html.v3 .standfirst {
  font-weight: 400;
  line-height: 1.5;
  color: var(--muted-foreground);
}

/* The film card's 14px radius and a hairline instead of the ring. These heroes
   are oil paintings with white speech bubbles composited into the sky, so a
   dark ground suits them better than the light one did — but the hairline
   still matters, or a dark painting bleeds into the page. */
html.v3 figure.hero-art img {
  border-radius: 14px;
  border: 1px solid var(--border);
}

html.v3 .byline {
  font-size: 13px;
  color: var(--muted-foreground);
}

/* ---------- contents rail ---------- */

html.v3 .toc nav {
  border-left-color: var(--border);
}
html.v3 .toc a {
  color: var(--muted-foreground);
  transition: color 160ms ease;
}

/* ---------- prose ----------
   Archivo runs wider than Inter at the same size, so the measure is trimmed and
   the leading opened a little: light type on a dark ground needs more air
   between lines to stop the counters filling in. */

html.v3 p,
html.v3 ul.plain > li {
  font-size: 1.0625rem;
  line-height: 1.75;
  max-width: 64ch;
  color: oklch(from var(--foreground) l c h / 0.86);
}

html.v3 h2 {
  font-size: clamp(1.625rem, 3vw, 2.375rem);
  font-weight: 700;
  letter-spacing: -0.045em;
  line-height: 1.04;
  max-width: 26ch;
  color: var(--foreground);
}
html.v3 h3 {
  font-weight: 600;
  letter-spacing: -0.02em;
}

/* Prose links keep a permanent hairline in cyan and go solid on hover, which is
   the quiet version of the landing's wipe. The wipe itself is reserved for the
   CTAs below: used on every link in a paragraph it turns body copy into a
   flickering surface.

   The list selectors name the two lists that are prose — a bullet in the body and
   a numbered source — rather than every `li a` in the article, and that precision
   is load-bearing. `article.doc li a` was the first version, and because the site
   map and the topic hubs slot their directories into the same `article.doc`, it
   painted all 120 rows of `/blog` cyan and, before that, the whole related list.
   Both times the instinct was to out-specify the offender; the actual fault is a
   rule claiming ground it has no business on, and there is no reason to think the
   next list added to an article will remember to fight it. */
html.v3 article.doc p a,
html.v3 article.doc ul.plain li a,
html.v3 .sources li a {
  color: var(--primary);
  text-decoration-color: oklch(from var(--primary) l c h / 0.4);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  transition: text-decoration-color 160ms ease;
}
html.v3 article.doc p a:hover,
html.v3 article.doc ul.plain li a:hover,
html.v3 .sources li a:hover {
  color: var(--primary);
  text-decoration-color: var(--primary);
}

html.v3 ul.plain > li::before {
  background: var(--primary);
}

html.v3 ::selection {
  background: oklch(from var(--primary) l c h / 0.25);
  color: var(--foreground);
}

/* ---------- verdict ----------
   The answer-first passage was a rounded card with a ring. v3 has no such
   object, so it becomes the featured treatment: 5% tint, solid cyan rule across
   the top, square. Same emphasis, drawn the way the landing draws it. */

html.v3 .verdict {
  background: var(--v3-tint);
  border-radius: 0;
  box-shadow: inset 0 var(--v3-rule) 0 var(--primary);
  padding: clamp(1.5rem, 3vw, 2.25rem);
  max-width: 64ch;
}
html.v3 .verdict p {
  font-size: clamp(1.125rem, 1.6vw, 1.3125rem);
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: -0.015em;
  color: var(--foreground);
}

/* ---------- the call, the note ----------
   Both were tinted or filled rounded boxes. Same conversion as the verdict: the
   call takes the featured treatment, the note drops to a plain hairline block,
   since it is an aside rather than a claim. */

html.v3 .call {
  background: var(--v3-tint);
  border-radius: 0;
  box-shadow: inset 0 var(--v3-rule) 0 var(--primary);
}
html.v3 .note {
  background: transparent;
  border-radius: 0;
  border-left: 1px solid var(--border);
  padding-left: 1.25rem;
}

/* ---------- hairline grids ----------
   `.glance` already built its rules out of a 1px grid gap, which is exactly the
   landing's pricing grid. It only needed its corners squaring and its ring
   removing. Tables get the same treatment. */

html.v3 .glance,
html.v3 .tablewrap {
  border-radius: 0;
}
/* The ring that used to bound a table is gone with the rest of the elevation, and
   without it a table has no edges at all: the last row's rule is suppressed by
   style.css, so the tier table simply faded into the page above its own source
   note. Two hairlines put the edges back, and they also restore the affordance
   that this box scrolls sideways on a narrow screen, which the card used to carry. */
html.v3 .tablewrap {
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
html.v3 .glance {
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
html.v3 .glance > div {
  background: var(--background);
}
html.v3 .glance .lead-cell {
  background: var(--v3-tint);
  box-shadow: inset 0 var(--v3-rule) 0 var(--primary);
}
/* The supporting line in the featured cell is the estate's worst pairing, and it
   was the only thing the 126-route sweep surfaced: `--muted-foreground` reads
   7.38:1 on the flat ground and 4.56:1 once the 5% tint is under it, which passes
   AA by six hundredths. The cell carries the page's central figure, so brightening
   its caption is right on its own terms rather than a contrast workaround. */
html.v3 .glance .lead-cell dd {
  color: oklch(from var(--foreground) l c h / 0.8);
}
html.v3 .glance .display {
  font-weight: 700;
  letter-spacing: -0.04em;
}

html.v3 table {
  background: transparent;
}
html.v3 thead th {
  background: var(--muted);
  color: var(--muted-foreground);
}
html.v3 table.decision .route.us {
  color: var(--primary);
}

/* ---------- quotes ---------- */

html.v3 .quote blockquote {
  border-left: var(--v3-rule) solid var(--primary);
  font-weight: 500;
  letter-spacing: -0.015em;
}

/* ---------- the Skippr panel ----------
   This was an inverted oxblood block, and inverting it here would mean a
   full-bleed cyan surface with dark text on it. The landing page never does
   that: cyan is punctuation there, and a panel that size in it would be the
   loudest thing on skippr.ai. So the panel keeps its rank by taking the same
   featured treatment as the verdict, with the heading in cyan carrying the
   emphasis the fill used to.

   Deliberate divergence from the page's own comment ("the one place on the page
   that flips ground and figure"), recorded here rather than silently: on a dark
   ground the flip is no longer available without breaking the palette. */

html.v3 .skippr {
  background: var(--v3-tint);
  color: var(--foreground);
  border-radius: 0;
  box-shadow: inset 0 var(--v3-rule) 0 var(--primary);
}
html.v3 .skippr .bar {
  border-bottom: 1px solid var(--border);
  color: var(--primary);
}
html.v3 .skippr h2 {
  color: var(--primary);
  font-weight: 700;
  letter-spacing: -0.035em;
}
html.v3 .skippr p {
  color: oklch(from var(--foreground) l c h / 0.86);
}
html.v3 .skippr p:last-child:not(.model) {
  color: var(--muted-foreground);
}
html.v3 .skippr .model {
  background: oklch(from var(--foreground) l c h / 0.06);
  border-radius: 0;
  color: oklch(from var(--foreground) l c h / 0.86);
}
html.v3 .skippr .model b,
html.v3 .skippr .model strong,
html.v3 .skippr .rel b,
html.v3 .skippr .rel strong {
  color: var(--foreground);
}
html.v3 .skippr a,
html.v3 .skippr .cite {
  color: var(--primary);
}

/* ---------- faq ----------
   Already hairline, so this is tone only: the rules brighten, the question sits
   at the landing's heading weight, and the chevron picks up cyan on hover the
   way every other affordance does. */

html.v3 .faq summary {
  font-weight: 600;
  letter-spacing: -0.015em;
}

/* ---------- end-stack ----------
   The landing page has no filled buttons. Its CTAs are text at body-plus size
   carrying a 2px rule — a permanent cyan one on the primary, a wipe-in one on
   the secondary — so the two pills become exactly that pair.

   `background-size` is the mechanism for both, not `border-bottom`, and that is
   the point rather than a style preference: a border snaps to whole device
   pixels while a background gradient antialiases, so declaring both "2px" by
   different mechanisms paints one heavier than the other. Same note lives in
   the landing page's own stylesheet. */

html.v3 .endstack {
  background: transparent;
  border-radius: 0;
  border-top: 1px solid var(--border);
  padding: clamp(1.75rem, 3.5vw, 2.5rem) 0 0;
  max-width: 64ch;
}
html.v3 .endstack h2 {
  font-size: clamp(1.5rem, 2.4vw, 2rem);
  font-weight: 700;
  letter-spacing: -0.04em;
  line-height: 1.06;
}
html.v3 .endstack .actions {
  gap: 1.75rem;
  margin-top: 1.5rem;
}
html.v3 .endstack a.btn {
  padding: 0 0 5px;
  border: none;
  border-radius: 0;
  background: linear-gradient(var(--primary), var(--primary)) no-repeat left bottom /
    100% var(--v3-rule);
  color: var(--primary);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.0125em;
  transition: padding-left 160ms ease;
}
html.v3 .endstack a.btn:hover {
  background: linear-gradient(var(--primary), var(--primary)) no-repeat left bottom /
    100% var(--v3-rule);
  color: var(--primary);
  padding-left: 8px;
}
/* The secondary has no rule at rest; it wipes one in from the left on hover. */
html.v3 .endstack a.btn.ghost {
  background: linear-gradient(currentColor, currentColor) no-repeat left bottom / 0%
    var(--v3-rule);
  color: var(--foreground);
  transition: background-size 260ms ease;
}
html.v3 .endstack a.btn.ghost:hover {
  background: linear-gradient(currentColor, currentColor) no-repeat left bottom / 100%
    var(--v3-rule);
  color: var(--foreground);
  padding-left: 0;
}

/* ---------- mesh ----------
   The landing's footer link columns: 14px, muted, brightening to full on hover.
   The `— kind` suffix stays quieter than the label it follows. */

html.v3 .mesh h2 {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--primary);
}
/* The landing page's footer link columns: muted at rest, full on hover. This no
   longer has to out-specify the prose-link rule, which now names the two lists it
   means; the extra `article.doc` is kept only because a related list is always
   inside one and it costs nothing to say so. */
html.v3 article.doc .mesh li a {
  color: var(--muted-foreground);
  text-decoration: none;
  transition: color 160ms ease;
}
html.v3 article.doc .mesh li a:hover {
  color: var(--foreground);
}
/* A mesh target in the manifest but not built yet, rendered as text rather than a
   dead href. style.css gives it `--foreground` because in the light theme the links
   beside it were oxblood and this had to read as quieter. Here the links are muted,
   so leaving it white made the one thing you cannot click the loudest item in the
   list. It takes the same tone as a real entry and the italic "in progress" suffix
   carries the difference, which is what actually tells a reader why nothing happens. */
html.v3 .mesh .pending {
  color: var(--muted-foreground);
}

/* ---------- sources ---------- */

html.v3 .sources {
  border-top-color: var(--primary);
}
html.v3 .sources li:target {
  background: var(--v3-tint);
}

/* ---------- the directory listings ----------
   `/blog` and the five topic hubs share one list, declared locally in both routes.
   Neither sets a colour, so both inherited the global `a { color: var(--primary) }`
   and rendered as 122 and 30 rows of solid cyan: a wall of accent on the one page
   type whose own comment says "no cards, no icons, no accent colour".

   Cyan is punctuation on the landing page, and a directory of page titles is the
   opposite of punctuation. The titles are the content here, so they sit at full
   `--foreground` and take a hairline on hover; the type label stays muted at the
   right, which is what gives the row its hierarchy. */

html.v3 .maplist a {
  color: var(--foreground);
  letter-spacing: -0.01em;
}
html.v3 .maplist a:hover {
  color: var(--primary);
}
/* The group heading is the eyebrow at directory scale, and it is also the way
   through to that bucket's hub, so it keeps the accent the eyebrow has. */
html.v3 .mapgroup h2 a {
  color: var(--primary);
}
/* Dev-only (`SHOW_EDIT_LINKS`), so this never ships. Squared anyway: a stray pill
   in a screenshot of the site map is the sort of thing that gets copied. */
html.v3 .mapedit {
  border-radius: 0;
}

/* ---------- footer ----------
   Flat black with a hairline above it, matching the landing's `borderTop: 1px
   solid var(--border)` and nothing else. The tinted band goes. */

html.v3 footer.foot {
  background: transparent;
  border-top: 1px solid var(--border);
  color: var(--muted-foreground);
}

/* ---------- focus ----------
   `--ring-1` was set to `none` above, and `--ring-focus` is a separate token, but
   both are re-declared here so a future edit to the elevation block cannot take
   the focus ring out with it. */

html.v3 :focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  box-shadow: none;
  border-radius: 2px;
}
html.v3 .skip {
  background: var(--primary);
  color: var(--primary-foreground);
}

@media (prefers-reduced-motion: reduce) {
  html.v3 * {
    transition: none !important;
  }
}
