/* ============================================================
   TechVault design system

   Rules this file follows, because each one was arrived at by
   taking something away:

   - One accent. Sienna is for action and nothing else. When it
     is also used for panels, borders and hover states it stops
     meaning "you can press this".
   - Hairlines, not shadows, separate content. A shadow is for
     something floating above the page (a drawer, a dialog) and
     nowhere else. Shadows on rows of content read as a template.
   - Monospace is metadata: labels, counts, codes. Body copy and
     headings are never mono. All-mono pages read as a terminal
     emulator rather than a publisher.
   - Panels are not decorative. A tinted box or a "card" behind
     every value is the clearest tell of generated filler, so
     colour is spent only where it carries meaning.
   - Numbers that cannot be acted on are not shown. "5.3M words"
     tells a buyer nothing; "360 questions" tells them what
     they are paying for.
   ============================================================ */

:root {
  /* Neutral ramp, warm. The page is paper; the ink is text. */
  --paper: #faf9f6;
  --surface: #ffffff;
  --surface-2: #f4f2ec;
  --ink: #191a1d;
  --ink-2: #3f4249;
  --muted: #6f737c;
  --faint: #9a9ea7;
  --line: #e3e0d8;
  --line-2: #d2cec2;

  /* The only accent. */
  --accent: #b3400a;
  --accent-deep: #8c3006;
  --accent-wash: #faf0e9;

  --pine: #1d5c4f;
  --focus: #1d5c4f;

  /* Elevation, for the three surfaces that genuinely float: the drawer, the dialog and the
     cart popover. Kept tight and low-alpha on purpose. The earlier values cast a wide
     diffuse glow, which is the one shadow treatment that reads as dated; these read as an
     edge. Everything else on the page is separated by a 1px hairline and no shadow at all. */
  --shadow-pop: 0 1px 2px rgba(25, 26, 29, .05), 0 6px 16px rgba(25, 26, 29, .07);
  --shadow-modal: 0 1px 2px rgba(25, 26, 29, .05), 0 12px 32px rgba(25, 26, 29, .10);

  --font-body: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  --font-display: "Newsreader", "Iowan Old Style", Georgia, serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Consolas, monospace;
  /* Type scale. Nine steps plus the two display sizes, and every size on the site is one of
     them. The stylesheet used to carry thirty-three, in 0.02rem steps, each chosen next to
     whatever sat above it. Near-identical sizes on unrelated elements are most of what
     makes a page look assembled rather than designed. */
  --fs-2xs: 0.6875rem;  /* 11px  micro labels */
  --fs-xs: 0.75rem;     /* 12px  eyebrows, counts, tags */
  --fs-sm: 0.8125rem;   /* 13px  metadata, spec values */
  --fs-md: 0.875rem;    /* 14px  buttons, small body */
  --fs-base: 0.9375rem; /* 15px  body */
  --fs-lg: 1.0625rem;   /* 17px  lead paragraph */
  --fs-xl: 1.1875rem;   /* 19px  row titles, prices */
  --fs-2xl: 1.25rem;    /* 20px  card titles */
  --fs-3xl: 1.5rem;     /* 24px  section headings */
  --fs-4xl: 2rem;       /* 32px  major headings */
  --fs-5xl: 2.75rem;    /* 44px  h1 */

  /* Spacing. One scale, and every gap in the layout is a step on it.
     The stylesheet carried forty-seven distinct px values for padding, margin and gap alone,
     including 3, 5, 7, 9, 11, 14, 18, 22, 26 and 34px. Nothing sits between two steps,
     which is what makes a page feel assembled: two blocks that should sit apart by the same
     amount as every other such pair differ by a pixel for no reason, and the eye reads the
     inconsistency as noise even though it cannot say what is wrong.
     The scale is 4px-based with a 2px half-step for the optical adjustments a layout needs,
     and the steps stop at 96 because the two values past it are a scrollbar and a page
     height, not a gap. */
  --sp-1: 4px;    /* hairline separations, icon gaps */
  --sp-2: 8px;    /* inside a control, chip padding */
  --sp-3: 12px;   /* between a label and its value */
  --sp-4: 16px;   /* inside a card, between fields */
  --sp-5: 24px;   /* between blocks */
  --sp-6: 32px;   /* between sections */
  --sp-7: 48px;   /* page-level separation */
  --sp-8: 64px;   /* section padding on desktop */
  --sp-9: 96px;   /* the largest deliberate gap */
  --sp-half: 2px; /* optical nudge only */

  /* Radii. Two steps and a pill. The stylesheet also carried 3px, 4px, 6px, 9px and 10px,
     so four corners on the same card could disagree about how round they were. */
  --r: 8px;
  --r-sm: 6px;

  /* Motion. Duration and easing are tokens because a transition written inline picks its own
     curve each time, and a drawer that eases out over 220ms next to a button that snaps in
     140ms reads as two different products sharing a page. `fast` is for a state change on a
     control the pointer is still on; `base` for anything that moves a panel. */
  --dur-fast: 140ms;
  --dur-base: 200ms;
  --dur-panel: 220ms;
  --ease: cubic-bezier(0.2, 0, 0.2, 1);
  --maxw: 1140px;
  --measure: 68ch;
  /* Page gutter. One token, because the catalogue rail has to cancel exactly this padding to
     bleed to the edge on a phone, and a hardcoded -24px against an 18px gutter is what put a
     horizontal scrollbar on the smallest screens. */
  --gutter: 24px;
  /* Height of the sticky header. scroll-padding-top has to clear it, and it is written in two
     places, so it is named once next to the gutter rather than guessed twice. */
  --header-h: 60px;
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    --paper: #131417;
    --surface: #1a1c20;
    --surface-2: #212429;
    --ink: #eceae4;
    --ink-2: #c6c7c3;
    --muted: #92969f;
    --faint: #6f737c;
    --line: #2b2e34;
    --line-2: #3a3e45;
    --accent: #e2793c;
    --accent-deep: #f0a375;
    --accent-wash: #2a1d15;
    --pine: #74b9a6;
    --focus: #74b9a6;
  --shadow-pop: 0 1px 2px rgba(0, 0, 0, .30), 0 6px 16px rgba(0, 0, 0, .35);
  --shadow-modal: 0 1px 2px rgba(0, 0, 0, .30), 0 12px 32px rgba(0, 0, 0, .40);
    color-scheme: dark;
  }
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: var(--header-h); }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-base);
  color: var(--ink);
  background: var(--paper);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: "kern", "liga";
}
a { color: var(--accent-deep); text-decoration: none; }
a:hover { text-decoration: underline; }
code { font-family: var(--font-mono); font-size: var(--fs-sm); background: var(--surface-2); padding: 1px var(--sp-1); border-radius: 4px; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.14;
  letter-spacing: -0.015em;
  margin: 0 0 .4em;
  text-wrap: balance;
}
p { margin: 0 0 1em; }
.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); }
.muted { color: var(--muted); }
.small { font-size: var(--fs-md); }
.center { text-align: center; }
.hidden { display: none !important; }

/* Layout utilities. These were style="..." attributes on the pages, which put layout
   decisions in the markup where they cannot be changed in one place. */
.u-narrow { max-width: 720px; }
.u-form-col { flex-direction: column; }
.u-mt-12 { margin-top: var(--sp-3); }
.u-mt-14 { margin-top: var(--sp-4); }
.u-mt-30 { margin-top: var(--sp-8); }
.u-flush { margin: 0; }
.u-my-6 { margin-top: var(--sp-6); margin-bottom: var(--sp-6); }
.u-ml-2 { margin-left: var(--sp-2); }
.u-ink { color: var(--ink-2); }
.u-hero-tight { padding-top: var(--sp-8); }
/* A standalone link that behaves like a small call to action, as opposed to a link inside a
   sentence. Inline prose links are exempt from the target-size floor, because the text around
   them is what makes them findable; a link standing on its own is not. */
.u-target { display: inline-block; padding: var(--sp-2) 0; }
/* Footer navigation, in the compact legal strip as well as the full footer. */
.legal a { display: inline-block; padding: var(--sp-2) 0; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ---------------------------- buttons ---------------------------- */
/* Radius is small and consistent, weight does the work, and the
   only colour that fills is the one that means "act on this". */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-6); border-radius: var(--r-sm); border: 1px solid transparent;
  font: inherit; font-weight: 550; font-size: var(--fs-base); cursor: pointer;
  text-decoration: none; white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible, a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, summary:focus-visible {
  outline: 2px solid var(--focus); outline-offset: 2px; border-radius: var(--r-sm);
}
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-deep); text-decoration: none; }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line-2); }
.btn-ghost:hover { background: var(--surface); border-color: var(--ink-2); color: var(--ink); text-decoration: none; }
.btn-sm { padding: var(--sp-2) var(--sp-4); font-size: var(--fs-md); }
.btn-block { width: 100%; }
.btn[disabled] { opacity: .45; cursor: not-allowed; }

/* ---------------------------- header ---------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 60;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(12px) saturate(150%);
  border-bottom: 1px solid var(--line);
}
.site-header .wrap { display: flex; align-items: center; gap: var(--sp-5); height: 68px; }
.logo {
  display: inline-flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) 0;
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-xl);
  letter-spacing: -0.01em; color: var(--ink);
}
.logo:hover { text-decoration: none; }
.logo .mark { width: 26px; height: 26px; flex: none; display: block; border-radius: 6px; }
.nav { display: flex; gap: var(--sp-1); margin-left: auto; align-items: center; }
.nav a {
  color: var(--ink-2); font-weight: 500; font-size: var(--fs-base);
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm);
}
.nav a:hover { background: var(--surface); color: var(--ink); text-decoration: none; }
.cart-btn { position: relative; }
.cart-count {
  position: absolute; top: -6px; right: -6px; min-width: 18px; height: 18px; padding: 0 var(--sp-1);
  border-radius: 9px; background: var(--accent); color: #fff;
  font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: 700;
  display: grid; place-items: center; border: 2px solid var(--paper);
}
/* Small screens get a tighter nav, not a shorter one.
   This used to be `.nav .hide-sm { display: none }` under 760px, which removed "Method" and
   "Blog" from phones with nothing put in their place -- no menu button, no overflow, no
   substitute. Losing two of three primary destinations on the device most people read on is
   not a responsive decision. */
@media (max-width: 760px) {
  .nav a { font-size: var(--fs-sm); padding: var(--sp-2) var(--sp-2); }
}

/* Below 480 the header also has to fit a 320px viewport with the cart still reachable.
   Measured at 320px: logo 112 + nav 245 + cart 63 + 48 padding + gaps = 393, so the
   document scrolled to 393 and the cart button -- the primary conversion control -- sat
   outside a 320px screen with no way to reach it.

   Dropping the wordmark keeps the brand mark, which is what identifies the site at this
   width; the accessible name stays on the anchor, so the link is still announced in full.
   The nav padding tightens a further notch for the same reason. Neither is applied above
   480px, where there is room for the full lockup. */
@media (max-width: 480px) {
  /* Visually hidden, not display:none.
     Hiding the wordmark with `display: none` removed it from the accessibility tree and from
     the link's text, which left the logo link with no accessible name on exactly the widths
     the rule applied to -- the page audit caught it as two nameless links. The clip pattern
     takes the same space as nothing while keeping the name announced, and the anchor's own
     aria-label carries it regardless. */
  .logo .wordmark {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap;
  }
  .nav a { padding: var(--sp-2) var(--sp-1); }
}

/* ---------------------------- hero ---------------------------- */
.hero { padding: var(--sp-8) 0 var(--sp-8); }
.hero-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-8); align-items: start; }
@media (max-width: 940px) { .hero-grid { grid-template-columns: 1fr; gap: var(--sp-8); } }
/* Grid children need min-width:0 for the same reason .catalog-layout's do: a grid item is
   sized by its min-content width otherwise, so one long line in the copy column stretches the
   whole track. `.hero-copy` and `.catalog-main` carried no rule at all and existed only as
   names, which is what the stylesheet-coverage gate in test-site.js is for. */
.hero-grid > *, .catalog-layout > * { min-width: 0; }

.eyebrow {
  font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted); margin: 0 0 var(--sp-4);
}
/* 4.4vw of a 1440px screen is 63px, which in a half-width hero column wraps to four ragged
   lines and reads as a poster rather than a sentence. Sized to the column it sits in. */
.hero h1 { font-size: clamp(1.75rem, 3.2vw, var(--fs-5xl)); margin: 0 0 var(--sp-6); max-width: 17em; }
.hero h1 em { font-style: italic; color: var(--accent-deep); }
.hero .lede { font-size: var(--fs-lg); color: var(--ink-2); max-width: 46ch; margin-bottom: var(--sp-8); }
.hero-cta { display: flex; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-8); }

/* What the free button actually delivers, filled from the catalog by store.js. */
.hero-note {
  margin: -14px 0 0; font-size: var(--fs-sm); color: var(--muted); letter-spacing: .01em;
}
.hero-note:empty { display: none; }

/* The same idea on the free-pack page, as a row of chips.
   There was no rule for `.spec-line` at all, in this stylesheet or any earlier one, so its
   five spans rendered as one run-on line: "360 Q&A 20 topics Cheat sheet 5-day plan
   Watermarked PDF". The numbers and words collided and the list stopped being readable,
   which is the one job the line exists to do. The markup was always right; only the styling
   was missing, which is why no test caught it: the text is present either way. */
.spec-line {
  display: flex; flex-wrap: wrap; gap: var(--sp-2);
  font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-2);
}
.spec-line > span {
  padding: var(--sp-half) var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  white-space: nowrap;
}

/* Reassurance as a quiet list, not a row of badges. */
  /* One quiet line rather than three bulleted ones. This list sat directly under the
     spec line, so it also repeated what that line had already said; and as bullets it read
     as three separate claims competing with the buttons above them. */
  .hero-trust {
  list-style: none; margin: 0; padding: var(--sp-4) 0 0; border-top: 1px solid var(--line);
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-2);
  font-size: var(--fs-sm); color: var(--muted);
}
.hero-trust li { display: inline-flex; align-items: center; }
.hero-trust li:not(:last-child)::after { content: "\00b7"; margin-left: var(--sp-2); color: var(--faint); }

/* ---------------------------- the sample ---------------------------- */
/* The one piece of proof on the page: a real question from a real
   pack with the real answer. Presented as a document excerpt, so it
   reads as "this is what you are buying" and not as a testimonial. */
.sample {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: var(--sp-8) var(--sp-8) var(--sp-5);
}
.sample-kicker {
  font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: .1em;
  text-transform: uppercase; color: var(--faint); margin: 0 0 var(--sp-4);
}
.sample-cta {
  display: inline-flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-4); padding: var(--sp-2) 0;
  font-size: var(--fs-md); font-weight: 550;
}
.sample-cta::after { content: "\2192"; }

.excerpt { margin: 0; }
.excerpt-tag {
  display: inline-block; font-family: var(--font-mono); font-size: var(--fs-2xs);
  letter-spacing: .1em; text-transform: uppercase; color: var(--accent-deep);
  margin-bottom: var(--sp-3);
}
.excerpt blockquote { margin: 0; }
.excerpt-q {
  font-family: var(--font-display); font-size: var(--fs-xl); line-height: 1.34;
  font-weight: 600; margin: 0 0 var(--sp-4); color: var(--ink);
}
.excerpt-a {
  font-size: var(--fs-base); line-height: 1.62; color: var(--ink-2);
  margin: 0; white-space: pre-wrap;
  max-height: 15.5em; overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, #000 74%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 74%, transparent 100%);
}
/* Code inside a real answer, kept small enough that a short snippet does not
   become the whole panel. */
.excerpt-a code {
  font-family: var(--font-mono); font-size: .85em;
  background: var(--surface-2); padding: 1px var(--sp-1); border-radius: 3px;
}
.excerpt-code {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: var(--sp-2) var(--sp-3); margin: var(--sp-2) 0;
  overflow-x: auto; white-space: pre;
}
.excerpt-code code { background: none; padding: 0; font-size: var(--fs-sm); color: var(--ink-2); }
.excerpt figcaption {
  display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap;
  margin-top: var(--sp-4); font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--faint);
}
.excerpt-level {
  border: 1px solid var(--line-2); border-radius: 4px; padding: 1px var(--sp-2); color: var(--muted);
}

/* ---------------------------- spec row ---------------------------- */
/* Replaces the old strip of catalogue totals. These are facts about
   what a buyer receives, not totals about the seller. */
.specs { border-block: 1px solid var(--line); background: var(--surface); }
.specs-row {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px;
  background: var(--line); margin: 0;
}
.specs-row > div { background: var(--surface); padding: var(--sp-8) var(--sp-5); }
.specs-row dt {
  font-family: var(--font-display); font-size: var(--fs-3xl); font-weight: 600;
  letter-spacing: -.02em; line-height: 1.1; margin-bottom: var(--sp-1);
}
.specs-row dd { margin: 0; font-size: var(--fs-md); color: var(--muted); }
@media (max-width: 760px) {
  .specs-row { grid-template-columns: repeat(2, 1fr); }
  .specs-row > div { padding: var(--sp-4) var(--sp-4); }
  .specs-row dt { font-size: var(--fs-2xl); }
}

/* ---------------------------- catalogue ---------------------------- */
.catalog { padding: var(--sp-8) 0 var(--sp-5); }
.section-head { max-width: 52ch; margin-bottom: var(--sp-8); }
.section-head .kicker {
  font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: .1em;
  text-transform: uppercase; color: var(--faint); display: block; margin-bottom: var(--sp-2);
}
.section-head h2 { font-size: clamp(1.5rem, 2.4vw, var(--fs-4xl)); margin: 0 0 var(--sp-2); }
.section-head p { color: var(--muted); font-size: var(--fs-base); max-width: 48ch; margin: 0; }

/* Rail on the left, results on the right. The rail is sticky so the
   categories stay reachable while reading a long list. */
.catalog-layout { display: grid; grid-template-columns: 210px 1fr; gap: var(--sp-8); align-items: start; }
/* Children need min-width:0 for the same reason the hero's do: without it a grid item is
     sized by its min-content width and one wide row stretches the whole column, which on a
     phone means the single column is as wide as the widest pack row. */
@media (max-width: 900px) { .catalog-layout { grid-template-columns: 1fr; gap: var(--sp-6); } }

/* min-width:0 is load-bearing. A grid item defaults to min-width:auto, so the rail sized
   itself to its widest label and the page grew a horizontal scrollbar instead of the rail
   scrolling inside it. */
.rail { position: sticky; top: 84px; min-width: 0; }
@media (max-width: 900px) { .rail { position: static; } }
.rail-item {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2);
  width: 100%; padding: var(--sp-2) var(--sp-3); border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--ink-2); font: inherit; font-size: var(--fs-md);
  cursor: pointer; text-align: left;
  border-left: 2px solid transparent;
}
.rail-item:hover { background: var(--surface); color: var(--ink); }
.rail-item[aria-pressed="true"] {
  color: var(--ink); font-weight: 550; background: var(--surface);
  border-left-color: var(--accent);
}
.rail-count { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--faint); }
.rail-item[aria-pressed="true"] .rail-count { color: var(--accent-deep); }

/* On a phone the rail becomes one scrolling line rather than eleven stacked rows pushing
   the first result off the screen. It scrolls inside the content width rather than bleeding
   to the page edge: a negative margin here made the rail wider than its grid column, and
   because a grid item does not clip, the overflow landed on the whole document. */
@media (max-width: 900px) {
  #catalog-rail {
    display: flex; gap: var(--sp-2); overflow-x: auto; scroll-snap-type: x proximity;
    padding-bottom: var(--sp-2); scrollbar-width: none;
  }
  #catalog-rail::-webkit-scrollbar { display: none; }
  .rail-item {
    width: auto; flex: none; scroll-snap-align: start;
    border: 1px solid var(--line); white-space: nowrap;
  }
  .rail-item[aria-pressed="true"] { border-color: var(--accent); }
}

.catalog-bar { display: flex; gap: var(--sp-3); align-items: center; margin-bottom: var(--sp-3); }
.search { flex: 1; min-width: 0; }
input[type="email"], input[type="text"], input[type="search"] {
  width: 100%; padding: var(--sp-3) var(--sp-4); border: 1px solid var(--line-2); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink); font: inherit; font-size: var(--fs-base);
}
input::placeholder { color: var(--faint); }
input:focus { outline: none; border-color: var(--focus); box-shadow: 0 0 0 3px color-mix(in srgb, var(--focus) 16%, transparent); }
.sortbox select {
  font: inherit; font-size: var(--fs-md); color: var(--ink-2); background: var(--surface);
  border: 1px solid var(--line-2); border-radius: var(--r-sm); padding: var(--sp-3) var(--sp-3); cursor: pointer;
}
.sortbox select:hover { border-color: var(--ink-2); color: var(--ink); }

.result-line {
  font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--muted);
  margin: 0 0 var(--sp-2); padding-bottom: var(--sp-3); border-bottom: 1px solid var(--line);
}

.cat-title {
  font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: .08em;
  text-transform: uppercase; color: var(--faint); font-weight: 500;
  margin: var(--sp-8) 0 var(--sp-2);
}
.cat-title:first-child { margin-top: var(--sp-4); }

/* ---------------------------- pack rows ---------------------------- */
/* A catalogue row, not a card. Hairline-separated, numbers in
   aligned columns, price and action on one steady right edge. */
.prows { border-top: 1px solid var(--line); }
.prow {
  display: grid;
  /* Fixed tracks, and .prow-head below uses the identical ones. Sized to `auto` instead,
     the header's empty trailing cell collapsed to zero, the flexible column swallowed the
     slack, and every column name landed 223px to the right of the numbers it labels. */
grid-template-columns: minmax(0, 1fr) 5rem 224px;
  gap: var(--sp-2) var(--sp-5);
  align-items: center;
  padding: var(--sp-6) var(--sp-1);
  border-bottom: 1px solid var(--line);
}
.prow:hover { background: var(--surface); }
.prow-main { min-width: 0; }
.prow-title { margin: 0 0 var(--sp-1); }
.prow-title button {
  display: block; padding: var(--sp-2) 0; border: 0; background: none;
  font-family: var(--font-display); font-size: var(--fs-xl); font-weight: 600;
  letter-spacing: -.01em; color: var(--ink); text-align: left; cursor: pointer;
}
.prow-title button:hover { color: var(--accent-deep); text-decoration: underline; text-underline-offset: 3px; }
.prow-blurb {
  margin: 0; color: var(--ink-2); font-size: var(--fs-md); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* Fixed tracks, and .prow-head below uses the identical ones. Sized to `auto` instead,
   the header's empty trailing cell collapsed to zero, the flexible column swallowed the
   slack, and every column name landed 223px to the right of the numbers it labels.
   The tracks are then as narrow as the widest thing in them: a header word or a value.
   Generous tracks here are paid for out of the title column, which is the one thing on
   the row a buyer actually reads. */
/* One column now, so the track is sized to the widest value it holds. Page counts run to
   three digits, and the column was previously 4rem plus a 7rem track for a value that
   renders in about half of that. */
.prow-specs {
display: grid; grid-template-columns: 5rem; gap: 0; margin: 0;
font-family: var(--font-mono); font-size: var(--fs-xs);
}
.prow-specs > div { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
/* A row, not a column: the number and its unit sit on one baseline with a real gap between
   them. As inline content they ran together and read "315pages". */
.prow-specs dd {
margin: 0; color: var(--ink-2); font-size: var(--fs-sm);
display: flex; align-items: baseline; gap: var(--sp-1);
}
.prow-unit { color: var(--ink-3); font-size: var(--fs-xs); }

/* Present to a screen reader, absent from the page. Each row keeps its own "Questions"
   term so the value is never announced as a bare number. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* The single row of column names, built on the same grid as a pack row so the labels sit
   over their columns. Hidden on a phone, where the rows stack and the labels would not. */
.prow-head {
  display: grid; grid-template-columns: minmax(0, 1fr) 276px 224px; gap: var(--sp-2) var(--sp-5);
  align-items: end; padding: 0 var(--sp-1) var(--sp-2);
}
.prow-head i {
  font-style: normal; font-family: var(--font-mono); font-size: var(--fs-2xs);
  letter-spacing: .05em; text-transform: uppercase; color: var(--faint);
}

/* Two tags, as words. Forty-seven bordered pills on one screen buried the titles. */
.prow-tags {
  margin: var(--sp-2) 0 0; font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--faint);
}

.prow-buy { display: flex; align-items: center; gap: var(--sp-2); }
.prow-price {
  font-family: var(--font-display); font-size: var(--fs-xl); font-weight: 600;
  min-width: 3.2ch; text-align: right; font-variant-numeric: tabular-nums;
}
.prow-note {
  grid-column: 1 / -1; margin: 0; font-size: var(--fs-sm); color: var(--muted);
}

@media (max-width: 860px) {
  /* Stacked, not side by side. Specs and buttons shared a line and their combined width
     became the page's minimum, which is how a 390px screen ended up scrolling sideways. */
  .prow { grid-template-columns: 1fr; gap: var(--sp-3); padding: var(--sp-6) var(--sp-half); }
  .prow-main, .prow-specs, .prow-buy, .prow-note { grid-column: 1; }
  /* Stacked rows have no columns to head, so the header row goes with them. */
  .prow-head { display: none; }
  .prow-specs { grid-template-columns: repeat(3, auto); gap: 0 var(--sp-6); }
  .prow-buy { justify-content: flex-start; }
  .prow-price { margin-right: var(--sp-2); }
}

.empty { padding: var(--sp-8) var(--sp-2); text-align: center; }
.empty p { color: var(--muted); }

/* ---------------------------- trust line ---------------------------- */
/* Checkable statements only. The refund wording has to match
   refunds.html exactly; sales are final once a link is issued. */
.trust-line {
  list-style: none; display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-6);
  margin: var(--sp-4) 0 0; padding-top: var(--sp-4); border-top: 1px solid var(--line);
  font-size: var(--fs-sm); color: var(--muted);
}
.trust-line li { display: flex; align-items: center; gap: var(--sp-2); }
/* A small filled dot. This was a hollow circle, which at this size and in this context read
   as an unselected radio button -- implying the three claims were options to choose between.
   They are statements about the order, not choices. */
.trust-line li::before {
  content: ""; width: 5px; height: 5px; border-radius: 50%;
  background: var(--line-2); flex: none;
}

/* The one interactive item in this list is the link to the refund policy, and it sits in
   the path between choosing a pack and paying for it. As inline text its box was exactly
   the text's: 219x21px, which is under the WCAG 2.2 minimum target of 24x24 and a long
   way under the 44px a thumb needs. A buyer trying to reach the refund policy from the
   cart was aiming at a target the height of a line of text.
   inline-block plus vertical padding grows the hit area without adding a visible border
   or changing the rhythm of the line, so the reassurance still reads as a quiet aside.
   Coarse pointers get the full comfortable target, because that is where 21px is actually
   hard to hit and a mouse user loses nothing by the extra pixels. */
.trust-line a { display: inline-block; padding: 3px 0; min-height: 24px; }
@media (pointer: coarse) {
  .trust-line a { min-height: 44px; }
}

/* ---------------------------- free card ---------------------------- */
/* Kept for free-pack.html and thanks.html. The spine is the one
   place a block of colour is allowed, because it is a book. */
.free-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 4px 10px 10px 4px;
  padding: var(--sp-8) var(--sp-8) var(--sp-5); position: relative; max-width: 460px;
}
.free-card::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 8px;
  background: var(--pine); border-radius: 4px 0 0 4px;
}
.free-card .badge {
  display: inline-block; font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: 600;
  letter-spacing: .09em; text-transform: uppercase; color: var(--pine);
  border: 1px solid color-mix(in srgb, var(--pine) 35%, transparent);
  border-radius: 4px; padding: var(--sp-1) var(--sp-2); margin-bottom: var(--sp-4);
}
.free-card h2, .free-card h3 { font-size: var(--fs-3xl); margin-bottom: var(--sp-2); }
.free-card .deck { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--muted); margin: 0 0 var(--sp-4); }
.free-card ul { margin: 0 0 var(--sp-4); padding-left: var(--sp-4); color: var(--ink-2); font-size: var(--fs-base); }
.free-card li { margin: var(--sp-1) 0; }
.inline-form { display: flex; gap: var(--sp-2); }
.inline-form input { flex: 1; min-width: 0; }
.form-note { font-size: var(--fs-xs); color: var(--muted); margin-top: var(--sp-2); }

/* ---------------------------- sections ---------------------------- */
.section { padding: var(--sp-8) 0; }
.section.alt { background: var(--surface); border-block: 1px solid var(--line); }

.method { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
@media (max-width: 800px) { .method { grid-template-columns: 1fr; } }
.method-item { background: var(--surface); padding: var(--sp-6) var(--sp-5); }
.method-item .k { font-family: var(--font-mono); font-size: var(--fs-2xs); letter-spacing: .08em; text-transform: uppercase; color: var(--faint); margin-bottom: var(--sp-2); }
.method-item h3 { font-size: var(--fs-lg); margin: 0 0 var(--sp-2); }
.method-item p { margin: 0; color: var(--ink-2); font-size: var(--fs-base); }

.faq { max-width: var(--measure); }
.faq details { border-bottom: 1px solid var(--line); padding: var(--sp-4) var(--sp-half); }
.faq summary { cursor: pointer; font-weight: 550; font-size: var(--fs-base); list-style: none; display: flex; justify-content: space-between; gap: var(--sp-4); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; color: var(--faint); font-family: var(--font-mono); }
.faq details[open] summary::after { content: "\2212"; }
.faq details p { margin: var(--sp-2) 0 0; color: var(--ink-2); font-size: var(--fs-base); max-width: var(--measure); }

/* ---------------------------- footer ---------------------------- */
.site-footer { border-top: 1px solid var(--line); padding: var(--sp-8) 0 var(--sp-6); margin-top: var(--sp-8); }
.footer-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: var(--sp-6); }
@media (max-width: 800px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
/* Column titles are h2 so the footer does not skip a level after the last h3 of the page.
   They are styled small on purpose: they label a list, they do not start a section. */
.site-footer h2 {
  font-family: var(--font-mono); font-size: var(--fs-2xs); font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--faint); margin: 0 0 var(--sp-3);
}
.site-footer ul { list-style: none; padding: 0; margin: 0; }
.site-footer li { margin: var(--sp-1) 0; }
/* Footer links are text, but they are still targets. Padding keeps each one at least
   32px tall without turning the footer into a stack of bars. */
.site-footer a { display: inline-block; padding: var(--sp-2) 0; color: var(--ink-2); font-size: var(--fs-base); }
.legal {
  margin-top: var(--sp-8); padding-top: var(--sp-4); border-top: 1px solid var(--line);
  color: var(--faint); font-size: var(--fs-sm); display: flex; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
}

/* ---------------------------- drawer ---------------------------- */
.overlay { position: fixed; inset: 0; background: rgba(20, 21, 24, .42); z-index: 80; opacity: 0; visibility: hidden; transition: opacity var(--dur-base) var(--ease); }
.overlay.open { opacity: 1; visibility: visible; }
.drawer {
  position: fixed; top: 0; right: 0; height: 100%; width: min(430px, 100vw); z-index: 90;
  background: var(--paper); border-left: 1px solid var(--line);
  box-shadow: var(--shadow-modal);
  transform: translateX(100%); transition: transform var(--dur-panel) var(--ease);
  display: flex; flex-direction: column;
}
.drawer.open { transform: none; }
.drawer-head { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-4) var(--sp-5); border-bottom: 1px solid var(--line); }
.drawer-head h3 { margin: 0; font-size: var(--fs-lg); }
.icon-btn { background: none; border: none; font-size: var(--fs-3xl); cursor: pointer; color: var(--muted); line-height: 1; padding: var(--sp-2) var(--sp-3); min-width: 36px; min-height: 36px; border-radius: var(--r-sm); }
.icon-btn:hover { background: var(--surface); color: var(--ink); }
.drawer-body { flex: 1; overflow-y: auto; padding: var(--sp-2) var(--sp-5); }
.drawer-foot { padding: var(--sp-4) var(--sp-5); border-top: 1px solid var(--line); background: var(--surface); }
.cart-line { display: flex; gap: var(--sp-4); padding: var(--sp-4) 0; border-bottom: 1px solid var(--line); }
.cart-line .info { flex: 1; min-width: 0; }
.cart-line .info h4 { margin: 0 0 var(--sp-1); font-size: var(--fs-base); font-weight: 550; }
.cart-line .info .m {
  color: var(--muted); font-size: var(--fs-sm);
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
}
.cart-line .unit { font-variant-numeric: tabular-nums; }

/* Quantity stepper.
   It sits inline with the price rather than on its own row so a two-item cart stays compact
   enough that the drawer does not open onto mostly empty space. */
.cart-line .qty { display: inline-flex; align-items: center; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); }
.cart-line .qty-btn {
  width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;
  background: none; border: none; cursor: pointer; color: var(--ink);
  font-size: var(--fs-base); line-height: 1; padding: 0; border-radius: var(--r-sm);
}
.cart-line .qty-btn:hover:not([disabled]) { background: var(--line); }
.cart-line .qty-btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
/* Disabled rather than hidden at the bounds. A control that disappears at the limit tells the
   buyer nothing; a greyed-out one tells them they have reached it. */
.cart-line .qty-btn[disabled] { color: var(--muted); opacity: .45; cursor: not-allowed; }
.cart-line .qty-n {
  min-width: 26px; text-align: center; font-variant-numeric: tabular-nums;
  font-weight: 600; font-size: var(--fs-sm); color: var(--ink);
}

/* Remove is a control, not a caption. It used to be a bare underlined word tucked against the
   price, where it read as more price copy than as something to click. */
.cart-line .rm {
  background: none; border: 1px solid transparent; border-radius: var(--r-sm);
  color: var(--muted); cursor: pointer; font: inherit; font-size: var(--fs-sm);
  padding: 3px var(--sp-2); margin: 0;
}
.cart-line .rm:hover { color: var(--accent-deep); border-color: var(--line); }
.cart-line .rm:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }

.cart-line .p { font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums; }
.subtotal { display: flex; justify-content: space-between; font-family: var(--font-display); font-size: var(--fs-xl); font-weight: 600; margin-bottom: var(--sp-4); }
.cart-flag { display: block; font-size: var(--fs-xs); color: var(--muted); margin-top: var(--sp-half); }

/* ---------------------------- modal ---------------------------- */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--ink); color: var(--paper);
  padding: var(--sp-3) var(--sp-4); border-radius: 0 0 var(--r-sm) 0;
  font-size: var(--fs-base); text-decoration: none;
}
.skip-link:focus { left: 0; }

.modal { position: fixed; inset: 0; z-index: 95; display: grid; place-items: center; padding: var(--sp-6); opacity: 0; visibility: hidden; transition: opacity var(--dur-base) var(--ease); }
.modal.open { opacity: 1; visibility: visible; }
.modal-card {
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--r);
  width: min(720px, 100%); max-height: 88vh; overflow-y: auto; box-shadow: var(--shadow-modal);
}
.modal-head { padding: var(--sp-6) var(--sp-8); border-bottom: 1px solid var(--line); display: flex; justify-content: space-between; gap: var(--sp-3); align-items: flex-start; }
.modal-head h3 { margin: 0 0 var(--sp-1); font-size: var(--fs-3xl); }
.modal-head .meta { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--muted); }
.modal-body { padding: var(--sp-6) var(--sp-8); }
.modal-body h4 { font-family: var(--font-mono); font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: .08em; color: var(--faint); margin: var(--sp-6) 0 var(--sp-2); }
.modal-body ul { padding-left: var(--sp-4); color: var(--ink-2); font-size: var(--fs-base); }
.modal-lede { font-size: var(--fs-base); color: var(--ink-2); margin: 0 0 var(--sp-4); }
.modal-facts { list-style: none; display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--line); margin: var(--sp-6) 0 0; padding: 0; border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.modal-facts li { display: flex; flex-direction: column; background: var(--surface); padding: var(--sp-3) var(--sp-4); }
.modal-facts .k { font-family: var(--font-display); font-size: var(--fs-xl); font-weight: 600; line-height: 1.1; }
.modal-facts .v { font-size: var(--fs-xs); color: var(--muted); margin-top: var(--sp-half); }
@media (max-width: 640px) { .modal-facts { grid-template-columns: repeat(2, 1fr); } }
.modal-foot { padding: var(--sp-4) var(--sp-8); border-top: 1px solid var(--line); display: flex; gap: var(--sp-2); justify-content: flex-end; background: var(--surface); }
.pack-facts { margin: 0 0 var(--sp-1); }

/* ---------------------------- toast ---------------------------- */
.toast {
  position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 14px); z-index: 100;
  background: var(--ink); color: var(--paper); padding: var(--sp-3) var(--sp-6); border-radius: var(--r-sm);
  font-size: var(--fs-md); opacity: 0; visibility: hidden; transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease); box-shadow: var(--shadow-pop);
}
.toast.show { opacity: 1; visibility: visible; transform: translate(-50%, 0); }

/* ---------------------------- prose / blog ---------------------------- */
.prose { max-width: 70ch; }
.prose h1 { font-size: clamp(1.5rem, 2.8vw, var(--fs-4xl)); }
.prose h2 { margin-top: 1.8em; font-size: var(--fs-3xl); }
.prose h3 { margin-top: 1.5em; font-size: var(--fs-lg); }
.prose p, .prose li { color: var(--ink-2); }
.prose pre { background: #17181b; color: #dcdee2; padding: var(--sp-4) var(--sp-4); border-radius: var(--r-sm); overflow-x: auto; font-size: var(--fs-md); }
.prose pre code { background: none; padding: 0; color: inherit; }
.prose blockquote { border-left: 2px solid var(--accent); margin: 1.4em 0; padding: var(--sp-half) 0 var(--sp-half) var(--sp-4); color: var(--muted); font-style: italic; font-family: var(--font-display); font-size: var(--fs-lg); }
.prose table { width: 100%; border-collapse: collapse; margin: 1.4em 0; font-size: var(--fs-base); }
.prose th, .prose td { border: 1px solid var(--line); padding: var(--sp-2) var(--sp-3); text-align: left; }
.prose th { background: var(--surface); font-family: var(--font-mono); font-size: var(--fs-xs); font-weight: 600; }
.post-list { display: grid; gap: 0; border-top: 1px solid var(--line); }
.post-item { border-bottom: 1px solid var(--line); padding: var(--sp-6) var(--sp-half); display: block; }
.post-item h2, .post-item h3 { margin: 0 0 var(--sp-2); font-size: var(--fs-xl); }
.post-item .meta { color: var(--faint); font-size: var(--fs-xs); margin-bottom: var(--sp-2); font-family: var(--font-mono); }
.post-item:hover { text-decoration: none; }
.post-item:hover h2, .post-item:hover h3 { color: var(--accent-deep); }

/* ---------------------------- misc ---------------------------- */
.banner { background: var(--pine); color: #f4fbf8; text-align: center; padding: var(--sp-2) var(--sp-4); font-size: var(--fs-md); }
.banner a { color: #fff; text-decoration: underline; }
.kv { width: 100%; border-collapse: collapse; font-size: var(--fs-md); }
.kv th, .kv td { text-align: left; padding: var(--sp-2) var(--sp-2); border-bottom: 1px solid var(--line); }
.kv th { color: var(--muted); font-weight: 550; }

/* ---------------------------- phone ---------------------------- */
@media (max-width: 760px) {
  html { scroll-padding-top: var(--header-h); }
  --gutter: 18px;
  .wrap { padding: 0 var(--gutter); }
  .site-header .wrap { height: var(--header-h); gap: var(--sp-3); }
  .hero { padding: var(--sp-8) 0 var(--sp-6); }
  .hero h1 { font-size: clamp(1.75rem, 7.6vw, var(--fs-4xl)); margin-bottom: var(--sp-4); }
  .hero .lede { font-size: var(--fs-base); line-height: 1.55; margin-bottom: var(--sp-6); }
  .eyebrow { font-size: var(--fs-2xs); margin-bottom: var(--sp-3); }
  .hero-cta { gap: var(--sp-2); margin-bottom: var(--sp-6); }
  .hero-cta .btn { flex: 1 1 auto; padding: var(--sp-3) var(--sp-4); }
  .hero-trust { padding-top: var(--sp-4); gap: var(--sp-2); }
  .sample { padding: var(--sp-6) var(--sp-4); }
  .excerpt-q { font-size: var(--fs-lg); }
  .excerpt-a { font-size: var(--fs-md); max-height: 12em; }
  .catalog { padding: var(--sp-8) 0 var(--sp-6); }
  .section { padding: var(--sp-8) 0; }
  .catalog-bar { flex-direction: column; align-items: stretch; }
  .sortbox select { width: 100%; }
  .free-card { padding: var(--sp-6) var(--sp-6) var(--sp-6); }
  .modal-head, .modal-body, .modal-foot { padding-inline: var(--sp-4); }
  .modal-foot { flex-direction: column-reverse; }
  .modal-foot .btn { width: 100%; }
  .prow-blurb { -webkit-line-clamp: 3; }
}

/* Motion is decoration. Someone who has asked their operating system to reduce motion
   should still be able to open the cart drawer and read the pack details, which is the
   whole purchase flow, so the panels drop their transitions rather than their function.
   Without this the drawer slides in for everyone, and it is the single largest movement on
   the page. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  /* The drawer and the dialog hide themselves with visibility, which is not animated, so
     nothing else is needed to keep them functional. */
}
