/* ==========================================================================
   BerKrai — design system

   The register is a verification desk: warm paper, near-black ink, one state
   colour per conclusion, and evidence set as an artefact rather than as a
   dashboard. Three devices carry the hierarchy:

   1. the state stamp — the bucket's label is a filled plaque and its card is
      a sheet of paper laid on the tinted band, not a hairline in the margin;
   2. chapter rails — a display numeral and a rule, the way a printed report
      opens a section;
   3. paper cards — reports, facts and forms sit on bordered sheets with a
      soft shadow, so a group of related rows reads as one object.

   Colour never carries meaning alone: the stamp is also a sentence, the
   square is filled or hollow, and every heat cell prints its digit. The four
   state palettes are semantic; there is deliberately no decorative accent,
   because on a page whose job is to keep "reported problem" apart from "no
   data", a third colour that means nothing is a reading error waiting to
   happen.

   Thai typography rules that must survive any edit: generous leading (1.7+
   display, 1.75 body), no letter-spacing on Thai, and Thai never in the mono
   stack (IBM Plex Mono has no Thai glyphs).
   ========================================================================== */

/* ---- Self-hosted Thai/Latin faces (no external CDN at runtime) ---- */
/* WOFF2 with the TTF as a fallback for clients that cannot read it. WOFF2 is
   ~36% of the TTF size for these faces (426 KB -> 153 KB for the set), which is
   the largest single LCP lever on this site. `font-display:swap` plus the
   metric-compatible fallback stack keeps text visible during the swap. */
@font-face{font-family:"Plex Thai";src:url("/static/fonts/IBMPlexSansThai-400.woff2") format("woff2"),url("/static/fonts/IBMPlexSansThai-400.ttf") format("truetype");font-weight:400;font-display:swap}
@font-face{font-family:"Plex Thai";src:url("/static/fonts/IBMPlexSansThai-500.woff2") format("woff2"),url("/static/fonts/IBMPlexSansThai-500.ttf") format("truetype");font-weight:500;font-display:swap}
@font-face{font-family:"Plex Thai";src:url("/static/fonts/IBMPlexSansThai-600.woff2") format("woff2"),url("/static/fonts/IBMPlexSansThai-600.ttf") format("truetype");font-weight:600;font-display:swap}
@font-face{font-family:"Plex Thai";src:url("/static/fonts/IBMPlexSansThai-700.woff2") format("woff2"),url("/static/fonts/IBMPlexSansThai-700.ttf") format("truetype");font-weight:700;font-display:swap}
@font-face{font-family:"Plex Thai Looped";src:url("/static/fonts/IBMPlexSansThaiLooped-500.woff2") format("woff2"),url("/static/fonts/IBMPlexSansThaiLooped-500.ttf") format("truetype");font-weight:500;font-display:swap}
@font-face{font-family:"Plex Thai Looped";src:url("/static/fonts/IBMPlexSansThaiLooped-600.woff2") format("woff2"),url("/static/fonts/IBMPlexSansThaiLooped-600.ttf") format("truetype");font-weight:600;font-display:swap}
@font-face{font-family:"Plex Mono";src:url("/static/fonts/IBMPlexMono-400.woff2") format("woff2"),url("/static/fonts/IBMPlexMono-400.ttf") format("truetype");font-weight:400;font-display:swap}
@font-face{font-family:"Plex Mono";src:url("/static/fonts/IBMPlexMono-500.woff2") format("woff2"),url("/static/fonts/IBMPlexMono-500.ttf") format("truetype");font-weight:500;font-display:swap}

/* ---- tokens -------------------------------------------------------------
   One scale for spacing (4px base), one for radii, one for elevation. A
   component that needs a value outside these is a component that is doing
   something the system has not decided. */
:root{
  /* paper & ink */
  --paper:#FBF9F4;
  --surface:#F4F1E8;
  --sunken:#EDE9DE;
  --ink:#17150F;
  --ink-2:#3D3830;
  --muted:#615A4C;          /* 6.5:1 on --paper */
  --line:#DFD8C8;           /* decorative hairline */
  --line-strong:#8B8271;    /* 3.6:1 on paper, 3.0:1 on the worst tint: control boundaries */
  --danger:#8C2F12;

  /* type */
  --sans:"Plex Thai","Noto Sans Thai","Sarabun",system-ui,-apple-system,"Segoe UI",sans-serif;
  --display:"Plex Thai Looped","Plex Thai","Noto Sans Thai",system-ui,sans-serif;
  --mono:"Plex Mono",ui-monospace,"SFMono-Regular",Menlo,Consolas,monospace;
  /* --mono is for DIGITS AND LATIN ONLY: IBM Plex Mono has no Thai coverage, so a
     Thai string in this stack silently falls back to the sans. Dates are Thai
     month names, so they use --sans-digits (tabular sans), not --mono. */
  --sans-digits:"Plex Thai","Noto Sans Thai",system-ui,sans-serif;

  /* geometry */
  --r-xs:4px;
  --r-sm:8px;
  --r:12px;
  --r-lg:18px;
  --r-pill:999px;
  --measure:66ch;

  /* elevation: warm-tinted, never neutral grey — a grey shadow on warm paper
     reads as dirt. */
  --shadow-1:0 1px 1px rgba(35,28,16,.04),0 2px 6px -2px rgba(35,28,16,.07);
  --shadow-2:0 2px 4px -1px rgba(35,28,16,.06),0 12px 28px -12px rgba(35,28,16,.18);
  --shadow-3:0 18px 48px -18px rgba(35,28,16,.28);

  /* motion */
  --ease:cubic-bezier(.2,.7,.3,1);
}

/* ---- State palettes: tint / accent / rule. Text always carries meaning. ---- */
.state-caution{--tint:#F7E7DA;--state:#7E2F0E;--rule:#B4551F;--soft:rgba(126,47,14,.30);--hair:rgba(23,21,15,.16)}
.state-no_concerns{--tint:#E7F0E9;--state:#1F4D38;--rule:#4E7D63;--soft:rgba(31,77,56,.28);--hair:rgba(23,21,15,.15)}
.state-stale{--tint:#F0EADA;--state:#57482A;--rule:#8A7A55;--soft:rgba(87,72,42,.30);--hair:rgba(23,21,15,.15)}
.state-insufficient{--tint:#E8EEF3;--state:#2E4557;--rule:#66798A;--soft:rgba(46,69,87,.26);--hair:rgba(23,21,15,.15)}
.state-missing{--tint:#F2EFE6;--state:#17150F;--rule:#17150F;--soft:rgba(23,21,15,.24);--hair:rgba(23,21,15,.15)}

/* ---- reset & base ------------------------------------------------------ */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--sans);font-size:16px;line-height:1.75;font-weight:400;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  font-synthesis-weight:none;
}
::selection{background:#EFD9BE;color:var(--ink)}
img{max-width:100%}
p{margin:0}
a{color:inherit;text-underline-offset:3px;text-decoration-thickness:1px;text-decoration-color:var(--line-strong)}
a:hover{text-decoration-color:currentColor}
.mono{font-family:var(--sans-digits);font-variant-numeric:tabular-nums;letter-spacing:0}
:where(a,button,input,label,summary,select,textarea):focus-visible{outline:2px solid var(--ink);outline-offset:3px;border-radius:var(--r-xs)}

.visually-hidden{
  position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}
.skip{position:absolute;left:16px;top:-80px;z-index:40;background:var(--ink);color:var(--paper);
  padding:10px 16px;border-radius:var(--r-sm);text-decoration:none;font-size:14px}
.skip:focus{top:12px}

.wrap{width:100%;max-width:1160px;margin-inline:auto;padding-inline:20px}
@media (min-width:760px){.wrap{padding-inline:32px}}
@media (min-width:1180px){.wrap{padding-inline:44px}}
/* A `.wrap` nested inside another `.wrap` (every guide page's sections) must
   not double its gutter. This was an inline `style="padding-inline:0"` on 25
   elements; a class says the same thing once and keeps layout out of the
   templates. */
.wrap-flush{padding-inline:0}

/* ---------- header ----------
   Sticky on desktop only. The search box is the site's front door and the
   reader is often deep in a long number page when they want to look up the
   next call; on a desktop it costs one 84px row. On a phone the header is two
   rows (~119px) because the search wraps, which is 19% of a 640px screen held
   permanently — so there it scrolls away, and the number page (where the
   search is redundant) already hides the box entirely. */
.site-head{
  background:rgba(251,249,244,.92);
  -webkit-backdrop-filter:saturate(1.4) blur(10px);
  backdrop-filter:saturate(1.4) blur(10px);
  border-bottom:1px solid var(--line);
}
@media (min-width:900px){
  .site-head{position:sticky;top:0;z-index:20}
}
.head-grid{display:grid;grid-template-columns:1fr auto;grid-template-areas:"brand nav" "search search";
  align-items:center;row-gap:6px;padding-block:8px}
.brand{grid-area:brand;display:inline-flex;align-items:center;gap:10px;
  font-weight:600;font-size:19px;line-height:1.3;letter-spacing:.005em;color:var(--ink);
  text-decoration:none;min-height:44px}
.brand:hover{text-decoration:none}
.brand-mark{width:24px;height:24px;display:block;flex:none;color:var(--ink)}
.brand-word{display:inline-flex;align-items:baseline;gap:1px}
.brand-word b{font-weight:600}
.brand-word span{color:var(--muted);font-weight:500}
.site-nav{grid-area:nav;display:flex;align-items:center;gap:4px;font-size:13.5px;line-height:1.4}
.site-nav a{color:var(--ink-2);text-decoration:none;display:inline-flex;align-items:center;
  min-height:44px;padding:0 10px;border-radius:var(--r-pill);transition:background .15s var(--ease),color .15s var(--ease)}
.site-nav a:hover{background:var(--sunken);color:var(--ink);text-decoration:none}
/* Mobile: six nav links wrapped into a ragged block that pushed the search box
   off the first screen and made the header taller than the content. Only the
   two destinations a phone visitor needs stay; the rest live in the footer,
   which every page already carries. */
@media (max-width:899px){
  .site-nav{justify-self:end;gap:2px;font-size:13px}
  /* `.site-nav a` sets display:inline-flex and is more specific than a bare
     class selector, so the hide rule must match that specificity or it loses. */
  .site-nav .nav-admin,.site-nav .nav-secondary{display:none}
}
@media (min-width:900px){
  .head-grid{grid-template-columns:auto 1fr 330px;grid-template-areas:"brand nav search";
    column-gap:28px;padding-block:14px}
  .site-nav{justify-self:start}
}
/* The pill's inner controls must clear 44px on their own: the audit measures
   the button's own box, not the pill's, so a 40px button inside a 52px pill
   still fails the tap-target check. */
.search{grid-area:search;display:flex;align-items:center;gap:6px;
  background:var(--paper);border:1px solid var(--line-strong);border-radius:var(--r-pill);
  padding:3px 3px 3px 14px;min-height:52px;transition:border-color .15s var(--ease),box-shadow .15s var(--ease)}
.search:focus-within{border-color:var(--ink);box-shadow:0 0 0 3px rgba(23,21,15,.10)}
.search .field{flex:1;min-width:0;display:flex;align-items:center;gap:8px;margin:0}
.search .field::before{content:"";width:14px;height:14px;flex:none;
  background:var(--muted);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E") center/contain no-repeat}
/* Selector is `.search .field input`, not `.search input`: the header's
   wrapper reuses `class="field"` for the pill layout, and the form-control
   rules below (`.field input`, same specificity but later in the file) were
   imposing a 50px bordered control on it — the header pill measured 84px tall
   on a 390px phone before this. */
.search .field input{flex:1;min-width:0;border:0;background:transparent;color:var(--ink);
  font-family:var(--mono);font-size:14px;letter-spacing:.01em;padding:6px 0;min-height:44px;
  border-radius:0;box-shadow:none}
.search .field input:focus{outline:none;border:0;box-shadow:none}
.search .field input::placeholder{color:var(--muted);font-family:var(--sans);letter-spacing:0}
.search button{flex:none;background:var(--ink);color:var(--paper);border:1px solid var(--ink);
  font-family:var(--sans);font-size:13.5px;font-weight:600;padding:0 18px;min-height:44px;
  border-radius:var(--r-pill);cursor:pointer;transition:background .15s var(--ease)}
.search button:hover{background:#332D22}

/* On a number page the header search is redundant on phones: the reader has
   already found their number, and the search box costs ~60px of the first
   screen. The hero search on the home page (and the breadcrumb link to it)
   still serves people who want to look up another number. Desktop keeps it. */
@media (max-width:899px){
  .is-number .site-head .search{display:none}
  .is-number .head-grid{grid-template-areas:"brand nav";row-gap:0;padding-block:6px}
}

/* ---------- breadcrumb ---------- */
.crumbs{padding-block:6px;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
/* The admin's way into the edit screen. Rendered only for a signed-in admin
   (the route sets no-store on that response), and styled as a quiet utility
   control rather than a primary action — it is not part of the reader's page. */
.edit-link{display:inline-flex;align-items:center;min-height:44px;padding:0 16px;
  border:1px solid var(--line-strong);border-radius:var(--r-pill);
  font-size:13px;font-weight:600;color:var(--ink-2);text-decoration:none;background:var(--paper);
  transition:border-color .15s var(--ease),background .15s var(--ease),color .15s var(--ease)}
.edit-link:hover{color:var(--ink);border-color:var(--ink-2);background:var(--sunken)}
.breadcrumb{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:13px;color:var(--muted)}
.breadcrumb a{color:var(--muted);display:inline-flex;align-items:center;min-height:44px;padding:0 2px}
.breadcrumb a:hover{color:var(--ink)}
.breadcrumb .sep{color:var(--line-strong)}
.breadcrumb [aria-current]{color:var(--ink);font-weight:500}

/* ---------- the record band ----------
   The tint is the page's state, stated once at full width. The bucket itself
   is a sheet of paper laid on it: the conclusion is an object, not a wash. */
.band{position:relative;background:var(--tint);border-top:1px solid var(--hair);
  padding-block:22px 40px}
.band::before{content:"";position:absolute;inset:0 0 auto 0;height:4px;background:var(--rule)}
@media (min-width:900px){.band{padding-block:34px 56px}}

.split{display:grid;grid-template-columns:minmax(0,1fr);gap:14px}
@media (min-width:920px){.split{grid-template-columns:196px minmax(0,1fr);column-gap:52px;row-gap:0}}

/* The chapter rail: a display numeral, a rule, then the heading. On a phone it
   collapses to one line so the answer starts sooner. */
.rail{padding-top:2px;align-self:start}
.rail .idx{font-family:var(--display);font-weight:600;font-size:30px;line-height:1;
  letter-spacing:0;color:var(--muted);margin:0 0 10px;font-variant-numeric:tabular-nums;
  display:flex;align-items:center;gap:12px}
.rail .idx::after{content:"";flex:1;max-width:44px;height:1px;background:var(--line-strong)}
.rail-title{font-size:16.5px;line-height:1.55;font-weight:600;margin:0;color:var(--ink);letter-spacing:.005em}
.rail-meta{font-size:12.5px;line-height:1.65;color:var(--muted);margin:8px 0 0;max-width:30ch}
/* A rail label that is a word rather than a section number ("หลังบ้าน",
   "อ่านต่อ") keeps the rail's rhythm but not its numeral scale — 30px display
   type on a Thai word reads as a mis-rendered number. */
.rail .idx-text{font-family:var(--sans);font-size:12.5px;font-weight:600;
  letter-spacing:.02em;color:var(--muted);margin-bottom:12px}
.rail .idx-text::after{max-width:32px}
@media (min-width:920px){
  .rail{position:sticky;top:88px}
}
@media (max-width:919px){
  .rail{display:flex;flex-wrap:wrap;align-items:center;gap:2px 10px;padding-top:0}
  .rail .idx{margin:0;font-size:15px;font-weight:600;color:var(--paper);
    background:var(--ink);border-radius:var(--r-xs);padding:3px 7px;line-height:1.4;gap:0}
  .rail .idx::after{display:none}
  .rail .idx-text{font-family:var(--sans);font-size:12px;margin:0;padding:4px 8px}
  .rail-title{font-size:19px;line-height:1.5}
  .rail-meta{flex:1 0 100%;margin-top:4px;max-width:none}
}

.eyebrow{font-size:12.5px;letter-spacing:.02em;color:var(--muted);line-height:1.5;
  display:inline-flex;align-items:center;gap:8px}
.eyebrow::before{content:"";width:6px;height:6px;background:var(--muted);flex:none}
/* `gap:0` also zeroed the *column* gap, so the heading column started 52px left
   of every section below it and the page's largest element aligned with
   nothing. Only the row gap is meant to collapse here. */
.band-identity{row-gap:0;margin-bottom:10px}
/* The identity block has no rail — its left column is empty space that keeps
   the number aligned with the body column of every section below. */
@media (min-width:920px){.band-identity .body{grid-column:2}}
.identity-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px}
.number-h1{margin:0;display:flex;flex-wrap:wrap;align-items:baseline;gap:0 14px}
.number{font-family:var(--display);font-weight:600;font-size:clamp(34px,5.6vw,62px);
  line-height:1.18;letter-spacing:-.015em;margin:0;color:var(--ink);font-variant-numeric:tabular-nums}
/* The query phrase sits beside the number, quieter, so the number still leads.
   Baseline alignment keeps it on the number's own line; the slight negative
   bottom offset counteracts the taller Thai line box of the smaller size. */
.number-q{font-family:var(--display);font-weight:600;font-size:clamp(17px,2.1vw,24px);
  line-height:1.7;color:var(--muted);letter-spacing:0;position:relative;top:-2px}
.alt-forms{font-size:13px;color:var(--muted);margin:0;font-family:var(--mono);letter-spacing:.01em}
/* The line type, as a chip beside the number. It sits on the number's own
   baseline, so it costs no line of its own on a phone and does not read as an
   orphan in the rail column on desktop. */
.kind-chip{display:inline-flex;align-items:center;min-height:28px;margin:0;
  padding:3px 12px;border:1px solid var(--line-strong);border-radius:var(--r-pill);
  font-size:12px;line-height:1.5;font-weight:500;color:var(--ink-2);
  background:var(--paper);white-space:nowrap}
@media (max-width:919px){.identity-row{gap:6px 0}.identity-row .kind-chip{margin-bottom:2px}}
.band-rule{height:1px;background:var(--hair);margin:20px 0 22px}
/* On a phone every pixel above the bucket is a pixel the instruction loses.
   The rule still separates the number from the answer; it just costs less. */
@media (max-width:560px){.band-rule{margin:14px 0 16px}}

/* ---------- the decision card ----------
   The bucket is the same four-part shape on every page — label, headline,
   action, then the explanatory tail — so a reader who has seen one page can
   read any other at a glance. The label is a filled stamp, the action is a
   tinted block, and the reasons fold underneath.

   Colour is a scanning aid only. The bucket name is a sentence, the action is
   set in a distinct weight, and the square is filled or hollow by state: a
   reader who cannot distinguish the hues still gets the whole answer from the
   words. All palettes are checked by scripts/a11y_check.py. */
/* A sheet of paper, not a wash: the conclusion is the one object on the band
   with an edge and a shadow, so it reads as the thing to look at before any
   section heading does. It fills the body column (minus a gutter) rather than
   shrinking to its text — a 66ch card left a ragged 160px gap on desktop and
   made the largest element on the page look like a tooltip. */
.bucket{position:relative;background:var(--paper);border:1px solid var(--bucket-hair);
  border-left:4px solid var(--bucket-rule);border-radius:var(--r);
  padding:24px 26px 22px;box-shadow:var(--shadow-2)}
@media (min-width:640px){.bucket{padding:30px 34px 28px}}
@media (max-width:560px){.bucket{padding:20px 18px 18px;border-left-width:3px}}

.bucket-label{display:inline-flex;align-items:center;gap:8px;
  background:var(--bucket);color:var(--paper);
  font-size:12.5px;font-weight:600;letter-spacing:0;line-height:1.5;
  padding:5px 13px;border-radius:var(--r-pill);margin:0 0 14px}
.bucket-label::before{content:"";width:7px;height:7px;background:currentColor;flex:none;border-radius:1px}

.bucket-line{font-family:var(--display);font-weight:600;
  font-size:clamp(25px,2.9vw,34px);line-height:1.58;margin:0;
  color:var(--ink);text-wrap:balance;letter-spacing:0}
@media (max-width:560px){.bucket-line{font-size:23px;line-height:1.55}}

/* The instruction. The heaviest text in the block after the headline, because
   it is the only part a reader has to act on. It sits above every explanatory
   sentence — measured on a 360x640 phone, the old order put it below the fold. */
.bucket-action{display:flex;align-items:flex-start;gap:10px;margin:18px 0 0;
  background:var(--bucket-tint);border:1px solid var(--bucket-hair);
  border-radius:var(--r-sm);padding:14px 16px;
  font-size:16.5px;line-height:1.7;font-weight:600;color:var(--bucket);max-width:58ch}
.bucket-action .sq{flex:none;margin-top:8px;background:var(--bucket);width:9px;height:9px}
@media (max-width:560px){.bucket-action{font-size:16px;padding:12px 14px}}

/* The explanatory tail: what the bucket means and how far the data goes. Both
   qualify the conclusion, so they sit below the instruction rather than
   between the headline and it. */
.bucket-foot{margin-top:22px;padding-top:16px;border-top:1px solid var(--bucket-hair)}
.bucket-meaning{font-size:15px;line-height:1.8;color:var(--ink-2);margin:0;max-width:58ch}
.bucket-foot .scope{margin-top:12px;padding-left:0;border-left:0;font-size:13.5px;max-width:58ch}

/* Four palettes. Each sets the stamp, the rule, the hairline and the wash the
   action block reads against. None of them is the only cue. */
.bucket-reported{--bucket:#8A2E0C;--bucket-rule:#B4551F;--bucket-tint:#FBEDE5;--bucket-hair:rgba(138,46,12,.26)}
/* There is no confirmed_benign bucket: the set is three (see BUCKETS in
   app/assessment.py). A fourth palette here would be a colour no page can
   ever set, and the next person to read the stylesheet would assume the
   product has four buckets. */
.bucket-identified{--bucket:#23445C;--bucket-rule:#5C7E96;--bucket-tint:#EAF1F6;--bucket-hair:rgba(35,68,92,.22)}
.bucket-unverified{--bucket:#4A4437;--bucket-rule:#8A7A55;--bucket-tint:#F2EDE1;--bucket-hair:rgba(74,68,55,.22)}

/* ---------- sections ---------- */
.sec{border-top:1px solid var(--line);padding-block:40px}
@media (min-width:820px){.sec{padding-block:60px}}
.sec:last-of-type{padding-bottom:72px}
.body{min-width:0;max-width:820px}
.body p{max-width:var(--measure)}
.h3{font-size:20px;line-height:1.55;font-weight:600;margin:0;letter-spacing:.005em;color:var(--ink)}
@media (min-width:820px){.h3{font-size:22px}}

/* ---------- the number's facts ----------
   A definition list as a paper card: label column, value column, hairlines
   between rows. The facts are structural, so they read as a spec sheet. */
.prov{margin:0;display:grid;gap:0;background:var(--paper);border:1px solid var(--line);
  border-radius:var(--r);box-shadow:var(--shadow-1);overflow:hidden}
.prov > div{display:grid;grid-template-columns:minmax(0,1fr);gap:2px;
  padding:13px 18px;border-top:1px solid var(--line)}
.prov > div:first-child{border-top:0}
@media (min-width:620px){.prov > div{grid-template-columns:168px minmax(0,1fr);gap:24px;align-items:baseline}}
.prov dt{font-size:12.5px;color:var(--muted);letter-spacing:.01em;line-height:1.6}
.prov dd{margin:0;font-size:15px;line-height:1.65;color:var(--ink-2);font-variant-numeric:tabular-nums}
.note{display:flex;gap:10px;align-items:flex-start;font-size:13.5px;line-height:1.72;
  color:var(--muted);margin:16px 0 0;max-width:62ch}
.note .sq-hollow{margin-top:7px}
.note-strong{color:var(--ink-2)}

/* ---------- ad (always below the answer) ---------- */
.ad{border-top:1px solid var(--line);padding-block:26px;background:var(--surface)}
.ad-inner{max-width:760px}
.ad-label{display:inline-block;font-family:var(--sans);font-size:12px;letter-spacing:.02em;
  color:var(--muted);border:1px solid var(--line-strong);border-radius:var(--r-xs);
  padding:2px 8px;line-height:1.5;background:var(--paper);position:relative;top:1px}
.ad-box{border:1px solid var(--line-strong);border-radius:0 var(--r-sm) var(--r-sm) var(--r-sm);
  min-height:120px;display:flex;align-items:center;justify-content:center;
  color:var(--muted);font-size:12.5px;background:var(--paper)}
@media (max-width:560px){.ad-box{min-height:100px}}

/* ---------- experiences ledger ----------
   Each report is a card: date and verification in a left column, what
   happened in the right. The card is what makes the ledger scannable at 12
   reports and still honest at one. */
.exp{display:grid;grid-template-columns:minmax(0,1fr);gap:8px;
  background:var(--paper);border:1px solid var(--line);border-radius:var(--r);
  padding:18px 20px;box-shadow:var(--shadow-1)}
.exp + .exp{margin-top:10px}
@media (min-width:700px){
  .exp{grid-template-columns:132px minmax(0,1fr);column-gap:26px;padding:20px 22px}
  .exp-side{padding-top:2px}
}
.exp-side{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px}
@media (min-width:700px){.exp-side{flex-direction:column;align-items:flex-start;gap:8px}}
.exp-date{font-family:var(--sans-digits);font-size:12.5px;letter-spacing:0;
  color:var(--ink-2);font-variant-numeric:tabular-nums;line-height:1.5}
.exp-verified{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;
  letter-spacing:0;color:var(--muted);line-height:1.6;
  border:1px solid var(--line);border-radius:var(--r-pill);padding:1px 9px}
.exp-verified .sq{background:var(--ink-2);width:6px;height:6px}
.exp-type{display:inline-block;font-size:12px;letter-spacing:.01em;color:var(--ink-2);
  background:var(--sunken);border-radius:var(--r-xs);padding:2px 8px;line-height:1.6}
.exp-body{font-size:16px;line-height:1.75;margin:10px 0 0;color:var(--ink-2);max-width:58ch}
.claim{margin:14px 0 0;padding:10px 14px;max-width:58ch;background:var(--surface);
  border:1px dashed var(--line-strong);border-radius:var(--r-sm)}
.claim-label{display:flex;align-items:center;gap:8px;font-size:12px;letter-spacing:0;
  color:var(--muted);line-height:1.6;margin:0 0 2px}
.claim-text{font-size:14.5px;line-height:1.65;color:var(--ink-2);margin:0}
@media (max-width:560px){.exp-body{font-size:16px}.exp{padding:16px}}

/* ---------- report frequency (heatmap + weekly strip) ----------
   Two plain counts, not a dashboard. The grid is the only dense element on the
   page, so it gets generous cells and a single sequential ramp.

   The ramp is driven by `--w` (0-100), set per cell from the count, and is
   scaled to 45% of the ink: at full strength the cell is still light enough
   for an ink digit (6.5:1), so every cell prints its count in the same ink as
   the rest of the page. A dark cell means *more reports*, never *worse* — the
   ramp never borrows the caution accent. Empty cells keep the page ground and
   print nothing, so "no reports here" is visible as an absence. */
.freq{margin:30px 0 0;background:var(--paper);border:1px solid var(--line);
  border-radius:var(--r);padding:20px;box-shadow:var(--shadow-1)}
.freq + .freq{margin-top:16px}
@media (max-width:560px){.freq{padding:16px}}

.freq-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 14px;margin-bottom:14px}
.freq-h{font-size:15px;line-height:1.5;font-weight:600;margin:0;color:var(--ink)}
.freq-meta{font-size:12.5px;line-height:1.6;color:var(--muted);margin:0;font-variant-numeric:tabular-nums}
.freq-lede{font-size:13.5px;line-height:1.7;color:var(--muted);margin:0 0 14px;max-width:58ch}
.freq-empty{font-size:14.5px;line-height:1.75;color:var(--ink-2);margin:0;max-width:54ch}
.freq-axis{display:flex;justify-content:space-between;margin:8px 0 0;
  font-size:11.5px;color:var(--muted)}

/* ---- the grid ---- */
.heat-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;padding-bottom:2px}
.heat{border-collapse:separate;border-spacing:3px;font-size:13px;margin:0}
.heat th{font-weight:500;color:var(--muted);font-size:11.5px;letter-spacing:0;padding:0 2px}
.heat-col{text-align:center;white-space:nowrap;font-family:var(--sans-digits);padding-bottom:2px}
.heat-row{text-align:right;white-space:nowrap;padding-right:8px;font-family:var(--sans-digits)}

.heat-cell{width:46px;height:38px;text-align:center;vertical-align:middle;
  border-radius:var(--r-xs);background:var(--paper);
  box-shadow:inset 0 0 0 1px var(--line)}
.heat-cell.is-filled{
  background:color-mix(in srgb, var(--ink) calc(var(--w) * 0.45), var(--paper));
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--ink) calc(var(--w) * 0.45), var(--line))}
.heat-n{font-family:var(--sans-digits);font-variant-numeric:tabular-nums;
  font-size:13.5px;font-weight:600;color:var(--ink)}

.heat-legend{display:flex;align-items:center;gap:5px;margin:12px 0 0}
.heat-legend-label{font-size:11.5px;color:var(--muted)}
.heat-swatch{width:20px;height:12px;border-radius:2px;display:inline-block;
  background:color-mix(in srgb, var(--ink) calc(var(--w) * 0.45), var(--paper));
  box-shadow:inset 0 0 0 1px var(--line)}

/* ---- the weekly strip ---- */
/* The strip is a flex row of equal columns on a shared baseline. Each column
   has a fixed-height *track*; the bar fills from the bottom of that track, so
   the percentage resolves against a box with a definite height. (The previous
   version put the percentage on a flex child whose parent height was
   `100%` of an auto-height row — no definite height, so every bar rendered at
   its 2px minimum.) */
.weeks{display:flex;align-items:flex-end;gap:5px;padding-top:6px;
  border-bottom:1px solid var(--line-strong)}
.week-col{flex:1 1 0;min-width:0;display:flex;flex-direction:column;
  align-items:center;gap:6px}
.week-track{position:relative;width:100%;height:96px}
.week-bar{position:absolute;left:0;right:0;bottom:0;
  border-radius:3px 3px 0 0;display:block;
  height:var(--h);min-height:3px;
  background:color-mix(in srgb, var(--ink) calc(var(--w) * 0.7), var(--paper))}
/* A zero week is a hairline, not nothing: the gap is information, and a strip
   that drops empty weeks compresses time. */
.week-bar[style*="--w:0%"]{background:transparent;box-shadow:inset 0 0 0 1px var(--line)}
.week-n{font-family:var(--sans-digits);font-variant-numeric:tabular-nums;
  font-size:11px;color:var(--muted);line-height:1}
/* The current week is marked by its label, not by colour: a bar is already
   carrying a magnitude, and a second meaning on the same mark is a reading
   error waiting to happen. */
.week-col.is-current .week-n{color:var(--ink);font-weight:600}

@media (max-width:560px){
  .heat{border-spacing:2px;font-size:12px}
  .heat-cell{width:40px;height:34px}
  .heat-n{font-size:12.5px}
  .heat-col{font-size:10.5px}
  .heat-row{padding-right:5px}
  .weeks{gap:3px}
  .week-track{height:84px}
  .week-n{font-size:10px}
}

/* 30-day demand strip. The weekly strip's 12 columns are too dense at 30 bars
   — empty days collapse into a dotted line and read as noise rather than as
   "nothing happened here". Tighter gap, shorter track, and empty days get no
   bar at all (the baseline carries the axis). Scoped to the demand strip only:
   an unscoped `.week-bar` rule here overrode the weekly strip's fill and made
   every bar transparent. */
.weeks:has(.week-col:nth-child(25)){gap:2px}
.weeks:has(.week-col:nth-child(25)) .week-track{height:72px}

/* ---------- FAQ (answer-engine extractable passages) ---------- */
.faq{margin:0;background:var(--paper);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--shadow-1);overflow:hidden}
.faq > div{padding:20px 22px;border-top:1px solid var(--line);max-width:none}
.faq > div:first-child{border-top:0}
.faq dt{font-weight:600;font-size:16.5px;line-height:1.6;color:var(--ink);margin:0 0 8px;
  display:flex;gap:10px;align-items:flex-start}
.faq dt::before{content:"";width:8px;height:8px;background:var(--ink);flex:none;margin-top:9px}
.faq dd{margin:0;font-size:16px;line-height:1.8;color:var(--ink-2);padding-left:18px;max-width:70ch}

/* ---------- contribute ---------- */
.cont-lead{font-size:17px;line-height:1.7;margin:0 0 4px;max-width:54ch}
.cont-actions{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;margin-top:22px}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:50px;
  background:var(--ink);color:var(--paper);border:1px solid var(--ink);border-radius:var(--r-pill);
  font-family:var(--sans);font-size:15px;font-weight:600;letter-spacing:.005em;padding:0 24px;
  text-decoration:none;cursor:pointer;transition:background .15s var(--ease),transform .15s var(--ease),box-shadow .15s var(--ease);
  box-shadow:var(--shadow-1)}
.btn:hover{background:#332D22;text-decoration:none;box-shadow:var(--shadow-2)}
.btn:active{transform:translateY(1px)}
.btn-ghost{background:var(--paper);color:var(--ink);border-color:var(--line-strong);box-shadow:none}
.btn-ghost:hover{background:var(--sunken);border-color:var(--ink-2)}
.link-quiet{display:inline-flex;align-items:center;min-height:44px;font-size:14.5px;
  font-weight:500;color:var(--ink);text-decoration-color:var(--line-strong);gap:6px}
.link-quiet:hover{text-decoration-color:currentColor}

/* ---------- forms ----------
   One card per form, one label above each control, and a 48px field height so
   the form is usable with a thumb. Errors are text first, colour second. */
.form{max-width:620px;margin-top:26px;background:var(--paper);border:1px solid var(--line);
  border-radius:var(--r);padding:24px 22px;box-shadow:var(--shadow-1)}
@media (max-width:560px){.form{padding:18px 16px}}
.field{margin-bottom:22px}
.field > label,.field > legend,.field-group > legend{
  display:block;font-weight:600;font-size:15px;margin-bottom:8px;color:var(--ink)}
.field input,.field textarea,.field select{
  width:100%;padding:12px 14px;border:1px solid var(--line-strong);border-radius:var(--r-sm);
  background:var(--paper);color:var(--ink);font:inherit;font-size:16px;min-height:50px;
  transition:border-color .15s var(--ease),box-shadow .15s var(--ease)}
.field input:focus,.field textarea:focus,.field select:focus{
  outline:none;border-color:var(--ink);box-shadow:0 0 0 3px rgba(23,21,15,.10)}
.field textarea{min-height:130px;line-height:1.7;resize:vertical}
.field select{
  appearance:none;-webkit-appearance:none;cursor:pointer;padding-right:44px;
  background-image:linear-gradient(45deg,transparent 50%,var(--ink-2) 50%),
                   linear-gradient(135deg,var(--ink-2) 50%,transparent 50%);
  background-position:calc(100% - 21px) calc(50% + 1px),calc(100% - 16px) calc(50% + 1px);
  background-size:5px 5px,5px 5px;background-repeat:no-repeat}
.field .hint{font-size:13px;line-height:1.65;color:var(--muted);margin:8px 0 0}
/* A field the server rejected. Colour is backed by the message below the
   control and by aria-invalid, so the error is never carried by colour alone. */
.field-invalid input,.field-invalid textarea,.field-invalid select{
  border-color:var(--danger);border-width:2px;background:#FDF6F2}
.field-error{font-size:14px;line-height:1.6;color:var(--danger);font-weight:500;margin:7px 0 0}
.field-error::before{content:"\26A0\00a0";font-weight:400}
/* "ไม่บังคับ" sits inside the label so a screen reader announces the field as
   optional rather than leaving the reader to infer it from the absence of an
   asterisk. */
.optional{font-weight:400;font-size:12.5px;color:var(--muted);margin-left:4px}
/* Date and time side by side; stacked on a phone where a date picker needs
   the full width. */
.field-row{display:grid;grid-template-columns:minmax(0,1fr);gap:0 16px}
@media (min-width:560px){.field-row{grid-template-columns:minmax(0,1.25fr) minmax(0,1fr)}}
.field-group{border:0;padding:0;margin:0 0 22px;min-width:0}
.group-legend{font-weight:600;font-size:15px;margin-bottom:10px;color:var(--ink)}
.radio{display:flex;gap:10px;align-items:center;font-weight:400;min-height:48px;margin:0;
  padding:2px 4px;border-radius:var(--r-sm)}
.radio:hover{background:var(--surface)}
.radio input{width:auto;min-height:0;margin:0;accent-color:var(--ink)}
/* Two columns where the labels fit keeps the whole choice visible without a
   long scroll. The grid flows down each column (column-major) so the visual
   order still matches the reading order. */
.radio-group{display:grid;grid-template-columns:minmax(0,1fr);column-gap:24px}
@media (min-width:620px){
  .radio-group{grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-flow:column;grid-template-rows:repeat(4,auto)}
}
fieldset{border:0;padding:0;margin:0 0 22px;min-width:0}
.counter{font-size:12.5px;line-height:1.6;color:var(--muted);margin:4px 0 0;font-variant-numeric:tabular-nums}
.counter.is-short{color:var(--danger)}
.form-actions{display:flex;flex-wrap:wrap;align-items:center;gap:12px 22px;margin-top:26px}
.error{color:var(--danger);font-size:14.5px;line-height:1.6}
/* A block-level error or note that follows a form rather than sitting in it. */
.error-block{margin-top:18px}
.note-block{margin-top:26px}
.note-tight{margin-top:16px}
/* A heading that opens a new group of content under a page header. */
.section-gap{margin-top:40px}
.notice{background:var(--surface);border:1px solid var(--line);border-left:3px solid var(--state,var(--ink));
  padding:14px 18px;font-size:14.5px;line-height:1.7;border-radius:0 var(--r-sm) var(--r-sm) 0;margin:20px 0}

/* ---------- receipts / tracking ---------- */
.receipt{border:1px solid var(--line);border-top:3px solid var(--ink);border-radius:var(--r-sm);
  padding:24px 26px;margin-top:26px;max-width:540px;background:var(--paper);box-shadow:var(--shadow-1)}
.receipt .tracking{font-family:var(--mono);font-size:clamp(26px,4vw,34px);font-weight:500;
  letter-spacing:.04em;margin:6px 0 10px;color:var(--ink)}

/* ---------- lists (search results, reports) ---------- */
.card-grid{list-style:none;padding:0;margin:22px 0 0;display:grid;gap:12px;
  grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
.card{background:var(--paper);border:1px solid var(--line);border-radius:var(--r);
  padding:18px 20px 20px;min-width:0;box-shadow:var(--shadow-1);
  transition:border-color .15s var(--ease),box-shadow .15s var(--ease),transform .15s var(--ease)}
.card:hover{border-color:var(--line-strong);box-shadow:var(--shadow-2);transform:translateY(-1px)}
.card a{display:inline-flex;align-items:center;min-height:44px;font-family:var(--sans-digits);
  font-size:17px;font-weight:600;text-decoration:none;color:var(--ink);letter-spacing:0;
  font-variant-numeric:tabular-nums}
/* A result with no page behind it is plain text, not a link into a 404. It is
   still a number the reader typed, so it keeps the number register and only
   loses the link affordance — before this it borrowed `.card a`'s type but not
   its weight, and read as a disabled control. */
.card-num{display:inline-flex;align-items:center;min-height:44px;font-family:var(--sans-digits);
  font-size:17px;font-weight:600;color:var(--ink-2);letter-spacing:0;
  font-variant-numeric:tabular-nums}
.card a:hover{text-decoration:underline}
/* A guide card's link is a page title, not a number: same card, different type.
   `.card a` above sets the number register (tabular, 17px), so this has to be
   more specific than a bare `.card-title`. */
.card a.card-title{font-family:var(--sans);font-size:16px;font-weight:600;
  font-variant-numeric:normal;color:var(--ink);line-height:1.6;text-wrap:balance}
.card p{margin:6px 0 0;font-size:14px;line-height:1.7;color:var(--muted)}
.reports{list-style:none;padding:0;margin:20px 0 0}
.reports li{padding:18px 20px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--paper);box-shadow:var(--shadow-1)}
.reports li + li{margin-top:10px}
.reports .rep-head{display:flex;flex-wrap:wrap;gap:6px 14px;align-items:baseline}
.reports .tracking{font-family:var(--mono);font-size:15px;font-weight:500;letter-spacing:.03em}
.status{font-size:13px;font-weight:600;letter-spacing:.02em}
.status-pending{color:#8A5A10}
.status-approved{color:#1F4D38}
.status-rejected{color:#8C2F12}
.review{border:1px solid var(--line);border-radius:var(--r);background:var(--paper);
  padding:20px 22px;margin-top:12px;box-shadow:var(--shadow-1)}
/* A run of queue cards under a section heading. */
.queue{margin-top:20px}
.queue-nav{margin-top:12px}
/* A hint that sits inside a flex row of metadata rather than under a control. */
.hint-inline{margin:0}
/* A hint that closes a section, set slightly apart from the block above it. */
.hint-after{margin-top:14px}
.review-head{display:flex;flex-wrap:wrap;gap:4px 14px;font-family:var(--sans-digits);
  font-size:12.5px;color:var(--muted);margin:0 0 8px;font-variant-numeric:tabular-nums}
.inline-form{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:14px}
.inline-form input{padding:10px 12px;border:1px solid var(--line-strong);border-radius:var(--r-sm);
  background:var(--paper);font:inherit;font-size:14px;min-height:44px;flex:1;min-width:160px}
.inline-form button{min-height:44px;padding:0 18px;border-radius:var(--r-pill);border:1px solid var(--ink);
  background:var(--ink);color:var(--paper);font:inherit;font-size:14px;font-weight:600;cursor:pointer}
.inline-form button.secondary{background:transparent;color:var(--ink);border-color:var(--line-strong)}
.log{width:100%;border-collapse:separate;border-spacing:0;margin-top:16px;font-size:13px;
  background:var(--paper);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.log th{text-align:left;font-weight:600;color:var(--muted);font-size:12px;letter-spacing:.01em;
  padding:11px 14px;border-bottom:1px solid var(--line-strong);background:var(--surface)}
.log td{padding:11px 14px;border-bottom:1px solid var(--line);vertical-align:top;color:var(--ink-2)}
.log tr:last-child td{border-bottom:0}
/* Six columns of Thai inside a 390px phone squeezed each cell to ~50px, which
   is narrower than a single Thai word and made the audit log unreadable. Below
   700px each row becomes a labelled stack instead: the column name is repeated
   per cell via data-label, so nothing depends on remembering the header. */
@media (max-width:699px){
  .log{display:block;border:0;background:transparent;overflow:visible}
  .log thead{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}
  .log tbody{display:block}
  .log tr{display:grid;grid-template-columns:minmax(0,1fr);padding:14px 16px;
    border:1px solid var(--line);border-radius:var(--r);background:var(--paper);
    box-shadow:var(--shadow-1);margin-top:10px}
  .log td{display:grid;grid-template-columns:96px minmax(0,1fr);gap:10px;padding:3px 0;border:0}
  .log td::before{content:attr(data-label);color:var(--muted);font-size:12px}
  .log td:empty{display:none}
}

/* ---------- number lists (index page, home page, siblings) ----------
   A list of numbers with the reason each one is on it. The rank is the list's
   own order made visible; the number is the link; the reason is the evidence,
   in the same muted register as every other provenance line. */
.num-list{list-style:none;margin:0;padding:0;counter-reset:rank;
  border:1px solid var(--line);border-radius:var(--r);background:var(--paper);
  box-shadow:var(--shadow-1);overflow:hidden}
.num-list li{display:flex;flex-wrap:wrap;align-items:center;gap:4px 16px;
  padding:12px 18px;border-top:1px solid var(--line);counter-increment:rank;
  transition:background .12s var(--ease)}
.num-list li:first-child{border-top:0}
.num-list li:hover{background:var(--surface)}
.num-list li::before{content:counter(rank,decimal-leading-zero);
  font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--muted);
  min-width:20px;line-height:1}
.num-list a{display:inline-flex;align-items:center;min-height:44px;text-decoration:none}
.num-list-n{font-family:var(--sans-digits);font-variant-numeric:tabular-nums;
  font-size:17.5px;font-weight:600;color:var(--ink);letter-spacing:0}
.num-list a:hover .num-list-n{text-decoration:underline;text-underline-offset:3px}
.num-list-reason{font-size:13px;color:var(--muted);line-height:1.6}
.num-list a:focus-visible{outline:2px solid var(--ink);outline-offset:3px}
/* The chevron is the affordance that the row is a link, and it costs no text. */
.num-list li::after{content:"";margin-left:auto;width:7px;height:7px;flex:none;
  border-right:1.5px solid var(--line-strong);border-bottom:1.5px solid var(--line-strong);
  transform:rotate(-45deg);transition:border-color .12s var(--ease)}
.num-list li:hover::after{border-color:var(--ink-2)}

/* Inline links inside .hint must clear the 44px tap target. a11y_check.py
   caught "ดูรายการทั้งหมด" at 22px, then "ดูทุกเบอร์ในช่วง" at the same size —
   so this is scoped to the container rather than to individual hrefs, which
   kept missing the next link someone added. */
.hint{font-size:13px;line-height:1.7;color:var(--muted);margin-top:10px}
.hint a{display:inline-flex;align-items:center;min-height:44px;color:var(--ink-2)}

/* ---------- prefix hub grid ----------
   One tile per allocated range. The digits lead because that is what a reader
   scans for; the allocation label is supporting evidence, in the muted
   register, and the count is the reason the tile exists. */
.prefix-grid{list-style:none;margin:22px 0 0;padding:0;display:grid;
  grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:10px}
.prefix-grid a{display:flex;flex-direction:column;gap:2px;min-height:96px;
  padding:16px 18px;background:var(--paper);border:1px solid var(--line);
  border-radius:var(--r);text-decoration:none;justify-content:center;
  box-shadow:var(--shadow-1);transition:border-color .15s var(--ease),box-shadow .15s var(--ease),transform .15s var(--ease)}
.prefix-grid a:hover{background:var(--paper);border-color:var(--line-strong);
  box-shadow:var(--shadow-2);transform:translateY(-1px);text-decoration:none}
.prefix-grid a:focus-visible{outline:2px solid var(--ink);outline-offset:2px}
.prefix-num{font-family:var(--sans-digits);font-variant-numeric:tabular-nums;
  font-size:22px;font-weight:600;color:var(--ink);line-height:1.2}
.prefix-label{font-size:12px;line-height:1.5;color:var(--ink-2)}
.prefix-count{font-size:11.5px;color:var(--muted);margin-top:4px}

/* ---------- inline report form ----------
   Two controls. The type chips are a radio group so the choice is one tap and
   the label is the target, not a 16px dot; the textarea is the whole point and
   gets the width. */
.quick-report{margin-top:18px;max-width:62ch}
.qr-types{border:0;padding:0;margin:0 0 20px;min-width:0}
.qr-types legend{font-size:13px;font-weight:600;color:var(--ink-2);padding:0;margin-bottom:10px}
.qr-chips{display:flex;flex-wrap:wrap;gap:8px}
.qr-chip{position:relative;display:inline-flex}
.qr-chip input{position:absolute;opacity:0;width:1px;height:1px}
.qr-chip span{display:inline-flex;align-items:center;min-height:46px;padding:8px 18px;
  border:1px solid var(--line-strong);border-radius:var(--r-pill);background:var(--paper);
  font-size:14px;font-weight:500;color:var(--ink-2);cursor:pointer;
  transition:background .15s var(--ease),border-color .15s var(--ease),color .15s var(--ease)}
.qr-chip input:checked + span{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.qr-chip input:focus-visible + span{outline:2px solid var(--ink);outline-offset:3px}
.qr-chip span:hover{border-color:var(--ink-2);color:var(--ink)}
.report-error{border:1px solid rgba(140,47,18,.30);border-left:3px solid var(--danger);
  padding:12px 16px;margin:0 0 18px;background:#FDF4EF;border-radius:0 var(--r-sm) var(--r-sm) 0}
.report-error p{margin:0;font-size:14px;line-height:1.7;color:var(--ink-2)}
.report-error p + p{margin-top:4px}
/* 3 rows is what the placeholder needs; the browser default stretched it to
   ~130px, which reads as "write an essay" for a report that is usually one
   sentence. */
.quick-report textarea{width:100%;min-height:96px;resize:vertical}
.quick-report .field + .field{margin-top:16px}

/* ---------- home ----------
   The hero is the site's one chance to say what it is before asking for a
   number. It gets a tinted field, a display headline and an elevated search
   card; everything below it is the live state of the database. */
.hero{position:relative;padding-block:52px 8px;border-top:2px solid var(--ink);
  background:
    radial-gradient(120% 90% at 85% 0%,rgba(180,85,31,.07),transparent 60%),
    radial-gradient(90% 80% at 0% 100%,rgba(46,69,87,.06),transparent 55%),
    var(--paper)}
@media (min-width:820px){.hero{padding-block:72px 12px}}
/* Thai tone marks paint above the line box at display sizes, so headings need
   more leading than Latin conventions would suggest (and a real gap above). */
.hero .eyebrow{margin:0 0 18px}
.hero h1{font-family:var(--display);font-weight:600;font-size:clamp(34px,5.4vw,58px);line-height:1.5;
  letter-spacing:-.01em;margin:0;color:var(--ink);max-width:16em}
.lede{font-size:17.5px;line-height:1.75;color:var(--ink-2);margin:16px 0 0;max-width:46ch}
.home-search{margin-top:30px;max-width:620px;background:var(--paper);
  border:1px solid var(--line);border-radius:var(--r-lg);padding:18px;
  box-shadow:var(--shadow-3)}
.home-search label{display:block;font-size:12.5px;letter-spacing:.03em;
  font-weight:600;color:var(--muted);margin-bottom:8px}
.home-search .row{display:flex;gap:10px}
.home-search input{flex:1;min-width:0;padding:13px 16px;border:1px solid var(--line-strong);
  border-radius:var(--r-sm);background:var(--paper);font-family:var(--mono);font-size:17px;
  color:var(--ink);min-height:54px;letter-spacing:.01em;
  transition:border-color .15s var(--ease),box-shadow .15s var(--ease)}
.home-search input:focus{outline:none;border-color:var(--ink);box-shadow:0 0 0 3px rgba(23,21,15,.10)}
.home-search input::placeholder{font-family:var(--sans);font-size:15px;color:var(--muted);letter-spacing:0}
.home-search button{flex:none;min-height:54px;padding-inline:26px}
@media (max-width:560px){.home-search .row{flex-direction:column}.home-search button{width:100%}}
.home-search .hint{margin-top:10px}
/* The three promises under the search: what the site does, in the reader's
   terms, before they type anything. */
.trust-row{list-style:none;display:flex;flex-wrap:wrap;gap:8px 18px;margin:16px 0 0;padding:0;
  font-size:12.5px;color:var(--muted)}
.trust-row li{display:inline-flex;align-items:center;gap:7px;line-height:1.6}
.trust-row li::before{content:"";width:5px;height:5px;background:var(--line-strong);flex:none}

.how{list-style:none;counter-reset:how;padding:0;margin:24px 0 0;
  display:grid;grid-template-columns:minmax(0,1fr);gap:10px}
@media (min-width:760px){.how{grid-template-columns:repeat(2,minmax(0,1fr))}}
.how li{display:grid;grid-template-columns:40px minmax(0,1fr);column-gap:14px;
  padding:18px 20px;background:var(--paper);border:1px solid var(--line);
  border-radius:var(--r);box-shadow:var(--shadow-1);
  font-size:15.5px;line-height:1.75}
.how li::before{counter-increment:how;content:counter(how,decimal-leading-zero);
  font-family:var(--display);font-weight:600;font-size:22px;color:var(--muted);
  line-height:1.4;letter-spacing:0}

/* ---------- guide / prose ---------- */
.prose{max-width:var(--measure)}
/* Guide pages put their h2 in the rail, so prose h2 is for in-body headings. */
.prose h2{font-size:20px;line-height:1.55;font-weight:600;margin:40px 0 10px;
  padding-top:20px;border-top:1px solid var(--line)}
/* The rail's h2 on a guide page is the visible section heading; prose inside the
   body starts with a paragraph, so it needs no leading rule of its own. */
.prose > p:first-child,.prose > ul:first-child,.prose > ol:first-child{margin-top:0}
.prose ol li,.prose ul li{margin-bottom:10px}
.prose h2:first-of-type{margin-top:28px}
.prose p,.prose li{font-size:16px;line-height:1.8;color:var(--ink-2)}
.prose ul,.prose ol{padding-left:22px;margin:12px 0}
.prose li{margin-bottom:6px}
.prose strong{color:var(--ink);font-weight:600}
/* Inline prose links sit inside running text, so they cannot be 44px tall
   without breaking the line box. Give them a padded hit area instead: the
   extra vertical padding is transparent and does not move text. */
.prose a{
  display:inline-block;min-height:44px;line-height:1.8;
  padding-block:7px;margin-block:-7px;vertical-align:middle}

/* ---------- state gallery (used on /guide/) ---------- */
.gallery{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;margin-top:26px}
@media (min-width:860px){.gallery{grid-template-columns:repeat(2,minmax(0,1fr))}}
.g-card{background:var(--tint);border:1px solid var(--hair);border-top:3px solid var(--rule);
  border-radius:var(--r);padding:22px 22px 24px;display:flex;flex-direction:column;
  box-shadow:var(--shadow-1)}
@media (min-width:860px){.g-card{padding:24px 26px 26px}}
.g-card .v-kicker{font-size:12.5px}
.g-line{font-family:var(--display);font-weight:600;font-size:21px;line-height:1.7;
  margin:14px 0 0;letter-spacing:0;max-width:22em}
.g-scope{font-size:12.5px;line-height:1.7;margin:16px 0 0;padding-top:12px;
  border-top:1px solid var(--soft);color:var(--muted);max-width:48ch}
.g-card-wide{grid-column:1/-1}

/* The verdict kicker (guide gallery and the old verdict vocabulary). */
.v-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.v-kicker{display:flex;align-items:center;gap:8px;margin:0;
  font-size:12.5px;letter-spacing:.02em;font-weight:600;color:var(--state)}
.sq{width:9px;height:9px;background:var(--state);display:inline-block;flex:none;border-radius:1px}
.sq-hollow{width:9px;height:9px;border:1.5px solid var(--muted);display:inline-block;flex:none;border-radius:1px}

/* ---------- footer ---------- */
.site-foot{background:var(--surface);border-top:1px solid var(--line);margin-top:0}
.foot-grid{display:grid;grid-template-columns:minmax(0,1fr);gap:24px;padding-block:40px}
@media (min-width:820px){.foot-grid{grid-template-columns:minmax(0,1.3fr) minmax(0,1fr) minmax(0,1fr);
  column-gap:56px;align-items:start}}
.foot-brand p{margin:14px 0 0;font-size:13.5px;line-height:1.7;color:var(--muted);max-width:34ch}
.foot-disclaim{font-size:13px;line-height:1.7;color:var(--muted);max-width:35ch;
  border-left:2px solid var(--line-strong);padding-left:14px}
.foot-guide{display:inline-flex;align-items:center;min-height:44px;font-size:13.5px;
  line-height:1.7;color:var(--ink-2);font-weight:500}
.foot-nav{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:12px 24px;
  margin-top:32px;padding-top:16px;border-top:1px solid var(--line);font-size:13px;color:var(--muted)}
.foot-nav nav{display:flex;gap:4px 18px;flex-wrap:wrap}
.foot-nav a{color:var(--ink-2);display:inline-flex;align-items:center;min-height:44px}
.foot-nav a:hover{color:var(--ink)}

/* ---------- misc ---------- */
h1.page{font-family:var(--display);font-weight:600;font-size:clamp(28px,3.8vw,40px);
  line-height:1.5;margin:30px 0 0;letter-spacing:-.005em;max-width:20em}
.page-lede{font-size:16.5px;line-height:1.75;color:var(--ink-2);margin:14px 0 0;max-width:56ch}
.error-box{border:1px solid rgba(140,47,18,.30);border-left:3px solid var(--danger);
  background:#FDF4EF;padding:14px 18px;margin:24px 0;font-size:14.5px;line-height:1.7;
  max-width:60ch;border-radius:0 var(--r-sm) var(--r-sm) 0}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-duration:.001ms!important;animation-duration:.001ms!important}
}

/* ---------- collapse (older reports, the verdict's reasons) ----------
   Native <details>: no JS, keyboard- and screen-reader-native, and the content
   stays in the served HTML so a crawler still reads every report and every
   reason. Only the visual height is saved. */
.exp-more{margin:14px 0 0}
.exp-more > summary,
.reasons-fold > summary{
  display:flex;align-items:center;gap:10px;min-height:52px;cursor:pointer;
  font-size:14.5px;font-weight:500;color:var(--ink);list-style:none;padding:6px 0}
.exp-more > summary::-webkit-details-marker,
.reasons-fold > summary::-webkit-details-marker{display:none}
.exp-more > summary::before,
.reasons-fold > summary::before{
  content:"";width:9px;height:9px;flex:none;border-right:1.5px solid var(--ink-2);
  border-bottom:1.5px solid var(--ink-2);transform:rotate(-45deg);margin-left:3px;
  transition:transform .15s var(--ease)}
.exp-more[open] > summary::before,
.reasons-fold[open] > summary::before{transform:rotate(45deg)}
.exp-more > summary:hover,
.reasons-fold > summary:hover{color:var(--ink)}
.exp-more > summary:focus-visible,
.reasons-fold > summary:focus-visible{
  outline:2px solid var(--ink);outline-offset:3px}
/* The verdict's working-out, folded. It sits under the action line, so the
   summary has no top border of its own — the reasons list brings one. */
.reasons-fold{margin:16px 0 0}
.reasons-fold > summary{min-height:48px;color:var(--ink-2)}
.reasons-fold .reasons{margin-top:0}

.reasons{list-style:none;margin:30px 0 0;padding:0;border-top:1px solid var(--line)}
.reasons li{display:grid;grid-template-columns:34px minmax(0,1fr);column-gap:10px;
  padding:14px 0;border-bottom:1px solid var(--line);font-size:16px;line-height:1.75}
.reasons .n{width:10px;height:1px;background:var(--muted);margin-top:12px;display:block}
@media (min-width:561px){.reasons .n{margin-top:13px}}
.reasons strong{font-weight:600}
@media (max-width:560px){.reasons li{grid-template-columns:26px minmax(0,1fr);font-size:16px;padding:13px 0}}

.scope{margin:24px 0 0;font-size:15px;line-height:1.8;color:var(--muted);max-width:62ch;
  padding-left:16px;border-left:2px solid var(--soft)}
.scope strong{color:var(--ink);font-weight:600;letter-spacing:0}

/* ---------- relationships ----------
   Two tiers, and the difference is visible: a cited row is a card, an uncited
   one is a dashed card with its caveat inside the block. */
.rel{background:var(--paper);border:1px solid var(--line);border-radius:var(--r);
  padding:18px 20px;box-shadow:var(--shadow-1)}
.rel + .rel{margin-top:10px}
.rel-usage{font-size:13.5px;color:var(--ink-2);margin:4px 0 0}
.rel-source{font-size:12.5px;line-height:1.7;color:var(--muted);margin:6px 0 0;max-width:60ch;
  overflow-wrap:anywhere}
/* A relationship the reviewer recorded but could not attribute. It is shown
   because a reader may recognise the name, but it must never look like the
   cited rows above it: dashed rule instead of solid, and the caveat is part of
   the block rather than a footnote. */
.rel-uncited{border-style:dashed;box-shadow:none;background:var(--paper)}
.rel-uncited .org-name{color:var(--ink-2)}
.rel-uncited-note{display:flex;align-items:flex-start;gap:9px;margin:8px 0 0;
  font-size:12.5px;line-height:1.7;color:var(--muted);max-width:60ch}
.rel-uncited-note .sq-hollow{flex:none;margin-top:7px}
.prov-empty{font-size:16px;line-height:1.75;color:var(--ink-2);margin:0;max-width:56ch}
.org-name{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 12px;
  font-size:20px;line-height:1.55;font-weight:600;margin:0;color:var(--ink)}

/* The evidence card's two hero figures: the two questions a reader arrives
   with, as figures rather than as rows in a table. */
.prov-hero{display:grid;grid-template-columns:minmax(0,1fr);gap:10px;margin:0 0 14px}
@media (min-width:620px){.prov-hero{grid-template-columns:1fr 1fr;column-gap:10px}}
.prov-stat{background:var(--paper);border:1px solid var(--line);border-radius:var(--r);
  padding:18px 20px;box-shadow:var(--shadow-1)}
.prov-n{font-family:var(--display);font-variant-numeric:tabular-nums;
  font-size:clamp(40px,5.2vw,54px);font-weight:600;line-height:1.1;color:var(--ink);display:block}
.prov-u{font-size:14px;font-weight:600;color:var(--ink-2);display:block;margin-top:4px}
.prov-sub{font-size:12.5px;line-height:1.65;color:var(--muted);display:block;margin-top:8px;max-width:36ch}
.prov-verdict{font-size:15.5px;line-height:1.8;color:var(--ink-2);margin:0 0 6px;max-width:62ch}
/* The audit detail. Same rows, smaller and quieter, so it reads as apparatus. */
.prov-quiet{margin:18px 0 0;box-shadow:none}
.prov-quiet > div{padding:10px 18px}
.prov-quiet dt{font-size:12px}
.prov-quiet dd{font-size:13.5px;color:var(--muted)}

/* ---------- the admin edit screen's relationship editor ---------- */
.edit-block{margin-top:44px;padding-top:28px;border-top:1px solid var(--line)}
.rel-edit-list{list-style:none;padding:0;margin:20px 0 0}
.rel-edit-row{display:flex;gap:16px;align-items:flex-start;justify-content:space-between;
  padding:16px 18px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--paper);box-shadow:var(--shadow-1)}
.rel-edit-row + .rel-edit-row{margin-top:10px}
.rel-edit-row.is-uncited{background:var(--surface);border-style:dashed;box-shadow:none}
.rel-edit-main{min-width:0}
.rel-edit-name{margin:0;font-size:16px;font-weight:600;color:var(--ink);line-height:1.6}
.rel-edit-meta{margin:4px 0 0;font-size:13px;line-height:1.7;color:var(--ink-2)}
.rel-edit-url{margin:4px 0 0;font-family:var(--mono);font-size:12px;
  color:var(--muted);overflow-wrap:anywhere}
.rel-edit-flag{display:flex;align-items:center;gap:8px;margin:8px 0 0;
  font-size:12.5px;line-height:1.6;color:var(--muted)}
.rel-edit-flag .sq{width:8px;height:8px;flex:none}
.btn-small{min-height:44px;padding:0 16px;font-size:13.5px}
.rel-form{margin-top:26px;max-width:none}
.rel-publishable{display:flex;align-items:center;gap:10px;margin:6px 0 0;
  font-size:14.5px;line-height:1.7;min-height:44px;cursor:pointer}
.rel-publishable input{width:18px;height:18px;min-height:0;flex:none;margin:0;accent-color:var(--ink)}

/* The demand page's "create this number" control. A form, not a link — the
   action writes — but it must look like the edit link it sits beside, so the
   two admin affordances read as one thing. */
.inline-create{display:inline-flex;margin:0}
.inline-create .edit-link{font-family:inherit;cursor:pointer}

/* The report an audit-log link points at. A left rule and a tint, not a
   colour-only cue: the row is also the page's scroll target. */
.review.is-highlighted{background:var(--surface);box-shadow:inset 3px 0 0 var(--ink),var(--shadow-1);
  padding-left:20px}

/* ---------- admin evidence queue & receipts ----------
   Small spacing decisions that used to be inline on the templates. */
.source-tabs{margin-bottom:18px}
.source-org{margin:10px 0 0}
.source-url{margin:6px 0 0}
.source-note{margin-top:10px}
.source-decide{margin-top:16px;max-width:640px}
.receipt-status{margin-top:14px}
.receipt-foot{margin-top:24px}
.rep-status{margin-top:6px}
.rep-empty-action{margin-top:20px}
.error-detail{margin-top:16px}

/* ---------- error page ---------- */
.band .body > .number{font-size:clamp(30px,4.4vw,48px)}
