/* ==========================================================================
   Grindstone Prep - site stylesheet
   Direction: Whetstone. The contract is app/docs/DESIGN-SYSTEM.md; every
   colour, radius and type step below is taken from it rather than invented.

   Hand-written. One file. No framework, no build step, no third-party CSS,
   and no request to any host but this one. The three faces are open-license
   and are served from ./fonts/ on this origin, so loading a page here tells
   nobody but us that you were here.
   ========================================================================== */

/* --- 1. Faces ------------------------------------------------------------ */

/* Archivo, weight 900, latin subset. SIL Open Font License 1.1.
   Display type only: headings, the brand mark, prices. */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url(fonts/archivo-900.woff2) format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 100 700;
  font-display: swap;
  src: url(fonts/ibm-plex-sans-var.woff2) format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: italic;
  font-weight: 100 700;
  font-display: swap;
  src: url(fonts/ibm-plex-sans-italic-var.woff2) format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(fonts/ibm-plex-mono-400.woff2) format('woff2');
}

/* --- 2. Tokens ------------------------------------------------------------
   DESIGN-SYSTEM.md section 1. This is the ONLY block in this file that is
   allowed to hold a literal colour value; the test suite checks that. Adding
   a colour here without adding it to the spec first is a spec violation even
   if it looks fine. */

:root {
  /* ground and surfaces */
  --bg:        #EDEEEF;   /* cool concrete. The page ground. Not a warm cream. */
  --surface:   #FFFFFF;   /* cards, tables, anything lifted off the ground */
  --ink:       #101418;   /* body and headings */
  --muted:     #525C66;   /* secondary text, labels, metadata */
  --line:      #D3D7DA;   /* rules, borders, dividers */

  /* accents */
  --spark:     #C8461A;   /* THE accent. Restraint rule, section 4 of the spec. */
  --spark-ink: #FFF6F2;   /* text on spark */
  --steel:     #3E5568;   /* links in body copy, citation links */
  --ok:        #256B4B;   /* correct answers, passing states, success only */

  /* form */
  --radius:    0;                             /* square. Deliberate. */
  --lift:      0 2px 0 rgba(16, 20, 24, .08); /* the only shadow in the system */

  /* faces */
  --display: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --sans:    'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --mono:    'IBM Plex Mono', ui-monospace, SFMono-Regular, 'Cascadia Mono', Consolas, monospace;

  /* measure and rhythm */
  --column:  66rem;   /* the content column */
  --measure: 38rem;   /* running text caps near 65 characters */
  --gutter:  1.5rem;
}

/* --- 3. Reset, only what is needed --------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.55;
  font-feature-settings: 'kern' 1, 'liga' 1;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

img, svg { max-width: 100%; height: auto; }

/* --- 4. The column ------------------------------------------------------- */

.column {
  max-width: var(--column);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
/* Kept as an alias so older markup that says column--wide still lands in the
   same place. There is one column width in this system. */
.column--wide { max-width: var(--column); }

/* Running prose inside the wide column is capped separately, because a 66rem
   line of body copy is unreadable however good the type is. */
.measure { max-width: var(--measure); }

/* --- 5. Type ------------------------------------------------------------- */

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 900;
  letter-spacing: -0.038em;
  line-height: 1.12;
  margin: 0 0 0.5em;
  text-wrap: balance;
}

/* Display L. One per page, the hero heading only. */
h1 { font-size: clamp(2rem, 4.6vw, 3.15rem); line-height: 1.04; }
/* Display M. Section headings. */
h2 { font-size: 1.5rem; }
/* Display S. Card titles and sub-headings. */
h3 { font-size: 1.08rem; }
/* Below Display S the display face is too heavy; h4 drops to the body face. */
h4 {
  font-family: var(--sans);
  font-weight: 600;
  font-size: 1rem;
  letter-spacing: 0;
}

p { margin: 0 0 1.05em; }
p:last-child { margin-bottom: 0; }

.lede {
  font-size: 1.05rem;
  line-height: 1.5;
  color: var(--muted);
}

.small {
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--muted);
}

strong, b { font-weight: 600; }

code, kbd, samp, .mono {
  font-family: var(--mono);
  font-size: 0.9em;
  font-variant-ligatures: none;
}

a {
  color: var(--steel);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}
a:hover { color: var(--ink); }
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--spark);
  outline-offset: 2px;
}

hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 2.6rem 0;
}

/* Micro: mono, letterspaced, uppercase. Eyebrows, labels, pills. */
.eyebrow, .micro {
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 0.85rem;
}
/* Spark as text is spent on the section eyebrow, at most one per section. */
.eyebrow--spark { color: var(--spark); }

/* --- 6. Masthead --------------------------------------------------------- */

.masthead {
  background: var(--bg);
  border-bottom: 1px solid var(--line);
  padding: 0.95rem 0;
}
.masthead__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1.6rem;
  justify-content: space-between;
}

/* Brand mark: GP in mono 600 on spark, 1.55rem square. The single rounded
   thing in the system - it reads as a stamped tool mark. It is identity, not
   accent, and is exempt from the restraint rule in section 4 of the spec. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--ink);
  text-decoration: none;
}
.brand__mark {
  display: inline-grid;
  place-items: center;
  width: 1.55rem;
  height: 1.55rem;
  border-radius: 3px;
  background: var(--spark);
  color: var(--spark-ink);
  font-family: var(--mono);
  font-weight: 600;
  font-size: 0.78rem;
  letter-spacing: 0;
}
.brand__name {
  font-family: var(--display);
  font-weight: 900;
  font-size: 1.02rem;
  letter-spacing: -0.038em;
}

.nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.15rem;
  font-size: 0.88rem;
}
.nav a {
  color: var(--muted);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
}
.nav a:hover { color: var(--ink); border-bottom-color: var(--line); }
.nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--ink); }

/* --- 7. Sections --------------------------------------------------------- */

main { display: block; }

.section {
  padding: 3rem 0;
  border-top: 1px solid var(--line);
}
/* The first section on a page sits under the masthead rule already. */
.section:first-child { border-top: 0; }

.section__head { margin-bottom: 1.6rem; max-width: var(--measure); }
.section__head h2 { margin-bottom: 0.45em; }
.section__head p:last-child { margin-bottom: 0; }

.stack {
  display: flex;
  flex-direction: column;
  gap: 1.05rem;
}

@media (max-width: 40rem) {
  .section { padding: 2.3rem 0; }
}

/* --- 8. Hero ------------------------------------------------------------- */

.hero {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 2.4rem;
  align-items: start;
  padding: 3.4rem 0 3rem;
}
@media (max-width: 62rem) {
  .hero { grid-template-columns: minmax(0, 1fr); gap: 2rem; padding: 2.6rem 0 2.3rem; }
}
.hero__copy { display: flex; flex-direction: column; gap: 1.1rem; }
.hero__copy h1 { margin: 0; }
.hero__copy .lede { margin: 0; max-width: 30rem; }   /* about 46 characters */

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem 0.8rem;
  align-items: center;
}

/* --- 9. Buttons ---------------------------------------------------------- */

/* .button is the primary: spark fill, spark-ink text, square. It is the one
   spark-filled element a section is allowed. The generated buy control on the
   home page emits this class name, so it stays. */
.button,
a.button,
button.button {
  display: inline-block;
  padding: 0.7rem 1.25rem;
  font-family: var(--sans);
  font-size: 0.94rem;
  font-weight: 600;
  line-height: 1.2;
  border: 1px solid var(--spark);
  border-radius: var(--radius);
  background: var(--spark);
  color: var(--spark-ink);
  text-decoration: none;
  cursor: pointer;
}
a.button:hover,
button.button:not([disabled]):hover {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--spark-ink);
}

.button--ghost,
a.button--ghost,
button.button--ghost {
  background: transparent;
  border-color: var(--line);
  color: var(--ink);
}
a.button--ghost:hover,
button.button--ghost:not([disabled]):hover {
  background: transparent;
  border-color: var(--spark);
  color: var(--spark);
}

/* Inert: the buy control before a store exists. Never spark - a disabled
   control must not spend the page's one accent. */
button.button[disabled] {
  background: transparent;
  border-color: var(--line);
  color: var(--muted);
  cursor: not-allowed;
}

.button--note {
  display: block;
  margin-top: 0.7rem;
  font-size: 0.84rem;
  color: var(--muted);
  max-width: var(--measure);
}

/* --- 10. Proof table ----------------------------------------------------- */

.proof {
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--lift);
}
.proof__list { margin: 0; }
.proof__title {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0.7rem 1rem;
  border-bottom: 1px solid var(--line);
  margin: 0;
}
.proof__list div {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1rem;
  justify-content: space-between;
  align-items: baseline;
  padding: 0.62rem 1rem;
  border-bottom: 1px solid var(--line);
}
.proof__list div:last-child { border-bottom: 0; }
.proof__list dt { font-size: 0.86rem; color: var(--muted); }
.proof__list dd {
  margin: 0;
  font-family: var(--mono);
  font-size: 0.86rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* --- 11. Product cards --------------------------------------------------- */

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 1.1rem;
}

.card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--lift);
}
.card--buyable { border-color: var(--spark); }
.card__body { padding: 1.1rem 1.15rem 1.2rem; flex: 1 1 auto; }
.card__code {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 0.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.7rem;
  align-items: center;
  justify-content: space-between;
}
.card__title { margin: 0 0 0.55rem; font-size: 1.08rem; }
.card__meta {
  font-size: 0.82rem;
  color: var(--muted);
  margin: 0 0 0.6rem;
}
.card__meta span + span::before { content: " \00B7 "; }
.card p { font-size: 0.9rem; }
.card__foot {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1rem;
  align-items: center;
  justify-content: space-between;
  padding: 0.85rem 1.15rem;
  border-top: 1px solid var(--line);
}
.card__price {
  font-family: var(--display);
  font-weight: 900;
  font-size: 1.08rem;
  letter-spacing: -0.038em;
  font-variant-numeric: tabular-nums;
}
.card__price small {
  font-family: var(--sans);
  font-weight: 400;
  font-size: 0.78rem;
  letter-spacing: 0;
  color: var(--muted);
  margin-left: 0.35rem;
}
.card__action { font-size: 0.88rem; margin-left: auto; }

/* What is inside a bundle, named on the card itself. A buyer comparing one exam
   against a bundle price has to be able to see what the bundle contains without
   scrolling to a detail block, so the list is part of the card. */
.card__list {
  list-style: none;
  margin: 0.15rem 0 0;
  padding: 0;
  font-size: 0.86rem;
  color: var(--muted);
}
.card__list li { margin: 0.2rem 0; padding-left: 0.95rem; position: relative; }
.card__list li::before {
  content: "4";
  position: absolute;
  left: 0;
  color: var(--line);
}

/* A pre-purchase disclosure on a catalogue card: the short form of the .callout
   block used on the detail pages, same flat left rule, no tint and no icon. It
   is the last thing above the card's action, because someone buying straight
   off the catalogue never scrolls to the detail block. Selector is doubled
   (.card .card__notice) to out-specify `.card p`, not with !important -- the
   style spec forbids that escape hatch. */
.card .card__notice {
  border-left: 3px solid var(--ink);
  padding-left: 0.75rem;
  margin: 0.85rem 0 0;
  font-size: 0.84rem;
  line-height: 1.5;
  color: var(--muted);
}

/* Pills. Available is spark-filled; Coming soon is an outline. The two must
   never be mistakable for each other at a glance. */
.pill {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: 0.16rem 0.5rem;
  border: 1px solid var(--line);
  color: var(--muted);
  white-space: nowrap;
}
.pill--live {
  background: var(--spark);
  border-color: var(--spark);
  color: var(--spark-ink);
}

/* --- 11b. Home exam picker ----------------------------------------------
   P-018 Concept D (CEO-approved 2026-10-14). One select over one product panel;
   app/site-src/catalog.js shows only the chosen panel. With JavaScript off the
   select stays hidden and every panel shows, stacked, so nothing is lost.
   The side list is desktop-only (900px and up): on a phone the select opens
   the phone's own picker, which already lists every exam. */

.pick { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.1rem 2rem; }
@media (min-width: 56.25rem) {
  .pick { grid-template-columns: minmax(0, 36rem) minmax(0, 1fr); align-items: start; }
}
[data-pick] [hidden] { display: none; }

.pick__box {
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--lift);
}
.pick__choose {
  padding: 1rem 1.05rem 0.75rem;
  border-bottom: 1px solid var(--line);
}
.pick__label {
  display: block;
  font-weight: 600;
  margin: 0 0 0.55rem;
}
/* Native control, restyled only as far as size and border: 48px tall so it is
   a comfortable thumb target, full width so a long title is not cut sooner
   than it has to be. */
.pick__select {
  display: block;
  width: 100%;
  min-height: 48px;
  padding: 0.55rem 0.7rem;
  font-family: var(--sans);
  font-size: 1rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--ink);
  border-radius: var(--radius);
}
.pick__summary {
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--muted);
  margin: 0.5rem 0 0;
}

.pick__panel { padding: 1rem 1.05rem 1.05rem; }
.pick__panel + .pick__panel { border-top: 1px solid var(--line); }
.pick__code {
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--muted);
  margin: 0 0 0.5rem;
}
.pick__title { margin: 0 0 0.6rem; font-size: 1.2rem; }
.pick__facts { margin: 0; border-top: 1px solid var(--line); }
.pick__facts div {
  display: flex;
  gap: 0 1rem;
  justify-content: space-between;
  align-items: baseline;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--line);
}
.pick__facts dt, .pick__facts dd { font-size: 0.92rem; }
.pick__facts dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
/* The pre-purchase notice: the card notice's flat left rule, in the same
   place relative to the Buy control -- directly above it. */
.pick__notice {
  border-left: 3px solid var(--ink);
  padding-left: 0.75rem;
  margin: 0.9rem 0 0;
  font-size: 0.86rem;
  line-height: 1.5;
}
.pick__price {
  font-family: var(--display);
  font-weight: 900;
  font-size: 1.6rem;
  letter-spacing: -0.038em;
  font-variant-numeric: tabular-nums;
  margin: 0.8rem 0 0.6rem;
}
.pick__price small {
  font-family: var(--sans);
  font-weight: 400;
  font-size: 0.78rem;
  letter-spacing: 0;
  color: var(--muted);
  margin-left: 0.4rem;
}
a.button.pick__buy { display: block; text-align: center; padding: 0.85rem 1.25rem; }
.pick__nobuy { font-size: 0.9rem; color: var(--muted); margin: 0; }
.pick__links { font-size: 0.88rem; margin: 0.8rem 0 0; }
.pick__links a + a { margin-left: 1rem; }

/* /exams: the same select at the top of the page, alone in its box, over
   the chosen exam's (or bundle's) own detail section. */
/* No top margin: the section head above already ends in its own 1.6rem. */
.pick__box--solo { max-width: 36rem; }
.pick__box--solo .pick__choose { border-bottom: 0; }
/* The picker and the section it shows read as one unit, so the gap between
   them is tighter than between two unrelated sections; the closing notes are
   two small lines and get a compact section of their own. */
.pickpage__top { padding-bottom: 1rem; }
.section[data-pick-panel] { padding: 2rem 0; }
.pickpage__notes { padding: 1.1rem 0; }
.pickpage__notes p { margin: 0.3rem 0; }
/* The price and Buy control closing each /exams section, directly after its
   pre-purchase notice where it has one. */
.pick__act { max-width: 24rem; margin-top: 1.1rem; }
.pick__act .pick__price { margin-top: 0; }

.pick__bundles {
  margin-top: 0.9rem;
  padding: 0.75rem 1.05rem;
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 0.9rem;
}
.pick__bundles p { margin: 0.2rem 0; }

.pick__list { display: none; }
@media (min-width: 56.25rem) {
  .pick__list { display: block; }
}
.pick__vendor {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0.4rem 0 0.45rem;
}
.pick__list ul { list-style: none; margin: 0 0 1.2rem; padding: 0; }
.pick__list li { margin: 0.35rem 0; font-size: 0.95rem; }
.pick__list a[aria-current] { color: var(--ink); font-weight: 600; }

/* --- 12. Question specimen ----------------------------------------------- */

.specimen {
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--lift);
}
.specimen__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.2rem;
  justify-content: space-between;
  padding: 0.7rem 1.15rem;
  border-bottom: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: .05em;
  color: var(--muted);
}
.specimen__body { padding: 1.2rem 1.15rem 1.35rem; }

.stem {
  font-size: 1rem;
  line-height: 1.55;
  margin: 0 0 1.15rem;
  max-width: var(--measure);
}

.options {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--line);
}
.options li {
  display: flex;
  gap: 0.85rem;
  padding: 0.62rem 0.7rem;
  border-bottom: 1px solid var(--line);
  font-size: 0.94rem;
  line-height: 1.5;
}
.options .key {
  font-family: var(--mono);
  font-size: 0.82rem;
  color: var(--muted);
  flex: 0 0 1.3rem;
  padding-top: 0.14em;
}
.options li.is-correct {
  border: 1px solid var(--ok);
  background: color-mix(in srgb, var(--ok) 9%, transparent);
}
.options li.is-correct .key { color: var(--ok); font-weight: 600; }
.options .verdict {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ok);
  padding-top: 0.2em;
  white-space: nowrap;
}

.explanation {
  margin-top: 1.3rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--line);
  max-width: var(--measure);
}
.explanation h3 {
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.6rem;
}
.explanation p { font-size: 0.94rem; line-height: 1.6; }

.citation {
  margin-top: 1.1rem;
  padding: 0.8rem 0.9rem;
  border: 1px dashed var(--line);
  font-size: 0.84rem;
  line-height: 1.5;
  color: var(--muted);
}
.citation .micro { margin: 0 0 0.3rem; }
.citation a {
  font-family: var(--mono);
  font-size: 0.94em;
  color: var(--steel);
  word-break: break-all;
}

/* --- 13. Per-domain score readout ---------------------------------------- */

.domains {
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--lift);
  padding: 1.1rem 1.15rem 1.2rem;
}
.domains ol { list-style: none; margin: 0; padding: 0; }
.domains li { padding: 0.55rem 0; border-bottom: 1px solid var(--line); }
.domains li:last-child { border-bottom: 0; }
.domains__row {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1rem;
  justify-content: space-between;
  align-items: baseline;
  font-size: 0.88rem;
}
.domains__pct {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
.domains__bar {
  margin-top: 0.35rem;
  height: 6px;
  background: var(--bg);
  border: 1px solid var(--line);
}
.domains__fill { display: block; height: 100%; background: var(--muted); }
.domains__fill.is-ok { background: var(--ok); }
/* The example readout's bar widths, one class per EXAMPLE_SCORES value in
   build-site-pages.py. Classes, not inline style="width:..": style-src 'self'
   blocks inline style attributes, which made every bar full width until
   2026-10-15. */
.domains__fill--55 { width: 55%; }
.domains__fill--61 { width: 61%; }
.domains__fill--78 { width: 78%; }
.domains__fill--84 { width: 84%; }
.domains__fill--92 { width: 92%; }

/* --- 14. Tables ---------------------------------------------------------- */

.scroller { overflow-x: auto; }

.table {
  width: 100%;
  border-collapse: collapse;
  margin: 0;
  font-size: 0.9rem;
  background: var(--surface);
}
.table caption {
  text-align: left;
  font-size: 0.84rem;
  color: var(--muted);
  padding-bottom: 0.6rem;
}
.table th, .table td {
  text-align: left;
  padding: 0.55rem 0.8rem;
  border-bottom: 1px solid var(--line);
  vertical-align: baseline;
}
.table thead th {
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.table tbody tr:last-child td { border-bottom: 0; }
.table td.num, .table th.num {
  text-align: right;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
.doc .table { border: 1px solid var(--line); margin: 1.5rem 0; }
.doc .table td, .doc .table th { vertical-align: top; }
.doc .table td p:last-child { margin-bottom: 0; }

/* Fact list, used on the long-form pages. */
.facts { margin: 1.6rem 0 0; border-top: 1px solid var(--line); }
.facts div {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1rem;
  justify-content: space-between;
  align-items: baseline;
  padding: 0.62rem 0;
  border-bottom: 1px solid var(--line);
}
.facts dt { font-size: 0.86rem; color: var(--muted); }
.facts dd {
  margin: 0;
  font-size: 0.86rem;
  font-family: var(--mono);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* --- 15. Footer ---------------------------------------------------------- */

.footer {
  border-top: 1px solid var(--line);
  padding: 2.4rem 0 3.2rem;
  font-size: 0.86rem;
  line-height: 1.6;
  color: var(--muted);
}
.footer p { margin-bottom: 0.9rem; }
.footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.1rem;
  margin: 0 0 1.2rem;
  padding: 0;
  list-style: none;
}
.footer__links a { color: var(--muted); }
.footer__links a:hover { color: var(--ink); }

.disclaimer {
  border-left: 2px solid var(--line);
  padding-left: 1rem;
  margin: 0 0 1.3rem;
  max-width: var(--measure);
}

/* --- 16. Utilities ------------------------------------------------------- */

.spaced      { margin-top: 1.4rem; }
.spaced-more { margin-top: 1.6rem; }

.skip { position: absolute; left: -9999px; }
.skip:focus {
  left: 0.5rem;
  top: 0.5rem;
  z-index: 10;
  background: var(--surface);
  color: var(--ink);
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--ink);
}

/* --- 17. Print ----------------------------------------------------------- */

@media print {
  body { background: var(--surface); font-size: 11pt; }
  .masthead, .nav, .button, .cta-row { display: none; }
  .section { border-top: 0; padding: 0.8rem 0; }
  .card, .proof, .specimen, .domains { box-shadow: none; }
  .citation a::after { content: ' (' attr(href) ')'; font-size: 0.85em; }
}

/* ---------------------------------------------------------------------------
   18. Long documents: terms, privacy, refunds, methodology.

   Read differently from the home page. Somebody arriving here is looking for
   one clause, not reading start to finish, so the numbered heading, the
   contents list at the top and the visible section rules matter more than the
   typography does. Measure stays narrow: legal prose read at 65 characters is
   legible; read at 110 it is not, and a refund clause nobody finishes is a
   refund clause nobody trusts.
   --------------------------------------------------------------------------- */

.doc { padding: 2.6rem 0 1rem; }
.doc .column > * { max-width: var(--measure); }
.doc .column > .scroller,
.doc .column > .table { max-width: none; }

.doc h1 { font-size: clamp(2rem, 4.6vw, 3.15rem); line-height: 1.04; }
.doc h2 { margin-top: 2.5rem; font-size: 1.5rem; }
.doc h3 { margin-top: 1.7rem; font-size: 1.08rem; }
.doc h2 + p, .doc h3 + p { margin-top: 0; }

.doc ul, .doc ol { margin: 0 0 1.05em; padding-left: 1.35rem; }
.doc li { margin-bottom: 0.42em; }
.doc li:last-child { margin-bottom: 0; }
.doc ol { list-style: decimal; }
.doc ul { list-style: none; padding-left: 1.1rem; }
.doc ul li { position: relative; }
.doc ul li::before {
  content: "\2014";                 /* em dash, not a bullet glyph */
  position: absolute; left: -1.1rem; top: 0;
  color: var(--line);
}
.doc ol ul, .doc ul ul { margin-top: 0.45em; }

/* The line under a document title: version, date, what it governs. */
.docmeta {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0.6rem 0 1.9rem;
  padding-bottom: 1.2rem;
  border-bottom: 1px solid var(--line);
}
.docmeta span + span::before { content: " \00B7 "; }

/* Contents. Deliberately a plain list of links, not a sticky sidebar. */
.toc {
  font-size: 0.92rem;
  margin: 0 0 2.4rem;
  padding: 1rem 0 1.15rem;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.toc h2 {
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 0.7rem;
}
.toc ol { list-style: none; margin: 0; padding: 0; columns: 2; column-gap: 2rem; }
.toc li { margin-bottom: 0.35em; break-inside: avoid; }
@media (max-width: 34rem) { .toc ol { columns: 1; } }

/* A call-out for the things a reader most needs to not miss. Flat: a rule on
   the left edge, no tinted panel, no icon, no rounded box. */
.callout {
  border-left: 3px solid var(--ink);
  padding: 0.1rem 0 0.1rem 1.05rem;
  margin: 1.5rem 0;
}
.callout p:last-child { margin-bottom: 0; }

/* An unresolved value the owner must fill before this site is published. It is
   styled so it cannot be mistaken for finished copy, and the test suite counts
   every one of them and refuses to call the folder deployable while any
   remain. */
.fillme {
  font-family: var(--mono);
  font-size: 0.9em;
  border-bottom: 2px solid var(--spark);
  white-space: nowrap;
}

.backlink { font-size: 0.9rem; margin-top: 2.6rem; }

/* --- 19. Account page ------------------------------------------------------
   /account is the only page with interactive controls that do something. */

.account__bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  align-items: baseline;
  justify-content: space-between;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--line);
  font-size: 0.9rem;
}

.account__signout {
  font-size: 0.86rem;
  color: var(--muted);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
}

.account__block { margin: 2rem 0; }
.account__block h2 { margin-bottom: 0.6rem; }

.account__packs { list-style: none; margin: 1.2rem 0; padding: 0; }
.account__packs li {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem 1rem;
  align-items: baseline;
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--line);
}
.account__packs li .button { margin-top: 0; }

.account__badge {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--line);
  padding: 0.14rem 0.45rem;
}
.account__packs .is-open .account__badge {
  color: var(--ok);
  border-color: var(--ok);
}

.account__expiry,
.account__note { font-size: 0.86rem; color: var(--muted); }

/* A pre-purchase disclosure inside a pack row. That row is a flex line of short
   chips; this is a sentence, so it takes a line of its own and sits directly
   above that product's Buy button rather than beside it. */
.account__packs .account__note--block {
  flex: 1 1 100%;
  border-left: 3px solid var(--ink);
  padding-left: 0.75rem;
  line-height: 1.5;
}

.account__error { font-size: 0.9rem; color: var(--ink); }
.account__ok    { font-size: 0.9rem; color: var(--ok); }

.account__claim {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  align-items: center;
  margin: 1rem 0;
}
.account__claim input {
  flex: 1 1 22rem;
  font-family: var(--mono);
  font-size: 0.92rem;
  padding: 0.6rem 0.7rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.account__claim .button { margin-top: 0; }

#auth-signin, #account-signin { margin: 1.2rem 0; }

/* --- 20. Objection form -------------------------------------------------- */

/* /object. A normal Whetstone component: square corners, --line borders, one
   --spark button, visible focus. Nothing here needs JavaScript; the page is
   served under script-src 'none' and the form posts to its own URL. */

.objform {
  margin: 2rem 0 2.4rem;
  padding: 1.4rem 1.4rem 1.5rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  max-width: var(--measure);
}

.objform__ctx { margin: 0 0 1.2rem; border-top: 1px solid var(--line); }
.objform__ctx div {
  display: flex;
  gap: 1rem;
  justify-content: space-between;
  align-items: baseline;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--line);
}
.objform__ctx dt { font-size: 0.86rem; color: var(--muted); }
.objform__ctx dd {
  margin: 0;
  font-family: var(--mono);
  font-size: 0.86rem;
  text-align: right;
  word-break: break-word;
}
.objform__none { font-size: 0.9rem; color: var(--muted); margin: 0 0 1.2rem; }

.objform__field { margin-bottom: 1.1rem; }
.objform__field label {
  display: block;
  font-weight: 600;
  font-size: 0.95rem;
  margin-bottom: 0.25rem;
}
.objform__opt {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--muted);
  margin-left: 0.4rem;
}
.objform__help { font-size: 0.86rem; color: var(--muted); margin: 0 0 0.5rem; }

.objform textarea,
.objform__input,
.notify__input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  font-family: var(--sans);
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.6rem 0.7rem;
}
.objform textarea { resize: vertical; min-height: 7rem; }
.objform textarea:hover,
.objform__input:hover,
.notify__input:hover { border-color: var(--muted); }

/* The honeypot. Off-screen rather than display:none, because some bots skip what
   is display:none and fill in what is merely invisible. Out of the tab order and
   out of the accessibility tree, so nobody who is not a bot ever meets it. */
.objform__pot,
.notify__pot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.objform__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem 1rem;
  align-items: center;
  margin-top: 1.3rem;
}
.objform__commit { margin: 0; font-size: 0.86rem; color: var(--muted); }

.objform__error {
  margin: 0 0 1.1rem;
  padding: 0.7rem 0.8rem;
  font-size: 0.9rem;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--spark);
  border-radius: var(--radius);
}

/* The confirmation, which replaces the form in place. */
.objform__done {
  margin: 2rem 0 2.4rem;
  padding: 1.4rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 3px solid var(--ok);
  border-radius: var(--radius);
  max-width: var(--measure);
}
.objform__done:focus-visible { outline: 2px solid var(--spark); outline-offset: 2px; }
.objform__done h2 { margin: 0 0 0.7rem; font-size: 1.3rem; }
.objform__done p { font-size: 0.94rem; }
.objform__done p:last-child { margin-bottom: 0; }
.objform__done--fail { border-left-color: var(--spark); }
.objform__note { color: var(--muted); font-size: 0.86rem; }
.objform__again { margin-top: 1.2rem; font-size: 0.9rem; }
.objform__copy {
  margin: 1rem 0 0;
  padding: 0.8rem;
  background: var(--bg);
  border: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 0.8rem;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
  overflow-x: auto;
}

/* --- The update list ------------------------------------------------------
   "Tell me when these questions change", at the foot of every free guide page.
   P-002 placement (b), CEO-approved 2026-09-22. Generated by
   app/tools/build-doc-pages.py; the same block on the /sample results screen is
   the exam engine's own and is styled in app/engine/exam-engine.css.

   It is DELIBERATELY QUIET. The reason is the same one that put it below the
   buy CTA on /sample rather than above it: a guide page's job is to be read and
   then to send somebody to the assessment or the catalog, and an email field
   that outshouts those is a field that costs more than it collects. So: the
   surface card the site already uses, the ghost button rather than the spark
   one, and a heading at the size of a subsection rather than a section.
   --------------------------------------------------------------------------- */

.notify {
  margin: 2.6rem 0 2.4rem;
  padding: 1.4rem 1.4rem 1.5rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  max-width: var(--measure);
}
.notify__h {
  margin: 0 0 0.6rem;
  font-size: 1.15rem;
  line-height: 1.3;
}
.notify__body {
  margin: 0 0 1.1rem;
  font-size: 0.94rem;
  color: var(--muted);
}
.notify__field { margin-bottom: 0.2rem; }
.notify__field label {
  display: block;
  font-weight: 600;
  font-size: 0.95rem;
  margin-bottom: 0.25rem;
}
.notify__input {
  max-width: 24rem;
}
.notify__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem 1rem;
  align-items: center;
  margin-top: 1.1rem;
}

/* ---------------------------------------------------------------------------
   The home page's content-suggestion box (app/server/suggest.js, CEO request
   2026-10-01). Generated by suggest_section() in app/tools/build-site-pages.py.

   Quiet for the same reason the update list is: it sits AFTER the buy section,
   and it must not outshout the thing the page is for. Same surface card, same
   ghost button, same subsection-sized heading as .notify above.
   --------------------------------------------------------------------------- */

.suggest {
  padding: 1.4rem 1.4rem 1.5rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  max-width: var(--measure);
}
.suggest__h {
  margin: 0 0 0.6rem;
  font-size: 1.15rem;
  line-height: 1.3;
}
.suggest__body {
  margin: 0 0 1.1rem;
  font-size: 0.94rem;
  color: var(--muted);
}
.suggest__field label {
  display: block;
  font-weight: 600;
  font-size: 0.95rem;
  margin-bottom: 0.25rem;
}
.suggest__input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  font-family: var(--sans);
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.6rem 0.7rem;
  resize: vertical;
  min-height: 6rem;
}
.suggest__input:hover { border-color: var(--muted); }
/* Off-screen, not display:none -- same reasoning as .notify__pot. */
.suggest__pot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.suggest__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem 1rem;
  align-items: center;
  margin-top: 1.1rem;
}
.suggest__actions .small { margin: 0; }

/* /teams: three Buy controls side by side, wrapping on a phone. */
.button-row { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.button-row .button { margin: 0; }
