/* ==================================================================
   SEAL SITES — root site · SEED A · "TRADE PRINTER"
   LAYOUT LAYER. Identity (colour, type, shape, rhythm) is tokens.css.

   ------------------------------------------------------------------
   WHY THIS IS A FILE AND NOT A <style> BLOCK (2026-08-02)
   ------------------------------------------------------------------
   It was inline in index.html until the Spanish page landed. Two pages
   sharing one design cannot each carry their own copy of it: the next
   CSS edit lands on one page and silently misses the other, which is
   this project's most-repeated bug in a new coat (the deleted dish in
   a second copy of the menu; the colour literals that would have kept
   the old palette through a re-skin; carlos-rail.js).

   The rule the project already settled for CONTENT is the opposite —
   marketing copy is duplicated per language on purpose, because it
   changes rarely and two static pages beat a JS string-swap (blueprint
   §6b). CSS gets the other answer because a stylesheet is machinery,
   not content: when it changes it must change everywhere at once.

   So: tokens.css = identity, site.css = layout, and the two HTML files
   hold nothing but their own language's words.
   ------------------------------------------------------------------

   These pages have ZERO JavaScript, deliberately: they are static copy,
   so the demo's whole class of failure — content that vanishes when a
   data file doesn't load — cannot exist here. Nothing to put in a
   <noscript>. If a future edit adds JS, that claim needs deleting in
   the same commit.
   ================================================================== */

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
/* height:auto is load-bearing, not tidiness: the img carries width/height
   attributes (they reserve layout space and stop the page jumping), and
   max-width alone scales the WIDTH while the height attribute still applies
   — the proof shot rendered 240x1624 instead of 240x520 until this landed. */
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; border-radius: 2px; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

h1, h2, h3, .display {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.06;
  letter-spacing: -0.015em;
  margin: 0;
}
p { margin: 0; }

.wrap { max-width: var(--w-page); margin: 0 auto; padding-inline: 20px; }
section { padding-block: var(--sp-5); }

/* the printer's kicker: letterspaced caps over a hairline */
.kicker {
  font-size: 12px; font-weight: 700; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--accent);
}

/* ---- controls ---- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 54px; padding: 12px 30px;
  border-radius: var(--r-pill);
  font-family: var(--font-body); font-weight: 700; font-size: 17px;
  text-decoration: none; border: 2px solid var(--ink);
  transition: transform 110ms ease, background-color 110ms ease;
}
.btn:active { transform: translateY(2px); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { background: var(--accent-2); border-color: var(--accent-2); }
.btn-ghost { background: transparent; color: var(--ink); }
.btn-ghost:hover { background: var(--panel); }
.cta-row { display: flex; flex-wrap: wrap; gap: 14px; margin-top: var(--sp-3); }

/* ---- header: a masthead strip with a heavy rule under it ---- */
header { border-bottom: var(--rule) solid var(--ink); }
.bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-2); min-height: 64px; flex-wrap: wrap;
}
/* Header links get a 44px hit area they do not visually occupy: at their
   natural line-box the wordmark was 118x22, half the minimum touch target,
   and the bar has the vertical room to give it away for free. */
.wordmark, .bar-mail, .lang-toggle { display: inline-flex; align-items: center; min-height: 44px; }
.wordmark { font-size: 21px; text-decoration: none; letter-spacing: -0.02em; }
.wordmark i { font-style: normal; color: var(--accent); }
.bar-mail { font-size: 15px; font-weight: 600; color: var(--ink-2); text-decoration: none; }
.bar-mail:hover { color: var(--accent); text-decoration: underline; }

/* ---- second-language slot (blueprint §6b) — NOW WIRED ----
   The comment that used to sit here said the toggle was deliberately not
   rendered, because the seeds shipped English-only and a toggle pointing
   at a page that does not exist is the dead-link defect the demo already
   shipped once (.example). www/es/index.html exists now, so it is real.

   It names the language in ITS OWN language — "Español" / "English" —
   and never a flag: flags are countries, not languages, and this audience
   spans several. The anchor carries hreflang AND lang so a screen reader
   pronounces "Español" in Spanish rather than reading it as English. */
.bar-right { display: flex; align-items: center; gap: 14px; }
.bar-sep { width: 1px; height: 18px; background: var(--hair); flex: none; }
.lang-toggle {
  font-size: 15px; font-weight: 700; color: var(--accent);
  text-decoration: none; white-space: nowrap;
}
.lang-toggle:hover { text-decoration: underline; }

/* ---- hero: the diagnosis, set like a headline on a spec sheet ---- */
.hero { padding-block: var(--sp-5) var(--sp-4); }
.hero h1 {
  font-size: clamp(38px, 9.4vw, 74px);
  margin-top: 14px; max-width: 15ch;
}
.hero h1 em { font-style: normal; color: var(--accent); }
.hero .lede { margin-top: var(--sp-3); max-width: 46ch; font-size: 19px; }
.hero-note { margin-top: var(--sp-2); font-size: 15px; color: var(--ink-2); max-width: 46ch; }

/* The one-line honesty note under a CTA that leaves for an English page.
   Only the ES page uses it today; it is deleted from that page the day
   Rosa's Spanish page is PUBLISHED — not the day it is built.

   ⚠ RESTORED 2026-08-03, hours after being deleted, and the round trip is the
   lesson. It was removed as "a rule that outlives its last consumer", which is
   a good instinct applied to the wrong fact: Rosa's Spanish page was BUILT, not
   DEPLOYED, and its Spanish was then rejected. The consumer had not gone away;
   it was a few hours ahead of itself. Deleting the rule turned a one-line copy
   revert into a two-file one, and a stylesheet is exactly where that kind of
   coupling hides — the restored <p> would have rendered unstyled with nothing
   in the markup to say why. Retire this rule when the /es/ demo is LIVE. */
.lang-note { margin-top: var(--sp-2); font-size: 15px; color: var(--ink-2); max-width: 46ch; }

/* ---- the docket: the four questions, answered, as one object ----
   Grafted 2026-08-14. Seed B's surviving mechanism (WWW_RERUN_BAR.md B4),
   the one thing kept from a rerun whose other three seeds Sami rejected on
   sight for stripping the page's personality.

   ⛔ THE POINT OF THE GRAFT IS THAT IT WEARS THIS PAGE'S CLOTHES. Numerals
   in Archivo Black and accent over hairline rows is not a borrowed device —
   .spec-row below has done exactly that since the page shipped, so the
   docket reads as the same printer's hand rather than as an import. The seed
   drew it in Archivo alone because its bar banned a second family; that bar
   is rejected and Archivo Black is a signature asset, not a violation.

   It is deliberately NOT a card, a panel, or a shadowed box. The hero's one
   earned moment is the poster headline; a second boxed object under it would
   compete with the thing the eye is supposed to land on first. Rules and
   whitespace do the organising — which is the page's whole point of view.

   The whole row is the link, not the sentence inside it: a 44px band the
   thumb cannot miss, hover/focus on the band, and one target per question
   instead of a phrase to hunt for. */
.docket {
  list-style: none; margin: var(--sp-4) 0 0; padding: 0;
  border-top: 1px solid var(--hair);
}
.docket li { border-bottom: 1px solid var(--hair); }
.docket a {
  display: grid; grid-template-columns: 34px 1fr; gap: 2px var(--sp-2);
  padding-block: 14px; min-height: 44px;   /* stated as intent, not left to line-height */
  text-decoration: none;
}
.docket a:hover { background: var(--panel); }
.docket .dk-no {
  font-family: var(--font-display); font-size: 14px; color: var(--accent);
  letter-spacing: 0; padding-top: 3px;
}
.docket .dk-what { font-size: 17px; line-height: 1.45; }
/* The question is the only teal on the row, and it is teal because it is the
   thing you click — colour carries the affordance, never decoration. The
   trailing description stays in ink so the row does not read as one long
   link label. */
.docket .dk-what b {
  font-weight: 700; color: var(--accent);
  text-decoration: underline; text-underline-offset: 3px;
}
/* The answer wears the page's existing meta-label costume — display face,
   letterspaced caps — the same device .step .n and .price-part .tag already
   use. Not decoration: at 375px the answer drops BELOW the sentence into the
   same column, and set as ordinary bold text it read as a third line of the
   sentence ("…open it on your phone / Open →"). Caps at 12px cannot be
   mistaken for prose, so the row stays a question-and-answer at every width.
   Grey, not accent: the question is the row's one teal. */
.docket .dk-go {
  grid-column: 2; margin-top: 4px;
  font-family: var(--font-display); font-size: 12px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-2);
}

/* ---- the heavy/light rule pair that opens every section ---- */
.sec-rule { border: 0; border-top: var(--rule) solid var(--ink); margin: 0; }
.sec-rule + .sec-rule { border-top-width: 1px; margin-top: 3px; }
.sec-head { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; margin-bottom: var(--sp-3); }
/* Every section heading sizes HERE. The contact band's h2 is deliberately
   named alongside .sec-head rather than given its own rule: it sits outside
   the .sec-head wrapper, so with a .sec-head-only selector it silently fell
   through to the UA default (1.5em = 26px against its siblings' 40px) —
   visible in a screenshot, invisible in the CSS. */
.sec-head h2, .contact h2 { font-size: clamp(27px, 5.6vw, 40px); }

/* ---- the proof: phone in a hard offset shadow ---- */
.proof-grid { display: grid; gap: var(--sp-4); align-items: start; }
.phone {
  /* Representational, not a component: this is a picture of a phone, so it
     keeps a phone's bezel radius while every panel on the page stays 4px. */
  width: 258px; max-width: 100%;
  border: 9px solid var(--ink); border-radius: 30px;
  background: var(--ink); overflow: hidden;
  box-shadow: var(--offset) var(--offset) 0 var(--accent);
}
.proof-text p + p { margin-top: var(--sp-2); }
.proof-text .lead { font-size: 19px; }
.proof-text .muted { color: var(--ink-2); }
.caption { margin-top: 14px; font-size: 13.5px; color: var(--ink-2); max-width: 258px; }

/* ---- what you get: a printer's spec list, rules between rows ---- */
.spec { border-top: 1px solid var(--hair); }
.spec-row {
  display: grid; grid-template-columns: 34px 1fr; gap: 4px var(--sp-2);
  padding-block: 18px; border-bottom: 1px solid var(--hair);
}
.spec-no {
  font-family: var(--font-display); font-size: 14px; color: var(--accent);
  padding-top: 4px; letter-spacing: 0;
}
.spec-row h3 { font-family: var(--font-body); font-weight: 700; font-size: 17.5px; line-height: 1.35; letter-spacing: 0; }
/* Targeted by class, never by tag: .spec-no is also a <p> inside .spec-row,
   so a bare `.spec-row p` rule places the ROW NUMBER as well as the
   description — which is what forced every heading into the 44px number
   column at desktop until this was scoped. */
.spec-desc { color: var(--ink-2); font-size: 16px; grid-column: 2; }

/* The numbered/itemised sequences are real lists; the markers are what we
   don't want.
   ⚠ CORRECTED 2026-08-02 — this comment used to claim outright that "a screen
   reader announces list, N items". THAT WAS FALSE and the CSS below is why:
   WebKit/VoiceOver strips list semantics from a ul/ol once list-style:none
   removes its markers, so in Safari these announced as loose paragraphs. The
   markup now carries explicit role="list" to put the semantics back, and that
   attribute is load-bearing — deleting it as "redundant" reintroduces the bug
   silently, in one browser, where no screenshot shows it.
   Found by a cold foreign review; it had been shipping on the live English
   page. A comment asserting an accessibility guarantee the code does not
   deliver is worse than no comment: it stops the next reader from checking. */
ol.steps, ul.spec { list-style: none; margin: 0; padding: 0; }
/* ---- how it works: three bordered boxes ---- */
.steps { display: grid; gap: var(--sp-2); }
.step { border: 2px solid var(--ink); border-radius: var(--r-box); padding: var(--sp-3); background: var(--paper); }
.step .n { font-family: var(--font-display); font-size: 13px; color: var(--accent); letter-spacing: 0.1em; }
.step h3 { font-size: 21px; margin-top: 6px; }
.step p { margin-top: 10px; color: var(--ink-2); font-size: 16px; }

/* ---- cost: the quoted panel, wearing the maker's mark ---- */
.quote-box {
  border: 2px solid var(--ink); border-radius: var(--r-box);
  background: var(--panel); padding: var(--sp-3);
  box-shadow: var(--offset) var(--offset) 0 var(--ink);
}
.price-split { display: grid; gap: var(--sp-3); margin-top: var(--sp-2); }
.price-part h3 { font-family: var(--font-body); font-weight: 700; font-size: 17px; letter-spacing: 0; }
.price-part .tag { font-family: var(--font-display); font-size: 12px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); }
.price-part p { margin-top: 6px; color: var(--ink-2); font-size: 16px; }
.compare { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--hair); font-size: 16px; }
.compare strong { font-weight: 700; }

/* ---- who ---- */
.who p + p { margin-top: var(--sp-2); }
.who .lead { font-size: 19px; }
.who .muted { color: var(--ink-2); }

/* ---- contact ---- */
.contact { background: var(--ink); color: var(--paper); }
.contact .kicker { color: var(--accent-lift); }   /* teal lifted for the dark ground — 8.9:1 */
.contact h2 { color: var(--paper); }
.contact p { color: var(--on-dark); max-width: 48ch; margin-top: var(--sp-2); }
.mailto {
  display: inline-block; margin-top: var(--sp-3);
  font-family: var(--font-display);
  font-size: clamp(22px, 5.4vw, 38px);
  color: var(--paper); text-decoration: none;
  border-bottom: 4px solid var(--accent-lift);
  padding-bottom: 4px; word-break: break-word;
  /* 44px stated as intent, not encoded as a magic padding number. At 320/375
     the clamp floors the type at 22px, which made this 43.188px tall — a
     PRE-EXISTING miss on the live page, measured at HEAD before this
     checkpoint touched anything, and recorded as clean by the seed build's
     pre-flight. It is the page's single biggest conversion control, so it
     gets the bar rather than an exemption. box-sizing is border-box globally,
     so this counts the padding and the underline; the rule moves the teal
     underline down by 0.8px and nothing else. */
  min-height: 44px;
}
.mailto:hover { color: var(--accent-lift); }
.contact :focus-visible { outline-color: var(--accent-lift); }
.who-for { margin-top: var(--sp-4); font-size: 16px; color: var(--on-dark-2); max-width: 56ch; }

/* ---- footer ---- */
footer { border-top: var(--rule) solid var(--ink); padding-block: var(--sp-3); }
.fineprint { font-size: 14px; color: var(--ink-2); }

/* ---- desktop ---- */
@media (min-width: 720px) {
  body { font-size: 17.5px; }
  .proof-grid { grid-template-columns: 258px 1fr; gap: var(--sp-5); }
  .caption { max-width: 258px; }
  .steps { grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); }
  .price-split { grid-template-columns: 1fr 1fr; gap: var(--sp-4); }
  .quote-box { padding: var(--sp-4); }
  .spec-row { grid-template-columns: 44px 17rem 1fr; align-items: baseline; }
  .spec-desc { grid-column: 3; }
  /* The answer moves out of the sentence's column and sets flush right, so
     the four answers stack into a readable second column of their own. It
     stays `auto` rather than a fixed track: row 04 has no answer by ruling,
     and a fixed track would leave a measured hole where nothing was meant. */
  .docket a { grid-template-columns: 44px 1fr auto; gap: 2px var(--sp-3); align-items: baseline; }
  .docket .dk-no { padding-top: 0; }
  .docket .dk-go { grid-column: 3; margin-top: 0; text-align: right; white-space: nowrap; }
}

/* Motion budget is button-presses only (inherited ruling, blueprint §5).
   The OS preference still outranks the budget. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .btn { transition: none; }
  .btn:active { transform: none; }
}
