/* SpainVisaGuide design system — "Dossier" direction (Paulo, 2026-07-18).
   Swiss grid on warm paper; official-document aesthetic. Canonical visual reference:
   design/dossier-style-reference.html.

   Rules (CLAUDE.md / F-002):
   - Semantic, static CSS. One margin/typography scale for all H1–H6 and P.
   - Strong defaults; overrides only where required, each commented with WHY.
   - Fonts are self-hosted (Google Fonts embedding is a GDPR exposure in the EU). */

/* ── Fonts ─────────────────────────────────────────────────────────────────────────────────── */
@font-face { font-family: 'Archivo'; font-weight: 400; font-display: swap;
  src: url('/static/fonts/archivo-regular.woff2') format('woff2'); }
@font-face { font-family: 'Archivo'; font-weight: 500; font-display: swap;
  src: url('/static/fonts/archivo-500.woff2') format('woff2'); }
@font-face { font-family: 'Archivo'; font-weight: 600; font-display: swap;
  src: url('/static/fonts/archivo-600.woff2') format('woff2'); }
@font-face { font-family: 'Archivo'; font-weight: 700; font-display: swap;
  src: url('/static/fonts/archivo-700.woff2') format('woff2'); }
@font-face { font-family: 'Archivo'; font-weight: 800; font-display: swap;
  src: url('/static/fonts/archivo-800.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-weight: 400; font-display: swap;
  src: url('/static/fonts/ibm-plex-mono-regular.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-weight: 500; font-display: swap;
  src: url('/static/fonts/ibm-plex-mono-500.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-weight: 600; font-display: swap;
  src: url('/static/fonts/ibm-plex-mono-600.woff2') format('woff2'); }

/* ── Tokens ────────────────────────────────────────────────────────────────────────────────── */
:root {
  --paper: #f7f3ec;        /* page background */
  --card: #fffdf8;         /* card/table surfaces */
  --ink: #1e2a3a;          /* text, borders, nav */
  --terra: #c2492f;        /* accent: stamps, links, primary CTA */
  --terra-dark: #9d3a25;   /* hover on terracotta */
  --rule: #dcd4c6;         /* hairlines */
  --band: #efe8db;         /* tinted section background */
  --verified: #2e7d4f;     /* verified-state green */
  --muted: #5c6675;        /* secondary text on paper */
  --faint: #98917f;        /* tertiary text, not-verified */

  --font-ui: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Type scale (major-third-ish) and the single shared block rhythm. */
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.1875rem;
  --text-xl: 1.5rem;
  --text-2xl: 1.875rem;
  --text-3xl: 2.375rem;
  --text-4xl: 3rem;
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --content-max: 70rem;    /* wide-desktop cap: line length, not stretch */
  --border-strong: 1.5px solid var(--ink);
}

/* ── Base ──────────────────────────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--text-base);
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
}

/* One margin scale for every heading and paragraph: space above, none below, so vertical rhythm
   comes from a single direction and never doubles up. */
h1, h2, h3, h4, h5, h6, p, ul, ol, table, blockquote, figure {
  margin: var(--space-4) 0 0;
}
h1 { font-size: clamp(var(--text-2xl), 4.8vw, var(--text-4xl)); line-height: 1.08;
     letter-spacing: -0.02em; font-weight: 800; margin-top: var(--space-8); }
h2 { font-size: var(--text-xl); line-height: 1.2; font-weight: 800; margin-top: var(--space-12); }
h3 { font-size: var(--text-lg); line-height: 1.3; font-weight: 700; margin-top: var(--space-8); }
h4, h5, h6 { font-size: var(--text-base); font-weight: 700; margin-top: var(--space-6); }
p { max-width: 65ch; color: inherit; }

a { color: var(--terra); text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 3px solid var(--terra); outline-offset: 2px; }

ul, ol { padding-left: 1.25rem; }
img { max-width: 100%; height: auto; }
hr { border: 0; border-top: 1px solid var(--rule); margin: var(--space-8) 0 0; }

code, pre, .mono { font-family: var(--font-mono); }

/* Layout container */
.wrap { max-width: var(--content-max); margin: 0 auto; padding: 0 var(--space-6); }
main { display: block; padding-bottom: var(--space-16); }

/* Skip link: visually hidden until focused (WCAG 2.4.1). */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--ink); color: var(--paper); padding: var(--space-2) var(--space-4);
}
.skip-link:focus { left: 0; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* ── Header: nav ───────────────────────────────────────────────────────────────────────────── */
.site-header { border-bottom: 2px solid var(--ink); background: var(--paper); }
.site-header .wrap { display: flex; align-items: center; gap: var(--space-6); min-height: 4.125rem; }
.brand { font-weight: 800; font-size: var(--text-lg); color: var(--ink); white-space: nowrap; }
.brand em { font-style: normal; color: var(--terra); }
.brand:hover { text-decoration: none; }

.site-nav { display: flex; align-items: center; gap: var(--space-6); flex: 1; }
.site-nav ul { display: flex; align-items: center; gap: var(--space-6); list-style: none;
               margin: 0; padding: 0; }
.site-nav a, .site-nav summary {
  font-size: var(--text-sm); font-weight: 500; color: var(--ink); cursor: pointer;
  white-space: nowrap;
}
.site-nav a:hover, .site-nav summary:hover { color: var(--terra); text-decoration: none; }
.site-nav .active > a, .site-nav .active > details > summary {
  font-weight: 700; box-shadow: inset 0 -3px 0 var(--terra);
}

/* Dropdown clusters (Visas, Services): native <details> so they work without JS. */
.site-nav details { position: relative; }
.site-nav summary { list-style: none; }
.site-nav summary::-webkit-details-marker { display: none; }
.site-nav summary::after { content: ' ▾'; font-size: 0.7em; }
.site-nav details > ul {
  position: absolute; top: calc(100% + 0.5rem); left: -0.75rem; z-index: 50;
  flex-direction: column; align-items: stretch; gap: 0;
  min-width: 14rem; background: var(--card); border: var(--border-strong);
  box-shadow: 6px 6px 0 var(--rule); padding: var(--space-2) 0;
}
.site-nav details > ul a { display: block; padding: var(--space-2) var(--space-4); font-weight: 500; }
.site-nav details > ul a:hover { background: var(--band); color: var(--ink); }

.nav-auth { margin-left: auto; display: flex; align-items: center; gap: var(--space-4); }
.nav-auth .login {
  background: var(--ink); color: var(--paper); font-weight: 600; font-size: var(--text-sm);
  padding: var(--space-2) var(--space-4);
  /* The label must never wrap: at 360px the flex header squeezes it into two lines otherwise. */
  white-space: nowrap;
}
.nav-auth .login:hover { background: var(--terra); text-decoration: none; }
.nav-auth a { font-size: var(--text-sm); font-weight: 500; color: var(--ink); white-space: nowrap; }
.nav-auth a:hover { color: var(--terra); text-decoration: none; }

/* Logged-in account menu: native <details>, mirroring the nav cluster dropdowns (task-013). */
.account-menu { position: relative; }
.account-menu summary {
  list-style: none; cursor: pointer; font-size: var(--text-sm); font-weight: 500;
  color: var(--ink); white-space: nowrap;
}
.account-menu summary::-webkit-details-marker { display: none; }
.account-menu summary::after { content: ' ▾'; font-size: 0.7em; }
.account-menu summary:hover { color: var(--terra); }
.account-menu-panel {
  position: absolute; top: calc(100% + 0.5rem); right: 0; z-index: 50;
  display: flex; flex-direction: column; align-items: stretch; gap: 0;
  min-width: 12rem; background: var(--card); border: var(--border-strong);
  box-shadow: 6px 6px 0 var(--rule); padding: var(--space-2) 0;
}
.account-menu-panel a { display: block; padding: var(--space-2) var(--space-4); }
.account-menu-panel a:hover { background: var(--band); }
/* The logout form sits in the menu like a menu item; its button reads as one, not a heavy CTA. */
.account-menu-panel .form { margin: 0; }
.account-menu-panel .form .btn {
  display: block; width: 100%; text-align: left; margin: 0;
  padding: var(--space-2) var(--space-4); background: none; color: var(--ink);
  border: 0; font-size: var(--text-sm); font-weight: 500; cursor: pointer;
}
.account-menu-panel .form .btn:hover { background: var(--band); color: var(--ink); }

/* Mobile disclosure menu: same four clusters, same order (F-015). Hidden on desktop. */
.nav-mobile { display: none; }

/* ── Utility row: breadcrumb + language switcher ───────────────────────────────────────────── */
.utility-row { border-bottom: 1px solid var(--rule); }
.utility-row .wrap {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-4); min-height: 2.5rem; font-size: var(--text-sm);
}
.breadcrumbs { color: var(--muted); margin: 0; }
.breadcrumbs a { color: var(--muted); }
.breadcrumbs .sep { margin: 0 var(--space-2); color: var(--faint); }

.lang-switcher { position: relative; margin-left: auto; }
.lang-switcher summary {
  list-style: none; cursor: pointer; font-family: var(--font-mono);
  font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted);
}
.lang-switcher summary::-webkit-details-marker { display: none; }
.lang-switcher summary::after { content: ' ▾'; }
.lang-switcher > div {
  position: absolute; right: 0; top: calc(100% + 0.5rem); z-index: 50;
  min-width: 15rem; background: var(--card); border: var(--border-strong);
  box-shadow: 6px 6px 0 var(--rule); padding: var(--space-4);
}
.lang-switcher ul { list-style: none; margin: 0; padding: 0; }
.lang-switcher li { padding: var(--space-1) 0; }
.lang-switcher .current { font-weight: 700; }
.lang-switcher .unavailable { color: var(--faint); }
.lang-switcher .unavailable small { display: block; font-size: var(--text-xs); }
.lang-switcher p { font-size: var(--text-sm); color: var(--muted); margin-top: var(--space-3); }

/* ── Buttons ───────────────────────────────────────────────────────────────────────────────── */
.btn {
  display: inline-block; background: var(--terra); color: #fff; font-weight: 700;
  font-size: var(--text-sm); padding: var(--space-3) var(--space-6);
  border: none; cursor: pointer; font-family: var(--font-ui);
}
.btn:hover { background: var(--ink); text-decoration: none; color: #fff; }
.btn-secondary { background: var(--card); color: var(--ink); border: var(--border-strong); }
.btn-secondary:hover { background: var(--band); color: var(--ink); }

/* ── Error pages (404 / 500) ───────────────────────────────────────────────────────────────── */
/* Official-document treatment (mocks/404.md, mocks/error-500.md): the status number is set large in
   mono like a stamped case number, the two visa pillars are boxed file-cards with the 6px offset
   hard shadow motif, and the reference id is a selectable mono ledger line. Recovery links carry the
   page — no illustration or personality. */
.error-page { max-width: 60rem; margin: 0 auto; text-align: center; }
.error-code {
  font-family: var(--font-mono); font-weight: 600; line-height: 1;
  font-size: clamp(var(--text-4xl), 12vw, 6rem); letter-spacing: 0.05em;
  color: var(--terra); margin-top: var(--space-12);
}
.error-page h1 { margin-top: var(--space-2); }
.error-lead { margin-left: auto; margin-right: auto; color: var(--muted); }
/* The requested path on the unsupported-locale 404: mono so the offending URL reads as data. */
.error-requested {
  font-family: var(--font-mono); font-size: var(--text-sm); color: var(--faint);
  word-break: break-all;
}
.error-actions { margin-top: var(--space-6); }
/* Reference id: its own selectable mono line (accessibility note, mocks/error-500.md). */
.error-reference {
  font-family: var(--font-mono); font-size: var(--text-sm); color: var(--muted);
  user-select: all;
}

/* Pillar cards: boxed file-cards, side by side on desktop. */
.pillar-cards {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-6);
  margin-top: var(--space-6); text-align: left;
}
.pillar-card {
  background: var(--card); border: var(--border-strong); box-shadow: 6px 6px 0 var(--rule);
  padding: var(--space-6);
}
.pillar-card h2 { margin-top: 0; }

/* Secondary "Or try" list: left-aligned, hairline-separated ledger rows, no bullet indent. */
.error-secondary { margin-top: var(--space-12); text-align: left; }
.error-secondary ul { list-style: none; padding-left: 0; margin-top: var(--space-3); }
.error-secondary li { padding: var(--space-2) 0; border-top: 1px solid var(--rule); }
.error-secondary li:first-child { border-top: 0; }

/* ── Footer ────────────────────────────────────────────────────────────────────────────────── */
.site-footer { border-top: 2px solid var(--ink); background: var(--band); margin-top: var(--space-16); }
.site-footer .wrap {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4);
  padding-top: var(--space-6); padding-bottom: var(--space-6);
  font-size: var(--text-sm); color: var(--muted);
}
.site-footer a { color: var(--muted); text-decoration: underline; }
.site-footer a:hover { color: var(--terra); }
.site-footer .brand-line { font-weight: 700; color: var(--ink); }

/* ── Component library (F-002) ──────────────────────────────────────────────────────────────────
   Reusable components from ui/Components.kt, Chips.kt, Forms.kt, Compliance.kt, ComparisonTable.kt.
   All share the Dossier motifs already used by the error pages: 1.5px ink borders, the 6px offset
   hard shadow in rule color, mono labels, ink table-header bars. No component sets its own colors
   outside the token set. */

/* Article body: constrain long-form prose to a readable measure. The type scale and block rhythm
   come from the base H1–P rules — this only sets the column so nothing here overrides them. */
.article-body { max-width: 44rem; }
/* Inside the article column the 44rem width IS the measure, so a paragraph must fill the column and
   every panel (.callout/.card nested here) to its right edge. Left with the global p{max-width:65ch}
   cap, prose re-caps ~9rem short of the 44rem column and wraps ragged of each panel edge — and the
   mono .source-cite (itself a <p>) re-caps even shorter, orphaning its trailing "↗". Release the cap
   here only: bare prose on wide pages that do NOT use this column still keeps 65ch for readability. */
.article-body p { max-width: none; }

/* File-card surface, shared by .card and .callout (same motif as .pillar-card). */
.card, .callout {
  background: var(--card); border: var(--border-strong); box-shadow: 6px 6px 0 var(--rule);
  padding: var(--space-6); margin-top: var(--space-6);
}
/* First heading/paragraph inside a panel drops its top margin: the panel padding already provides
   the space, so the shared "margin above" rule would otherwise double it. */
.card > :first-child, .callout > :first-child, .modal-body > :first-child,
.cta-block > :first-child { margin-top: 0; }

.callout-title { font-weight: 800; font-size: var(--text-lg); margin-top: 0; }
.callout-title + * { margin-top: var(--space-4); }
/* Warning tone: a terracotta left rule marks it without a loud fill (official-document restraint). */
.callout-warning { border-left: 4px solid var(--terra); }

/* An inked stamp: the shared mono-label motif for a short status word set beside a heading
   ("Start here" on the services hub, "suggested" on a selector result card). Unscoped because more
   than one page needs it — a page-local copy of this rule would be the drift it exists to prevent. */
.stamp {
  font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--paper); background: var(--terra); padding: var(--space-1) var(--space-2); white-space: nowrap;
}

/* CTA block: boxed inline offer with one primary button (never a sticky bar). */
.cta-block {
  background: var(--band); border: var(--border-strong);
  padding: var(--space-6); margin-top: var(--space-8);
}
.cta-block-text { margin-top: 0; font-weight: 500; }
.cta-block .btn { margin-top: var(--space-4); }

/* Progress bar: fill tracks done/total; the count is always shown as text alongside (never bar-only). */
.progress { display: flex; align-items: center; gap: var(--space-4); margin-top: var(--space-4); }
.progress-track {
  flex: 1; height: 0.75rem; background: var(--card);
  border: 1.5px solid var(--ink); overflow: hidden;
}
.progress-fill { height: 100%; background: var(--terra); }
.progress-count {
  font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 600;
  white-space: nowrap; color: var(--ink);
}

/* Breadcrumb current page (the crumb with no href): plain, not a link, marked aria-current. */
.breadcrumbs .current { color: var(--ink); font-weight: 500; }

/* Modal: overlay card over the current page. The page behind stays intact (never replaced). */
.modal-overlay {
  position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center;
  padding: var(--space-6); background: rgba(30, 42, 58, 0.55);
}
.modal {
  background: var(--card); border: var(--border-strong); box-shadow: 8px 8px 0 var(--rule);
  width: 100%; max-width: 30rem; max-height: 90vh; overflow-y: auto;
}
.modal-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4);
  padding: var(--space-4) var(--space-6); border-bottom: var(--border-strong);
}
.modal-title { margin-top: 0; font-size: var(--text-xl); }
.modal-close { color: var(--muted); font-weight: 700; cursor: pointer; }
.modal-close:hover { color: var(--terra); text-decoration: none; }
.modal-body { padding: var(--space-6); }

/* Source-citation footnote: every financial figure carries one, set in mono like a ledger line. */
.source-cite {
  font-family: var(--font-mono); font-size: var(--text-xs); line-height: 1.5;
  color: var(--muted); margin-top: var(--space-3);
}
.source-cite > span { display: block; }
.source-figure { font-weight: 600; color: var(--ink); }
.source-label a { color: var(--muted); text-decoration: underline; }
.source-label a:hover { color: var(--terra); }
/* nowrap keeps the ↗/→ glyph on the same line as the link's last word (no orphaned arrow). */
.ext-mark { font-family: var(--font-mono); white-space: nowrap; }

/* Document-handling chips: inline mono notation (‹orig›, ‹≤90d old›, …). */
.chips { display: inline-flex; flex-wrap: wrap; gap: var(--space-1); }
.chip {
  font-family: var(--font-mono); font-size: var(--text-xs); white-space: nowrap;
  color: var(--muted); background: var(--band); border: 1px solid var(--rule);
  padding: 0 var(--space-1);
}
/* Positional markers: ★ (consulate override) terracotta, ↑ (long lead) ink — glyphs, not chips. */
.mark { font-weight: 700; }
.mark-consulate { color: var(--terra); }
.mark-lead { color: var(--ink); }

/* Chip legend: definition list of every chip and marker, shown before the first requirement. */
.chip-legend {
  display: grid; grid-template-columns: max-content 1fr; gap: var(--space-2) var(--space-4);
  margin-top: var(--space-4); align-items: baseline;
}
.chip-legend dt { margin: 0; }
.chip-legend dd { margin: 0; color: var(--muted); }
.chip-legend-note { font-size: var(--text-sm); color: var(--muted); }

/* Not-legal-advice disclaimer (F-003): boxed note on every guide/checklist page. */
.disclaimer {
  background: var(--band); border: 1px solid var(--rule);
  padding: var(--space-4) var(--space-6); margin-top: var(--space-8);
}
.disclaimer-title { margin-top: 0; font-weight: 700; }
.disclaimer-body { margin-top: var(--space-1); color: var(--muted); }

/* Legal pages (F-003): the "last updated" line, set in mono like a document revision stamp. */
.legal-updated {
  font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted);
  margin-top: var(--space-2);
}
/* Draft placeholder (task-010): a <… — TBD> or <pending — …> gap only Paulo/legal can fill. Loud on
   purpose — mono on a terracotta tint — so a reviewer cannot mistake it for finished copy. */
.draft-marker {
  font-family: var(--font-mono); font-size: 0.9em; white-space: nowrap;
  color: var(--terra-dark); background: #f4dfd8; padding: 0 var(--space-1);
  border: 1px solid var(--terra);
}

/* Monetized region (F-054): a compliance grouping, not a design element. It exists so the
   disclosure line and the affiliate links it covers are one unit in the DOM — that adjacency is
   what the enforcement test asserts. It draws nothing of its own on purpose. */
.monetized { display: block; }

/* Affiliate-disclosure line (F-054): compact, adjacent to the monetized element, not a banner. */
.affiliate-disclosure {
  font-size: var(--text-sm); color: var(--muted); margin-top: var(--space-4); max-width: none;
}
.affiliate-disclosure-mark { margin-right: var(--space-1); }
.affiliate-disclosure-link { text-decoration: underline; white-space: nowrap; }

/* ── Pillar & guide pages (F-010) ─────────────────────────────────────────────────────────────
   The topic-cluster hubs and their supporting guides. Byline + reviewed line, hero image, the
   settings-sourced "Figures on this page" block, the cluster/related listing, and the visible
   Sources list. All inside .article-body so prose keeps the shared readable measure. */

/* Byline: author line in body weight, the dates line set in mono like a document revision stamp. */
.byline { margin-top: var(--space-4); }
.byline-author { margin-top: 0; font-weight: 500; color: var(--ink); }
.byline-dates {
  margin-top: var(--space-1); font-family: var(--font-mono);
  font-size: var(--text-xs); color: var(--muted);
}

/* Hero image: bordered like every other file-card surface. */
.guide-hero { margin-top: var(--space-6); border: var(--border-strong); display: block; }

/* Figures-on-this-page: each figure's mono source line (year + source) stacked under a rule. */
.figures-cited { margin-top: var(--space-8); border-top: 1px solid var(--rule); }
.figures-cited .source-cite { margin-top: var(--space-4); }

/* Cluster listing / related guides: a "›"-led link per row, with an optional excerpt beneath. */
.guide-list { list-style: none; padding-left: 0; margin-top: var(--space-4); }
.guide-list li { padding: var(--space-3) 0; border-top: 1px solid var(--rule); }
.guide-list li:first-child { border-top: 0; }
.guide-list li > a { font-weight: 600; }
.guide-list li > a::before { content: '› '; color: var(--terra); }
.guide-list-excerpt { margin-top: var(--space-1); font-size: var(--text-sm); color: var(--muted); }

/* Living in Spain hub (task-024): planned (not-yet-published) guides render as inert text plus a
   "coming soon" chip, not a link — overrides the "›"-led anchor above, which does not apply here. */
.guide-list-planned .planned-guide-title { font-weight: 600; margin-right: var(--space-2); }

/* The hub's visa callout: one block per pillar, button on its own line below the blurb. */
.visa-callout-item { margin-top: var(--space-4); }
.visa-callout-item p { margin-top: 0; }

/* A guide's back-link to its cluster hub. */
.pillar-backlink { margin-top: var(--space-8); font-weight: 500; }

/* Sources: the visible numbered citation list required on every article (F-012). */
.source-list { margin-top: var(--space-4); color: var(--muted); }
.source-list li { padding: var(--space-1) 0; }
.source-list a { color: var(--muted); text-decoration: underline; }
.source-list a:hover { color: var(--terra); }

/* ── Author profile (task-019, F-012) ─────────────────────────────────────────────────────────
   /authors/{slug}: the byline's own page. Credentials read like the byline's own credential
   fragment (same weight/color as .byline-author's trailing text); the standing note is a small
   aside, not body copy. */
.author-credentials { margin-top: 0; color: var(--muted); font-size: var(--text-sm); }
.author-standing-note {
  margin-top: var(--space-6); padding-top: var(--space-4); border-top: 1px solid var(--rule);
  font-size: var(--text-sm); color: var(--muted);
}

/* ── Public requirements page (F-044) ─────────────────────────────────────────────────────────
   The read-only, indexable list for both visas. An article shaped like a list: static bullets, not
   checkboxes — nothing here is interactive (F-044). Reuses the shared file-card motif for its
   panels; only the income ledger lines and the phase/requirement rows are specific to this page. */

/* Income ledger (shared .ledger builder, ui/Components.kt): the worked example rendered as a real
   two-column table — a row-header label on the left, a right-aligned mono value on the right — so
   the figures are announced as tabular data, not loose flexed text. No page renders a div variant. */
.ledger { width: 100%; border-collapse: collapse; margin-top: var(--space-3); }
.ledger caption {
  text-align: left; color: var(--muted); font-size: var(--text-sm); margin-bottom: var(--space-2);
}
.ledger th {
  text-align: left; font-weight: 400; color: var(--ink);
  padding: var(--space-1) 0; vertical-align: baseline;
}
/* Numeric cells are right-aligned and mono; the alignment class is scoped to the table. */
.ledger .ledger-num {
  font-family: var(--font-mono); white-space: nowrap; text-align: right;
  padding: var(--space-1) 0; vertical-align: baseline;
}
/* Total row: the heavier ink rule (the shared file-card border token) and bold weight mark it. */
.ledger-total th, .ledger-total .ledger-num {
  border-top: var(--border-strong); padding-top: var(--space-3); font-weight: 700;
}
/* The annual figure sits under the monthly one, aligned to the same right edge. */
.ledger-subvalue { display: block; font-weight: 400; color: var(--muted); }
.income-account-note { font-size: var(--text-sm); color: var(--muted); }
/* Stale-figure notice (F-046 corner case): loud enough that a reader does not trust a lapsed value. */
.income-pending { font-size: var(--text-sm); color: var(--terra-dark); font-weight: 500; }

/* Processing summary: one chip + count per handling attribute across the whole template. */
.processing-summary { list-style: none; padding-left: 0; margin-top: var(--space-4); }
.processing-summary li {
  display: flex; align-items: baseline; gap: var(--space-3); padding: var(--space-1) 0;
}
.processing-count { color: var(--muted); font-size: var(--text-sm); }

/* A phase: mono-style heading with the item count pushed to the right, then its requirement list. */
.req-phase { margin-top: var(--space-8); }
.req-phase-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-4);
  /* 2px is a deliberate phase divider, one step heavier than the 1.5px --border-strong file-card
     rule; there is no 2px token, so the literal stays on purpose. */
  border-bottom: 2px solid var(--ink); padding-bottom: var(--space-2);
}
.req-phase-title { font-size: var(--text-lg); font-weight: 800; }
.req-phase-count {
  font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); white-space: nowrap;
}
/* Requirement rows: static list, a terracotta bullet standing in for the mock's "·" — deliberately
   NOT a checkbox, which would imply something can be ticked (F-044). */
.req-list { list-style: none; padding-left: 0; margin-top: var(--space-2); }
.requirement {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2);
  padding: var(--space-3) 0; border-top: 1px solid var(--rule);
}
.requirement:first-child { border-top: 0; }
.req-text { position: relative; padding-left: var(--space-4); }
.req-text::before { content: '·'; position: absolute; left: 0; color: var(--terra); font-weight: 700; }

/* Comparison table (F-050): columns rendered from category attribute definitions. */
.table-scroll { overflow-x: auto; margin-top: var(--space-4); }
.comparison {
  border: var(--border-strong); background: var(--card); border-collapse: collapse; width: 100%;
}
.comparison th {
  font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.1em;
  text-transform: uppercase; font-weight: 500; text-align: left;
  background: var(--ink); color: var(--paper); padding: var(--space-3) var(--space-4);
}
.comparison td {
  padding: var(--space-4); border-top: 1px solid var(--rule); vertical-align: top;
  font-size: var(--text-sm);
}
.comparison .provider-name { font-weight: 700; display: block; }
.comparison .value { display: block; }
/* Verified stamp: mono green (never a badge or checkmark — the words carry the state, F-050). */
.comparison .value-verified {
  display: block; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--verified);
}
/* Unverified: the literal words "not verified", in the value position, same weight as a real value. */
.comparison .value-unverified {
  display: block; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--faint);
}
.comparison .go { font-weight: 700; white-space: nowrap; }
.comparison .col-action { text-align: right; }

/* Forms: labelled fields with hint and inline error, one control per row. */
.form { margin-top: var(--space-6); }
.field { margin-top: var(--space-4); }
.field label { display: block; font-weight: 500; font-size: var(--text-sm); }
.field input {
  display: block; width: 100%; max-width: 24rem; margin-top: var(--space-1);
  font-family: var(--font-ui); font-size: var(--text-base); color: var(--ink);
  background: var(--card); border: 1.5px solid var(--ink); padding: var(--space-2) var(--space-3);
}
.field input:focus-visible { outline: 3px solid var(--terra); outline-offset: 2px; }
.field-hint { margin-top: var(--space-1); font-size: var(--text-xs); color: var(--muted); }
.field-error { margin-top: var(--space-1); font-size: var(--text-sm); color: var(--terra-dark); font-weight: 500; }
.field-error-mark { margin-right: var(--space-1); }
/* Invalid field: terracotta border echoes the error text without a color-only signal (the ⚠ + text). */
.field-invalid input { border-color: var(--terra); }
/* Checkbox and radio: control inline with its label, not stacked. */
.field-check, .field-radio { display: grid; grid-template-columns: auto 1fr; gap: var(--space-2); align-items: start; }
.field-check label, .field-radio label { margin: 0; font-weight: 400; }
.field-check input, .field-radio input { width: auto; margin-top: 0.2rem; }
.field-radio .field-hint { grid-column: 2; }
.field-group { margin-top: var(--space-4); }

/* Consent banner (F-060): fixed to the viewport bottom, gone the instant a decision is made — never
   a modal, never blocking the page it sits over. The two decision buttons share the same .btn/
   .btn-secondary sizing used everywhere else, so accepting and declining read as equally weighted. */
.consent-banner {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 150;
  background: var(--ink); color: var(--paper); border-top: var(--border-strong);
  box-shadow: 0 -6px 0 var(--rule);
}
.consent-banner-inner {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-6);
  flex-wrap: wrap; padding: var(--space-4) var(--space-6);
}
.consent-banner-text { margin: 0; max-width: 42rem; color: inherit; font-size: var(--text-sm); }
.consent-banner-text a { color: var(--paper); text-decoration: underline; }
.consent-banner-actions .form { margin-top: 0; display: flex; gap: var(--space-3); flex-wrap: wrap; }
.consent-banner-actions .btn-secondary { background: transparent; color: var(--paper); border-color: var(--paper); }
.consent-banner-actions .btn-secondary:hover { background: var(--paper); color: var(--ink); }

/* Account pages (registration, email verification, resend): the registration-modal card rendered
   standalone and centered (mocks/registration-modal.md). Same file-card motif as .card/.modal. */
.auth-page { display: flex; justify-content: center; padding: var(--space-8) var(--space-4); }
.auth-card { width: 100%; max-width: 30rem; }
.auth-title { margin-top: 0; font-size: var(--text-xl); }
.auth-lead { margin-top: var(--space-3); color: var(--ink); }
/* Top-of-form notice (expired CSRF, cookies needed): terracotta like an inline error, not decorative. */
.auth-notice { margin-top: var(--space-3); font-size: var(--text-sm); color: var(--terra-dark); font-weight: 500; }
.auth-card .field input { max-width: none; }
.auth-card .form .btn { margin-top: var(--space-6); }
/* The Google button and the blocked-variant primary action span the card, like the email submit. */
.auth-google { display: inline-block; width: 100%; text-align: center; margin-top: var(--space-4); }
/* Google sign-in unavailable (no OAuth secrets): render the control visibly off, never a live-looking
   button that would fail on click (F-031). */
.auth-google-off { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
.auth-switch { margin-top: var(--space-4); font-size: var(--text-sm); }
.auth-trust { margin-top: var(--space-4); font-size: var(--text-xs); color: var(--muted); }
/* "─── or ───" rule between the email form and the Google button. */
.auth-divider {
  display: flex; align-items: center; gap: var(--space-3);
  margin-top: var(--space-6); color: var(--muted); font-size: var(--text-sm);
}
.auth-divider::before, .auth-divider::after { content: ""; flex: 1; border-top: 1px solid var(--rule); }

/* Account data screens (settings "Your data", GDPR export, GDPR deletion). Wider than the auth card:
   the deletion screen itemizes what is destroyed and that list must not wrap into a column of
   fragments (mocks/account-settings.md, mocks/account-delete-confirm.md). */
.account-card { max-width: 38rem; }
.account-section-title { margin-top: 0; font-size: var(--text-lg); }
/* The scope list is the user-facing specification of what export/delete cover — set as a real list,
   with the same measure as body prose. */
.account-scope { margin-top: var(--space-3); padding-left: var(--space-6); }
.account-scope li { margin-top: var(--space-2); }
.account-note { margin-top: var(--space-4); font-size: var(--text-sm); color: var(--muted); }
/* "This cannot be undone" — terracotta, the same weight every irreversible warning on the site gets. */
.account-warning { margin-top: var(--space-4); color: var(--terra-dark); }
.account-data-actions { display: flex; gap: var(--space-4); margin-top: var(--space-6); flex-wrap: wrap; }
/* Profile/password/email-preferences sections (task-015): a real fieldset per section
   (mocks/account-settings.md accessibility note), reset to the card's own rhythm rather than the
   browser default border-and-inset-padding look. */
.account-fieldset { border: none; padding: 0; margin: var(--space-8) 0 0; }
.account-fieldset legend { padding: 0; margin-bottom: var(--space-2); font-size: var(--text-lg); font-weight: 600; }
.account-fieldset select {
  display: block; width: 100%; margin-top: var(--space-2); padding: var(--space-2);
  border: 1px solid var(--rule); border-radius: 4px; background: var(--paper); color: var(--ink);
  font: inherit;
}
.account-fieldset .field-check + .field-hint { margin-top: var(--space-1); }

/* Consulates index (F-019): GET search box, one row per consulate grouped by country. */
.consulate-search { margin-top: var(--space-6); max-width: 32rem; }
.consulate-search label { display: block; font-weight: 500; font-size: var(--text-sm); }
.consulate-search-row { display: flex; gap: var(--space-2); margin-top: var(--space-1); }
.consulate-search-row input {
  flex: 1; font-family: var(--font-ui); font-size: var(--text-base); color: var(--ink);
  background: var(--card); border: 1.5px solid var(--ink); padding: var(--space-2) var(--space-3);
}
.consulate-search-row input:focus-visible { outline: 3px solid var(--terra); outline-offset: 2px; }
.search-result-lead { font-weight: 600; margin-top: var(--space-6); }
.consulate-row {
  border-top: 1px solid var(--rule); padding: var(--space-4) 0; display: grid; gap: var(--space-1);
}
.consulate-row-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); }
.consulate-city { font-weight: 700; font-size: var(--text-lg); }
.consulate-district { color: var(--muted); max-width: 50rem; }
/* A consulate with a missing (not merely unlinked) district: the loud TBD placeholder, same
   treatment as a legal-page draft marker — a gap to fill, never blank or invented. */
.consulate-district-tbd {
  font-family: var(--font-mono); font-size: 0.9em; display: inline-block;
  color: var(--terra-dark); background: #f4dfd8; padding: 0 var(--space-1); border: 1px solid var(--terra);
}
.consulate-unverified-note { color: var(--muted); font-size: var(--text-sm); }
/* Verified/stale/appointment facts: mono, same "words carry the state, never a badge" convention
   as the comparison table's value-verified/value-unverified cells. */
.consulate-verified, .consulate-appointment {
  font-family: var(--font-mono); font-size: var(--text-xs); margin-top: 0;
}
.consulate-verified-mark { color: var(--verified); }
.consulate-stale-mark { color: var(--terra-dark); font-weight: 700; }
.consulate-appointment { color: var(--faint); }
.consulate-view-link { font-weight: 700; white-space: nowrap; }
.consulate-uncovered-note { color: var(--muted); margin-top: var(--space-8); }
.consulate-pillar-links { display: flex; gap: var(--space-4); margin-top: var(--space-4); flex-wrap: wrap; }

/* ── Home page (F-017, task-025, mocks/home.md) ───────────────────────────────────────────────
   The front door. Reuses the shared .pillar-cards / .pillar-card file-card motif for the two visa
   cards; everything else is prose sections capped to the readable measure by the base p rules. */

/* Hero: the lead sits one step up from body copy, not a second heading. */
.home-hero { margin-top: var(--space-8); }
.home-lead { font-size: var(--text-lg); color: var(--ink); max-width: 42rem; }

/* Visa cards: the .pillar-card surface, laid out as a column so the CTA anchors at the foot. */
.home-visa-cards { align-items: stretch; }
.visa-card { display: flex; flex-direction: column; }
.visa-card h2 { margin-top: 0; }
.visa-card-summary { color: var(--muted); }
/* The income block: a hairline-bounded ledger inside the card, so the figures read as data. */
.visa-card-income {
  margin-top: var(--space-4); padding-top: var(--space-4);
  border-top: 1px solid var(--rule);
}
.visa-income-heading {
  margin-top: 0; font-family: var(--font-mono); font-size: var(--text-xs);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted);
}
.visa-income-figures { list-style: none; padding-left: 0; margin-top: var(--space-2); }
.visa-income-figures li {
  font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums;
}
/* The derivation and base restatement: mono, subordinate to the figures they explain. */
.visa-income-rule, .visa-income-base {
  font-size: var(--text-xs); color: var(--muted); margin-top: var(--space-2);
}
.visa-income-base { margin-top: var(--space-1); }
/* The card's source line sits under the figures; the CTA is pushed to the card foot. */
.visa-card-income .source-cite { margin-top: var(--space-3); }
.visa-card > .btn { margin-top: var(--space-6); align-self: flex-start; }

/* "Which visa" prompt: a quiet band between the cards and the disclaimer. */
.home-selector-prompt { margin-top: var(--space-8); }
.home-selector-lead { margin-top: 0; font-weight: 500; }
.home-selector-note { margin-left: var(--space-3); color: var(--muted); font-size: var(--text-sm); }

/* "How this works": numbered ledger rows, hairline-separated, mono step numbers. */
.home-steps { counter-reset: step; list-style: none; padding-left: 0; margin-top: var(--space-4); }
.home-steps li {
  counter-increment: step; position: relative; padding: var(--space-4) 0 var(--space-4) var(--space-8);
  border-top: 1px solid var(--rule); max-width: 60ch;
}
.home-steps li:first-child { border-top: 0; }
.home-steps li::before {
  content: counter(step); position: absolute; left: 0; top: var(--space-4);
  font-family: var(--font-mono); font-weight: 600; color: var(--terra);
}

/* "Start reading" clusters: each a linked hub heading with its published guides (or a coming note). */
.home-cluster { margin-top: var(--space-8); }
.home-cluster h3 { margin-top: 0; }
.home-cluster-coming { color: var(--faint); font-size: var(--text-sm); margin-top: var(--space-2); }

/* "What this site is": the honest business-model statement, set on the tinted band. */
.home-about {
  margin-top: var(--space-16); padding: var(--space-6); background: var(--band);
  border: 1px solid var(--rule);
}
.home-about h2 { margin-top: 0; }
/* ── Services hub & category pages (F-051) ────────────────────────────────────────────────────
   The hub is a card grid; the anchor category (health insurance) spans the full width and keeps a
   heavier treatment. Category pages reuse the comparison table / annotated list components. */

/* Two-column card grid; the anchor card spans both so it stays visually dominant. */
.service-cards { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-6); margin-top: var(--space-8); }
.service-card { margin-top: 0; }
.service-card-anchor { grid-column: 1 / -1; border-width: 2.5px; box-shadow: 8px 8px 0 var(--rule); }
.service-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); }
.service-card-head h2 { margin-top: 0; }
.compared-on { color: var(--muted); font-size: var(--text-sm); }
.compared-on-label { font-weight: 600; color: var(--ink); }
/* Verified count: mono, like every other verified stamp on the site. */
.service-count { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--verified); margin-top: var(--space-4); }
/* Coming-soon: the honest pre-publication state, in the not-verified tertiary tone, never a link. */
.service-coming-soon { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--faint); margin-top: var(--space-4); }
.services-verify-note { color: var(--muted); margin-top: var(--space-8); max-width: 44rem; }

/* Filter bar: labelled radio groups laid out inline, one Apply button (mocks/services-health-insurance.md). */
.service-filters {
  margin-top: var(--space-6); padding: var(--space-4) var(--space-6);
  background: var(--band); border: 1px solid var(--rule);
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-6);
}
.service-filters .filter-group { border: 0; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: center; }
.service-filters legend { font-weight: 600; font-size: var(--text-sm); padding: 0; margin-right: var(--space-2); }
.service-filters .field-radio { grid-template-columns: auto auto; align-items: center; gap: var(--space-1); }
.service-filters .btn { margin-left: auto; }

.results-count { font-weight: 600; margin-top: var(--space-6); }
/* Footnote below the table: mono like a ledger note, muted. */
.comparison-footnote { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--muted); margin-top: var(--space-4); max-width: 44rem; }
.callout-mark { color: var(--terra); font-weight: 700; }

/* Zero-match empty state: a useful panel, never a blank table (F-051). */
.empty-state-title { margin-top: 0; font-weight: 700; }
.empty-state-actions { display: flex; gap: var(--space-4); margin-top: var(--space-4); flex-wrap: wrap; }

/* Annotated-list presentation for thin categories (F-051): same data, lighter than a matrix. */
.annotated-list { list-style: none; padding-left: 0; margin-top: var(--space-6); counter-reset: annotated; }
.annotated-entry { border-top: 1px solid var(--rule); padding: var(--space-4) 0; }
.annotated-entry:first-child { border-top: 0; }
.annotated-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); }
.annotated-head .provider-name { font-weight: 700; font-size: var(--text-lg); }
.annotated-head .provider-name::before { counter-increment: annotated; content: counter(annotated) '. '; color: var(--terra); }
.annotated-attrs { margin-top: var(--space-2); font-size: var(--text-sm); color: var(--ink); }
.annotated-label { color: var(--muted); }
.annotated-attrs .value { display: inline; }
.annotated-attrs .value-unverified { display: inline; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--faint); }
.annotated-sep { color: var(--faint); }

/* ── Guided visa selector (F-017, task-026, mocks/which-visa.md) ───────────────────────────────
   Three question steps and a result, all inside one HTMX-swapped panel. The question steps read as
   a short form on paper; the result reuses the shared .card file-card surface so a suggested visa
   looks like the same kind of object as a pillar card elsewhere on the site. */

.which-visa { max-width: 48rem; }
.selector-lead { font-size: var(--text-lg); }
/* The suggestion-not-a-decision line sits directly under the shared disclaimer it extends, so the
   two read as one note rather than two competing warnings. */
.selector-suggestion-note { margin-top: var(--space-2); color: var(--muted); }

.selector-step { margin-top: var(--space-6); }
.selector-step h2 { margin-top: var(--space-6); }
/* Full-width tap targets: the whole row is the label, so no answer is ever truncated or fiddly. */
.selector-step .field-radio {
  padding: var(--space-3) var(--space-4); border: 1px solid var(--rule); background: var(--card);
  margin-top: var(--space-2);
}
.selector-step .field-radio:hover { border-color: var(--ink); }
.selector-step .field-radio label { cursor: pointer; }

.selector-actions { display: flex; gap: var(--space-4); align-items: center; margin-top: var(--space-6); }
/* Next sits at the trailing edge, Back at the leading one (mocks/which-visa.md). */
.selector-next { margin-left: auto; }
/* Nothing advances until an option is chosen. The radios carry `required`, so the browser blocks the
   submit natively; this dims the button to show that up front. It is deliberately NOT `disabled` and
   NOT pointer-events:none — a visitor without JavaScript could never re-enable a disabled button,
   and suppressing the click would also suppress the browser's own "choose one" message. */
.selector-step:not(:has(input[type='radio']:checked)) .selector-next { opacity: 0.55; }

/* "Prefer to just read?" — both pillars, offered on every step. */
.selector-read-instead { margin-top: var(--space-12); padding-top: var(--space-6); border-top: 1px solid var(--rule); }
.selector-read-links { display: flex; flex-wrap: wrap; gap: var(--space-4); margin-top: var(--space-4); }

/* Result. The warning sits above everything the visitor might act on. */
.result-warning { margin-top: var(--space-6); }
.result-basis-heading { font-weight: 600; margin-top: var(--space-8); }
.result-basis { margin-top: var(--space-2); }
.result-reason { max-width: 44rem; }
/* The under-90-days note and the ruled-out list are facts about the answer, set apart from prose. */
.result-short-stay { padding: var(--space-3) var(--space-4); background: var(--band); border-left: 4px solid var(--rule); }
.result-ruled-out { margin-top: var(--space-4); }

.visa-result-card { margin-top: var(--space-8); }
.visa-result-card h2 { margin-top: 0; }
/* The suggested card carries the heavier border and shadow of an anchor card, so which one is being
   suggested is legible before a word is read — without the other card being reduced or hidden. */
.visa-result-suggested { border-width: 2.5px; box-shadow: 8px 8px 0 var(--rule); }
.visa-result-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); }
.visa-result-secondary-lead { color: var(--muted); }
.visa-result-card h3 { font-size: var(--text-base); margin-top: var(--space-6); }
.result-gates { margin-top: var(--space-2); }
.visa-result-card > .btn { margin-top: var(--space-6); }
.selector-change { margin-top: var(--space-8); }

/* ── Responsive ────────────────────────────────────────────────────────────────────────────── */
@media (max-width: 45rem) {
  /* Mobile 360px: nav collapses to a disclosure menu carrying the SAME four clusters in the
     same order (F-015 critical) — only the presentation changes, never the content. */
  .site-nav { display: none; }
  .nav-mobile { display: block; margin-left: auto; }
  .nav-mobile > summary {
    list-style: none; cursor: pointer; font-weight: 600; font-size: var(--text-sm);
    padding: var(--space-2) var(--space-3); border: var(--border-strong);
  }
  .nav-mobile > summary::-webkit-details-marker { display: none; }
  .nav-mobile[open] > summary { background: var(--ink); color: var(--paper); }
  .nav-mobile > nav {
    position: absolute; left: 0; right: 0; z-index: 60;
    background: var(--card); border-bottom: var(--border-strong);
    padding: var(--space-4) var(--space-6);
  }
  .nav-mobile ul { list-style: none; margin: 0; padding: 0; }
  .nav-mobile li { padding: var(--space-2) 0; }
  .nav-mobile a, .nav-mobile summary { font-weight: 600; color: var(--ink); }
  .nav-mobile details summary { list-style: none; cursor: pointer; }
  .nav-mobile details summary::after { content: ' ▾'; font-size: 0.7em; }
  .nav-mobile details ul { padding-left: var(--space-4); }
  .nav-mobile .nav-auth-mobile { border-top: 1px solid var(--rule); margin-top: var(--space-3);
    padding-top: var(--space-3); }

  /* Error pages at 360px (mocks/404.md, mocks/error-500.md): pillar cards stack full-width, the
     action buttons stack primary-first, and the reference id keeps its own selectable line. */
  .pillar-cards { grid-template-columns: 1fr; }
  .error-actions .btn { display: block; width: 100%; }
  .error-actions .btn + .btn { margin-top: var(--space-3); }

  .wrap { padding: 0 var(--space-4); }
  /* The switcher popover anchors to the viewport edge on narrow screens (mock: bottom sheet
     behavior approximated without JS). */
  .lang-switcher > div { position: fixed; left: var(--space-4); right: var(--space-4); top: auto;
    bottom: var(--space-4); }

  /* Comparison table collapses to one card per provider (mocks/services-banking.md): each cell shows
     its column label so no context is lost, and nothing scrolls sideways. The column headers are
     hidden and re-expressed per cell via the data-label the row carries. */
  .comparison, .comparison tbody, .comparison tr, .comparison td { display: block; width: 100%; }
  .comparison thead { position: absolute; left: -9999px; }
  .comparison tr { border-top: var(--border-strong); }
  .comparison tr:first-child { border-top: none; }
  .comparison td { border-top: 1px solid var(--rule); }
  .comparison td:first-child { border-top: none; }
  /* Re-express each column header per cell, in mono, so a stacked card keeps every label. */
  .comparison td[data-label]::before {
    content: attr(data-label); display: block;
    font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--muted);
  }
  .comparison .col-action { text-align: left; }

  /* Modal becomes a full-screen sheet rather than a floating card (mocks/registration-modal.md). */
  .modal-overlay { padding: 0; }
  .modal { max-width: none; max-height: 100vh; min-height: 100vh; box-shadow: none; }

  /* Consent banner stacks text above the two buttons rather than fighting them for width. */
  .consent-banner-inner { flex-direction: column; align-items: stretch; }
  .consent-banner-actions .form { justify-content: stretch; }
  .consent-banner-actions .btn { flex: 1; text-align: center; }
  /* Services hub at 360px (mocks/services-hub.md): cards stack single-column, the anchor keeping
     its heavier treatment and first position. Filters stack and the Apply button goes full-width. */
  .service-cards { grid-template-columns: 1fr; }
  .service-filters { flex-direction: column; align-items: stretch; }
  .service-filters .filter-group { flex-direction: column; align-items: flex-start; gap: var(--space-2); }
  .service-filters .btn { margin-left: 0; width: 100%; text-align: center; }
  /* The export/delete button pair stacks rather than compressing side by side (mocks/account-settings.md). */
  .account-data-actions { flex-direction: column; }
  .account-data-actions .btn { display: block; width: 100%; text-align: center; }

  .empty-state-actions { flex-direction: column; }
  .empty-state-actions .btn { display: block; width: 100%; text-align: center; }
  /* On the stacked comparison card, the /go action goes full-width like a mobile card CTA. */
  .comparison .col-action .go { display: block; text-align: center; padding: var(--space-2) 0; }
  .annotated-head { flex-direction: column; align-items: flex-start; gap: var(--space-2); }

  /* Consulates index at 360px (mocks/consulates-index.md): search row stacks, and the pillar CTAs
     go full-width and stack primary-first, matching the error pages' action-button convention. */
  .consulate-search-row { flex-direction: column; }
  .consulate-row-head { flex-direction: column; align-items: flex-start; gap: var(--space-1); }
  .consulate-pillar-links { flex-direction: column; }
  .consulate-pillar-links .btn { display: block; width: 100%; text-align: center; }

  /* Selector at 360px (mocks/which-visa.md): the two step controls stack full-width with Next on
     top. column-reverse keeps the DOM order Back-then-Next (the desktop left-to-right reading
     order) while putting the forward action where a thumb lands first. */
  .selector-actions { flex-direction: column-reverse; align-items: stretch; }
  .selector-actions .btn { width: 100%; text-align: center; }
  .selector-next { margin-left: 0; }
  .selector-read-links .btn { display: block; width: 100%; text-align: center; }
  /* The non-suggested result card keeps its full content on small screens; only the stamp row
     wraps. Collapsing it to a link would quietly defeat the always-link-both rule. */
  .visa-result-head { flex-wrap: wrap; }
}

/* Gazetteer attribution (CC BY 4.0 obligation for GeoNames UK data): quiet mono footnote. */
.consulate-data-credit { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--faint); margin-top: var(--space-8); }

/* ── Checklist setup (mocks/checklist-setup.md) ────────────────────────────────────────────────
   One screen, not a wizard: the sections are numbered headings in the ordinary page flow, with no
   progress chrome of any kind. The income panel sits directly below the counts that drive it so
   cause and effect are adjacent (mock: it is deliberately NOT floated beside the form). */
.setup-page { max-width: 44rem; margin: 0 auto; padding: var(--space-8) var(--space-4); }
.setup-title { margin-top: 0; }
.setup-lead { color: var(--muted); }
.setup-section { margin-top: var(--space-12); }
.setup-section-title { font-size: var(--text-xl); margin-bottom: var(--space-2); }
.setup-section-help { color: var(--muted); margin-top: 0; }
.setup-actions { margin-top: var(--space-12); }

/* The "you already have one" way out, so setup is never a trap for a returning member. */
.setup-resume { border: var(--border-strong); background: var(--band); padding: var(--space-4); margin-top: var(--space-6); }
.setup-resume-lead { margin: 0 0 var(--space-2); font-weight: 500; }
.setup-resume-link { display: block; }

.setup-visa-choices { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); margin-top: var(--space-8); }
.setup-visa-choice h2 { margin-top: 0; font-size: var(--text-lg); }
.setup-visa-read { display: block; margin-top: var(--space-3); font-size: var(--text-sm); }

/* Steppers: 44px-plus targets on every device, because these are the controls the whole screen
   exists for. The number input stays a real spinbutton (keyboard arrows, typeable). */
.stepper-controls { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-2); }
.stepper-btn {
  min-width: 2.75rem; min-height: 2.75rem; font-size: var(--text-lg); font-weight: 700;
  background: var(--card); color: var(--ink); border: var(--border-strong); cursor: pointer;
}
.stepper-btn:hover:not(:disabled) { background: var(--band); }
.stepper-btn:disabled { color: var(--faint); cursor: not-allowed; }
.stepper-btn:focus-visible { outline: 3px solid var(--terra); outline-offset: 2px; }
.stepper .stepper-value { width: 4.5rem; text-align: center; font-family: var(--font-mono); font-size: var(--text-lg); }

/* Derived party size: styled as a computed value, not a control. No border, no cursor, not
   focusable — the derivation is shown beneath it so it is visible rather than asserted (F-042). */
.party-derived { border-top: var(--border-strong); margin-top: var(--space-6); padding-top: var(--space-3); }
.party-derived-label { display: block; font-size: var(--text-sm); color: var(--muted); }
.party-derived-value { display: block; font-family: var(--font-mono); font-size: var(--text-3xl); font-weight: 600; }
.party-derived-derivation { display: block; font-family: var(--font-mono); font-size: var(--text-sm); color: var(--muted); }

.income-panel { border: var(--border-strong); background: var(--card); padding: var(--space-4); margin-top: var(--space-6); box-shadow: 6px 6px 0 var(--ink); }
.income-panel-head { border-bottom: var(--border-strong); padding-bottom: var(--space-2); margin-bottom: var(--space-3); }
.income-panel-title { font-weight: 800; }
.income-changed-note, .income-pending { font-size: var(--text-sm); color: var(--muted); margin-top: var(--space-3); }
/* A failed computation is loud, never a blank that reads as zero (error-handling philosophy). */
.income-unavailable { font-weight: 600; color: var(--terra-dark); }

.checklist-landing { max-width: 48rem; margin: 0 auto; padding: var(--space-8) var(--space-4); }
.checklist-title { margin-top: 0; }
.checklist-subhead { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--muted); }
.checklist-subhead span + span::before { content: " · "; }

/* task-039: the phase/step tree. <details>/<summary> gives a real, no-JS collapsible without
   inventing a second toggle mechanism task-061 would have to keep in sync. */
.checklist-verify-banner { margin-top: var(--space-4); }
.checklist-phase { margin-top: var(--space-6); border-top: var(--border-strong); padding-top: var(--space-4); }
.checklist-phase-head {
  display: flex; justify-content: space-between; align-items: baseline; cursor: pointer;
  list-style: none; font-weight: 800; font-size: var(--text-lg);
}
.checklist-phase-head::-webkit-details-marker { display: none; }
.checklist-phase-head::before { content: "▸"; margin-right: var(--space-2); color: var(--terra); }
.checklist-phase[open] > .checklist-phase-head::before { content: "▾"; }
.checklist-phase-count { font-family: var(--font-mono); font-size: var(--text-sm); color: var(--muted); }
.checklist-step { margin-top: var(--space-4); padding-left: var(--space-2); }
.checklist-step-row { display: flex; align-items: baseline; gap: var(--space-2); flex-wrap: wrap; }
.checklist-step-subject { color: var(--muted); }
.checklist-step-help, .checklist-step-note, .checklist-step-na {
  font-size: var(--text-sm); color: var(--muted); margin: var(--space-1) 0 0 1.75rem;
}
.checklist-step-note { white-space: pre-wrap; }
/* Retired instances stay visible and dimmed — never dropped (F-041/F-042 critical). */
.checklist-retired { margin-top: var(--space-4); opacity: 0.7; }
.checklist-retired .checklist-step { margin-top: var(--space-3); }
.checklist-obtain-later { margin: var(--space-2) 0 0 1.75rem; padding: var(--space-3); }

/* task-064: the mutation controls (toggle/NA/date/note). A shared unstyled-button reset — every
   mutating control here is a real <button>, never a link masquerading as one, so keyboard and
   screen-reader semantics stay correct while the visual treatment matches the site's text links. */
.btn-link {
  background: none; border: none; padding: 0; font: inherit; color: var(--terra-dark);
  text-decoration: underline; cursor: pointer;
}
.btn-link:hover { color: var(--terra); }
/* htmx's default indicator CSS toggles this element's opacity while a request from this row is in
   flight (mocks/checklist.md "[~] ... ⋯ Saving…" pending state) — no custom JS needed. */
.checklist-step-saving { display: block; opacity: 0; font-size: var(--text-sm); color: var(--muted); margin: var(--space-1) 0 0 1.75rem; }
.checklist-step-na-mark, .checklist-step-na-undo { margin: var(--space-1) 0 0 1.75rem; display: block; }
.checklist-step-date { margin: var(--space-2) 0 0 1.75rem; display: flex; align-items: baseline; gap: var(--space-2); flex-wrap: wrap; }
.checklist-step-date-form form { display: flex; align-items: center; gap: var(--space-2); }
.checklist-step-date-past-note { font-size: var(--text-sm); color: var(--muted); width: 100%; }
.checklist-step-note-toggle { margin: var(--space-1) 0 0 1.75rem; display: block; }
.checklist-step-note-form { margin: var(--space-2) 0 0 1.75rem; }
.checklist-step-note-form textarea { width: 100%; min-height: 4rem; font: inherit; }
.checklist-step-note-actions { display: flex; gap: var(--space-2); margin-top: var(--space-1); }
.checklist-still-to-process-row { display: flex; gap: var(--space-2); align-items: baseline; }
.checklist-next-actions { margin-top: var(--space-4); }
.checklist-next-actions-list { list-style: none; padding: 0; }
.checklist-next-actions-list li { margin-top: var(--space-2); }
.checklist-next-action-reason { font-size: var(--text-sm); color: var(--muted); margin: 0 0 0 1.5rem; }

@media (max-width: 30rem) {
  /* Mobile (mocks/checklist-setup.md mock 4): the stepper takes a full row, controls centred. */
  .stepper-controls { justify-content: center; }
  .party-derived { text-align: center; }
  .setup-visa-choices { grid-template-columns: 1fr; }
  .setup-actions .btn { display: block; width: 100%; text-align: center; }
}

/* ── Site search (mocks/search-results.md, task-023) ───────────────────────────────────────────
   Same file-card/search-box motifs as the consulate district search (.consulate-search,
   .search-result-lead), rather than a second visual language for "type a query, see a list". */
.search-page { max-width: 44rem; }
.site-search { margin-top: var(--space-6); }
.site-search label { display: block; font-weight: 500; font-size: var(--text-sm); }
.site-search-row { display: flex; gap: var(--space-2); margin-top: var(--space-1); }
.site-search-row input {
  flex: 1; font-family: var(--font-ui); font-size: var(--text-base); color: var(--ink);
  background: var(--card); border: 1.5px solid var(--ink); padding: var(--space-2) var(--space-3);
}
.site-search-row input:focus-visible { outline: 3px solid var(--terra); outline-offset: 2px; }
.search-prompt-lead { color: var(--muted); }
.search-no-results-hint { color: var(--muted); }
.search-results { list-style: none; padding: 0; margin-top: var(--space-4); }
.search-hit { border-top: 1px solid var(--rule); padding: var(--space-4) 0; }
.search-hit:first-child { border-top: none; }
.search-hit-title { font-weight: 700; font-size: var(--text-lg); }
.search-hit-snippet {
  margin-top: var(--space-1); color: var(--muted);
  /* Mobile spec (mocks/search-results.md responsive note): snippets truncate to two lines. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* The standing path to the two pillars, reusing the .card file-card surface so the suggestion
   block reads as a distinct panel, not a continuation of the results list. */
.search-suggestions { margin-top: var(--space-8); }
.search-suggestion-links { display: flex; flex-wrap: wrap; gap: var(--space-4); margin-top: var(--space-4); }
.search-locale-note { color: var(--muted); font-size: var(--text-sm); margin-top: var(--space-8); }

@media (max-width: 30rem) {
  /* Search at 360px (mocks/search-results.md responsive note): search row stacks, suggestion
     buttons go full-width, same convention as the consulate index and error pages. */
  .site-search-row { flex-direction: column; }
  .search-suggestion-links .btn { display: block; width: 100%; text-align: center; }
}
