/* ════════════════════════════════════════════════════════════════════════
   habitat — v2 design system
   ONE palette, ONE type scale, ONE space scale, ONE button, ONE card.
   Everything else is a MODIFIER on those. If something needs a new look it
   gets a modifier — never a new component. That rule is the system.
   ════════════════════════════════════════════════════════════════════════ */
:root{
  /* GROUNDS — one ramp, lightest to darkest. Every surface sits on it. */
  --g-0:#fffced;  /* lit    — brightest band (datasets)  */
  --g-1:#fbf6ea;  /* card   — raised off the page        */
  --g-2:#f3ead6;  /* page   — default ground             */
  --g-3:#e9dcc4;  /* recess — panels that sit back       */
  --g-4:#5e5d09;  /* olive  — the instrument             */
  --g-5:#803c18;  /* terra  — the hero                   */
  --g-6:#2a2118;  /* ink    — deepest                    */

  /* INK — two families. Dark for grounds 0-3, light for 4-6. */
  --i-1:#2a2118; --i-2:rgba(42,33,24,.78);
  /* .60 measured 3.81 on --g-3, failing AA for the labels, kv keys, card meta
     and small print that all use it. .70 clears every ground at >=5.05. */
  --i-3:rgba(42,33,24,.70);
  --l-1:#fffaf1; --l-2:#f6ead9;            --l-3:#e4d6bb;

  /* ACCENT — one hue, three steps, SPLIT BY ROLE.
     Measured: cream on #d24d06 = 4.20 and #d24d06 on cream = 4.05 — both under
     the 4.5 line. So the bright step is an EDGE colour (UI needs only 3.0), and
     text/fills use the deep step, which clears at 7.84. */
  --a-1:#d24d06;  /* bright — edges: selection, hover borders. NEVER text.  */
  /* #ae5523 is the wordmark rust and it is NOT a small-text colour: measured
     3.76 on --g-3. palette.css already darkened it 4% the other way (#a44e1f)
     because cream-on-rust missed AA at 4.29; the reverse direction needs more.
     #8f4319 clears every ground at >=5.19 and stays in the same hue family.
     The wordmark itself is large and keeps the original rust. */
  --a-2:#8f4319;  /* mid    — links, labels, eyebrows on light               */
  --a-2-mark:#ae5523; /* the wordmark rust, large text only                  */
  --a-3:#803c18;  /* deep   — button fills and button text                  */

  /* SEMANTIC — never warmed, never decorative. Each has a FILL value and,
     where the fill is too light to read as type, a separate INK value.
     Measured: --warn as text is 2.13 on the chip tint; --ok is 4.20 on --g-3.
     Both fail. The fills are correct and stay; the inks are new. */
  --ok:#067647;   --ok-ink:#05633c;       /* >=5.43 on every ground   */
  --warn:#be8621; --warn-ink:#6f4c0d;     /* >=5.20 on the chip tint  */
  --bad:#B42318;  --bad-ink:#B42318;      /* passes as-is, 4.85       */
  --pulled:#9c3d16; --pulled-ink:#9c3d16; /* passes as-is, 5.01       */

  --line:rgba(42,33,24,.16); --line-strong:rgba(42,33,24,.30);
  --line-soft:rgba(42,33,24,.09); --line-dark:rgba(245,238,224,.28);
  --chip:rgba(42,33,24,.06);

  /* TYPE — EIGHT steps, nothing between them. Audited against the rendered
     page: labels, chips and run-ins were sitting off-scale at .66/.65/.62rem,
     and the digest at .9rem. All folded onto steps below. */
  --t-2xs:.66rem;  /* labels · eyebrows · chips · run-ins   10.6px */
  --t-xs:.72rem;   /* card meta/foot · data table · fine    11.5px */
  --t-sm:.82rem;   /* buttons · card body · small           13.1px */
  --t-md:.94rem;   /* body · card title · digest            15.0px */
  --t-lg:1.02rem;  /* lede                                  16.3px */
  --t-xl:1.2rem;   /* panel title — the missing step; 1.02→1.5 was a 1.47x
                      jump where every other step is ~1.1x    19.2px */
  --t-2xl:1.5rem;   /* section head                          24.0px */
  --t-3xl:2rem;    /* page h1                               32.0px */
  --t-4xl:2.7rem;  /* door display                          43.2px */
  /* LEADING — five steps. The audit found 1.62/1.60/1.55/1.50 all doing the
     same job; they are one step now. */
  --lh-flat:1;      /* buttons                     */
  --lh-display:1.16;/* the display headline        */
  --lh-head:1.25;   /* section + page headings     */
  --lh-tight:1.3;   /* card titles, meta, data     */
  --lh-body:1.6;    /* everything that is a sentence */
  /* SPACE — one unit, seven steps. */
  --s-1:.25rem; --s-2:.5rem; --s-3:.75rem; --s-4:1rem;
  --s-5:1.5rem; --s-6:2rem; --s-7:3rem;
  --r-sm:3px; --r-md:6px;
  --measure:40rem; --sheet:54rem; --sheet-narrow:45rem;

  --serif:"Source Serif 4",Georgia,serif;
  --sans:"Inter",system-ui,-apple-system,"Segoe UI",sans-serif;
  --mono:"Roboto Mono",ui-monospace,SFMono-Regular,monospace;

  /* CONTEXT tokens — flipped wholesale by .on-dark */
  --ink:var(--i-1); --ink-2:var(--i-2); --ink-3:var(--i-3);
  --surface:var(--g-1); --edge:var(--line); --act:var(--a-3); --on-act:#fffaf1;
  --act-hover:var(--a-2); --act-line:var(--a-3); --act-wash:rgba(128,60,24,.07);
}
/* RULE: components read --ink / --ink-2 / --ink-3, never --i-1/2/3 directly.
   The --i-* and --l-* families are RAW VALUES that only a context may assign.
   A component that reads --i-2 renders dark-on-dark the moment it lands inside
   .on-dark — which is exactly how .note broke at 2.08 contrast.

   One class flips every context token. No component knows whether it sits on
   a dark ground — it asks the context. That is the whole trick. */
.on-dark{
  --ink:var(--l-1); --ink-2:var(--l-2); --ink-3:var(--l-3);
  --surface:rgba(255,255,255,.07); --edge:var(--line-dark);
  --act:#fffaf1; --on-act:var(--a-3);
  --act-hover:#ffffff; --act-line:rgba(245,238,224,.55); --act-wash:rgba(255,255,255,.08);
}
*{box-sizing:border-box}
body{margin:0;background:var(--g-2);color:var(--ink-2);font-family:var(--sans);
  font-size:16px;line-height:var(--lh-body);-webkit-font-smoothing:antialiased}

/* REVIEW BAR — never ships */
.review{background:var(--g-6);color:var(--g-2);padding:var(--s-2) var(--s-5);font-size:var(--t-xs)}
.review b{font-weight:600;letter-spacing:.09em;text-transform:uppercase;font-size:var(--t-2xs);opacity:.7;margin-right:var(--s-3)}
.review a{color:var(--g-2);opacity:.65;margin-left:var(--s-3)}

/* CHROME */
/* CHROME — the live treatment (assets/site.css:67-72): terracotta band, cream
   wordmark and nav. The DOOR overrides to cream with .top--light: its hero is
   already terracotta, so a terracotta bar above it would read as one slab. The
   inner pages open on paper, and there the band is what separates chrome from
   content. Two treatments, one component, chosen by what sits beneath it. */
.top{background:var(--g-5)}
.top--light{background:var(--g-2);border-bottom:1px solid var(--line)}
/* .top.top--light is (0,3,1) so it beats the base .top nav a (0,2,1) that is
   declared later in this file. Same-specificity source order was making the
   links cream on cream. */
.top.top--light .wordmark{color:var(--ink)}
.top.top--light nav a{color:var(--ink-2)}
.top.top--light nav a:hover,.top.top--light nav a[aria-current]{color:var(--a-2)}
.top-in{max-width:var(--sheet);margin:0 auto;padding:1.1rem var(--s-5);
  display:flex;align-items:center;gap:var(--s-5)}
/* verbatim in effect from the live root page (index.html:252 + site.css:70) —
   cream on the terracotta band, sans not serif, with the mark. Do not restyle. */
.wordmark{display:inline-flex;align-items:center;gap:.55rem;font-family:var(--sans);
  font-size:1.22rem;font-weight:600;letter-spacing:-.01em;color:var(--g-2);text-decoration:none}
.wordmark img,.wordmark svg{width:1.6rem;height:1.6rem;display:block;flex:0 0 auto}

.top nav{margin-left:auto;display:flex;gap:1.5rem;flex-wrap:wrap;row-gap:var(--s-2)}
.top nav a{font-size:.875rem;color:rgba(243,234,214,.80);text-decoration:none;
  padding:.5rem .3rem;margin:-.5rem -.3rem}
.top nav a:hover,.top nav a[aria-current]{color:var(--g-2)}

/* BANDS — every full-width section is .band + a ground modifier */
.band--lit{background:var(--g-0)}
.band--page{background:var(--g-2)}
.band--recess{background:var(--g-3)}
.band--olive{background:var(--g-4);border-top:1px solid var(--line-dark)}
.band--terra{background:var(--g-5)}
/* --hero-vh: the opening band's share of the viewport. min-height, never
   height, so the band GROWS if the copy needs more and never crops.
   dvh is listed second so browsers that support it win: on mobile, vh is
   measured against the tallest possible viewport and the address bar then
   covers the bottom of it; dvh tracks the real one. */
.band--hero{--hero-vh:70;min-height:calc(var(--hero-vh) * 1vh);
  min-height:calc(var(--hero-vh) * 1dvh);display:flex;align-items:center}
.band--hero>.band-in{width:100%}
/* Short viewports — landscape phones, split screens. Below this the copy is
   taller than the target anyway, so centring only adds dead space. */
@media(max-height:640px){.band--hero{min-height:0;display:block}}

.band-in{max-width:var(--sheet);margin:0 auto;padding:var(--s-7) var(--s-5)}
.band-in--narrow{max-width:var(--sheet-narrow)}

/* TYPE */
h1,h2,h3{margin:0;color:var(--ink);font-weight:400;font-family:var(--serif)}
.h-display{font-size:var(--t-4xl);line-height:var(--lh-display);letter-spacing:-.014em;max-width:22ch}
.h-section{font-size:var(--t-2xl);line-height:var(--lh-head)}
.h-page{font-size:var(--t-3xl);line-height:var(--lh-head);letter-spacing:-.01em}
.lede{font-size:var(--t-lg);line-height:var(--lh-body);color:var(--ink-2);margin:0;max-width:var(--measure)}
.body{font-size:var(--t-md);line-height:var(--lh-body);color:var(--ink-2);margin:0;max-width:var(--measure)}
.small{font-size:var(--t-sm);line-height:var(--lh-body);color:var(--ink-3);margin:0;max-width:var(--measure)}
.eyebrow{font-size:var(--t-2xs);letter-spacing:.14em;text-transform:uppercase;color:var(--a-2);font-weight:600}
.on-dark .eyebrow{color:var(--l-3)}
b,strong{font-weight:600;color:var(--ink)}
.mono{font-family:var(--mono)}
.label{font-size:var(--t-2xs);letter-spacing:.14em;text-transform:uppercase;font-weight:600;
  color:var(--a-2);padding-bottom:var(--s-3);border-bottom:1px solid var(--line-strong);margin:0 0 var(--s-4)}
.on-dark .label{color:var(--l-3);border-bottom-color:var(--line-dark)}

/* BUTTON — one anatomy, three weights, one size modifier */
.btn{font-family:var(--sans);font-size:var(--t-sm);font-weight:500;line-height:var(--lh-flat);
  padding:.68rem 1.1rem;border-radius:var(--r-sm);border:1px solid transparent;cursor:pointer;
  text-decoration:none;display:inline-flex;align-items:center;gap:var(--s-2);
  transition:background .12s,border-color .12s,color .12s,opacity .12s}
.btn:focus-visible{outline:2px solid var(--act);outline-offset:2px}
.btn:disabled{opacity:.45;cursor:default}
.btn--solid{background:var(--act);color:var(--on-act);border-color:var(--act)}
.btn--solid:hover:not(:disabled){background:var(--act-hover);border-color:var(--act-hover)}
.btn--outline{background:transparent;color:var(--act);border-color:var(--act-line)}
.btn--outline:hover:not(:disabled){background:var(--act-wash);border-color:var(--act)}
.btn--quiet{background:transparent;color:var(--act);border-color:transparent;padding-inline:0}
.btn--quiet:hover:not(:disabled){text-decoration:underline;text-underline-offset:3px}
.btn--sm{font-size:var(--t-xs);padding:.45rem .8rem}
.btn-row{display:flex;flex-wrap:wrap;gap:var(--s-2);align-items:center}

/* CARD — one anatomy, modifiers for state and ground */
.card{background:var(--surface);border:1px solid var(--edge);border-radius:var(--r-md);
  padding:var(--s-4);display:block;text-decoration:none;color:inherit;
  transition:border-color .12s,box-shadow .12s}
/* the title reserves two lines so every card in a grid has the same internal
   rhythm — otherwise a one-line title leaves a bigger gap at the bottom and
   the row reads as ragged even though the boxes are identical heights */
.card__title{font-size:var(--t-md);font-weight:600;line-height:var(--lh-tight);letter-spacing:-.006em;
  color:var(--ink);min-height:2.6em}
.card__meta{font-family:var(--mono);font-size:var(--t-xs);line-height:var(--lh-tight);color:var(--ink-3);margin:var(--s-2) 0 0}
/* run-in label: says what the number is, in the same voice as a kv key */
.card__meta-k{font-family:var(--sans);font-size:var(--t-2xs);letter-spacing:.1em;text-transform:uppercase;
  font-weight:600;color:var(--ink-3);margin-right:var(--s-2)}
.card__size{font-family:var(--sans);font-size:var(--t-2xs);color:var(--ink-3);margin-left:var(--s-2)}
.card__foot{font-size:var(--t-xs);line-height:var(--lh-tight);color:var(--ink-3);margin:var(--s-2) 0 0}
/* on a card that navigates, the foot IS the action — the whole line reads as
   the link, not just a trailing cue */
.card--link .card__foot{color:var(--act);text-decoration:underline;text-underline-offset:2px;
  text-decoration-color:var(--act-line);text-decoration-thickness:1px}
.card--link:hover .card__foot{text-decoration-color:var(--act)}
.card__body{font-size:var(--t-sm);line-height:var(--lh-body);color:var(--ink-2);margin:var(--s-2) 0 0}
.card--action{cursor:pointer;text-align:left;width:100%;font-family:var(--sans)}
.card--action:hover,.card--link:hover{border-color:var(--a-1);box-shadow:0 1px 4px rgba(42,33,24,.10)}
/* SELECTED — a material change, not a border tweak. The olive was previously
   "computes on your own bench"; serving all nine emptied that category, so the
   second material now marks the record you are holding. It encodes a STATE, not
   a judgement about the result — a distinction that ranked cards by outcome
   would be the page arguing with its own copy. */
.card--selected{background:var(--g-4);border-color:var(--g-4);border-width:1px;
  padding:var(--s-4);box-shadow:0 2px 10px -4px rgba(42,33,24,.35);
  --ink:var(--l-1); --ink-2:var(--l-2); --ink-3:var(--l-3);
  --act:var(--l-1); --act-line:rgba(245,238,224,.45)}
.card--selected:hover{border-color:var(--g-4);box-shadow:0 2px 10px -4px rgba(42,33,24,.35)}
.card--olive{background:var(--g-4);border-style:dashed;border-color:var(--line-dark);
  --ink:var(--l-1); --ink-2:var(--l-2); --ink-3:var(--l-3);
  --act:var(--l-1); --act-line:rgba(245,238,224,.45)}
.card--olive:hover{border-color:var(--l-1);box-shadow:none}
/* a record with no destination yet: same surface, no affordance, no promise */
.card--inert{cursor:default}
.card--inert:hover{border-color:var(--line-dark);box-shadow:none}
.card--pulled{border-color:rgba(156,61,22,.40);background:rgba(156,61,22,.05)}
.card--pulled .card__title{color:var(--pulled)}
.card-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(15.5rem,1fr));
  gap:var(--s-2);grid-auto-rows:1fr}
.card-grid--2{grid-template-columns:repeat(2,1fr);grid-auto-rows:auto}

/* CHIP — a small status token. Replaces the ad-hoc .tag and .pill that the
   receipt and ledger pages each invented separately. One anatomy, four tones. */
.chip{display:inline-block;font-size:var(--t-2xs);letter-spacing:.08em;text-transform:uppercase;
  font-weight:600;padding:.18rem .45rem;border-radius:2px;background:var(--chip);color:var(--ink-3)}
.chip--ok{color:var(--ok-ink);background:rgba(6,118,71,.10)}
.chip--warn{color:var(--warn-ink);background:rgba(190,134,33,.12)}
.chip--pulled{color:var(--pulled-ink);background:rgba(156,61,22,.10)}
.chip-row{display:flex;flex-wrap:wrap;gap:var(--s-1);align-items:center}

/* PANEL — a card that holds a readout rather than a summary.
   A panel is a LIGHT surface, so it RESETS the context even inside .on-dark.
   Without this, buttons on an inset panel inherit the dark-ground tokens and
   render cream-on-cream. Context resets at every surface boundary. */
.panel{background:var(--g-1);border:1px solid var(--line);border-radius:var(--r-md);
  --ink:var(--i-1); --ink-2:var(--i-2); --ink-3:var(--i-3);
  --surface:var(--g-1); --edge:var(--line); --act:var(--a-3); --on-act:#fffaf1;
  --act-hover:var(--a-2); --act-line:var(--a-1); --act-wash:rgba(210,77,6,.07)}
.panel--inset{background:rgba(251,246,234,.95)}
.panel__head{padding:var(--s-4) var(--s-4) var(--s-3);border-bottom:1px solid var(--line-soft)}
.panel__body{padding:var(--s-4)}
.panel__title{font-size:var(--t-xl);font-family:var(--sans);color:var(--ink);
  margin-top:var(--s-2);line-height:var(--lh-head);font-weight:600;letter-spacing:-.01em}
.panel__sub{font-size:var(--t-sm);color:var(--ink-3);font-weight:400;margin-top:var(--s-2);
  font-family:var(--mono)}
.kv{display:grid;grid-template-columns:9rem 1fr;gap:var(--s-4);padding:var(--s-1) 0;align-items:baseline}
.kv__k{font-size:var(--t-xs);letter-spacing:.055em;text-transform:uppercase;color:var(--ink-3);font-weight:600}
.kv__v{font-family:var(--mono);font-size:var(--t-md);line-height:var(--lh-body);color:var(--ink);word-break:break-all}
.kv__v--plain{font-family:var(--sans);font-size:var(--t-md);word-break:normal;color:var(--ink-2)}

/* VERDICT */
.verdict{display:flex;gap:var(--s-2);align-items:baseline;margin-top:var(--s-3);font-size:var(--t-md);font-weight:600}
.verdict--pass{color:var(--ok-ink)} .verdict--ring{color:var(--warn-ink)} .verdict--fail{color:var(--bad-ink)}
.verdict__note{font-size:var(--t-sm);font-weight:400;color:var(--ink-2);margin-top:var(--s-2);
  max-width:var(--measure);line-height:var(--lh-body)}

/* NOTE — one component, four tones */
.note{border-left:3px solid var(--a-1);background:var(--g-3);padding:var(--s-3) var(--s-4);
  border-radius:0 var(--r-sm) var(--r-sm) 0;font-size:var(--t-sm);line-height:var(--lh-body);color:var(--ink-2)}
.note--warn{border-left-color:var(--warn);background:rgba(190,134,33,.10)}
.note--pulled{border-left-color:var(--pulled);background:rgba(156,61,22,.08)}
.note--quiet{border-left-color:var(--line-strong);background:transparent}

/* FOLD */
.fold{border-top:1px solid var(--line-soft);padding-top:var(--s-3);margin-top:var(--s-4)}
.fold>summary{cursor:pointer;list-style:none;font-size:var(--t-sm);color:var(--a-2);font-weight:500}
.fold>summary::-webkit-details-marker{display:none}
.fold>summary::before{content:"\2304";display:inline-block;width:1em;color:var(--ink-3)}
.fold__body{padding-top:var(--s-3);font-size:var(--t-sm);color:var(--ink-2);line-height:var(--lh-body);max-width:var(--measure)}

/* DATA TABLE */
.data-scroll{overflow-x:auto;border:1px solid var(--line);border-radius:var(--r-sm)}
table.data{border-collapse:collapse;font-family:var(--mono);font-size:var(--t-xs);min-width:100%}
table.data th{background:var(--chip);color:var(--ink);font-weight:500;text-align:right;
  padding:.4rem .55rem;white-space:nowrap;border-bottom:1px solid var(--line)}
table.data th:first-child{text-align:left}
table.data td{padding:.28rem .55rem;text-align:right;color:var(--ink-2);
  border-bottom:1px solid var(--line-soft);white-space:nowrap}
table.data td:first-child{text-align:left;color:var(--ink-3)}

/* FOOTER + STACK */
/* SITE FOOTER — grouped, not a flat row. Three columns of links by KIND,
   then a rule, then the entity line. Nothing competes with anything. */
.site-foot{margin-top:var(--s-7);padding-top:var(--s-5);border-top:1px solid var(--line-strong)}
.site-foot__cols{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-5)}
.site-foot__head{font-size:var(--t-2xs);letter-spacing:.14em;text-transform:uppercase;
  font-weight:600;color:var(--a-2);margin-bottom:var(--s-3);
  padding-bottom:var(--s-2);border-bottom:1px solid var(--line-soft)}
.site-foot__col ul{list-style:none;margin:0;padding:0}
.site-foot__col li+li{margin-top:var(--s-2)}
.site-foot__col a{font-size:var(--t-sm);color:var(--ink-2);text-decoration:none}
.site-foot__col a:hover{color:var(--a-2);text-decoration:underline;text-underline-offset:3px}
.site-foot__legal{margin-top:var(--s-5);padding-top:var(--s-4);
  border-top:1px solid var(--line-strong);font-size:var(--t-xs);color:var(--ink-3)}
.site-foot__legal p{margin:0}
.site-foot__legal p+p{margin-top:var(--s-2)}
.site-foot__claim{color:var(--a-2);font-weight:500}
.site-foot__legal b{font-weight:600;color:var(--ink-2)}
.site-foot__legal a{color:var(--ink-3);text-decoration:underline;text-underline-offset:3px}
.site-foot__legal a:hover{color:var(--a-2)}

@media(max-width:640px){.site-foot__cols{grid-template-columns:1fr;gap:var(--s-4)}
}
.stack>*+*{margin-top:var(--s-4)}
.stack--tight>*+*{margin-top:var(--s-3)}
.stack--loose>*+*{margin-top:var(--s-6)}
@media(max-width:640px){
  :root{--t-4xl:1.95rem;--t-3xl:1.6rem}
  .kv{grid-template-columns:1fr;gap:0}
  .card-grid--2{grid-template-columns:1fr}
}
