/* =============================================================================
   FaucetDynasty — "Atelier" UI system
   Single source of truth for every screen. Hand-written, served as-is (no build step).

   The direction: warm paper, ink, a terracotta accent, hairline rules instead of
   boxes, and a serif (Newsreader) for every number and headline. Operational text
   stays in Inter — the serif is the voice, not the whole page.

   Rules (see docs/UI.md):
   1. Use the tokens below. Never a raw hex, px size or radius in a view.
   2. Surfaces are quiet; hairlines carry the structure. Radius is small and on
      controls only — a shape that means "press this" or "this is a field".
   3. Compact: --s3/--s4 padding on blocks, --s2 table cells. No big empty areas.
   4. New pattern? Add a component here and show it on /admin/style before using it.
   ============================================================================= */

/* ---------- fonts (self-hosted; no CDN at runtime) ---------- */
@font-face {
    font-family: "Inter";
    src: url("/assets/fonts/inter-var.woff2") format("woff2");
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "Newsreader";
    src: url("/assets/fonts/newsreader-var.woff2") format("woff2");
    font-weight: 200 800;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "IBM Plex Mono";
    src: url("/assets/fonts/ibm-plex-mono-var.woff2") format("woff2");
    font-weight: 100 700;
    font-style: normal;
    font-display: swap;
}

:root {
    /* surfaces — warm paper, not white; the white is reserved for raised cards */
    --paper: #faf7f2;
    --paper-2: #f3eee6;
    --surface: #fffdfa;
    --sunken: #f6f2ea;
    --side: #f3eee6;

    --rule: #e5ddd0;
    --rule-2: #d3c8b6;
    --rule-strong: #e5ddd0;
    --rule-ink: #211d1a;   /* the one structural hairline that is ink, not paper */

    /* ink */
    --text: #211d1a;
    --text-2: #4a443e;
    --muted: #6e665e;   /* 4.9:1 on --paper-2 — AA at 10.5px */
    --dim: #736857;     /* 4.7:1 on --paper-2 — AA at 10.5px, still visibly quieter than --muted */

    /* signal — terracotta, plus the three states */
    --accent: #b4542a;
    --accent-2: #8f3f1c;
    --accent-ink: #fffdfa;
    --accent-line: #e6c4ae;
    --accent-soft: #f7ebe4;

    --moss: #4c6b4a;          /* success / "this is right" */
    --moss-line: #cbdcc8;
    --moss-soft: #eaf0e8;

    --brass: #8a6d2f;         /* money pending — never for a primary action */
    --brass-line: #e2d3a8;
    --brass-soft: #f6efdd;

    --bad: #a3401f;           /* destructive / refused */
    --bad-line: #edc8b8;
    --bad-soft: #f9e9e2;

    /* radius — small, and only where it means something */
    --r: 3px;        /* controls, badges, flashes, cards */
    --r-lg: 5px;      /* the raised panel: claim card, the member's primary panel */
    --r-pill: 20px;   /* badges and status dots only — nothing else is round */

    /* space */
    --s1: 4px;
    --s2: 8px;
    --s3: 13px;
    --s4: 18px;
    --s5: 26px;
    --s6: 38px;
    --s7: 54px;

    /* type */
    --f-xs: 11px;
    --f-sm: 12.5px;
    --f: 14px;
    --f-lg: 15.5px;
    --f-xl: 18px;
    --f-h1: 30px;
    --f-h2: 22px;
    --f-stat: 27px;
    --f-hero: 46px;
    --side-w: 252px;

    --measure: 68ch;   /* prose never runs wider than a comfortable read */

    --shadow-sm: 0 1px 2px rgba(33, 29, 26, 0.05);
    --shadow: 0 1px 2px rgba(33, 29, 26, 0.05), 0 8px 24px rgba(33, 29, 26, 0.05);
    --shadow-lg: 0 2px 4px rgba(33, 29, 26, 0.05), 0 18px 48px rgba(33, 29, 26, 0.09);
    --ring: 0 0 0 3px var(--accent-soft);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

html, body {
    margin: 0;
    background: var(--paper);
    color: var(--text);
    font: var(--f)/1.6 "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }

::selection { background: var(--accent-soft); }

/* The serif is the voice: headlines and every number a member reads. */
h1, h2, .display, .stat, .big-num { font-family: "Newsreader", "Iowan Old Style", Palatino, Georgia, serif; }

h1 { font-size: var(--f-h1); font-weight: 500; letter-spacing: -0.02em; line-height: 1.16; margin: 0 0 var(--s1); }
h2 {
    font-size: var(--f-h2);
    font-weight: 500;
    letter-spacing: -0.012em;
    color: var(--text);
    margin: var(--s6) 0 var(--s3);
}
h3 { font-size: var(--f-lg); font-weight: 600; letter-spacing: -0.008em; margin: 0 0 var(--s2); }

.mono { font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--f-sm); letter-spacing: -0.01em; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.muted { color: var(--muted); }
.dim { color: var(--dim); }
.nowrap { white-space: nowrap; }
.trunc { max-width: 210px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

/* ---------- shell ----------
   A sidebar and a reading column. minmax(0,…) plus min-width:0 on the children is
   load-bearing: a grid track defaults to min-width:auto, so one wide table would
   stretch the whole layout past the viewport instead of scrolling inside its card. */
.shell { display: grid; grid-template-columns: var(--side-w) minmax(0, 1fr); min-height: 100vh; }
.shell > * { min-width: 0; }

.side {
    background: var(--side);
    border-right: 1px solid var(--rule);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    padding: var(--s5) 0 var(--s4);
}
.side .brand {
    display: flex;
    align-items: baseline;
    gap: 5px;
    padding: 0 var(--s5) var(--s4);
    font-family: "Newsreader", "Iowan Old Style", Palatino, Georgia, serif;
    font-size: var(--f-xl);
    font-weight: 500;
    letter-spacing: -0.02em;
    color: var(--text);
}
.side .brand:hover { text-decoration: none; }
.side .brand span { color: var(--accent); }
.side .brand img { width: 19px; height: 19px; align-self: center; }
.side .who {
    padding: 0 var(--s5) var(--s3);
    border-bottom: 1px solid var(--rule);
    margin-bottom: var(--s3);
    font-size: var(--f-sm);
    color: var(--muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.side nav { display: flex; flex-direction: column; padding: 0 var(--s3); flex: 1; overflow-y: auto; }
.nav-grp {
    padding: var(--s4) var(--s2) 5px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--dim);
}
.side nav a {
    display: flex;
    align-items: center;
    gap: var(--s2);
    padding: 6px var(--s3);
    border-radius: var(--r);
    color: var(--text-2);
    font-size: var(--f);
    transition: background 0.12s, color 0.12s;
}
.side nav a:hover { background: var(--paper); color: var(--text); text-decoration: none; }
.side nav a.active { background: var(--surface); color: var(--text); font-weight: 600; box-shadow: var(--shadow-sm); }
.side nav a .pill { margin-left: auto; }
.side .foot { padding: var(--s3) var(--s5) 0; border-top: 1px solid var(--rule); }
.side .foot form { margin: 0; }
.side .foot button {
    background: none; border: 0; padding: var(--s1) 0; cursor: pointer;
    color: var(--muted); font-size: var(--f); font-weight: 500;
}
.side .foot button:hover { color: var(--accent); }
.side .foot a { color: var(--muted); font-size: var(--f); }
.side .foot a:hover { color: var(--accent); }

/* The console's domain scope: a field, so it gets a field's radius. */
.side .scope { padding: 0 var(--s5) var(--s4); border-bottom: 1px solid var(--rule); }
.side .scope label {
    display: block; font-size: 10px; font-weight: 700; letter-spacing: 0.14em;
    text-transform: uppercase; color: var(--dim); margin-bottom: 5px;
}
.side .scope select { width: 100%; }

.content { padding: var(--s6) var(--s7) var(--s7); max-width: 1200px; }
.content.wide { max-width: 1440px; }

/* ---------- front page ----------
   The public face of the network: a masthead, a reading measure, a colophon. Distinct from
   the signed-in shell on purpose — a visitor should not mistake the front page for a panel. */
.front-body { display: flex; flex-direction: column; min-height: 100vh; }
.masthead {
    display: flex; align-items: center; gap: var(--s5);
    padding: var(--s4) var(--s6);
    border-bottom: 1px solid var(--rule);
    position: sticky; top: 0; z-index: 40;
    background: rgba(250, 247, 242, 0.9);
    backdrop-filter: blur(10px);
}
.masthead .brand {
    display: flex; align-items: baseline; gap: 5px;
    font-family: "Newsreader", "Iowan Old Style", Palatino, Georgia, serif;
    font-size: var(--f-xl); font-weight: 500; letter-spacing: -0.02em; color: var(--text);
}
.masthead .brand:hover { text-decoration: none; }
.masthead .brand i { font-style: normal; color: var(--accent); }
.masthead .brand img { width: 19px; height: 19px; align-self: center; }
.masthead nav { margin-left: auto; display: flex; gap: var(--s5); min-width: 0; overflow-x: auto; scrollbar-width: none; }
.masthead nav::-webkit-scrollbar { display: none; }
.masthead nav > * { flex: 0 0 auto; }
.masthead nav a { color: var(--muted); font-size: var(--f); position: relative; padding: 2px 0; }
.masthead nav a::after {
    content: ""; position: absolute; left: 0; right: 100%; bottom: -2px; height: 1px;
    background: var(--accent); transition: right 0.22s ease;
}
.masthead nav a:hover { color: var(--text); text-decoration: none; }
.masthead nav a:hover::after { right: 0; }
.masthead nav a.btn,
.masthead nav a.btn:hover { color: var(--accent-ink); background: var(--accent); text-decoration: none; }
.masthead nav a.btn:hover { background: var(--accent-2); border-color: var(--accent-2); }
.masthead nav a.btn.ghost,
.masthead nav a.btn.ghost:hover { color: var(--text); background: var(--surface); border-color: var(--rule-2); }
.masthead nav a.btn::after { display: none; }

.front { flex: 1; width: 100%; max-width: 1180px; margin: 0 auto; padding: var(--s7) var(--s6) var(--s7); }
.front > .flash { max-width: 700px; }
.front h1 { font-size: var(--f-hero); line-height: 1.06; letter-spacing: -0.03em; margin: 0 0 var(--s4); max-width: 18ch; }
.front h1 em { font-style: italic; color: var(--accent); }
.front h2 { font-size: var(--f-h2); }
.front .lead { max-width: 56ch; }
.front-cta { display: flex; gap: var(--s3); flex-wrap: wrap; margin-top: var(--s5); }

/* The hero's live panel: the one place the front page shows a fact rather than a claim. */
.front-hero { display: grid; grid-template-columns: 1.32fr 0.68fr; gap: var(--s7); align-items: start; margin-bottom: var(--s6); }
.front-rule { width: 44px; height: 2px; background: var(--accent); margin-bottom: var(--s4); }
.front-ledger { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-lg); box-shadow: var(--shadow); overflow: hidden; }
.front-ledger .hd { display: flex; align-items: center; justify-content: space-between; padding: var(--s3) var(--s4); border-bottom: 1px solid var(--rule); background: var(--sunken); }
.front-ledger .row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); padding: 10px var(--s4); border-bottom: 1px solid var(--rule); }
.front-ledger .row:last-child { border-bottom: 0; }
.front-ledger .row .k { font-size: var(--f); color: var(--text-2); }
.front-ledger .row .v { font-family: "Newsreader", "Iowan Old Style", Palatino, Georgia, serif; font-size: var(--f-lg); font-weight: 500; font-variant-numeric: tabular-nums; letter-spacing: -0.015em; }

/* The domains as a directory: a rule above each row, not a grid of boxes. */
.dirlist { border-top: 1px solid var(--rule-ink); }
.dirrow {
    display: grid; grid-template-columns: 1fr 1.4fr auto; gap: var(--s5); align-items: baseline;
    padding: var(--s5) var(--s2); border-bottom: 1px solid var(--rule);
    transition: background 0.14s;
}
.dirrow:hover { background: var(--surface); text-decoration: none; }
.dirrow .t { display: block; font-family: "Newsreader", "Iowan Old Style", Palatino, Georgia, serif; font-size: var(--f-xl); font-weight: 500; letter-spacing: -0.015em; }
.dirrow .u { display: block; margin-top: 2px; font-family: "IBM Plex Mono", ui-monospace, monospace; font-size: var(--f-xs); color: var(--dim); }
.dirrow .desc { font-size: var(--f); color: var(--text-2); line-height: 1.6; }
.dirrow .cta { font-size: var(--f); color: var(--accent); white-space: nowrap; }
.dirrow:hover .cta { text-decoration: underline; text-underline-offset: 3px; }

.front-notes { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s5); margin-top: var(--s6); }
.note-card { border-top: 2px solid var(--rule-ink); padding-top: var(--s3); }
.note-card h3 { font-family: "Inter", sans-serif; font-size: var(--f); font-weight: 600; margin-bottom: 4px; }
.note-card p { font-size: var(--f); margin: 0; }

.colophon { border-top: 1px solid var(--rule); background: var(--paper-2); }
.colophon .inner { max-width: 1180px; margin: 0 auto; padding: var(--s5) var(--s6); display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--s4); font-size: var(--f-sm); color: var(--muted); }
.colophon nav { display: flex; gap: var(--s4); flex-wrap: wrap; }
.colophon a { color: var(--muted); }
.colophon a:hover { color: var(--accent); }

/* ---------- the group rail (Settings) ----------
   A left-hand list of what exists, so an operator can see the shape of the whole settings set
   without scrolling past seven groups to reach the eighth. */
.rail-layout { display: grid; grid-template-columns: 196px minmax(0, 1fr); gap: var(--s5); align-items: start; }
.rail { position: sticky; top: var(--s4); display: flex; flex-direction: column; gap: 1px; }
.rail a {
    padding: 5px var(--s3); border-radius: var(--r);
    font-size: var(--f-sm); color: var(--text-2);
    border-left: 2px solid transparent;
}
.rail a:hover { background: var(--paper-2); color: var(--text); text-decoration: none; }
.rail a.active { background: var(--surface); color: var(--accent); border-left-color: var(--accent); font-weight: 600; }

/* A settings group: one row per key, in three aligned columns. */
.set-list { display: flex; flex-direction: column; }
.set-row {
    display: grid; grid-template-columns: minmax(0, 1fr) 200px 150px;
    gap: var(--s4); align-items: center;
    padding: var(--s3) var(--s5);
    border-bottom: 1px solid var(--rule);
}
.set-row:last-child { border-bottom: 0; }
.set-row:hover { background: var(--paper-2); }
.set-row.locked { background: var(--paper-2); }
.set-row.locked .set-k { color: var(--muted); }
.set-k { font-size: var(--f); font-weight: 600; color: var(--text); display: block; }
.set-h { font-size: var(--f-xs); color: var(--dim); margin-top: 1px; line-height: 1.45; }
.set-ctl input, .set-ctl select { width: 100%; }
.set-state { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; }
.set-clear { font-size: var(--f-xs); color: var(--accent); }
.panel-form .panel-foot { padding: var(--s3) var(--s5); border-top: 1px solid var(--rule); background: var(--sunken); }

/* ---------- the page index (Pages editor) ----------
   A list of pages on the left, the one open page on the right. The list scrolls on its own so
   the editor stays put — thirteen stacked editors meant scrolling past every page to reach one. */
.page-search { display: flex; gap: var(--s2); align-items: center; }
.page-search input { flex: 1; min-width: 0; }

.page-index { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--shadow-sm); }
.page-index > a {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px var(--s2);
    padding: 9px var(--s3); border-bottom: 1px solid var(--rule);
    color: var(--text-2);
}
.page-index > a:last-child { border-bottom: 0; }
.page-index > a:hover { background: var(--paper-2); text-decoration: none; }
.page-index > a.active { background: var(--accent-soft); color: var(--text); }
.page-index > a.active .pi-t { color: var(--accent); }
.pi-t { font-size: var(--f); font-weight: 600; }
.pi-s { grid-column: 1; font-size: var(--f-xs); color: var(--dim); }
.pi-b { grid-row: 1; grid-column: 2; display: flex; gap: 4px; align-items: center; }

.page-fields { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr) 72px; gap: var(--s3); }
.page-fields .field { min-width: 0; }
.page-fields input { width: 100%; }

/* ---------- plain pages (sign-in, single-column forms) ---------- */
.plain { max-width: 720px; margin: 0 auto; padding: var(--s6) var(--s5) var(--s7); }
.plain .top { display: flex; align-items: center; gap: var(--s3); margin-bottom: var(--s6); }
.plain .top .brand {
    display: flex; align-items: baseline; gap: 5px;
    font-family: "Newsreader", "Iowan Old Style", Palatino, Georgia, serif;
    font-size: var(--f-xl); font-weight: 500; letter-spacing: -0.02em; color: var(--text);
}
.plain .top .brand span { color: var(--accent); }
.plain .top .brand img { width: 19px; height: 19px; align-self: center; }
.plain .top nav { margin-left: auto; display: flex; gap: var(--s4); }
.plain .top nav a { color: var(--muted); font-size: var(--f); }
.plain .top nav a:hover { color: var(--text); text-decoration: none; }

/* ---------- page head ---------- */
.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s4); margin-bottom: var(--s5); }
.page-head .t { flex: 1; min-width: 0; }
.page-head .t h1 { margin: 0 0 2px; }
.page-head .t .lead { margin: 0; }
.page-head .actions { display: flex; gap: var(--s2); flex-shrink: 0; flex-wrap: wrap; align-items: center; }

p.lead { color: var(--muted); margin: 0 0 var(--s5); font-size: var(--f-lg); line-height: 1.65; max-width: var(--measure); }
p.lead:last-child { margin-bottom: 0; }
.sub { color: var(--muted); font-size: var(--f); margin-top: 3px; }
.hint { color: var(--dim); font-size: var(--f-sm); margin-top: var(--s1); }
.eyebrow {
    font-family: "Inter", sans-serif;
    font-size: 10.5px; font-weight: 700; letter-spacing: 0.15em;
    text-transform: uppercase; color: var(--dim);
}

/* ---------- blocks ----------
   A card is a quiet raised surface. Structure comes from hairlines and space,
   not from a border on every box. */
.card {
    background: var(--surface);
    border: 1px solid var(--rule);
    border-radius: var(--r-lg);
    padding: var(--s4) var(--s5);
    box-shadow: var(--shadow-sm);
}
.card + .card, .card + .grid, .grid + .card { margin-top: var(--s4); }
.card > h3 {
    font-family: "Inter", sans-serif;
    font-size: var(--f-xs);
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--dim);
    margin: 0 0 var(--s3);
}
.card.flush { padding: 0; }               /* a card that is only a table or a list */
.card.flush > h3 { padding: var(--s4) var(--s5) 0; margin-bottom: var(--s2); }
.card .row-actions { display: flex; gap: var(--s2); flex-wrap: wrap; }

/* A panel with a real header — used where a card is a list or a table, not a stat. */
.panel { background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-lg); box-shadow: var(--shadow-sm); overflow: hidden; }
.panel-hd {
    display: flex; align-items: center; justify-content: space-between; gap: var(--s3);
    padding: var(--s3) var(--s5);
    border-bottom: 1px solid var(--rule);
    background: var(--sunken);
    font-weight: 600;
}
.panel-hd h2, .panel-hd h3 { margin: 0; font-family: "Inter", sans-serif; font-size: var(--f); letter-spacing: 0; }
.panel-bd { padding: var(--s4) var(--s5); }

/* a grid of statistics — hairlines between cells, no gaps, one surface */
.grid { display: grid; gap: 1px; background: var(--rule); border: 1px solid var(--rule); border-radius: var(--r-lg); overflow: hidden; }
.grid > * { background: var(--surface); padding: var(--s4) var(--s5); min-width: 0; }
/* `auto-fit` leaves a filler cell when the last row has fewer items than columns, and the
   filler inherits the grid's background. The empty track is the grid's, not a cell's. */
.grid:not(.cols-keep) { grid-auto-flow: row; }
.grid > .stat-cell { display: flex; flex-direction: column; justify-content: center; }
.grid > .stat-cell > h3, .stat-cell > h3 {
    font-family: "Inter", sans-serif; font-size: 10.5px; font-weight: 700;
    letter-spacing: 0.12em; text-transform: uppercase; color: var(--dim);
    margin: 0 0 4px;
}
.stat-cell.accent .stat { color: var(--accent); }
.stat-cell.moss .stat { color: var(--moss); }
.stat-cell.brass .stat { color: var(--brass); }
.cols-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.cols-3 { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.cols-4 { grid-template-columns: repeat(auto-fit, minmax(172px, 1fr)); }

.stat { font-size: var(--f-stat); font-weight: 500; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; line-height: 1.15; }
.stat.sm { font-size: var(--f-lg); font-weight: 500; }
.stat.accent { color: var(--accent); }
.stat.moss { color: var(--moss); }
.stat.brass { color: var(--brass); }

/* ---------- badges ---------- */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 1px 9px;
    border: 1px solid var(--rule-2);
    border-radius: var(--r-pill);
    background: var(--paper-2);
    color: var(--text-2);
    font-family: "Inter", sans-serif;
    font-size: var(--f-xs);
    font-weight: 600;
    line-height: 17px;
    white-space: nowrap;
}
.badge .dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex: none; }
.badge.good, .badge.moss { background: var(--moss-soft); border-color: var(--moss-line); color: var(--moss); }
.badge.bad { background: var(--bad-soft); border-color: var(--bad-line); color: var(--bad); }
.badge.muted { background: var(--paper-2); border-color: var(--rule); color: var(--muted); }
.badge.brass { background: var(--brass-soft); border-color: var(--brass-line); color: var(--brass); }
.badge.accent { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent); }

/* ---------- tables ---------- */
.table-wrap { overflow-x: auto; max-width: 100%; -webkit-overflow-scrolling: touch; }
.table { width: 100%; border-collapse: collapse; font-size: var(--f); }
.table th, .table td { text-align: left; padding: 8px var(--s5); border-bottom: 1px solid var(--rule); vertical-align: middle; }
.table th {
    font-family: "Inter", sans-serif;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--dim);
    background: var(--surface);
    border-bottom: 1px solid var(--rule-ink);
    white-space: nowrap;
}
.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr { transition: background 0.1s; }
.table tbody tr:hover { background: var(--paper-2); }
/* The "you are here" row on the level ladder: a warm wash and an ink marker, never a shadow. */
.table tbody tr.current { background: var(--accent-soft); }
.table tbody tr.current:hover { background: var(--accent-soft); }
.table tbody tr.current td:first-child { border-left: 2px solid var(--accent); }
.table td.actions { white-space: nowrap; }
.table .row-actions { display: flex; gap: var(--s2); align-items: center; flex-wrap: wrap; }
.table td.num, .table th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ---------- forms ---------- */
.row { display: flex; gap: var(--s3); flex-wrap: wrap; align-items: flex-end; }
.stack { display: flex; flex-direction: column; gap: var(--s3); }
.field { min-width: 0; }
.field > label {
    display: block;
    margin-bottom: 4px;
    color: var(--text-2);
    font-size: var(--f-sm);
    font-weight: 600;
}
input[type=text], input[type=email], input[type=password], input[type=search], input[type=number], select, textarea {
    background: var(--surface);
    border: 1px solid var(--rule-2);
    border-radius: var(--r);
    color: var(--text);
    font: var(--f)/1.5 inherit;
    padding: 7px 10px;
    min-width: 0;
    transition: border-color 0.12s, box-shadow 0.12s;
}
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: var(--ring); }
input::placeholder, textarea::placeholder { color: var(--dim); }
textarea { resize: vertical; min-height: 86px; }
.field .error { color: var(--bad); font-size: var(--f-sm); margin-top: 4px; }

.btn, button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    border: 1px solid var(--accent);
    border-radius: var(--r);
    background: var(--accent);
    color: var(--accent-ink);
    font: 550 var(--f)/1.3 "Inter", sans-serif;
    padding: 7px 13px;
    cursor: pointer;
    transition: background 0.13s, border-color 0.13s, color 0.13s, transform 0.08s, box-shadow 0.13s;
    box-shadow: var(--shadow-sm);
}
.btn:hover, button:hover { background: var(--accent-2); border-color: var(--accent-2); text-decoration: none; }
.btn:active, button:active { transform: translateY(1px); }
.btn.ghost, button.ghost { background: var(--surface); border-color: var(--rule-2); color: var(--text); }
.btn.ghost:hover, button.ghost:hover { background: var(--paper-2); border-color: var(--muted); }
.btn.quiet, button.quiet { background: transparent; border-color: transparent; color: var(--muted); box-shadow: none; }
.btn.quiet:hover, button.quiet:hover { background: var(--paper-2); color: var(--text); }
.btn.danger, button.danger { background: transparent; border-color: var(--bad-line); color: var(--bad); box-shadow: none; }
.btn.danger:hover, button.danger:hover { background: var(--bad-soft); border-color: var(--bad); }
.btn.sm, button.sm { padding: 4px 10px; font-size: var(--f-sm); }
.btn.lg, button.lg { font-size: var(--f-lg); padding: 11px 20px; }
.btn:disabled, button:disabled { opacity: 0.45; cursor: not-allowed; }
.linkish { background: none; border: 0; padding: 0; color: var(--accent); font-size: var(--f); cursor: pointer; }
.linkish:hover { text-decoration: underline; }

/* ---------- flash + states ---------- */
.flash {
    border: 1px solid var(--rule-2);
    border-left-width: 3px;
    border-radius: var(--r);
    padding: 10px var(--s4);
    margin-bottom: var(--s4);
    font-size: var(--f);
}
.flash.ok { border-left-color: var(--moss); color: var(--moss); background: var(--moss-soft); border-color: var(--moss-line); border-left-color: var(--moss); }
.flash.err { border-left-color: var(--bad); color: var(--bad); background: var(--bad-soft); border-color: var(--bad-line); }
.flash.note { border-left-color: var(--accent); color: var(--text-2); background: var(--accent-soft); border-color: var(--accent-line); }
.empty { color: var(--muted); font-size: var(--f); padding: var(--s5) var(--s4); text-align: center; }

/* ---------- pager ---------- */
.pager { display: flex; align-items: center; gap: var(--s2); margin-top: var(--s3); color: var(--muted); font-size: var(--f-sm); }
.pager a, .pager .off { border: 1px solid var(--rule-2); border-radius: var(--r); padding: 3px 10px; }
.pager a:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
.pager .off { color: var(--dim); opacity: 0.6; }
.pager .sp { flex: 1; }

/* ---------- utilities ---------- */
.mt { margin-top: var(--s4); }
.mt-sm { margin-top: var(--s2); }
.mb0 { margin-bottom: 0; }

/* ---------- the daily bonus strip ----------
   A thing to DO, not a statistic: a full-width band, one sentence, one button on the right.
   The accent wash is the only place the app uses it, because it is the only member action
   that is time-limited rather than always available. */
.bonus-strip { border-color: var(--accent-line); background: var(--accent-soft); box-shadow: none; }
.bonus-strip-in { display: flex; align-items: center; gap: var(--s4); padding: var(--s3) var(--s5); flex-wrap: wrap; }
.bonus-strip-in .bonus-text { flex: 1; min-width: 220px; }
.bonus-strip-in .eyebrow { color: var(--accent); }
.bonus-strip-in .bonus-line { font-family: "Newsreader", "Iowan Old Style", Palatino, Georgia, serif; font-size: var(--f-xl); font-weight: 500; letter-spacing: -0.015em; margin-top: 1px; }
.bonus-strip-in .hint { margin-top: 2px; }

/* An achievement waiting to be claimed: name and reward, action on the right. */
.ready-row { display: flex; align-items: center; gap: var(--s3); padding: var(--s3) 0; border-bottom: 1px solid var(--rule); flex-wrap: wrap; }
.ready-row:last-of-type { border-bottom: 0; }
.ready-row > div { flex: 1; min-width: 170px; }
.ready-t { font-weight: 600; }
.mt-lg { margin-top: var(--s5); }
.spread { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); }
.mw-460 { max-width: 460px; }
.w-240 { width: 240px; }
.w-280 { width: 280px; }
.state-ok { color: var(--moss); }
.state-bad { color: var(--bad); }
.split { display: grid; grid-template-columns: minmax(0, 1fr) 344px; gap: var(--s5); align-items: start; }
.listrow { display: grid; grid-template-columns: 1fr auto auto; gap: var(--s3); align-items: center; padding: var(--s3) var(--s5); border-bottom: 1px solid var(--rule); }
.listrow:last-child { border-bottom: 0; }
.listrow:hover { background: var(--paper-2); }
.listrow .t { font-weight: 600; }
.listrow .s { font-family: "IBM Plex Mono", ui-monospace, monospace; font-size: var(--f-xs); color: var(--dim); }

/* ---------- satellite shell ----------
   An earning domain is a **site**, not a single-purpose page, so it gets the same shell the hub uses:
   a sidebar and a reading column. The thing that made a domain with fourteen pages look like a
   one-page website was not the page count — it was that the only navigation on screen was a top bar
   with one link and a hidden overflow scroller, so nothing said anything else existed.

   `.sat-shell` reuses `.shell`'s grid rather than restating it, which is the point: one system, two
   doors. The reading column is narrower than the hub's because an earning domain is for one task at a
   time, not for a table of everything.

   `.side` is a fixed-width track and a grid item defaults to `min-width: auto`, so a long domain or a
   long sentence in a link would size the whole column — the fault that made 27 of 32 pages overflow
   before the last rebuild. `minmax(0, …)` and `min-width: 0` here for the same reason. */
.sat-shell { grid-template-columns: var(--side-w) minmax(0, 1fr); }
.sat-shell > * { min-width: 0; }

.sat-content { padding: var(--s5) var(--s5) var(--s6); }
.sat-content .hubbar { margin-bottom: var(--s5); }

/* The hub bar sits at the top of the reading column, not above it: the sidebar already says where you
   are, so the bar's job is only "the balance you are adding to", and it does that better as the first
   thing inside the page. */
.sat-side { background: var(--side); }

/* A satellite's own accent carries the brand in the sidebar, the same as the hub's — the theme decides
   the colour, the layout does not. */
.sat-side .brand { color: var(--text); }
.sat-side .brand span { color: var(--accent); }

/* The footer became a colophon line at the end of the reading column. */
.sat-foot {
    display: flex; gap: var(--s4); flex-wrap: wrap; align-items: baseline;
    margin-top: var(--s6); padding-top: var(--s3); border-top: 1px solid var(--rule);
    color: var(--muted); font-size: var(--f-sm);
}
.sat-foot a { color: var(--muted); }
.sat-foot a:hover { color: var(--accent); }

/* ---------- hub bar ---------- */
.hubbar {
    display: flex; align-items: center; gap: var(--s5); flex-wrap: wrap;
    background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-lg);
    padding: var(--s3) var(--s4); margin-bottom: var(--s5); box-shadow: var(--shadow-sm);
}
.hub-item { display: flex; flex-direction: column; gap: 1px; min-width: 96px; }
.hub-item .k { color: var(--dim); font-size: 10.5px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; }
.hub-item .v { font-family: "Newsreader", "Iowan Old Style", Palatino, Georgia, serif; font-size: var(--f-xl); font-weight: 500; font-variant-numeric: tabular-nums; color: var(--text); letter-spacing: -0.015em; }
.hub-item .sub { font-size: var(--f-xs); margin-top: 0; color: var(--dim); }
.hub-item .pg { width: 130px; }
.hub-user { margin-left: auto; display: flex; align-items: center; gap: var(--s3); }
.hub-user form { margin: 0; }

/* ---------- progress ---------- */
.pg { appearance: none; -webkit-appearance: none; display: block; width: 100%; height: 5px; border: 0; border-radius: var(--r-pill); background: var(--paper-2); margin: var(--s1) 0 3px; overflow: hidden; }
.pg::-webkit-progress-bar { background: var(--paper-2); border-radius: var(--r-pill); }
.pg::-webkit-progress-value { background: var(--accent); border-radius: var(--r-pill); }
.pg::-moz-progress-bar { background: var(--accent); border-radius: var(--r-pill); }
.pg.alt::-webkit-progress-value { background: var(--moss); }
.pg.alt::-moz-progress-bar { background: var(--moss); }

/* ---------- claim ---------- */
.claim-card { padding: var(--s4); }
.claim-actions { display: flex; align-items: center; gap: var(--s5); flex-wrap: wrap; }
.claim-payout { display: grid; grid-template-columns: auto auto; gap: 2px var(--s3); align-items: baseline; }
.claim-payout .k { color: var(--muted); font-size: var(--f-sm); }
.claim-payout .v { font-family: "Newsreader", "Iowan Old Style", Palatino, Georgia, serif; font-size: var(--f-xl); font-weight: 500; font-variant-numeric: tabular-nums; letter-spacing: -0.015em; }
.ad {
    margin-top: var(--s5); min-height: 92px;
    border: 1px dashed var(--rule-2); border-radius: var(--r);
    display: flex; align-items: center; justify-content: center;
    color: var(--dim); font-family: "Inter", sans-serif; font-size: 10.5px;
    letter-spacing: 0.15em; text-transform: uppercase; background: var(--paper-2);
}

/* The page a member is being paid to look at. Neutral background: the framed site supplies its own. */
.surf-frame { width: 100%; height: 460px; border: 1px solid var(--rule-2); background: #fff; }
@media (max-width: 860px) { .surf-frame { height: 360px; } }

.prose { line-height: 1.7; max-width: var(--measure); }
.prose h2, .prose h3 { margin-top: var(--s5); }
.prose p { margin: 0 0 var(--s3); }
.prose ul { margin: 0 0 var(--s3); padding-left: var(--s4); }
.prose li { margin-bottom: 5px; }

/* A checkbox with its label, used where a form offers a set of options (domain modules). */
.check { display: flex; align-items: center; gap: 6px; font-size: var(--f-sm); }
.check input { width: auto; }

/* ---------- secrets and codes (operator two-step sign-in, recovery codes) ---------- */
.label { color: var(--muted); font-size: var(--f-sm); margin-bottom: var(--s1); }
.secret { font-family: "IBM Plex Mono", ui-monospace, monospace; font-size: var(--f-lg); letter-spacing: 1px; word-break: break-all; }
.uri { font-size: var(--f-xs); color: var(--muted); word-break: break-all; }
.codes { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: var(--s2); margin-top: var(--s3); }
.codes div { background: var(--paper-2); border: 1px solid var(--rule); padding: 6px var(--s2); border-radius: var(--r); }

/* ---------- narrow screens ----------
   The same single file, one breakpoint. A sidebar becomes a horizontal rail; tables
   scroll inside their card; the stat grids go 2-up rather than squeezing to one. */
@media (max-width: 860px) {
    .shell { grid-template-columns: minmax(0, 1fr); }
    .side { position: static; height: auto; border-right: 0; border-bottom: 1px solid var(--rule); padding: var(--s4) 0 0; }
    .side .brand { padding: 0 var(--s4) var(--s3); }
    .side .who { display: none; }
    .side nav { flex-direction: row; overflow-x: auto; padding: 0 var(--s3) var(--s3); }
    .side nav .nav-grp { display: none; }
    .side nav a { white-space: nowrap; border-radius: var(--r); }
    .side .foot { padding: var(--s2) var(--s4); }
    .side .scope { padding: 0 var(--s4) var(--s3); }
    .content { padding: var(--s5) var(--s4) var(--s6); }
    .page-head { flex-direction: column; gap: var(--s3); }
    .split { grid-template-columns: minmax(0, 1fr); }
    .sat { padding: var(--s4) var(--s4) var(--s5); }
    .hubbar { gap: var(--s4); }
    .hub-user { margin-left: 0; }
    .cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .rail-layout { grid-template-columns: minmax(0, 1fr); }
    .rail { position: static; flex-direction: row; overflow-x: auto; padding-bottom: var(--s2); }
    .rail a { white-space: nowrap; border-left: 0; border-bottom: 2px solid transparent; }
    .rail a.active { border-bottom-color: var(--accent); }
    .set-row { grid-template-columns: minmax(0, 1fr); gap: var(--s2); }
    .page-fields { grid-template-columns: minmax(0, 1fr); }
    .plain { padding: var(--s5) var(--s4) var(--s6); }
}
@media (max-width: 520px) {
    .cols-4 { grid-template-columns: minmax(0, 1fr); }
    .cols-3, .cols-2 { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- accent swatches (the style gallery) ----------
   Each domain's accent, shown as it actually appears: a bar, a label and a button. The swatch
   sets data-theme on itself, so a theme is visible in the gallery without leaving the page. */
.accent-swatch { flex: 1; min-width: 150px; border: 1px solid var(--rule); border-radius: var(--r); overflow: hidden; background: var(--surface); }
.accent-swatch .sw-bar { height: 6px; background: var(--accent); }
.accent-swatch .sw-label { padding: 7px var(--s3) 3px; font-size: var(--f-sm); color: var(--text-2); }
.accent-swatch button { margin: 6px var(--s3) var(--s3); }

/* The rail's count, so a group with 14 keys and a group with 2 do not look the same size. */
.rail-n { float: right; font-family: "IBM Plex Mono", ui-monospace, monospace; font-size: var(--f-xs); color: var(--dim); }
.rail a.active .rail-n { color: var(--accent); }

/* The settings legend: the three states, named once. */
.legend { display: flex; gap: var(--s4); flex-wrap: wrap; font-size: var(--f-sm); color: var(--text-2); }
.legend > span { display: inline-flex; align-items: center; gap: 6px; }

/* A three-part reward ("300.00 coins + 10 XP + 5 energy") is wider than the side rail, so the
   claim button takes its own line rather than being clipped by the panel. */
.ready-form { flex: 1 1 100%; }
.ready-form button { width: 100%; }

/* The three reward fields, as one thing: what this achievement pays. */
.reward-fields { display: grid; grid-template-columns: minmax(0, 1.4fr) 100px 100px; gap: var(--s3); }
.reward-fields .field { min-width: 0; }
.reward-fields input { width: 100%; }
.a-meta { display: flex; gap: var(--s4); flex-wrap: wrap; padding: var(--s3) var(--s5); }
.ink-strong { color: var(--text); font-weight: 600; }
.pi-c { font-family: "IBM Plex Mono", ui-monospace, monospace; font-size: var(--f-xs); color: var(--dim); min-width: 18px; text-align: right; }

@media (max-width: 900px) {
    .reward-fields { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- the level ladder ----------
   One line per level. The inputs are sized to their content rather than to the column, so a 20-row
   table is 20 short rows instead of twenty tall cards. */
.inp-sm { width: 110px; padding: 5px 8px; font-size: var(--f-sm); text-align: right; }
.right { text-align: right; }
.w-90 { width: 90px; }
.row-empty td { background: var(--paper-2); }
.row-empty .mono { color: var(--muted); }
.table td.badge, .table td .badge { margin-left: 6px; }


/* ---------- the earning desks (/earn) ----------
   One card per way to earn, so the network reads as a list of choices rather than as a claim button
   and an account page. The head is two columns (what it is / what it pays) because that is the
   question a member arrives with; everything under it is the rule and their own state.

   minmax(0, …) and min-width: 0 on the paying column for the same reason as every other grid here: a
   long reward figure must not size the whole card, and at 390px the two columns stack. */
.earn-desk { display: flex; flex-direction: column; gap: var(--s3); margin-bottom: var(--s3); }
.earn-desk-head { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--s4); }
.earn-desk-head > div { min-width: 0; }
.earn-desk-head h2 { margin: 2px 0 1px; }
.earn-desk-head .k { color: var(--dim); font-size: var(--f-xs); text-transform: uppercase; letter-spacing: 0.06em; }
.earn-desk-pays { text-align: right; flex: 0 0 auto; }
.earn-desk-pays .v { font-family: "Newsreader", Georgia, serif; font-size: 1.35rem; line-height: 1.2; }
.earn-desk-rule { margin: 0; }
.earn-desk-state .badge { margin: 0; }
.earn-desk-progress .k { display: flex; justify-content: space-between; gap: var(--s3); margin-bottom: 5px; color: var(--text-2); font-size: var(--f-sm); }
.earn-desk-cta { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.earn-desk-cta .hint { margin: 0; }

@media (max-width: 520px) {
    .earn-desk-head { flex-direction: column; gap: var(--s2); }
    .earn-desk-pays { text-align: left; }
}


/* ---------- the dashboard's next action and desk strip ----------
   The first thing on arrival is one line saying what to do, and the desks are the same rows /earn
   shows in full. Both are three-column rows rather than cards: a card per desk would be a wall of
   boxes on a page that already has a strip, a grid and a split below it.

   minmax(0, …) on every track and min-width: 0 on the cells, for the reason every grid here carries
   it — a long domain or a long state sentence must not size the column. */
/* An inset shadow rather than a border: `.panel` already carries a 1px border on every side and clips
   its own overflow, so a real `border-left` here would double up and press the text against it. */
.next-action { box-shadow: var(--shadow-sm), inset 3px 0 0 var(--accent); }
.next-action-in { display: flex; align-items: center; justify-content: space-between; gap: var(--s4); flex-wrap: wrap; }
.next-action-in > div { min-width: 0; }
.next-action-head { font-family: "Newsreader", Georgia, serif; font-size: 1.3rem; line-height: 1.25; margin: 2px 0 3px; }
.next-action .eyebrow { color: var(--dim); }

.desk-strip { display: flex; flex-direction: column; }
.desk-strip-row {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr) auto;
    gap: var(--s4);
    align-items: center;
    padding: var(--s3) 0;
    border-top: 1px solid var(--rule);
}
.desk-strip-row:first-child { border-top: 0; padding-top: 0; }
.desk-strip-t, .desk-strip-s { min-width: 0; }
.desk-strip-t .k { color: var(--dim); font-size: var(--f-xs); text-transform: uppercase; letter-spacing: 0.06em; }
.desk-strip-s .v { color: var(--text); }
.desk-strip-a { text-align: right; }

@media (max-width: 640px) {
    .desk-strip-row { grid-template-columns: minmax(0, 1fr); gap: var(--s2); }
    .desk-strip-a { text-align: left; }
}


/* ---------- the activity feed and the news ----------
   The feed is the cheapest credibility item in the product, so it is built to be read: one sentence a
   row, the amount inside the sentence rather than in a column, and the age quiet on the right. It is
   server-rendered first — the script only refreshes a list that already has content — because a feed
   that needs JavaScript is invisible to a crawler and blank to a visitor who blocks it. */
.feed-list { list-style: none; margin: 0; padding: 0; }
.feed-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s3);
    padding: 7px 0;
    border-top: 1px solid var(--rule);
}
.feed-row:first-child { border-top: 0; padding-top: 0; }
.feed-sentence { min-width: 0; }
.feed-ago { color: var(--dim); font-size: var(--f-xs); white-space: nowrap; }
.feed-empty .feed-sentence { color: var(--muted); }

.link-list { list-style: none; margin: 0; padding: 0; }
.link-list li { padding: 6px 0; border-top: 1px solid var(--rule); }
.link-list li:first-child { border-top: 0; padding-top: 0; }

.news-post { max-width: 68ch; }
.news-post h1 { margin: 2px 0 var(--s3); }
.news-post .eyebrow { color: var(--dim); }
.prose p { margin: 0 0 var(--s4); }
.prose p:last-child { margin-bottom: 0; }
.min0 { min-width: 0; }

/* ---------- the satellite hub bar in a sidebar layout ----------
   Signed out, the bar is one right-aligned button in a full-width box — a large empty rectangle whose
   only content is a small button in the corner. A box that size for one link reads as a loading
   state. Signed in it carries four figures and earns its size. So the two states get two shapes: the
   signed-out bar is a quiet line, not a card. */
.sat-content .hubbar:has(.btn:only-child) { background: none; border: 0; box-shadow: none; padding: 0; }
