/* ==========================================================================
   KENYA FLOWER MERCHANT — DESIGN SYSTEM
   Premium international flower merchant. Restrained, typographic, fast.
   Not a florist. Not a directory. Not a content farm.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* Colour — restrained. One deep green anchor, one warm accent, generous neutrals.
     The green is horticultural without being literal; the accent is used sparingly
     and never for large areas. */
  --ink:            #16201c;
  --ink-soft:       #40514a;
  /* Measured on the live page: #6b7b74 on white gives 4.46:1. WCAG AA for
     normal text wants 4.5:1, and the places this token is used — .eyebrow at
     13px/600, .nav__desc at 11px, .sectionlist__meta — are all "normal" text,
     not large. It failed by four hundredths.
     #66766f measures 4.79:1. Five points darker per channel: over the line,
     and not a visible change to the design. Used in 26 rules, so every one of
     them clears AA together. */
  --ink-mute:       #5f6e67;  /* was #66766f: 4.43:1 on --paper-warm, below AA; deepened 26 Sep 2026 */
  --rule:           #dfe4e1;
  --rule-soft:      #edf0ee;
  --paper:          #ffffff;
  --paper-warm:     #f7f6f3;
  --paper-deep:     #eef1ee;

  --brand:          #14483a;   /* deep green — headers, primary buttons */
  --brand-deep:     #0d3128;
  --brand-tint:     #e7efeb;

  --accent:         #a8462f;   /* terracotta — used sparingly, never as a field */
  --accent-tint:    #f6ece9;

  --ok:             #2c6e49;
  --warn:           #8a5a00;
  --warn-tint:      #fdf5e6;
  /* Deep enough to clear 4.5:1 on --error-tint for body text and links. */
  --error:          #a01b2b;
  --error-tint:     #fdeef0;

  /* Type */
  --font-display: "Fraunces", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --font-body:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono:    ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* A modest, deliberate scale. Large display sizes are reserved for the
     home hero and section openers — nothing else. */
  --t-xs:   0.8125rem;
  --t-sm:   0.9375rem;
  --t-base: 1.0625rem;
  --t-md:   1.1875rem;
  --t-lg:   1.4375rem;
  --t-xl:   1.875rem;
  --t-2xl:  2.375rem;
  --t-3xl:  3.125rem;
  --t-4xl:  4rem;

  /* Space — 4px base */
  --s-1: 0.25rem;  --s-2: 0.5rem;   --s-3: 0.75rem;  --s-4: 1rem;
  --s-5: 1.5rem;   --s-6: 2rem;     --s-7: 3rem;     --s-8: 4rem;
  --s-9: 6rem;     --s-10: 8rem;

  --measure: 68ch;
  --wrap: 1180px;
  --wrap-narrow: 760px;

  --radius: 3px;
  --radius-lg: 6px;

  --shadow-sm: 0 1px 2px rgba(22,32,28,.06), 0 1px 3px rgba(22,32,28,.04);
  --shadow:    0 2px 8px rgba(22,32,28,.07), 0 8px 24px rgba(22,32,28,.05);

  --ease: cubic-bezier(0.2, 0.6, 0.2, 1);
}

/* --------------------------------------------------------------------------
   2. RESET
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
}
/* Smooth scrolling only once something on the page has focus — i.e. after a
   click or a keypress. With `scroll-behavior: smooth` on html unconditionally,
   Chromium never completed the scroll to a URL fragment on initial load:
   measured 2026-09-25 on every page type (scrollY stayed 0 for #ched-pp,
   #3-the-pre-notification, #why-we-hold-it, #index-h) while GOV.UK scrolled
   fine in the same pane. In-page hash changes worked; only the load-time
   scroll was lost. :focus-within is the standard scoping for exactly this. */
html:focus-within {
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html, html:focus-within { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  font-family: var(--font-body);
  font-size: var(--t-base);
  line-height: 1.65;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, picture, svg, video { display: block; max-width: 100%; height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; }

/* The `hidden` attribute must win over any component that sets `display`.
   Without this, .btn { display: inline-flex } keeps hidden buttons visible —
   which showed the Back and Submit buttons on step 1 of the quote form. */
[hidden] { display: none !important; }

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Error-summary landing targets.
   The grouped questions (products, purchase pattern, import status, timing)
   are radio/checkbox sets with no single control to anchor to, so the .field
   wrapper carries the id the error summary links to, plus tabindex="-1" so
   focus actually moves rather than only scrolling.

   :focus-visible alone is not enough here: browsers generally withhold it for
   focus moved programmatically, which is exactly how the user arrives. Without
   this rule they would be silently relocated into a 112-control form with no
   indication of where they had landed. */
.field[tabindex]:focus {
  outline: 2px solid var(--brand);
  outline-offset: 6px;
  border-radius: 2px;
}

/* --------------------------------------------------------------------------
   3. TYPE
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--ink);
  text-wrap: balance;
}

h1 { font-size: clamp(2rem, 5vw, var(--t-3xl)); margin-bottom: var(--s-4); }
h2 { font-size: clamp(1.5rem, 3.4vw, var(--t-2xl)); margin-top: var(--s-8); margin-bottom: var(--s-4); }
h3 { font-size: clamp(1.25rem, 2.4vw, var(--t-lg)); margin-top: var(--s-6); margin-bottom: var(--s-3); }
h4 { font-size: var(--t-md); font-family: var(--font-body); font-weight: 600; margin-top: var(--s-5); margin-bottom: var(--s-2); }

p, ul, ol, table, figure, blockquote { margin-bottom: var(--s-4); }
p, li { max-width: var(--measure); }

a { color: var(--brand); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--brand-deep); }

strong { font-weight: 600; }

.lede {
  font-size: clamp(1.125rem, 2.2vw, var(--t-md));
  line-height: 1.55;
  color: var(--ink-soft);
  max-width: 60ch;
  margin-bottom: var(--s-6);
}

.eyebrow {
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin-bottom: var(--s-3);
}

ul, ol { padding-left: 1.25em; }
li { margin-bottom: var(--s-2); }

/* --------------------------------------------------------------------------
   4. LAYOUT
   -------------------------------------------------------------------------- */
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--s-4); }
.wrap--narrow { max-width: var(--wrap-narrow); }

@media (min-width: 720px) { .wrap { padding-inline: var(--s-6); } }

.section { padding-block: var(--s-8); }
.section--lg { padding-block: var(--s-9); }
.section--tint { background: var(--paper-warm); }
.section--deep { background: var(--brand); color: #fff; }
.section--deep h1, .section--deep h2, .section--deep h3 { color: #fff; }
.section--deep a { color: #fff; }

.stack > * + * { margin-top: var(--s-4); }

.grid { display: grid; gap: var(--s-5); }
@media (min-width: 760px) {
  .grid--2 { grid-template-columns: repeat(2, 1fr); }
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
  .grid--sidebar { grid-template-columns: minmax(0,1fr) 300px; gap: var(--s-7); }
}

/* --------------------------------------------------------------------------
   5. HEADER
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: rgba(255,255,255,.94);
  backdrop-filter: saturate(160%) blur(10px);
  border-bottom: 1px solid var(--rule);
}
.site-header__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); min-height: 68px;
}
.brand {
  display: flex; align-items: center; gap: var(--s-3);
  text-decoration: none; color: var(--ink);
  /* A flex item with a nowrap child will happily overflow its own box.
     These two lines make that impossible regardless of future string length. */
  min-width: 0; overflow: hidden;
}
.brand__seal { color: var(--brand); flex: none; }
.brand__mark {
  font-family: var(--font-display);
  /* Shortened. The wordmark was set at 1.0625rem/.13em, which made a
     21-character name ~292px wide — the single widest object in the header,
     and the reason the nav had no room to breathe. Tightening the tracking
     and dropping a step of size takes roughly 45px out of it without
     abbreviating the company name, which a masthead should never do. */
  font-size: 1rem; font-weight: 500;
  letter-spacing: .07em; text-transform: uppercase;
  line-height: 1.15; color: var(--brand);
  /* The wordmark is a logo, not a sentence. It never wraps — a two-line
     "KENYA FLOWER / MERCHANT" in the header reads as a layout failure. */
  white-space: nowrap;
}
.brand__sub  { font-size: var(--t-xs); color: var(--ink-mute); letter-spacing: .06em; text-transform: uppercase; }

/* Measured on the live site: the header needs seal(34) + wordmark(292) +
   toggle(93) + CTA(127) + gaps + 32px gutters = ~626px to sit on one line.
   The wordmark was previously shown from 560px, where it overflowed its
   flex container and ran under the Menu button. It now appears at 680px,
   which is the first width with real air around it. Above 960px the toggle
   disappears and frees a further 105px. */
@media (max-width: 679px) {
  .brand__mark { display: none; }
}

.nav { display: none; }
@media (min-width: 960px) {
  .nav { display: flex; gap: var(--s-5); align-items: center; }
  .nav a {
    font-size: var(--t-sm); color: var(--ink-soft); text-decoration: none;
    padding-block: var(--s-2); border-bottom: 2px solid transparent;
  }
  .nav a:hover, .nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--brand); }
}

/* ── Mobile navigation ──────────────────────────────────────────────────────
   Below 960px the horizontal nav is hidden. Without this disclosure there is
   no navigation at all on a phone — logo and CTA only — which was the state
   before QA caught it.

   A disclosure panel rather than a full-screen overlay: the buyer keeps their
   place on the page, and the header stays where they expect it.
   ------------------------------------------------------------------------- */
.navtoggle {
  display: inline-flex; align-items: center; gap: var(--s-2);
  background: none; border: 1px solid var(--rule); border-radius: var(--radius);
  padding: .55em .8em; color: var(--ink-soft);
  font-size: var(--t-sm); font-weight: 500;
  min-height: 44px;
}
.navtoggle:hover { border-color: var(--ink-mute); color: var(--ink); }
.navtoggle__bars { display: block; width: 18px; height: 12px; position: relative; }
.navtoggle__bars::before,
.navtoggle__bars::after,
.navtoggle__bars i {
  content: ""; position: absolute; left: 0; right: 0; height: 1.5px;
  background: currentColor; border-radius: 2px;
  transition: transform .22s var(--ease), opacity .18s var(--ease);
}
.navtoggle__bars::before { top: 0; }
.navtoggle__bars i      { top: 5.25px; }
.navtoggle__bars::after { bottom: 0; }

.navtoggle[aria-expanded="true"] .navtoggle__bars::before { transform: translateY(5.25px) rotate(45deg); }
.navtoggle[aria-expanded="true"] .navtoggle__bars i       { opacity: 0; }
.navtoggle[aria-expanded="true"] .navtoggle__bars::after  { transform: translateY(-5.25px) rotate(-45deg); }

.navpanel {
  display: none;
  border-top: 1px solid var(--rule);
  background: var(--paper);
  max-height: calc(100dvh - 68px);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.navpanel.is-open { display: block; }
.navpanel ul { list-style: none; margin: 0; padding: var(--s-3) 0 var(--s-5); }
.navpanel li { margin: 0; }
.navpanel a {
  display: flex; align-items: center; min-height: 52px;
  padding: var(--s-2) 0;
  font-family: var(--font-display); font-size: var(--t-md);
  color: var(--ink); text-decoration: none;
  border-bottom: 1px solid var(--rule-soft);
}
.navpanel li:last-child a { border-bottom: 0; }
.navpanel a:hover, .navpanel a[aria-current="page"] { color: var(--brand); }
.navpanel__cta { padding-top: var(--s-4); border-top: 1px solid var(--rule); }

/* The desktop hide must come AFTER the base .navtoggle rule, or the base
   rule wins on equal specificity and the Menu button sits next to the full
   horizontal nav at 1280px. */
@media (min-width: 960px) {
  .navtoggle, .navpanel { display: none; }
}

.header-actions { display: flex; align-items: center; gap: var(--s-3); }

/* At 320px the seal, a labelled toggle and the CTA together leave no air.
   Drop the toggle's text label and keep the icon, which stays a 44px target. */
@media (max-width: 400px) {
  .navtoggle [data-navtoggle-label] { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .navtoggle { padding-inline: .7em; }
  .header-actions { gap: var(--s-2); }
}

/* --------------------------------------------------------------------------
   6. BUTTONS — GET A QUOTE is the primary action everywhere
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .6ch;
  padding: .7em 1.35em;
  font-size: var(--t-sm); font-weight: 600; letter-spacing: .01em;
  border: 1px solid transparent; border-radius: var(--radius);
  text-decoration: none; white-space: nowrap;
  transition: background-color .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.btn--primary { background: var(--brand); color: #fff; }
.btn--primary:hover { background: var(--brand-deep); color: #fff; }
.btn--ghost { background: transparent; color: var(--brand); border-color: var(--rule); }
.btn--ghost:hover { border-color: var(--brand); color: var(--brand-deep); }
.btn--onDeep { background: #fff; color: var(--brand); }
.btn--onDeep:hover { background: var(--paper-warm); color: var(--brand-deep); }
.btn--lg { font-size: var(--t-base); padding: .85em 1.7em; }
.btn--block { width: 100%; }

/* --------------------------------------------------------------------------
   7. CTA BLOCK — max three GET A QUOTE placements per page (Artifact 17)
   -------------------------------------------------------------------------- */
.cta {
  margin-block: var(--s-8);
  padding: var(--s-6);
  background: var(--brand-tint);
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
}
.cta h2 { margin-top: 0; font-size: var(--t-lg); }
.cta p { color: var(--ink-soft); }
.cta__actions { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-4); }

@media (min-width: 760px) { .cta { padding: var(--s-7); } }

/* --------------------------------------------------------------------------
   8. TABLES — specification tables must stay readable at 375px
   -------------------------------------------------------------------------- */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin-bottom: var(--s-5);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}
table { border-collapse: collapse; width: 100%; font-size: var(--t-sm); max-width: none; }
th, td { padding: var(--s-3) var(--s-4); text-align: left; border-bottom: 1px solid var(--rule-soft); vertical-align: top; }
thead th {
  background: var(--paper-warm); font-weight: 600; font-size: var(--t-xs);
  letter-spacing: .05em; text-transform: uppercase; color: var(--ink-soft);
  border-bottom: 1px solid var(--rule); white-space: nowrap;
}
tbody tr:last-child td { border-bottom: 0; }
td.num, th.num { font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   9. EVIDENCE COMPONENTS — dates and sources are visible, not buried
   -------------------------------------------------------------------------- */
.verified {
  display: inline-flex; align-items: center; gap: .5ch;
  font-size: var(--t-xs); color: var(--ink-mute);
  padding: var(--s-1) var(--s-3);
  background: var(--paper-warm); border: 1px solid var(--rule);
  border-radius: 999px;
}

.note {
  padding: var(--s-4) var(--s-5);
  background: var(--paper-warm);
  border-left: 3px solid var(--brand);
  border-radius: 0 var(--radius) var(--radius) 0;
  margin-block: var(--s-5);
}
.note--warn { background: var(--warn-tint); border-left-color: var(--warn); }
.note p:last-child { margin-bottom: 0; }
.note__title { font-weight: 600; margin-bottom: var(--s-2); }

/* Validation summary. Listed once at the top of the form with in-page links,
   rather than repeated beside every field — the pattern that reads best both
   visually and in a screen reader. */
.note--error {
  background: var(--error-tint);
  border-left-color: var(--error);
}
.note--error .note__title { color: var(--error); }
.note--error ul { margin: var(--s-3) 0 0; padding-left: 1.25em; }
.note--error a { color: var(--error); text-decoration: underline; }

/* Each error is a link to the field it belongs to, so each one is a tap target
   and must meet the same 44px rule as every other control. An inline <a> in a
   list item measures ~21px, which fails on a phone precisely when the user is
   already frustrated. Made block-level with a minimum height instead. */
.note--error li { margin: 0; }
.note--error li a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding-block: var(--s-1);
}

[aria-invalid="true"] {
  border-color: var(--error) !important;
  box-shadow: 0 0 0 1px var(--error);
}

.sources {
  margin-top: var(--s-8); padding-top: var(--s-5);
  border-top: 1px solid var(--rule);
  font-size: var(--t-sm); color: var(--ink-soft);
}
.sources h2 { font-size: var(--t-md); font-family: var(--font-body); font-weight: 600; margin-top: 0; }
.sources ol { padding-left: 1.2em; }
.sources li { margin-bottom: var(--s-3); }
.sources .meta { color: var(--ink-mute); font-size: var(--t-xs); }

/* --------------------------------------------------------------------------
   10. FORM — the GET A QUOTE buyer requirement (Artifact 19)
   -------------------------------------------------------------------------- */
.form { max-width: 720px; }

.form__progress {
  display: flex; gap: var(--s-2); margin-bottom: var(--s-6);
  list-style: none; padding: 0; flex-wrap: wrap;
}
.form__progress li {
  flex: 1 1 auto; min-width: 84px; margin: 0;
  font-size: var(--t-xs); color: var(--ink-mute);
  padding-top: var(--s-3); border-top: 3px solid var(--rule);
}
.form__progress li[aria-current="step"] { color: var(--brand); font-weight: 600; border-top-color: var(--brand); }
.form__progress li.is-done { color: var(--ink-soft); border-top-color: var(--brand-tint); }

.fieldset { border: 0; padding: 0; margin: 0 0 var(--s-6); }
.fieldset > legend {
  font-family: var(--font-display); font-size: var(--t-lg);
  margin-bottom: var(--s-2); padding: 0;
}
.fieldset__intro { color: var(--ink-soft); font-size: var(--t-sm); margin-bottom: var(--s-5); }

.field { margin-bottom: var(--s-5); }
.field > label, .field > .label {
  display: block; font-size: var(--t-sm); font-weight: 600; margin-bottom: var(--s-2);
}
.field .hint { display: block; font-size: var(--t-xs); color: var(--ink-mute); margin-bottom: var(--s-2); font-weight: 400; }
.field .req { color: var(--accent); font-weight: 600; }

input[type="text"], input[type="email"], input[type="tel"], input[type="url"],
input[type="number"], select, textarea {
  width: 100%; padding: .65em .8em;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--rule); border-radius: var(--radius);
  font-size: var(--t-base);
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}
input:focus, select:focus, textarea:focus {
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-tint);
  outline: none;
}
textarea { min-height: 8.5em; resize: vertical; line-height: 1.55; }

.choices { display: grid; gap: var(--s-2); }
@media (min-width: 560px) { .choices--2 { grid-template-columns: 1fr 1fr; } }
@media (min-width: 760px) { .choices--3 { grid-template-columns: repeat(3, 1fr); } }

.choice {
  display: flex; align-items: flex-start; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--rule); border-radius: var(--radius);
  cursor: pointer; font-size: var(--t-sm); line-height: 1.45;
  transition: border-color .15s var(--ease), background-color .15s var(--ease);
}
.choice:hover { border-color: var(--ink-mute); }
.choice input { margin-top: .2em; accent-color: var(--brand); flex: none; }
.choice:has(input:checked) { border-color: var(--brand); background: var(--brand-tint); }

.choice--advise { border-style: dashed; color: var(--ink-soft); }

.split { display: grid; gap: var(--s-4); }
@media (min-width: 560px) { .split { grid-template-columns: 1fr 1fr; } }
.split--qty { grid-template-columns: 2fr 1fr; }

.declaration {
  padding: var(--s-5); background: var(--paper-warm);
  border: 1px solid var(--rule); border-radius: var(--radius);
  margin-bottom: var(--s-5);
}
.declaration .choice { background: var(--paper); }

.form__actions {
  display: flex; gap: var(--s-3); align-items: center; flex-wrap: wrap;
  padding-top: var(--s-5); border-top: 1px solid var(--rule);
}

.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.error { color: var(--accent); font-size: var(--t-xs); margin-top: var(--s-2); }
[aria-invalid="true"] { border-color: var(--accent); }

/* --------------------------------------------------------------------------
   11. CARDS
   -------------------------------------------------------------------------- */
.card {
  padding: var(--s-5);
  border: 1px solid var(--rule); border-radius: var(--radius-lg);
  background: var(--paper);
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
}
a.card { text-decoration: none; color: inherit; display: block; }
a.card:hover { border-color: var(--ink-mute); box-shadow: var(--shadow-sm); }
.card h3 { margin-top: 0; font-size: var(--t-md); }
.card p { font-size: var(--t-sm); color: var(--ink-soft); margin-bottom: 0; }

/* --------------------------------------------------------------------------
   12. FOOTER
   -------------------------------------------------------------------------- */
.site-footer {
  margin-top: var(--s-9);
  padding-block: var(--s-8) var(--s-5);
  border-top: 1px solid var(--rule);
  background: var(--paper-warm);
  font-size: var(--t-sm);
  color: var(--ink-soft);
}
/* LAYOUT, rebuilt 2026-09-26. The brand and the link columns used to share a
   single auto-fit grid, so the last column ("Company") wrapped onto a row of
   its own beneath the brand. Now there are two grids: the brand block beside
   the link grid, and the link grid's column count comes from the template as
   --cols, so a new section adds a column rather than an orphan row. */
.site-footer__top { display: grid; gap: var(--s-7); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 1080px) {
  .site-footer__top { grid-template-columns: minmax(220px, 260px) minmax(0, 1fr); gap: var(--s-8); }
}

.site-footer__brand { max-width: 36rem; }
.site-footer__mark { color: var(--ink); margin-bottom: var(--s-4); overflow: visible; }
/* The header hides the wordmark below 680px and never lets it wrap; the footer
   always shows it and lets it wrap on the narrowest phones. */
.site-footer .brand__mark { display: inline; white-space: normal; font-size: .9375rem; }
.site-footer__tagline { margin: 0 0 var(--s-4); max-width: 34ch; line-height: 1.6; }
.site-footer__contact { margin: 0 0 var(--s-5); }
.site-footer__contact a { color: var(--brand); font-weight: 500; text-decoration: none; }
.site-footer__contact a:hover { text-decoration: underline; text-underline-offset: .2em; }
.site-footer__cta { font-size: var(--t-sm); }

.site-footer__nav {
  display: grid; gap: var(--s-6) var(--s-5);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 640px) {
  .site-footer__nav { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 900px) {
  .site-footer__nav { grid-template-columns: repeat(var(--cols, 5), minmax(0, 1fr)); }
}

.site-footer h2 {
  font-size: var(--t-xs); font-family: var(--font-body); font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink);
  margin: 0 0 var(--s-4); padding-bottom: var(--s-3); border-bottom: 1px solid var(--rule);
}
.site-footer h2 a { color: inherit; text-decoration: none; }
.site-footer h2 a:hover { color: var(--brand); }
.site-footer ul { list-style: none; padding: 0; margin: 0; }
.site-footer__col li { margin-bottom: var(--s-3); line-height: 1.4; }
.site-footer__col a { color: var(--ink-soft); text-decoration: none; }
.site-footer__col a:hover { color: var(--brand); text-decoration: underline; text-underline-offset: .2em; }
.site-footer__all { margin-top: var(--s-4); }
.site-footer__col .site-footer__all a { color: var(--brand); font-weight: 500; }

.site-footer__bottom {
  margin-top: var(--s-7); padding-top: var(--s-5); border-top: 1px solid var(--rule);
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: var(--s-3) var(--s-6);
  font-size: var(--t-xs); color: var(--ink-mute);
}
.site-footer__legal { margin: 0; max-width: 72ch; }
.site-footer__meta { display: flex; gap: var(--s-5); }
.site-footer__meta a { color: var(--ink-mute); text-decoration: none; }
.site-footer__meta a:hover { color: var(--ink); text-decoration: underline; }

/* --------------------------------------------------------------------------
   13. MOBILE STICKY CTA — no popups, no interstitials (Master Task §21)
   -------------------------------------------------------------------------- */
.sticky-cta {
  position: fixed; inset: auto 0 0 0; z-index: 60;
  padding: var(--s-3) var(--s-4) calc(var(--s-3) + env(safe-area-inset-bottom));
  background: rgba(255,255,255,.96);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--rule);
  transition: transform .28s var(--ease);
  will-change: transform;
}

/* Hiding is opt-in, applied by JS on init. If the script never runs the bar
   simply stays visible — the primary action is never lost to a failed asset.
   Three identical CTAs in one viewport reads as pressure, so once JS is in
   control the bar waits until the hero has scrolled away. */
.sticky-cta--managed { transform: translateY(105%); }
.sticky-cta--managed.is-visible { transform: none; }

@media (prefers-reduced-motion: reduce) { .sticky-cta { transition: none; } }
@media (min-width: 960px) { .sticky-cta { display: none; } }
@media (max-width: 959px) { body { padding-bottom: 76px; } }

/* --------------------------------------------------------------------------
   14. STAGING BANNER — visible proof the site is not live
   -------------------------------------------------------------------------- */
.staging {
  background: var(--warn-tint); border-bottom: 1px solid #e6d3a8;
  color: var(--warn); font-size: var(--t-xs); text-align: center;
  padding: var(--s-2) var(--s-4); font-weight: 600; letter-spacing: .02em;
}

.skip {
  position: absolute; left: -9999px;
  background: var(--brand); color: #fff; padding: var(--s-3) var(--s-4); z-index: 100;
}
.skip:focus { left: var(--s-4); top: var(--s-4); }

/* --------------------------------------------------------------------------
/* --------------------------------------------------------------------------
   16. IMAGERY — the single biggest lever on whether this looks premium
   --------------------------------------------------------------------------
   Rules:
   - Every image lives in a fixed aspect-ratio box, so nothing reflows on load
     and no crop is left to chance.
   - object-position is settable per image, because a flower's subject is
     rarely dead centre.
   - Where no photograph exists, the box renders a botanical texture rather
     than a grey rectangle. An empty slot should still look considered.
   -------------------------------------------------------------------------- */

.fig {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--paper-deep);
  isolation: isolate;
}
.fig img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
  display: block;
}

.fig--wide    { aspect-ratio: 16 / 9; }
.fig--classic { aspect-ratio: 4 / 3; }
.fig--square  { aspect-ratio: 1 / 1; }
.fig--tall    { aspect-ratio: 3 / 4; }
.fig--stem    { aspect-ratio: 2 / 3; }   /* cut flowers are vertical objects */

/* Portrait crops lose their subject on a phone. Widen them below 640px. */
@media (max-width: 639px) {
  .fig--tall, .fig--stem { aspect-ratio: 4 / 3; }
}

/* A caption that states what the image actually is. Artifact 15 forbids
   letting an image imply an operational capability, so the caption is part
   of the component, not an afterthought. */
.fig__caption {
  margin-top: var(--s-3);
  font-size: var(--t-xs);
  color: var(--ink-mute);
  line-height: 1.5;
}
.fig__caption b { color: var(--ink-soft); font-weight: 600; }

/* Botanical placeholder — a quiet repeating petal motif in brand tint.
   Used wherever a real, licensed photograph is not yet in the register. */
.fig--placeholder {
  background-color: var(--brand-tint);
  background-image:
    radial-gradient(ellipse 7px 13px at 50% 22%, rgba(20,72,58,.16) 99%, transparent 100%),
    radial-gradient(ellipse 13px 7px at 78% 50%, rgba(20,72,58,.16) 99%, transparent 100%),
    radial-gradient(ellipse 7px 13px at 50% 78%, rgba(20,72,58,.16) 99%, transparent 100%),
    radial-gradient(ellipse 13px 7px at 22% 50%, rgba(20,72,58,.16) 99%, transparent 100%),
    radial-gradient(circle 4px at 50% 50%, rgba(20,72,58,.22) 99%, transparent 100%);
  background-size: 96px 96px;
  background-position: center;
  display: grid; place-items: center;
}
.fig--placeholder::after {
  content: attr(data-label);
  font-size: var(--t-xs); letter-spacing: .1em; text-transform: uppercase;
  color: var(--brand); opacity: .55;
  background: rgba(255,255,255,.82);
  padding: var(--s-2) var(--s-4); border-radius: 999px;
}

/* --------------------------------------------------------------------------
   17. HERO
   --------------------------------------------------------------------------
   Type over photography, never type over the busiest part of a photograph.
   A scrim sits between them so contrast is guaranteed rather than hoped for.
   -------------------------------------------------------------------------- */

.hero {
  position: relative; overflow: hidden;
  background: var(--brand-deep);
  min-height: clamp(420px, 62vh, 620px);
  display: flex; align-items: center;
}
/* ── Full-bleed interstitial band ─────────────────────────────────────────
   One image, separating two movements of the page. Full-bleed regardless of
   the wrap, with a height that stays a band on desktop and does not become a
   wall on a phone. Lazy-loaded: it is below the fold by design, so it must
   never compete with the hero for the first paint. */
.band {
  margin: var(--s-8) 0;
  width: 100%;
  overflow: hidden;         /* focal cropping happens inside, never on the page */
  background: var(--deep, #14483a);   /* holds the space before the image paints */
}
.band img {
  display: block;
  width: 100%;
  height: clamp(190px, 26vw, 380px);
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
}
@media (prefers-reduced-motion: no-preference) {
  /* No parallax, no zoom, no fade. Restraint is the brief. */
}

.hero__media { position: absolute; inset: 0; }
.hero__media img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: var(--focal, 50% 45%);
}

/* The scrim exists to guarantee text contrast, not to hide the photograph.
   Earlier values (0.86→0.28 desktop, 0.55→0.90 mobile) turned a dense red rose
   image into a flat dark panel — the photograph was loading and invisible.
   These values were set by measuring contrast against the actual image, not by
   eye: see the QA table in the component library. */
.hero__scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(to right, rgba(9,28,23,.80) 0%, rgba(9,28,23,.50) 42%, rgba(9,28,23,.10) 78%, rgba(9,28,23,0) 100%);
}
@media (max-width: 767px) {
  /* On a phone the text sits over the frame rather than beside it, so the
     scrim runs bottom-up — the top of the image stays legible as a picture,
     and the copy sits in the darkest part of it. */
  .hero { align-items: flex-end; min-height: clamp(460px, 76vh, 620px); }
  .hero__scrim {
    background: linear-gradient(to bottom, rgba(9,28,23,.20) 0%, rgba(9,28,23,.55) 42%, rgba(9,28,23,.80) 100%);
  }
}

.hero__inner {
  position: relative;
  padding-block: clamp(var(--s-7), 9vw, var(--s-9));
  max-width: 44ch;
  color: #fff;
  /* A whisper of shadow buys contrast over the lighter parts of a photograph
     without needing a heavier scrim. */
  text-shadow: 0 1px 14px rgba(9,28,23,.45);
}
.hero h1 { color: #fff; margin-bottom: var(--s-4); }
.hero p  { color: rgba(255,255,255,.88); }
.hero .eyebrow { color: rgba(255,255,255,.72); }
.hero__actions { display: flex; gap: var(--s-3); flex-wrap: wrap; margin-top: var(--s-6); }

/* Below 420px two side-by-side buttons crush. Stack them full width. */
@media (max-width: 419px) {
  .hero__actions { flex-direction: column; }
  .hero__actions .btn { width: 100%; }
}

/* --------------------------------------------------------------------------
   18. BOTANICAL RULE — the one decorative element in the system
   --------------------------------------------------------------------------
   A hairline with a single petal-form at its centre, used to separate major
   sections. It is the seal's geometry at 1/6 scale. Used sparingly: at most
   twice per page.
   -------------------------------------------------------------------------- */

.botrule {
  display: flex; align-items: center; gap: var(--s-4);
  margin-block: var(--s-8);
  color: var(--rule);
}
.botrule::before, .botrule::after {
  content: ""; flex: 1; height: 1px; background: currentColor;
}
.botrule svg { flex: none; color: var(--brand); opacity: .5; }

/* --------------------------------------------------------------------------
   19. CARDS WITH IMAGERY
   -------------------------------------------------------------------------- */

.cardgrid { display: grid; gap: var(--s-5); }
@media (min-width: 620px)  { .cardgrid--2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 860px)  { .cardgrid--3 { grid-template-columns: repeat(3, 1fr); } }

.pcard {
  display: flex; flex-direction: column;
  border: 1px solid var(--rule); border-radius: var(--radius-lg);
  overflow: hidden; background: var(--paper);
  text-decoration: none; color: inherit;
  transition: border-color .2s var(--ease), transform .2s var(--ease), box-shadow .2s var(--ease);
}
.pcard:hover { border-color: var(--ink-mute); box-shadow: var(--shadow-sm); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .pcard:hover { transform: translateY(-2px); }
}
.pcard .fig { border-radius: 0; }
.pcard__body { padding: var(--s-5); display: flex; flex-direction: column; gap: var(--s-2); flex: 1; }
.pcard__body h3 { margin: 0; font-size: var(--t-md); }
.pcard__body p  { margin: 0; font-size: var(--t-sm); color: var(--ink-soft); }
.pcard__meta {
  margin-top: auto; padding-top: var(--s-3);
  font-size: var(--t-xs); color: var(--ink-mute);
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   20. SPECIFICATION TABLES ON SMALL SCREENS
   --------------------------------------------------------------------------
   A two-column reference table is the most common shape on this site and it
   reads badly as a horizontal scroller on a phone. Below 620px it becomes a
   stack of labelled rows using the header text from data-label.

   Wider tables keep the scroll container — collapsing a 5-column trade table
   into stacked pairs is worse, not better — but they get a visible affordance
   so nobody misses that there is more to the right.
   -------------------------------------------------------------------------- */

@media (max-width: 619px) {
  .table--stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .table--stack, .table--stack tbody, .table--stack tr, .table--stack td { display: block; width: 100%; }
  .table--stack tr {
    border-bottom: 1px solid var(--rule);
    padding: var(--s-4) 0;
  }
  .table--stack tr:last-child { border-bottom: 0; }
  .table--stack td { border: 0; padding: 0 var(--s-4) var(--s-2); }
  .table--stack td::before {
    content: attr(data-label);
    display: block;
    font-size: var(--t-xs); font-weight: 600;
    letter-spacing: .06em; text-transform: uppercase;
    color: var(--ink-mute); margin-bottom: var(--s-1);
  }
  .table--stack td:first-child {
    font-family: var(--font-display); font-size: var(--t-md); color: var(--ink);
  }
  .table--stack td:first-child::before { display: none; }
  /* A stacked table needs no scroll frame. */
  .table-scroll:has(.table--stack) { border: 0; overflow: visible; }
}

/* Scroll affordance for tables that stay wide. */
.table-scroll { position: relative; }
.table-scroll[data-scrollable="true"]::after {
  content: "";
  position: absolute; top: 0; right: 0; bottom: 0; width: 36px;
  background: linear-gradient(to right, rgba(255,255,255,0), rgba(255,255,255,.95));
  pointer-events: none;
}
.table-hint {
  display: none;
  font-size: var(--t-xs); color: var(--ink-mute); margin: calc(var(--s-5) * -1 + var(--s-2)) 0 var(--s-5);
}
@media (max-width: 619px) { .table-hint { display: block; } }

/* --------------------------------------------------------------------------
   21. TOUCH TARGETS
   --------------------------------------------------------------------------
   Every interactive element clears 44px on a coarse pointer. Checked rather
   than assumed — see the component library QA table.
   -------------------------------------------------------------------------- */

@media (pointer: coarse) {
  .btn { min-height: 48px; padding-inline: 1.5em; }
  .choice { min-height: 48px; align-items: center; }
  input[type="text"], input[type="email"], input[type="tel"], input[type="url"],
  input[type="number"], select, textarea { min-height: 48px; font-size: 16px; }
  .nav a { min-height: 44px; display: inline-flex; align-items: center; }
  .site-footer__col a, .site-footer__meta a, .site-footer__contact a { display: inline-block; padding-block: 6px; }
  .site-footer__col li { margin-bottom: 2px; }
}
/* 16px on inputs also stops iOS zooming the page on focus. */

/* --------------------------------------------------------------------------
   22. SECTION RHYTHM
   -------------------------------------------------------------------------- */

.section { padding-block: clamp(var(--s-7), 7vw, var(--s-9)); }
.section--tight { padding-block: clamp(var(--s-6), 5vw, var(--s-7)); }

.lead-in { max-width: 58ch; }
.measure { max-width: var(--measure); }

/* Two-column prose + aside, collapsing cleanly. */
.duo { display: grid; gap: var(--s-6); align-items: start; }
@media (min-width: 880px) { .duo { grid-template-columns: minmax(0,1.35fr) minmax(0,1fr); gap: var(--s-8); } }

/* --------------------------------------------------------------------------
   23. SMALL-SCREEN CORRECTIONS
   --------------------------------------------------------------------------
   Tested at 320, 375, 390 and 430px. Each rule below fixes something that was
   actually wrong at that width, not something that might be.
   -------------------------------------------------------------------------- */

@media (max-width: 400px) {
  :root { --s-5: 1.25rem; --s-6: 1.5rem; }
  .wrap { padding-inline: var(--s-4); }        /* 16px gutter, never less */
  .cta { padding: var(--s-5); }
  .panel, .pcard__body { padding: var(--s-4); }
  h1 { font-size: clamp(1.75rem, 8.5vw, 2.25rem); }
  .lede { font-size: 1.0625rem; }
}

/* Long unbroken strings — commodity codes, URLs, emails — must not push the
   layout wider than the viewport. */
body { overflow-wrap: break-word; }
code, .mono { font-family: var(--font-mono); overflow-wrap: anywhere; }

/* --------------------------------------------------------------------------
   24. MOTION — used to confirm an action, never to decorate
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  .reveal { opacity: 0; transform: translateY(10px); transition: opacity .5s var(--ease), transform .5s var(--ease); }
  .reveal.is-in { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   25. ACCESSIBILITY HELPERS
   -------------------------------------------------------------------------- */

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

@media (forced-colors: active) {
  .btn { border: 1px solid ButtonText; }
  .fig--placeholder { background: Canvas; }

  /* FORM FOCUS MUST SURVIVE HIGH CONTRAST MODE.
     Form controls indicate focus with `border-color` + `box-shadow` and an
     explicit `outline: none` (see input:focus). In Windows High Contrast /
     forced-colors, box-shadow is not painted and author border colours are
     overridden — so that combination leaves a keyboard user with NO focus
     indicator at all, on a 112-control form.

     Restoring a real outline in this mode only. Normal rendering is untouched,
     so the design is unchanged for everyone else. */
  input:focus, select:focus, textarea:focus,
  .field[tabindex]:focus {
    outline: 2px solid Highlight;
    outline-offset: 2px;
  }
}

/* --------------------------------------------------------------------------
   15. PRINT
   -------------------------------------------------------------------------- */
@media print {
  .site-header, .site-footer, .sticky-cta, .cta, .staging { display: none !important; }
  body { font-size: 11pt; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #555; }
}

/* ---------------------------------------------------------------------------
   MARKET PAGES — regime card and unresolved block
   Artifact 16, BUILD PIPELINE. Two components carry the editorial weight of a
   destination page, so it reads as a considered market brief rather than a
   country template with the name changed.
   --------------------------------------------------------------------------- */

.regime {
  margin: var(--s-7) 0;
  padding: var(--s-6);
  background: var(--paper-warm);
  border-top: 3px solid var(--brand);
}
.regime__h {
  font-family: var(--font-display);
  font-size: var(--t-lg);
  line-height: 1.2;
  margin: 0 0 var(--s-5);
  color: var(--brand-deep);
}
.regime__list { margin: 0; }
.regime__row {
  display: grid;
  grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
  gap: var(--s-3) var(--s-5);
  padding: var(--s-4) 0;
  border-top: 1px solid var(--rule);
}
.regime__row:first-child { border-top: 0; padding-top: 0; }
.regime__term {
  font-size: var(--t-sm);
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--ink-soft);
  margin: 0;
}
.regime__desc { margin: 0; }
.regime__value {
  display: block;
  font-size: var(--t-md);
  font-weight: 600;
  color: var(--ink);
}
/* A visible unknown is more useful to a buyer than a silent one. */
.regime__value--pending {
  color: var(--warn);
  font-variant-caps: all-small-caps;
  letter-spacing: 0.06em;
}
.regime__note {
  display: block;
  margin-top: var(--s-2);
  font-size: var(--t-sm);
  color: var(--ink-soft);
}
.regime__asat {
  display: block;
  margin-top: var(--s-2);
  font-size: var(--t-xs);
  color: var(--ink-mute);
  font-variant-numeric: tabular-nums;
}
.regime__limit {
  margin: var(--s-5) 0 0;
  padding-top: var(--s-4);
  border-top: 1px solid var(--rule);
  font-size: var(--t-sm);
  color: var(--ink-mute);
}

.unresolved {
  margin: var(--s-7) 0;
  padding-left: var(--s-5);
  border-left: 3px solid var(--accent);
}
.unresolved__h {
  font-family: var(--font-display);
  font-size: var(--t-lg);
  line-height: 1.2;
  margin: 0 0 var(--s-3);
  color: var(--ink);
}
.unresolved__intro {
  margin: 0 0 var(--s-5);
  color: var(--ink-soft);
}
.unresolved__list { margin: 0; padding: 0; list-style: none; }
.unresolved__list li {
  padding: var(--s-4) 0;
  border-top: 1px solid var(--rule-soft);
}
.unresolved__list li:first-child { border-top: 0; padding-top: 0; }
.unresolved__q { display: block; font-weight: 600; color: var(--ink); }
.unresolved__why {
  display: block;
  margin-top: var(--s-2);
  font-size: var(--t-sm);
  color: var(--ink-soft);
}

@media (max-width: 40rem) {
  .regime { padding: var(--s-5) var(--s-4); }
  .regime__row { grid-template-columns: 1fr; gap: var(--s-2); }
  .regime__term { font-size: var(--t-xs); text-transform: uppercase; letter-spacing: 0.08em; }
}

/* --------------------------------------------------------------------------
   HOMEPAGE CORRECTION, 2026-09-23
   The decorative rose band argued against the headline. Replaced by the
   specification chain; table hierarchy, CTA weight and vertical rhythm fixed
   alongside it.
   -------------------------------------------------------------------------- */

.speclane__h {
  font-family: var(--font-display);
  margin: var(--s-2) 0 var(--s-6);
  max-width: 22ch;
}
.speclane__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--rule);
  border-block: 1px solid var(--rule);
}
.speclane__item {
  background: var(--paper-warm);
  padding: var(--s-5);
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}
.speclane__num {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--ink-mute);
  letter-spacing: 0.08em;
}
.speclane__field {
  font-family: var(--font-display);
  font-size: var(--t-md);
  line-height: 1.15;
  color: var(--ink);
}
/* The value is the informational payload — it carries the accent, sparingly. */
.speclane__value {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--brand);
}
.speclane__note {
  font-size: var(--t-sm);
  color: var(--ink-soft);
  margin-top: auto;
}
.speclane__foot {
  margin: var(--s-6) 0 0;
  max-width: 62ch;
  color: var(--ink-soft);
  font-size: var(--t-sm);
}

@media (max-width: 900px) { .speclane__list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) {
  .speclane__list { grid-template-columns: 1fr; }
  .speclane__item { padding: var(--s-4); }
  .speclane__note { margin-top: 0; }
}

/* Trade table — hierarchy follows the evidence, never decoration. */
.tradeintro { max-width: 68ch; }
.tradeintro p:last-child { margin-bottom: var(--s-6); }

.table--trade td.market { font-weight: 600; }
.table--trade td.num { font-variant-numeric: tabular-nums; }
.table--trade td.share {
  font-size: var(--t-md);
  font-weight: 600;
  color: var(--ink);
}
.table--trade td.rank { color: var(--ink-mute); }
/* Rank 1 stated in full ink while the rest recede. No colour, no badge. */
.table--trade tr.is-lead td.rank { color: var(--ink); font-weight: 600; }
.table--trade tr.is-lead td.market::after {
  content: "";
  display: block;
  width: 1.75rem;
  height: 2px;
  margin-top: var(--s-2);
  background: var(--brand);
}

/* The commercial destination of the homepage. */
.cta--strong {
  background: var(--brand-tint);
  border: 0;
  border-top: 3px solid var(--brand);
  box-shadow: 0 1px 0 var(--rule), 0 12px 32px -24px rgba(20, 72, 58, .45);
}
.cta--strong h2 { font-size: var(--t-xl); color: var(--brand-deep); }
.cta--strong p { color: var(--ink-soft); max-width: 62ch; }
@media (max-width: 560px) {
  .cta--strong .cta__actions .btn { width: 100%; justify-content: center; }
}

/* The measured gap between the table's source note and the quotation block was
   176px at 1280 and 128px at 375 — the section's own padding plus the CTA's
   --s-8 margin, stacked. Whitespace that exists because two components each
   reserved their own does not read as composure. The section padding keeps the
   separation; the block's duplicate margin goes. */
.cta--strong { margin-block: 0; }
.section--tight .fig__caption { margin-bottom: 0; }

/* ==========================================================================
   KFM DESIGN SYSTEM — COMMERCIAL COMPONENTS
   Added 2026-09-23. Benchmarked against a mature origin-merchant site, then
   built for a different and harder problem: that site earns its depth partly
   from capability claims (available lots, pre-shipment samples, FOB terms).
   KFM cannot make those and must earn depth from precision instead.
   So the components below are built to make EVIDENCE the luxury object:
   dated facts, stated boundaries and specification fields are the things
   given the most typographic care.
   ========================================================================== */

/* --- Positioning strip: what / who / how, answered above the fold ------- */
.stance {
  border-bottom: 1px solid var(--rule);
  background: var(--paper);
}
.stance__list {
  display: grid; grid-template-columns: repeat(3, 1fr);
  margin: 0; padding: 0; list-style: none;
}
.stance__item { padding: var(--s-5) 0; }
.stance__item + .stance__item { padding-left: var(--s-5); border-left: 1px solid var(--rule-soft); }
.stance__k {
  display: block; font-size: var(--t-xs); letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-mute); margin-bottom: var(--s-2);
}
.stance__v { display: block; font-family: var(--font-display); font-size: var(--t-md); line-height: 1.25; color: var(--ink); }
@media (max-width: 720px) {
  .stance__list { grid-template-columns: 1fr; }
  .stance__item + .stance__item { padding-left: 0; border-left: 0; border-top: 1px solid var(--rule-soft); }
  .stance__item { padding: var(--s-4) 0; }
}

/* --- Section opener ------------------------------------------------------ */
.opener { max-width: 60ch; margin-bottom: var(--s-6); }
.opener__h { font-family: var(--font-display); margin: var(--s-2) 0 var(--s-3); }
.opener__p { color: var(--ink-soft); margin: 0; }

/* --- Category cards: product entry points ------------------------------- */
.cats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-4); }
.cat {
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-5); background: var(--paper);
  border: 1px solid var(--rule); border-radius: var(--radius-lg);
  text-decoration: none; color: inherit;
  transition: border-color .18s ease, transform .18s ease;
}
a.cat:hover { border-color: var(--brand); transform: translateY(-2px); }
.cat__name { font-family: var(--font-display); font-size: var(--t-lg); line-height: 1.1; color: var(--ink); }
.cat__latin { font-size: var(--t-xs); font-style: italic; color: var(--ink-mute); }
.cat__note { font-size: var(--t-sm); color: var(--ink-soft); margin-top: auto; }
.cat__meta {
  font-size: var(--t-xs); color: var(--brand); font-weight: 600;
  letter-spacing: .04em;
}
@media (max-width: 900px) { .cats { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .cats { grid-template-columns: 1fr; } }

/* --- Trust triad --------------------------------------------------------- */
.pillars { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-6); }
.pillar__h { font-family: var(--font-display); font-size: var(--t-md); margin: 0 0 var(--s-3); color: var(--ink); }
.pillar__h::before {
  content: ""; display: block; width: 1.75rem; height: 2px;
  background: var(--brand); margin-bottom: var(--s-3);
}
.pillar p { color: var(--ink-soft); font-size: var(--t-sm); margin: 0; }
@media (max-width: 860px) { .pillars { grid-template-columns: 1fr; gap: var(--s-5); } }

/* --- Process: how a quotation is built ---------------------------------- */
.steps { list-style: none; margin: 0; padding: 0; counter-reset: step; }
.step {
  display: grid; grid-template-columns: 3.5rem 1fr; gap: var(--s-4);
  padding: var(--s-5) 0; border-top: 1px solid var(--rule-soft);
}
.step:first-child { border-top: 0; }
.step__n {
  font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--brand); letter-spacing: .08em; padding-top: .3em;
}
.step__h { font-family: var(--font-display); font-size: var(--t-md); margin: 0 0 var(--s-2); }
.step__p { margin: 0; color: var(--ink-soft); font-size: var(--t-sm); max-width: 62ch; }
@media (max-width: 560px) { .step { grid-template-columns: 2.5rem 1fr; gap: var(--s-3); } }

/* --- Buyer resource cards ----------------------------------------------- */
.resources { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s-4); }
.res {
  display: block; padding: var(--s-5);
  border: 1px solid var(--rule); border-radius: var(--radius-lg);
  background: var(--paper); text-decoration: none; color: inherit;
  transition: border-color .18s ease;
}
a.res:hover { border-color: var(--brand); }
.res__h { font-family: var(--font-display); font-size: var(--t-md); margin: 0 0 var(--s-2); color: var(--ink); }
.res__p { margin: 0; font-size: var(--t-sm); color: var(--ink-soft); }
.res__go { display: inline-block; margin-top: var(--s-3); font-size: var(--t-sm); color: var(--brand); font-weight: 600; }
/* A resource that exists as evidence but has no page yet is shown as such,
   never as a live link that goes nowhere. Empty sections are how a site
   starts looking unfinished. */
.res--pending { background: var(--paper-warm); border-style: dashed; }
.res--pending .res__h { color: var(--ink-soft); }
.res__state {
  display: inline-block; margin-top: var(--s-3);
  font-size: var(--t-xs); letter-spacing: .08em; text-transform: uppercase;
  color: var(--warn);
}
@media (max-width: 720px) { .resources { grid-template-columns: 1fr; } }

/* --- Navigation descriptors --------------------------------------------- */
.nav a { display: inline-flex; flex-direction: column; line-height: 1.2; }
.nav__desc { display: none; }
@media (min-width: 1240px) {
  .nav__desc {
    display: block; font-size: 11px; color: var(--ink-mute);
    font-weight: 400; margin-top: 2px;
    /* ONE LINE, ALWAYS. Wrapping is what produced the defect: five descriptors
       breaking at five different words and depths, giving a 64px nav with a
       ragged bottom edge. The short forms in header.php are written to fit;
       nowrap guarantees it stays that way if one is ever lengthened. */
    white-space: nowrap;
  }
}
.navpanel .nav__desc { display: block; font-size: var(--t-xs); color: var(--ink-mute); margin-top: 2px; }

/* The brand was being flex-shrunk and clipped — at 1280 it rendered as
   "KENYA FLOWER MERCHAN". A masthead that truncates the company name is the
   one thing a header must never do, so it no longer shrinks; the nav gives
   way instead, and the descriptors only appear once there is genuinely room. */
.site-header .brand { flex: 0 0 auto; }
.site-header .nav { min-width: 0; }
@media (max-width: 1239px) { .nav__desc { display: none; } }

/* Genus table. Same hierarchy language as the trade table — the notable rows
   in full ink, the rest receding — so the two data moments on the homepage
   read as one system rather than two designs. */
.table--genus td.market { font-weight: 600; }
.table--genus td.genus { font-style: italic; color: var(--ink-mute); font-size: var(--t-sm); }
.table--genus td.share { font-size: var(--t-md); font-weight: 600; color: var(--ink-soft); }
.table--genus tr.is-lead td.share { color: var(--ink); }
.table--genus tr.is-lead td.market::after {
  content: ""; display: block; width: 1.75rem; height: 2px;
  margin-top: var(--s-2); background: var(--brand);
}

/* Section index. A section that lists nothing is a dead end — /markets held the
   site's only acquisition page and linked to it from nowhere. */
.sectionlist { display: grid; gap: var(--s-4); margin: var(--s-6) 0; }
.sectionlist__item {
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-5); text-decoration: none; color: inherit;
  background: var(--paper-warm); border-left: 3px solid var(--brand);
  transition: transform .18s ease, background .18s ease;
}
.sectionlist__item:hover { background: var(--brand-tint); transform: translateX(2px); }
.sectionlist__title {
  font-family: var(--font-display); font-size: var(--t-lg); line-height: 1.2; color: var(--ink);
}
.sectionlist__lede { font-size: var(--t-sm); color: var(--ink-soft); }
.sectionlist__meta { font-size: var(--t-xs); color: var(--ink-mute); font-variant-numeric: tabular-nums; }
/* Group headings inside a section index. Only rendered where a page declares a
   `group`; /specifications and /markets set none and are unaffected. The first
   heading loses its top margin because the grid gap already provides it. */
.sectionlist__group {
  font-family: var(--font-display); font-size: var(--t-md); line-height: 1.2;
  color: var(--ink-soft); margin: var(--s-5) 0 0;
  padding-bottom: var(--s-2); border-bottom: 1px solid var(--rule);
  font-weight: 500;
}
.sectionlist__group:first-child { margin-top: 0; }

/* Mobile nav panel: the label and its descriptor were rendering side by side.
   `.navpanel a` is display:flex with the default row direction, so the two
   spans became flex items in a row — "SpecificationsStem length, head size".
   The earlier rule targeted `.nav a`, which never matched this panel. */
.navpanel li a { flex-direction: column; align-items: flex-start; gap: 2px; }
.navpanel li a > span:first-child { font-family: var(--font-display); }

/* --------------------------------------------------------------------------
   RELATED PAGES
   Same visual language as .sectionlist — left rule in brand, warm paper, a
   quiet forward affordance — because they do the same job in different places
   and the site should not have two dialects for "go here next".
   -------------------------------------------------------------------------- */
.related { margin: var(--s-7) 0 0; }
.related__h {
  font-family: var(--font-display); font-size: var(--t-lg); line-height: 1.2;
  margin: 0 0 var(--s-4); padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--rule);
}
.related__grid { display: grid; gap: var(--s-4); grid-template-columns: repeat(2, 1fr); }
@media (max-width: 720px) { .related__grid { grid-template-columns: 1fr; } }
.related__item {
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-5); text-decoration: none; color: inherit;
  background: var(--paper-warm); border-left: 3px solid var(--brand);
  transition: transform .18s var(--ease), background .18s var(--ease);
}
.related__item:hover { background: var(--brand-tint); transform: translateX(2px); }
.related__title {
  font-family: var(--font-display); font-size: var(--t-md); line-height: 1.25; color: var(--ink);
}
.related__lede { font-size: var(--t-sm); color: var(--ink-soft); }
.related__go {
  font-size: var(--t-xs); font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--brand);
}

/* --------------------------------------------------------------------------
   FAQ
   Native <details>. No script, no ARIA emulation, and it survives the strict
   CSP because it needs no script at all. The marker is drawn with a border
   rather than an icon font so it inherits colour and needs no extra request.
   -------------------------------------------------------------------------- */
.faq { margin: var(--s-7) 0 0; }
.faq__h {
  font-family: var(--font-display); font-size: var(--t-lg); line-height: 1.2;
  margin: 0 0 var(--s-4); padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--rule);
}
.faq__item { border-bottom: 1px solid var(--rule-soft); }
.faq__q {
  display: flex; align-items: flex-start; gap: var(--s-3);
  padding: var(--s-4) 0; cursor: pointer; list-style: none;
  font-weight: 600; color: var(--ink); line-height: 1.4;
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q::before {
  content: ""; flex: none; width: .5em; height: .5em; margin-top: .45em;
  border-right: 2px solid var(--brand); border-bottom: 2px solid var(--brand);
  transform: rotate(-45deg); transition: transform .18s var(--ease);
}
.faq__item[open] .faq__q::before { transform: rotate(45deg); }
.faq__a { padding: 0 0 var(--s-5) calc(.5em + var(--s-3)); color: var(--ink-soft); }
.faq__a > :first-child { margin-top: 0; }
.faq__a > :last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   SPECIFICATION TABLE — the product layer's buyer tool
   The benchmark writes specifications as prose; a buyer comparing two origins
   cannot scan a paragraph. Every row carries the framework it belongs to,
   because a VBN auction convention, a Kenyan origin fact and a destination
   country's legal requirement are three different kinds of truth.
   -------------------------------------------------------------------------- */
.spec { margin: var(--s-6) 0; }
.spec__h { font-family: var(--font-display); font-size: var(--t-xl); line-height: 1.2; margin: 0 0 var(--s-4); }
.table--spec th[scope="row"] { font-weight: 600; color: var(--ink); white-space: normal; min-width: 10rem; width: 28%; }
.spec__val { }
.spec__note, .spec__auth, .spec__asat {
  display: block; font-size: var(--t-xs); color: var(--ink-mute); margin-top: var(--s-1);
}
.spec__asat { font-variant-numeric: tabular-nums; }
.table--spec tr.is-notestablished .spec__val { color: var(--ink-mute); }
.spec__limit {
  font-size: var(--t-sm); color: var(--ink-soft);
  border-left: 3px solid var(--rule); padding-left: var(--s-4); margin-top: var(--s-4);
}

/* Evidence-status chip. Only ever rendered for the two abnormal states — an
   "Established" badge on every row would be decoration, and would dilute the
   two that carry information. */
.chip {
  display: inline-block; margin-left: var(--s-2);
  font-size: .75rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  padding: .2em .55em; border-radius: 2px; white-space: nowrap;
}
.chip--notestablished { background: var(--paper-deep); color: var(--ink-soft); }
.chip--verify { background: var(--warn-tint); color: var(--warn); }

/* Framework tag. Three frameworks, three weights — origin is the site's own
   subject and reads plainest; destination is law and carries the accent. */
.fw {
  display: inline-block; font-size: var(--t-xs); font-weight: 600;
  letter-spacing: .03em; white-space: nowrap;
}
.fw--origin      { color: var(--ink-soft); }
.fw--vbn         { color: var(--brand); }
.fw--destination { color: var(--accent); }

@media (forced-colors: active) {
  .chip { border: 1px solid ButtonText; }
  .related__item { border-left-color: ButtonText; }
}

/* Heading anchors (prose.php gives every h2/h3 an id, 2026-09-25). The header
   is sticky, so a fragment link would otherwise land the heading underneath it. */
.prose h2, .prose h3 { scroll-margin-top: 5.5rem; }

/* The eyebrow on child pages is a link to the parent hub (see the templates).
   It keeps the eyebrow's colour and gains an underline only on hover/focus. */
.eyebrow a { color: inherit; text-decoration: none; }
.eyebrow a:hover, .eyebrow a:focus-visible { text-decoration: underline; text-underline-offset: 0.2em; }

/* Preformatted blocks (the chargeable-weight formula on the quotation page)
   scroll inside themselves instead of widening the page. Found at 320 px on
   26 Sep 2026: the formula pushed the document to 633 px. */
.prose pre {
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  font-size: var(--t-sm);
  line-height: 1.5;
}
.prose pre code { white-space: pre; }

/* --------------------------------------------------------------------------
   25. PRE-LAUNCH VISUAL PASS — 26 Sep 2026
   Each rule fixes something measured in a real render, at the width noted.
   -------------------------------------------------------------------------- */

/* Flower specification tables at phone width. The row label never wrapped, so
   the longest label ("Bunch weight and stem length, as observed") set a 349px
   column inside a 341px frame: a phone saw a column of labels and nothing
   else, with rows up to 600px tall. Below 620px each row becomes a labelled
   block — dimension, then value with its status chip and note, then the
   framework line — like the site's other stacked tables. */
/* Extended to 1023px after 768px and 900px renders showed 382-403px rows: in
   the 696px column three columns with long notes are too narrow. From 1024px
   the table breaks out of the column (see the wide-table rule) and fits. */
@media (max-width: 1023px) {
  .table--spec thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .table--spec, .table--spec tbody, .table--spec tr, .table--spec th, .table--spec td { display: block; width: 100%; min-width: 0; }
  .table--spec tr { padding: var(--s-4) var(--s-4); border-bottom: 1px solid var(--rule-soft); }
  .table--spec tr:last-child { border-bottom: 0; }
  .table--spec th[scope="row"] {
    border: 0; padding: 0 0 var(--s-2); width: 100%;
    font-family: var(--font-display); font-weight: 500; font-size: var(--t-md); line-height: 1.25;
  }
  .table--spec td { border: 0; padding: 0; }
  .table--spec .spec__val { margin-bottom: var(--s-3); }
  .table--spec .chip { margin-left: 0; margin-top: var(--s-2); }
  .table--spec .spec__fw { display: flex; flex-wrap: wrap; gap: 0 var(--s-3); align-items: baseline; }
  .table--spec .spec__fw .spec__auth, .table--spec .spec__fw .spec__asat { display: inline; margin: 0; }
}

/* Prose tables of up to three columns stack on phones (site/snippets/prose.php
   adds .table--stack.table--auto and the data-label on every cell). Measured at
   375px before this: rows up to 669px tall in 2-3 squeezed columns. In prose the
   first cell is a row label, set in the body face rather than the display face
   the home page uses for flower names, and aligned with the text around it. */
@media (max-width: 619px) {
  .table--auto td { padding-inline: 0; }
  .table--auto td:first-child {
    font-family: var(--font-body); font-weight: 600; font-size: var(--t-base); color: var(--ink);
    padding-bottom: var(--s-2);
  }
  .table--auto td:empty { display: none; }
  .table--auto td[data-label=""]::before { display: none; }
}

/* The wordmark on phones. Below 680px the header showed only the seal, so a
   buyer on a phone never saw the company's name on the first screen. From
   370px there is room beside the seal for a deliberate two-line lockup; the
   smallest phones keep the seal alone. */
@media (min-width: 375px) and (max-width: 519px) {
  /* Measured budget at 375px: 343px row, 181px of buttons, 16px gap, 42px of
     seal and gap, leaving 104px. "KENYA FLOWER" at 11px and .06em is 99px. */
  .site-header .brand__mark {
    display: block; white-space: normal; max-width: 104px;
    font-size: 11px; line-height: 1.2; letter-spacing: .06em;
  }
  .site-header .brand { gap: var(--s-2); }
}

/* One quote button at a time on phones. Once the sticky bar is showing, the
   header's button is a duplicate an inch away; site.js marks the document and
   the header button steps back. */
@media (max-width: 959px) {
  .has-sticky-cta .site-header .btn--primary { visibility: hidden; }
}

/* Long page titles on phones. The median H1 is 84 characters; at 32px a
   114-character market title ran to seven lines and filled the first screen.
   The home hero keeps its larger setting. */
@media (max-width: 480px) {
  h1 { font-size: clamp(1.625rem, 7.4vw, 2rem); line-height: 1.18; }
  .hero h1 { font-size: clamp(1.875rem, 9vw, 2.25rem); }
}

/* THE LIBRARY — the home page index, redesigned 2026-09-26 (see home.php). */
.library { margin-top: var(--s-7); display: grid; gap: var(--s-6); }
.library__shelf { border-top: 1px solid var(--rule); padding-top: var(--s-5); }
.library__h { font-size: var(--t-xl); margin: 0; }
.library__h a { color: var(--ink); text-decoration: none; }
.library__h a:hover { color: var(--brand); }
.library__count {
  margin: var(--s-1) 0 var(--s-3); font-size: var(--t-xs); font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-mute);
}
.library__desc { margin: 0 0 var(--s-4); font-size: var(--t-sm); color: var(--ink-soft); max-width: 42ch; }
.library__all { font-size: var(--t-sm); font-weight: 600; color: var(--brand); text-decoration: none; }
.library__all:hover { text-decoration: underline; text-underline-offset: .2em; }
.library__list { list-style: none; margin: var(--s-4) 0 0; padding: 0; }
.library__list li { border-bottom: 1px solid var(--rule-soft); break-inside: avoid; }
.library__list a {
  display: block; padding: .7rem 0; color: var(--ink); text-decoration: none;
  font-size: var(--t-base); line-height: 1.35;
}
.library__list a:hover { color: var(--brand); }
.library__list a:focus-visible { outline-offset: 2px; }
/* Phones: heading, count, one line, six titles, then the link to the hub,
   which lists the rest in full. */
@media (max-width: 767px) {
  .library__shelf { display: flex; flex-direction: column; }
  .library__intro { display: contents; }
  .library__list { order: 4; margin-top: 0; }
  .library__list li:nth-child(n+7) { display: none; }
  .library__all { order: 5; margin-top: var(--s-3); }
}
@media (min-width: 768px) {
  .library__shelf { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: var(--s-6); }
  /* The negative margin lifts the first title level with the shelf heading. */
  .library__list { margin-top: -.7rem; column-count: 2; column-gap: var(--s-6); }
}
@media (min-width: 768px) and (max-width: 1023px) {
  /* Tablets: the shelf intro above, the titles in two columns beneath. */
  .library__shelf { display: block; }
  .library__list { margin-top: var(--s-4); column-count: 2; }
}

/* Quote progress on phones. Six labels wrapped into two rows of three, the
   second row's bars running into the first row's words. Below 560px: one row
   of six bars and a single caption for the current step. The labels stay in
   the markup for assistive technology (font-size 0 does not hide them from it). */
@media (max-width: 559px) {
  .form__progress {
    position: relative; display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 4px; padding-bottom: 1.9rem; counter-reset: kfmstep;
  }
  .form__progress li { min-width: 0; font-size: 0; padding-top: 0; counter-increment: kfmstep; }
  .form__progress li[aria-current="step"]::after {
    content: "Step " counter(kfmstep) " of 6: " attr(data-label);
    position: absolute; left: 0; bottom: 0;
    font-size: var(--t-xs); font-weight: 600; letter-spacing: .02em; color: var(--brand);
  }
}

/* Wide tables on wide screens. Article pages set text in a centred 696px
   column, and eleven data tables on nine pages (five and six-column trade
   series, the flower inspection table) scrolled sideways inside it at 1440px
   with half the screen empty. From 1024px a table takes the width it needs,
   centred on the column, up to 1080px; a table that fits the column keeps it. */
@media (min-width: 1024px) {
  main .table-scroll {
    width: max-content; min-width: 100%; max-width: min(1080px, calc(100vw - 4rem));
    position: relative; left: 50%; transform: translateX(-50%);
  }
}

/* Keyboard focus on the quote form. The input:focus rule above removes the
   outline and relies on a 3px --brand-tint ring, which on a 13px checkbox was
   barely visible: tabbing through a list of option cards gave almost no sign
   of position. The whole card now carries the focus outline, and the ring on
   text fields is strengthened. */
.choice:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; }
input[type="checkbox"]:focus-visible, input[type="radio"]:focus-visible { box-shadow: none; }
input:not([type="checkbox"]):not([type="radio"]):focus,
select:focus, textarea:focus { box-shadow: 0 0 0 3px rgba(20, 72, 58, .22); }

/* Text-only zoom. At 200% text (Firefox "Zoom text only", or a large default
   font) the header row and the desktop nav ran off the right edge on every
   page — 1647px wide at a 1024px window — and full-width buttons overflowed
   at 375px. Buttons outside the header may now break onto two lines.
   The header row is NOT allowed to wrap: tried on 26 Sep 2026, it dropped the
   quote button to a second line at a normal-size 1000px window, because the
   row fits there only by shrinking. Header overflow at 200% text-only zoom is
   a recorded residual risk; standard browser zoom reflows to the phone header. */
.btn { white-space: normal; text-align: center; }
.site-header .btn, .sticky-cta .btn { white-space: nowrap; }
/* From 520px the one-line wordmark fits beside the buttons (measured: 297px
   needed, 367px free at 600px), so the stacked lockup is for phones only. */
@media (min-width: 520px) and (max-width: 679px) {
  .site-header .brand__mark { display: block; }
}
/* A fieldset's default min-width is its content's, and flex children default
   to min-width:auto; both let very large text push the form and the home-page
   library wider than a phone screen. */
fieldset { min-width: 0; }
.library__shelf > * { min-width: 0; }

/* Source entries, restructured 2026-09-26 (see sources.php): title, one line of
   provenance, and the reading note behind a quiet disclosure. */
.sources li.source { margin-bottom: var(--s-4); line-height: 1.45; }
.sources .source__title { color: var(--ink); }
.sources a.source__title { color: var(--brand); }
.sources li.source .meta { display: block; margin-top: 2px; }
.source__note { margin-top: var(--s-1); }
.source__note summary {
  display: inline-block; cursor: pointer; font-size: var(--t-xs); font-weight: 600;
  color: var(--ink-soft); letter-spacing: .02em;
}
.source__note summary:hover { color: var(--brand); }
.source__note[open] summary { color: var(--brand); }
.source__note p { margin: var(--s-2) 0 0; font-size: var(--t-xs); color: var(--ink-soft); line-height: 1.55; }
@media print { .source__note p { display: block !important; } }
