/* Escrow operator console.
 *
 * Design direction: dense operator console for financial back-office work. The visual language is
 * intentionally light, calm and high-contrast: blue actions, clean panels and
 * compact tabular numerics keep money movement easy to scan.
 */

:root {
  color-scheme: light;

  /* Surfaces */
  --bg:           #f5f7fb;
  --bg-subtle:    #ffffff;
  --bg-elevated:  #ffffff;
  --bg-inset:     #eef2f8;

  /* Text */
  --fg:           #111827;
  --fg-muted:     #344054;
  --fg-subtle:    #667085;
  --fg-inverse:   #f4f7fb;

  /* Lines */
  --border:        #d9e0eb;
  --border-strong: #aeb9ca;

  /* Accent: confident cobalt blue */
  --accent:        #2563d8;
  --accent-hover:  #1747ad;
  --accent-fg:     #ffffff;
  --accent-soft:   #e4edff;
  --accent-line:   #9dbcf4;

  /* Semantics */
  --ok:        #1a6b3c;   --ok-soft:      #e3f0e7;   --ok-line:      #a7ceb6;
  --warn:      #8a5a06;   --warn-soft:    #faf0dc;   --warn-line:    #ddc088;
  --danger:    #9b2226;   --danger-soft:  #f8e6e4;   --danger-line:  #e0b0ac;
  --info:      #1e4f7a;   --info-soft:    #e4eef6;   --info-line:    #a8c6dd;

  /* Ledger directions */
  --debit:  #9b2226;
  --credit: #1a6b3c;

  /* Depth. The light theme's shadows are tinted navy; the dark theme's are
   * plain black, where a tint would read as a glow. */
  --shadow-panel:   0 5px 16px rgba(31, 50, 90, 0.07);
  --shadow-pop:     0 18px 48px rgba(31, 50, 90, 0.22);
  --shadow-primary: 0 5px 12px rgba(33, 66, 164, 0.18);
  --shadow-auth:    0 18px 48px rgba(28, 49, 82, 0.12);
  --shadow-pill:    0 10px 28px -8px rgba(0, 0, 0, 0.45);
  --scrim:          rgba(17, 24, 39, 0.45);

  /* One-off inks that used to be written into the rules. */
  --th-fg:      #475467;   /* table headings */
  --on-fg:      #ffffff;   /* text on an --fg fill */
  --brand-ink:  #11463c;   /* the wordmark on a light surface */
  --auth-input-border: #c8d2e1;

  /* The navigation rail and the sign-in panel: deep teal in the light theme.
   * Everything drawn on them is white at some opacity, which reads on the
   * dark theme's graphite rail as well, so only the solids are tokens. */
  --rail-bg:            #123f45;
  --rail-line:          #0d3339;
  --rail-active-bg:     #ffffff;
  --rail-active-fg:     #123f45;
  --rail-active-border: #ffffff;
  --rail-highlight:     #f5cf57;

  /* Chart series. Canvas cannot read CSS, so reports.js reads these and the
   * server sends their names (internal/admin/charts.go). */
  --chart-accent:     #2563d8;
  --chart-ok:         #1a6b3c;
  --chart-warn:       #c58a12;
  --chart-danger:     #9b2226;
  --chart-info:       #1e4f7a;
  --chart-neutral-1:  #667085;
  --chart-neutral-2:  #94a3b8;
  --chart-indigo:     #6366f1;
  --chart-sky:        #0ea5e9;
  --chart-tooltip-bg: rgba(17, 24, 39, 0.94);
  --chart-tooltip-fg: #ffffff;

  /* Type scale */
  --t-xs: 11px; --t-sm: 12px; --t-md: 13px; --t-base: 14px;
  --t-lg: 17px; --t-xl: 22px; --t-2xl: 30px;

  /* Spacing scale */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px; --s7: 48px;

  --radius: 8px;
  --rail: 248px;

  --font: "Avenir Next", "Helvetica Neue", Helvetica, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

/* ---------- Dark theme ----------
 *
 * Neutral graphite, the same family as Sabi Dashboard's, rather than a dark
 * version of the brand teal: a screen read for hours should not be tinted.
 * Text and status colours are lifted until they clear WCAG AA on the darker
 * surfaces (4.5:1 for text, 3:1 for control borders), and solid fills carry
 * dark text. theme-init.js sets data-theme before the first paint.
 *
 * Screen only: a page printed from the dark theme comes out on paper in the
 * light one (see the print rules at the end of this file). */
@media screen {
  :root[data-theme="dark"] {
    color-scheme: dark;

    --bg:           #0d0f12;
    --bg-subtle:    #14171b;
    --bg-elevated:  #14171b;
    --bg-inset:     #1b1f25;

    --fg:           #eceef2;
    --fg-muted:     #c4c9d2;
    --fg-subtle:    #9299a5;
    --fg-inverse:   #0d0f12;

    --border:        #2a2f37;
    --border-strong: #5f6672;

    --accent:        #6f9ef6;
    --accent-hover:  #93b6f9;
    --accent-fg:     #07101e;
    --accent-soft:   #16233a;
    --accent-line:   #34528a;

    --ok:        #4cc38a;   --ok-soft:      #0f2a1d;   --ok-line:      #25573d;
    --warn:      #e6a94f;   --warn-soft:    #2c2112;   --warn-line:    #5e4521;
    --danger:    #f47b72;   --danger-soft:  #2d1614;   --danger-line:  #63302b;
    --info:      #6cb2e8;   --info-soft:    #0f1f2c;   --info-line:    #28496a;

    --debit:  #f47b72;
    --credit: #4cc38a;

    --shadow-panel:   0 1px 2px rgba(0, 0, 0, 0.45);
    --shadow-pop:     0 18px 48px rgba(0, 0, 0, 0.6);
    --shadow-primary: none;
    --shadow-auth:    0 18px 48px rgba(0, 0, 0, 0.5);
    --shadow-pill:    0 10px 28px -8px rgba(0, 0, 0, 0.8);
    --scrim:          rgba(0, 0, 0, 0.62);

    --th-fg:      #aab1bc;
    --on-fg:      #0d0f12;
    --brand-ink:  #eceef2;
    --auth-input-border: #5f6672;

    --rail-bg:            #121519;
    --rail-line:          #262a31;
    --rail-active-bg:     #262b33;
    --rail-active-fg:     #ffffff;
    --rail-active-border: #3d444f;
    --rail-highlight:     #f5cf57;

    --chart-accent:     #6f9ef6;
    --chart-ok:         #4cc38a;
    --chart-warn:       #e6a94f;
    --chart-danger:     #f47b72;
    --chart-info:       #6cb2e8;
    --chart-neutral-1:  #9299a5;
    --chart-neutral-2:  #5f6672;
    --chart-indigo:     #9497f8;
    --chart-sky:        #45c0f5;
    --chart-tooltip-bg: rgba(38, 43, 51, 0.97);
    --chart-tooltip-fg: #eceef2;
  }
}

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

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: var(--t-base);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

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

h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -0.01em; }
h1 { font-size: var(--t-xl); }
h2 { font-size: var(--t-lg); }
h3 { font-size: var(--t-base); }

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

/* ---------- Shell ---------- */

.shell { display: grid; grid-template-columns: var(--rail) 1fr; min-height: 100vh; }

.rail {
  background: var(--rail-bg);
  border-right: 1px solid var(--rail-line);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  /* The rail itself never scrolls: the brand stays at the top and the
   * signed-in operator at the bottom, while the sections between them take
   * whatever room is left. More features can be added to the navigation
   * without pushing "Sign out" off the bottom of a laptop screen. */
  overflow: hidden;
}

.nav-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding-bottom: var(--s2);
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.24) transparent;
}
.nav-scroll::-webkit-scrollbar { width: 8px; }
.nav-scroll::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.2);
  border-radius: 4px;
}

.brand {
  padding: 22px var(--s4) 18px var(--s5);
  background: transparent;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s2);
}
.brand-id { min-width: 0; }
/* ---------- Brand ---------- */
/* ---------- Brand ----------
 *
 * The mark is transparent artwork with no panel behind it: it sits directly on
 * whatever surface it lands on, dark rail or white card. The name beside it is
 * live text, two-tone like the logo, so it stays sharp at any zoom and takes
 * its colour from the surface rather than shipping one. */
.brand-mark {
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: 100%;
}
/* The artwork is a background rather than an <img> so each surface can choose
 * the variant that reads on it: the logo as drawn on light, and a reversed one
 * on dark, where the dark green keyhole would otherwise vanish into the teal.
 * It carries no accessible name because the wordmark beside it already does. */
.brand-logo {
  height: 34px;
  aspect-ratio: 446 / 354;
  flex: none;
  display: block;
  background: url("/console/static/logo-mark.png?v=2") center / contain no-repeat;
}
.brand-word {
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
/* Light surfaces -- the sign-in card. */
.brand-word-a { color: var(--brand-ink); }

/* Dark surfaces -- the rail and the sign-in panel. Near-black would read as a
 * hole on dark teal, so the name goes white. */
.rail .brand-logo,
.auth-aside .brand-logo {
  background-image: url("/console/static/logo-mark-light.png?v=2");
}
.rail .brand-word-a,
.auth-aside .brand-word-a { color: #ffffff; }

.auth-aside .brand-logo { height: 44px; }
.auth-aside .brand-word { font-size: 24px; }

.brand-sub {
  font-size: var(--t-xs);
  color: rgba(255, 255, 255, 0.62);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-top: 8px;
}
.brand-sub-dark {
  color: var(--fg-muted);
}

.nav-group { padding: var(--s3) var(--s3) 0; }

/* A section heading is also the control that folds the section away. It is a
 * <summary>, so it works from the keyboard and without JavaScript; the
 * remembered state is written to a cookie and applied when the page renders. */
.nav-label {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: rgba(255, 255, 255, 0.52);
  padding: var(--s1) var(--s2) var(--s2);
  cursor: pointer;
  list-style: none;
  user-select: none;
  border-radius: var(--radius);
}
.nav-label::-webkit-details-marker { display: none; }
.nav-label:hover { color: rgba(255, 255, 255, 0.86); }
.nav-label::after {
  content: "";
  width: 5px;
  height: 5px;
  margin-left: auto;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translate(-1px, -1px);
  transition: transform 120ms cubic-bezier(.4, 0, .2, 1);
}
.nav-group[open] > .nav-label::after {
  transform: rotate(225deg) translate(-1px, -1px);
}
.nav-label:focus-visible {
  outline: 2px solid var(--rail-highlight);
  outline-offset: 1px;
}
.nav-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s2);
  padding: 7px var(--s3);
  border-radius: var(--radius);
  color: rgba(255, 255, 255, 0.76);
  font-size: var(--t-md);
  border: 1px solid transparent;
  transition: background-color 120ms cubic-bezier(.4,0,.2,1), color 120ms cubic-bezier(.4,0,.2,1);
}
.nav-item:hover { background: rgba(255, 255, 255, 0.1); color: #fff; text-decoration: none; }
.nav-item[aria-current="page"] {
  background: var(--rail-active-bg);
  border-color: var(--rail-active-border);
  color: var(--rail-active-fg);
  font-weight: 600;
}
.nav-count {
  font-family: var(--mono);
  font-size: var(--t-xs);
  color: rgba(255, 255, 255, 0.62);
  font-variant-numeric: tabular-nums;
}
.nav-count.is-alert { color: var(--rail-highlight); font-weight: 700; }

.rail-foot {
  margin-top: auto;
  padding: var(--s3) var(--s4);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  font-size: var(--t-sm);
  color: rgba(255, 255, 255, 0.7);
}
.rail-foot strong { display: block; color: #fff; font-size: var(--t-md); }
.rail-foot .btn-ghost { color: rgba(255, 255, 255, 0.72); }
.rail-foot .btn-ghost:hover { background: rgba(255, 255, 255, 0.1); color: #fff; text-decoration: none; }

.main { min-width: 0; display: flex; flex-direction: column; }

/* ---------- Trust strip: the number this business is judged on ---------- */

.trust-strip {
  display: flex;
  align-items: stretch;
  gap: 0;
  background: var(--bg-elevated);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
}
.trust-cell {
  padding: 10px var(--s4);
  border-right: 1px solid var(--border);
  min-width: 150px;
  flex: 0 0 auto;
}
.trust-cell:last-child { border-right: 0; }
.trust-k {
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fg-subtle);
}
.trust-v {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-lg);
  font-weight: 700;
  letter-spacing: -0.02em;
}
.trust-cell.is-balanced .trust-v { color: var(--ok); }
.trust-cell.is-broken   .trust-v { color: var(--danger); }
.trust-cell.is-primary  { background: var(--accent-soft); }

/* ---------- Page furniture ---------- */

.page { padding: var(--s5) var(--s6) var(--s7); max-width: 1500px; width: 100%; }
.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s4);
  margin-bottom: var(--s4);
}
.page-title { display: flex; flex-direction: column; gap: 2px; }
.eyebrow {
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--fg-subtle);
}
.page-actions { display: flex; gap: var(--s2); align-items: center; }

.section { margin-top: var(--s5); }
.section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s3); margin-bottom: var(--s2);
}

/* ---------- Panels ---------- */

.panel {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-panel);
}
/* A folded group of fields.
   Closed by default, so the form asks for what it needs and keeps the rest
   within reach. The summary is a real control: it takes focus, and it says
   what is inside rather than "more". */
.fold {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0 var(--s3);
  margin-top: var(--s3);
  background: var(--bg-sunken, transparent);
}
.fold > summary {
  cursor: pointer;
  padding: var(--s2) 0;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-muted);
  list-style: none;
}
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::before { content: "+ "; font-weight: 600; }
.fold[open] > summary::before { content: "\2212 "; }
.fold > summary:hover { color: var(--text); }
.fold > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.fold[open] { padding-bottom: var(--s3); }

/* The danger zone.
   Bordered in the danger tone rather than tinted through, so it reads as a
   different kind of section at a glance without the text inside it becoming
   an alert — most of what it says is explanation, and explanation set in red
   is harder to read, not more serious. */
.panel-danger { border-color: var(--danger-line); }
.panel-danger > .panel-head {
  background: var(--danger-soft);
  border-bottom-color: var(--danger-line);
}
.panel-danger > .panel-head h2 { color: var(--danger); }
.panel-danger .stack { max-width: 34rem; margin-top: var(--s3); }
.panel-danger input[type="text"] { font-family: var(--font-mono, monospace); }

.panel-head {
  padding: 10px var(--s4);
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: var(--s3);
}
.panel-body { padding: var(--s4); }
.panel-body.is-flush { padding: 0; }

.grid { display: grid; gap: var(--s4); }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-detail { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
@media (max-width: 1100px) {
  .grid-2, .grid-3, .grid-detail { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- Summary strip: what a listing adds up to ----------
   The trust strip answers this for the whole company; these answer it for
   whatever the operator has just filtered to, so a page of movements states
   its own totals instead of leaving them to be added up by eye. */

.stat-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: var(--s3);
  margin-bottom: var(--s4);
}
.stat {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px var(--s4) 12px;
  box-shadow: var(--shadow-panel);
}
.stat-k {
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--fg-muted);
}
.stat-v {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--t-lg);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-top: 2px;
}
.stat-sub { font-size: var(--t-xs); color: var(--fg-subtle); margin-top: 2px; }

/* Direction is carried by the sign and the colour together, never by colour
   alone, so the two read the same to anyone who cannot tell them apart. */
.amount-in  { color: var(--ok); }
.amount-out { color: var(--fg); }

/* ---------- Definition rows ---------- */

.facts { display: grid; gap: 0; }
.fact {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr);
  gap: var(--s3);
  padding: 7px 0;
  border-bottom: 1px solid var(--border);
  font-size: var(--t-md);
}
.fact:last-child { border-bottom: 0; }
.fact dt { color: var(--fg-muted); }
.fact dd { margin: 0; }
.num, .mono {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
.num { letter-spacing: -0.01em; }
.mono-sm { font-family: var(--mono); font-size: var(--t-sm); color: var(--fg-muted); }

/* ---------- Tables ---------- */

.table-wrap { overflow-x: auto; }
table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-md);
}
table.data th {
  text-align: left;
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--th-fg);
  font-weight: 600;
  padding: 8px var(--s4);
  border-bottom: 1px solid var(--border-strong);
  background: var(--bg-inset);
  position: sticky;
  top: 0;
  white-space: nowrap;
}
table.data td {
  padding: 8px var(--s4);
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
table.data tbody tr { transition: background-color 120ms ease; }
table.data tbody tr:hover { background: var(--bg-inset); }
table.data tbody tr:last-child td { border-bottom: 0; }
table.data td.right, table.data th.right { text-align: right; }
table.data td.num { white-space: nowrap; }
.cell-primary { font-weight: 600; }
.cell-sub { color: var(--fg-subtle); font-size: var(--t-sm); }

.empty {
  padding: var(--s6) var(--s4);
  text-align: center;
  color: var(--fg-muted);
}
.empty strong { display: block; color: var(--fg); margin-bottom: var(--s1); }

/* ---------- Badges ---------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 7px;
  border-radius: 3px;
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  border: 1px solid var(--border);
  background: var(--bg-inset);
  color: var(--fg-muted);
  white-space: nowrap;
}
.badge::before {
  content: "";
  width: 5px; height: 5px; border-radius: 50%;
  background: currentColor;
}
.badge.is-ok     { background: var(--ok-soft);     border-color: var(--ok-line);     color: var(--ok); }
.badge.is-warn   { background: var(--warn-soft);   border-color: var(--warn-line);   color: var(--warn); }
.badge.is-danger { background: var(--danger-soft); border-color: var(--danger-line); color: var(--danger); }
.badge.is-info   { background: var(--info-soft);   border-color: var(--info-line);   color: var(--info); }
.badge.is-accent { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent); }
.badge.is-plain::before { display: none; }

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 30px;
  padding: 0 12px;
  border-radius: var(--radius);
  border: 1px solid var(--border-strong);
  background: var(--bg-elevated);
  color: var(--fg);
  font-family: inherit;
  font-size: var(--t-md);
  font-weight: 500;
  cursor: pointer;
  transition: background-color 120ms cubic-bezier(.4,0,.2,1), border-color 120ms cubic-bezier(.4,0,.2,1);
}
.btn:hover { background: var(--bg-inset); text-decoration: none; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
  box-shadow: var(--shadow-primary);
}
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-danger { border-color: var(--danger-line); color: var(--danger); background: var(--danger-soft); }
.btn-danger:hover { background: var(--danger-soft); border-color: var(--danger); }
.btn-ghost { border-color: transparent; background: transparent; color: var(--fg-muted); }
.btn-ghost:hover { background: var(--bg-inset); color: var(--fg); }
.btn-lg { height: 38px; padding: 0 18px; font-size: var(--t-base); }
.btn-sm { height: 26px; padding: 0 9px; font-size: var(--t-sm); }

/* ---------- Forms ---------- */

.field { display: flex; flex-direction: column; gap: 5px; margin-bottom: var(--s3); }
.field label { font-size: var(--t-sm); font-weight: 600; color: var(--fg-muted); }
.field .hint { font-size: var(--t-xs); color: var(--fg-subtle); }
input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="date"], input[type="datetime-local"],
select, textarea {
  font-family: inherit;
  font-size: var(--t-md);
  color: var(--fg);
  background: var(--bg-elevated);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  padding: 6px 9px;
  width: 100%;
  min-height: 30px;
}
input[type="number"], input.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }
textarea { min-height: 72px; resize: vertical; line-height: 1.45; }
select { appearance: none; padding-right: 26px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 14px) 13px, calc(100% - 9px) 13px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
input:disabled, select:disabled, textarea:disabled { background: var(--bg-inset); color: var(--fg-subtle); }
.form-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s3); }
.form-actions {
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--s3); margin-top: var(--s4);
  padding-top: var(--s3); border-top: 1px solid var(--border);
}
fieldset { border: 0; padding: 0; margin: 0 0 var(--s4); }
legend {
  padding: 0 0 var(--s2);
  font-size: var(--t-xs);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--fg-subtle);
  font-weight: 600;
}

.filters {
  display: flex; flex-wrap: wrap; gap: var(--s2); align-items: flex-end;
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--border);
}
.filters .field { margin: 0; min-width: 150px; }

/* ---------- Alerts ---------- */

.alert {
  display: flex; gap: var(--s3); align-items: flex-start;
  padding: 10px var(--s4);
  border: 1px solid var(--border);
  border-left-width: 3px;
  border-radius: var(--radius);
  font-size: var(--t-md);
  margin-bottom: var(--s4);
}
.alert-ok     { background: var(--ok-soft);     border-color: var(--ok-line);     border-left-color: var(--ok); }
.alert-warn   { background: var(--warn-soft);   border-color: var(--warn-line);   border-left-color: var(--warn); }
.alert-danger { background: var(--danger-soft); border-color: var(--danger-line); border-left-color: var(--danger); }
.alert-info   { background: var(--info-soft);   border-color: var(--info-line);   border-left-color: var(--info); }
.alert strong { display: block; }

.secret-reveal {
  font-family: var(--mono);
  font-size: var(--t-md);
  background: var(--bg-inset);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  padding: var(--s2) var(--s3);
  word-break: break-all;
  margin: var(--s2) 0;
}

/* ---------- Ledger entries: debit left, credit right ---------- */

.entry { border-bottom: 1px solid var(--border); padding: var(--s3) var(--s4); }
.entry:last-child { border-bottom: 0; }
.entry-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s3); margin-bottom: 6px;
}
.entry-type { font-weight: 600; font-size: var(--t-md); }
.entry-meta { color: var(--fg-subtle); font-size: var(--t-sm); }
.legs { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--s5); font-size: var(--t-sm); }
.leg {
  display: flex; justify-content: space-between; gap: var(--s3);
  padding: 3px 0; border-bottom: 1px dotted var(--border);
}
.leg:last-child { border-bottom: 0; }
.leg-account { font-family: var(--mono); color: var(--fg-muted); }
.leg-amount { font-family: var(--mono); font-variant-numeric: tabular-nums; font-weight: 600; }
.leg.debit  .leg-amount { color: var(--debit); }
.leg.credit .leg-amount { color: var(--credit); }
.legs-col-label {
  font-size: var(--t-xs); text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--fg-subtle); padding-bottom: 3px; border-bottom: 1px solid var(--border);
  margin-bottom: 3px;
}

/* ---------- Timeline ---------- */

.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li {
  position: relative;
  padding: 0 0 var(--s4) var(--s5);
  border-left: 1px solid var(--border);
  margin-left: 5px;
}
.timeline li:last-child { border-left-color: transparent; padding-bottom: 0; }
.timeline li::before {
  content: ""; position: absolute; left: -4px; top: 5px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--bg-elevated); border: 1px solid var(--border-strong);
}
.timeline li.is-key::before { background: var(--accent); border-color: var(--accent); }
.timeline .t-when { font-size: var(--t-xs); color: var(--fg-subtle); font-family: var(--mono); }
.timeline .t-what { font-size: var(--t-md); }

/* ---------- Pagination ---------- */

.pager {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s3); padding: 9px var(--s4); border-top: 1px solid var(--border);
  font-size: var(--t-sm); color: var(--fg-muted);
}
.pager { flex-wrap: wrap; }
.pager-range { font-variant-numeric: tabular-nums; }
.pager-page { white-space: nowrap; }
.pager-links { display: flex; flex-wrap: wrap; gap: var(--s2); }
.ledger-export-note { margin: calc(-1 * var(--s2)) 0 var(--s3); }

/* ---------- Login ---------- */

.auth-wrap {
  min-height: 100vh;
  display: grid;
  grid-template-columns: minmax(420px, 1.15fr) minmax(380px, 0.85fr);
  background: var(--bg);
}
@media (max-width: 900px) { .auth-wrap { grid-template-columns: minmax(0, 1fr); } }
/* The sign-in panel carries the same deep teal identity as the navigation rail. */
.auth-aside {
  position: relative;
  overflow: hidden;
  background: var(--rail-bg);
  color: #e8f2ee;
  padding: var(--s6) clamp(28px, 6vw, 84px);
  display: flex; flex-direction: column; justify-content: space-between; gap: var(--s7);
}
.auth-aside::before,
.auth-aside::after {
  content: "";
  position: absolute;
  border: 1px solid rgba(255, 255, 255, 0.13);
  transform: rotate(35deg);
  pointer-events: none;
}
.auth-aside::before { width: 480px; height: 480px; right: -220px; top: 12%; border-radius: 42px; }
.auth-aside::after { width: 330px; height: 330px; left: -190px; bottom: 8%; border-radius: 50%; }
.auth-aside > * { position: relative; z-index: 1; }
.auth-aside .brand-sub { color: rgba(232, 242, 238, 0.62); }
.auth-aside h2 { color: #ffffff; }
.auth-aside h2 { margin-top: var(--s3); font-size: clamp(30px, 4vw, 48px); line-height: 1.06; max-width: 9ch; letter-spacing: -0.04em; }
.auth-kicker { color: var(--rail-highlight); font-size: var(--t-sm); font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; }
.auth-aside p { max-width: 42ch; color: rgba(232, 242, 238, 0.78); font-size: var(--t-base); line-height: 1.65; margin-top: var(--s4); }
.auth-points { display: grid; gap: var(--s3); margin-top: var(--s5); font-size: var(--t-sm); color: rgba(255, 255, 255, 0.78); }
.auth-points span { display: flex; align-items: center; gap: 9px; }
.auth-points i { width: 7px; height: 7px; border-radius: 50%; background: var(--rail-highlight); }
.auth-stat { font-family: var(--mono); font-size: var(--t-sm); color: rgba(232, 242, 238, 0.6); display: grid; gap: 4px; }
.auth-stat strong { color: #ffffff; font-family: var(--font); font-size: var(--t-md); font-weight: 500; }
.auth-main { display: flex; align-items: center; justify-content: center; padding: clamp(24px, 4vw, 56px); }
.auth-card { width: min(100%, 520px); background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 14px; padding: clamp(32px, 4vw, 48px); box-shadow: var(--shadow-auth); }
.auth-card h1 { margin-bottom: 6px; font-size: 32px; letter-spacing: -0.04em; }
.auth-card .lede { color: var(--fg-muted); font-size: var(--t-md); margin: 0 0 30px; }
.auth-card .field { margin-bottom: 20px; }
.auth-card .field label { color: var(--fg); font-size: var(--t-md); }
.auth-card input[type="email"], .auth-card input[type="password"] { min-height: 44px; padding: 10px 12px; border-color: var(--auth-input-border); border-radius: 7px; }
.auth-card input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); outline: none; }
.auth-submit { width: 100%; height: 46px; margin-top: 8px; border-radius: 7px; font-size: var(--t-base); font-weight: 700; }
.auth-mobile-brand { display: none; }
@media (max-width: 900px) {
  .auth-wrap { display: block; }
  .auth-aside {
    display: flex;
    min-height: 0;
    padding: 32px clamp(24px, 7vw, 72px);
  }
  .auth-aside h2 { font-size: clamp(32px, 5vw, 44px); max-width: 12ch; }
  .auth-aside p { margin-top: 14px; }
  .auth-points { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-top: 20px; font-size: var(--t-sm); }
  .auth-points span { align-items: flex-start; gap: 5px; }
  .auth-points i { flex: 0 0 auto; margin-top: 4px; }
  .auth-main { padding: 24px; }
  .auth-card { max-width: 500px; }
  .auth-mobile-brand { display: block; margin-bottom: 42px; }
}

/* ---------- Utilities ---------- */

.muted { color: var(--fg-muted); }
.subtle { color: var(--fg-subtle); }
.small { font-size: var(--t-sm); }
.xs { font-size: var(--t-xs); }
.strong { font-weight: 600; }
.row { display: flex; align-items: center; gap: var(--s2); }
.row-wrap { flex-wrap: wrap; }
.spread { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); }
.stack { display: flex; flex-direction: column; gap: var(--s3); }
.stack-sm { display: flex; flex-direction: column; gap: var(--s1); }
.mt-4 { margin-top: var(--s4); }
.mb-0 { margin-bottom: 0; }
.nowrap { white-space: nowrap; }
.truncate { max-width: 34ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.inline-form { display: inline; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

@media (max-width: 760px) {
  .shell { grid-template-columns: 1fr; }
  .rail {
    position: static;
    height: auto;
    border-right: 0;
    border-bottom: 1px solid var(--border);
  }
  .brand { padding: 14px var(--s4); }
  .nav-scroll { overflow-y: visible; }
  .nav-group {
    display: flex;
    align-items: center;
    gap: var(--s2);
    padding: var(--s2) var(--s3);
    overflow-x: auto;
  }
  /* Folding sections away is a choice about a tall rail; on a phone the rail
   * is a horizontal strip, so every link stays reachable whatever was
   * remembered on the desktop. */
  .nav-group > .nav-item { display: flex !important; }
  .nav-label { display: none; }
  .nav-item { white-space: nowrap; padding: 7px 10px; }
  .rail-foot { display: none; }
  .page { padding: var(--s4); }
  .page-head { flex-direction: column; }
  .page-actions { width: 100%; }
  .page-actions .btn, .page-actions form { width: 100%; }
  .form-row { grid-template-columns: 1fr; gap: 0; }
  .legs { grid-template-columns: 1fr; gap: var(--s2); }
  .form-actions { align-items: stretch; flex-direction: column; }
}

@media (max-width: 900px) {
  .shell { grid-template-columns: minmax(0, 1fr); }
  .rail { position: static; height: auto; border-right: 0; border-bottom: 1px solid var(--border); }
  .page { padding: var(--s4); }
}

/* ---------- Confirmation dialog ---------- */
/* The prompt shown before a control moves money. Rendered in the console's
 * own panel language so an operator never sees the browser's default chrome. */

.confirm-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s4);
  background: var(--scrim);
}
.confirm-overlay[hidden] {
  display: none !important;
}
.confirm-overlay:not([hidden]) {
  animation: confirm-fade-in 120ms ease-out;
}
@keyframes confirm-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.confirm-panel {
  width: min(440px, 100%);
  padding: var(--s5);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  color: var(--fg);
  box-shadow: var(--shadow-pop);
  animation: confirm-in 120ms ease-out;
}
@keyframes confirm-in {
  from { opacity: 0; transform: translateY(6px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

.confirm-title {
  margin: 0 0 var(--s2);
  font-size: var(--t-lg);
  font-weight: 600;
  letter-spacing: -0.01em;
}
.confirm-body {
  margin: 0 0 var(--s5);
  font-size: var(--t-base);
  line-height: 1.55;
  color: var(--fg-muted);
}
.confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--s2);
}

/* ---------- Reports ---------- */

.subnav {
  display: flex;
  gap: var(--s2);
  margin-bottom: var(--s4);
}
.subnav-item {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-subtle);
  color: var(--fg-muted);
  font-size: var(--t-sm);
  font-weight: 500;
}
.subnav-item:hover { background: var(--bg-inset); text-decoration: none; color: var(--fg); }
.subnav-item.is-active {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  color: var(--accent-hover);
}

/* ---------- Charts ----------
 * A frame with a fixed height and a canvas that fills it. Chart.js measures its
 * container, so the container is what has to be sized; the canvas carries a
 * height attribute as a fallback for the moment before the script runs.
 *
 * Nothing here sets geometry through an inline style attribute. The console's
 * Content-Security-Policy is style-src 'self', which refuses those — which is
 * how the CSS bar and donut this replaced came to render as empty shapes.
 */
.chart-frame {
  position: relative;
  height: 240px;
  margin-bottom: var(--s4);
}
.chart-frame.is-wide { height: 260px; }
.chart-frame canvas { display: block; width: 100% !important; }

/* The figures beside a chart. A canvas is not readable by a screen reader or a
 * printer, and on this screen the numbers are the point. */
.chart-legend { margin-top: var(--s2); }
.chart-legend td,
.chart-legend th { padding-top: var(--s2); padding-bottom: var(--s2); }

.column-picker {
  border: 0;
  padding: 0;
  margin: 0;
}
.column-picker legend {
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--fg-muted);
  margin-bottom: var(--s3);
}
.column-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--s2) var(--s4);
}
.column-form .form-actions { display: flex; gap: var(--s2); flex-wrap: wrap; }
.check {
  display: flex;
  align-items: center;
  gap: var(--s2);
  font-size: var(--t-sm);
  cursor: pointer;
}
.check input { margin: 0; }

.grid-2 {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s4);
}
@media (max-width: 900px) {
  .grid-2 { grid-template-columns: 1fr; }
  .chart-frame { height: 220px; }
}

/* ---------- Action menu ----------
 * A page-action button that opens a small list of related actions. Used by
 * the demonstration-data control on the overview: one button, each choice a
 * form of its own so the confirm overlay can speak to exactly what it does. */

.menu { position: relative; }
.menu > summary { list-style: none; user-select: none; }
.menu > summary::-webkit-details-marker { display: none; }
.menu > summary::after { content: "▾"; font-size: 10px; margin-left: 6px; color: var(--fg-subtle); }
.menu[open] > summary { border-color: var(--accent); }

.menu-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 30;
  width: 300px;
  padding: var(--s2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-pop);
  animation: confirm-in 120ms ease-out;
}

.menu-heading {
  padding: var(--s2) var(--s2) var(--s1);
  font-size: var(--t-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-subtle);
}
.menu-heading + .menu-heading,
form + .menu-heading { margin-top: var(--s2); border-top: 1px solid var(--border); padding-top: var(--s3); }

.menu-item {
  display: flex;
  flex-direction: column;
  gap: 1px;
  width: 100%;
  padding: var(--s2);
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--fg);
  font-family: inherit;
  font-size: var(--t-md);
  text-align: left;
  cursor: pointer;
}
.menu-item:hover { background: var(--bg-inset); }
.menu-item strong { font-weight: 600; }
.menu-item span { font-size: var(--t-sm); color: var(--fg-subtle); }

/* The "new activity" offer, shown only when the page would otherwise have
   reloaded under somebody who is typing. It sits out of the way, says what it
   is, and does the thing when asked. */
.rt-activity {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 60;
  border: 1px solid var(--border-strong);
  background: var(--fg);
  color: var(--on-fg);
  border-radius: 999px;
  padding: 0.55rem 1rem;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--shadow-pill);
}
.rt-activity:hover { filter: brightness(1.15); }
.rt-activity:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* The live indicator in the rail foot.
 *
 * An operator watching a console that updates itself has to be able to tell
 * "nothing has happened" from "this page stopped listening ten minutes ago",
 * and without a light there is no difference between the two on screen. Green
 * says the socket is up; amber says it is trying. The element is rendered only
 * when the deployment can actually mint a token, so nobody is shown a dot that
 * is never going to go green.
 *
 * The rail is dark, so these are the rail-safe pair rather than the page
 * tokens, which are mixed for a light background and go muddy here. The label
 * has a fixed width because the rail must not shift when the text changes
 * between "Live" and "Reconnecting".
 */
.rt-status {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.66);
}
.rt-status[data-state="stopped"] { display: none; }
.rt-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--rail-highlight);
  flex: none;
}
/* The word behind the light is for assistive technology only: the colour
   says it, and the rail has no room to spend on a label that reads "Live"
   all day. */
.rt-status[data-state="open"] .rt-dot { background: #6fd39a; }
.rt-status[data-state="open"] { color: rgba(255, 255, 255, 0.78); }
.rt-status[data-state="connecting"] .rt-dot,
.rt-status[data-state="reconnecting"] .rt-dot { animation: rt-pulse 1.4s ease-in-out infinite; }
@keyframes rt-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
@media (prefers-reduced-motion: reduce) {
  .rt-status .rt-dot { animation: none; }
}
.rail-foot .rt-status { margin-bottom: 0.45rem; }

/* A card's one-line explanation. It was an inline style attribute, which
   `style-src 'self'` refuses outright: the console dropped the spacing and
   logged six policy violations on every page that has a card with a
   description. */
.card-note { margin-bottom: 6px; }

/* ---------- Theme switch ----------
 * A square icon button: a lit bulb in the light theme, a switched-off bulb in
 * the dark one. It sits at the top of the rail on every signed-in screen and
 * in the corner of the sign-in page. The rail is dark in both themes, so the
 * rail's button is drawn in the rail's white-on-dark language. */
.theme-toggle {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  color: var(--fg-muted);
  cursor: pointer;
  transition: background-color 120ms cubic-bezier(.4,0,.2,1), color 120ms cubic-bezier(.4,0,.2,1), border-color 120ms cubic-bezier(.4,0,.2,1);
}
.theme-toggle:hover { background: var(--bg-inset); color: var(--fg); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.theme-icon { display: block; }
.theme-icon-bulb-off { display: none; }
:root[data-theme="dark"] .theme-icon-bulb-off { display: block; }
:root[data-theme="dark"] .theme-icon-bulb { display: none; }

.rail .theme-toggle {
  background: transparent;
  border-color: rgba(255, 255, 255, 0.36);
  color: rgba(255, 255, 255, 0.86);
}
.rail .theme-toggle:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
.rail .theme-toggle:focus-visible { outline-color: var(--rail-highlight); }

.auth-wrap { position: relative; }
.auth-tools { position: absolute; top: var(--s4); right: var(--s4); z-index: 2; }
@media (max-width: 900px) {
  /* Below 900px the corner is over the teal panel, so the button takes the
   * rail's look there. */
  .auth-tools .theme-toggle {
    background: transparent;
    border-color: rgba(255, 255, 255, 0.36);
    color: rgba(255, 255, 255, 0.86);
  }
  .auth-tools .theme-toggle:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
  .auth-tools .theme-toggle:focus-visible { outline-color: var(--rail-highlight); }
}

/* The dark theme draws the mark reversed wherever it lands, like the rail. */
:root[data-theme="dark"] .brand-logo {
  background-image: url("/console/static/logo-mark-light.png?v=2");
}

/* ---------- Print ----------
 * Paper is light whatever the screen is: the dark tokens above apply to the
 * screen only, and this undoes the color-scheme theme-init.js writes on the
 * root element so form controls print light too. */
@media print {
  :root { color-scheme: light !important; }
  .theme-toggle { display: none; }
}
