/* ============================================================
   SASCO Finance Intelligence — PoC demo
   Design language ported from the legacy prototype's tokens and
   component patterns (finding cards, badges, tables, ledger blocks),
   trimmed to what this MVP shell actually uses.
   Light only · one accent (teal) · zinc neutrals · logical
   properties throughout so RTL support stays structural, not a
   mirrored stylesheet, if this is ever localised.
   ============================================================ */

/* ---------- tokens ---------- */
:root {
  --bg: #f6f6f7;
  --panel: #ffffff;
  --panel-soft: #f8f9fa;
  --ink-900: #18181b;
  --ink-800: #27272a;
  --ink-700: #3f3f46;
  --ink-600: #52525b;
  --ink-500: #71717a;
  --ink-400: #a1a1aa;
  /* --ink-muted is the floor for any text a reader must actually read.
     --ink-400 measures 2.56:1 on white, which is below WCAG AA for normal
     text; it stays for hairlines and decorative glyphs only. */
  --ink-muted: #64646d;
  --line: #e4e4e7;
  --line-soft: #ececef;
  --accent: #009da0;
  --accent-text: #00737a;
  --accent-tint: #ebf7f7;
  --neg: #b91c1c;
  --neg-tint: #fdecec;
  --amber: #b45309;
  --amber-tint: #fef3c7;
  --navy: #1a2733;
  --navy-soft: #243546;
  --green: #15803d;
  --green-tint: #e9f6ee;
  --blue: #2b5fb3;
  --blue-tint: #ecf2fb;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  /* No Google Fonts import here on purpose — no CDN/external requests
     allowed in this build. Falls back to the platform UI font stack.
     A production build should self-host IBM Plex Sans (+ Arabic) as
     woff2 with font-display: optional instead of adding a webfont link. */
  --font-en: system-ui, -apple-system, "Segoe UI", "IBM Plex Sans", sans-serif;
  --r-panel: 8px;
  --r-ctl: 6px;
  --r-pill: 999px;

  /* Type. Tracking is size-specific on purpose: large text reads too loose at
     0, small uppercase labels read too tight. One value for every size is
     wrong somewhere. */
  --track-display: -0.02em;
  --track-title: -0.01em;
  --track-label: 0.06em;

  /* Shadows are tinted to the surface hue rather than neutral black, so the
     light source reads as one source across the page. */
  --shadow-card: 0 1px 2px rgba(26, 39, 51, 0.04), 0 8px 24px rgba(26, 39, 51, 0.07);
  --shadow-raised: 0 1px 2px rgba(26, 39, 51, 0.05), 0 2px 8px rgba(26, 39, 51, 0.06);

  /* Layer scale. Four named steps beat scattered magic numbers. */
  --z-sticky: 10;
  --z-footer: 40;

  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

/* The whole shell toggle runs on the `hidden` attribute: app.js sets
   `loginShell.hidden` / `appShell.hidden` and nothing else decides which
   screen you see. `hidden` is enforced only by the UA rule `[hidden] {
   display: none }`, and ANY author rule that sets `display` on the same
   element beats it — so the moment `.login-shell` gained `display: grid`
   below, the login card stopped hiding and painted over the app. Stating it
   here, once, with `!important` makes the attribute authoritative no matter
   what any component rule sets. Note that a test asserting `el.hidden` cannot
   catch this: the property is still true, the pixels just do not agree. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink-800);
  font-family: var(--font-en);
  font-size: 15px;
  line-height: 1.5;
  /* dvh, not vh: on mobile Safari `100vh` is the URL-bar-less height, so a
     full-height login sits taller than the visible viewport and scrolls. */
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Headings balance across lines; body copy avoids a one-word last line. */
h1, h2, h3 { text-wrap: balance; }
p { text-wrap: pretty; }

button, input, select, textarea { font: inherit; color: inherit; }
/* Focus is load-bearing in this product, not decoration: the claim a four-eyes
   approval makes is that a person reached a control and acted on it, so the
   keyboard path has to be plainly visible, not a hairline tint. The accent
   alone measures 3.07:1 against the page — the minimum for a non-text
   indicator and no more. A dark inner ring (17.7:1) with an accent halo reads
   on white panels, on tinted rows and on the navy footer alike. */
:focus-visible {
  outline: 2px solid var(--ink-900);
  outline-offset: 2px;
  border-radius: 3px;
  box-shadow: 0 0 0 5px var(--accent-tint);
}
/* On dark or saturated grounds the rings swap so the bright one is outermost. */
.app-footer :focus-visible,
.data-table th :focus-visible {
  outline-color: #ffffff;
  box-shadow: 0 0 0 5px rgba(0, 157, 160, 0.55);
}
/* A pointer press should never paint the keyboard ring. */
:focus:not(:focus-visible) { outline: none; }
a { color: var(--accent-text); }

/* ---------- header ---------- */
.app-header {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: var(--bg);
  border-block-end: 1px solid var(--line);
}
.header-row {
  max-width: 1160px;
  margin-inline: auto;
  padding: 14px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.wordmark {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: 17px;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.wm-name { font-weight: 600; color: var(--ink-900); }
.wm-rest  { font-weight: 400; color: var(--ink-500); }
.wm-accent { color: var(--accent-text); font-weight: 600; }
.wm-divider {
  display: inline-block;
  inline-size: 6px;
  block-size: 6px;
  background: var(--accent);
  border-radius: 1px;
  transform: translateY(-2px);
}
.wm-tag {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-500);
  background: var(--panel-soft);
  border: 1px solid var(--line-soft);
  border-radius: 999px;
  padding: 2px 9px;
  margin-inline-start: 4px;
}
.header-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.session-box { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-600); }
.role-badge {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  border-radius: 999px;
  padding: 2px 9px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink-600);
}
.role-badge.approver { border-color: var(--accent); background: var(--accent-tint); color: var(--accent-text); }
.role-badge.preparer { border-color: var(--blue); background: var(--blue-tint); color: var(--blue); }
.role-badge.reader { border-color: var(--line); background: var(--panel-soft); color: var(--ink-500); }
.session-user { font-weight: 600; color: var(--ink-800); }
.logout-btn {
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink-600);
  border-radius: var(--r-ctl);
  padding: 6px 12px;
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
}
.logout-btn { transition: border-color 0.15s var(--ease-out), color 0.15s var(--ease-out), transform 0.1s var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .logout-btn:hover { border-color: var(--accent); color: var(--accent-text); }
}
.logout-btn:active { transform: scale(0.98); }
.masked-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 6px 16px;
  background: var(--line-soft);
  border-block-start: 1px solid var(--line-soft);
  color: var(--ink-700);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.01em;
}
.masked-banner svg { color: var(--ink-500); flex: none; }

/* ---------- layout ---------- */
.layout { flex: 1; max-width: 1160px; margin-inline: auto; width: 100%; }
.mainpane { min-width: 0; }

/* ---------- nav tabs ---------- */
/* Keyboard users reach the tab bar through six header controls. On a product
   whose audit trail asserts that a person reviewed something, the keyboard
   route to the content is part of the claim, not a nicety. */
.skip-link {
  position: absolute;
  inset-inline-start: 12px;
  inset-block-start: -60px;
  z-index: calc(var(--z-footer) + 1);
  background: var(--panel);
  color: var(--accent-text);
  border: 1px solid var(--accent);
  border-radius: var(--r-ctl);
  padding: 9px 14px;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  transition: inset-block-start 0.15s var(--ease-out);
}
.skip-link:focus-visible { inset-block-start: 12px; }

.tabs {
  display: flex;
  gap: 4px;
  max-width: 900px;
  margin-inline: auto;
  padding: 20px 24px 0;
  border-block-end: 1px solid var(--line-soft);
}
.tab {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 0;
  background: none;
  padding: 9px 12px;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-500);
  border-block-end: 2px solid transparent;
  margin-block-end: -1px;
  cursor: pointer;
}
.tab { transition: color 0.15s var(--ease-out), border-color 0.15s var(--ease-out); }
.tab.is-active { color: var(--ink-900); border-block-end-color: var(--accent); }
/* Gated: a touch tap fires :hover and leaves the tab stuck in a hover state. */
@media (hover: hover) and (pointer: fine) {
  .tab:hover:not(.is-active) { color: var(--ink-700); border-block-end-color: var(--line); }
}
.tab:active { transform: translateY(0.5px); }
.tab-count {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--accent-text);
  background: var(--accent-tint);
  border-radius: 10px;
  padding: 1px 7px;
}

/* ---------- view shell ---------- */
.view-inner { max-width: 900px; margin-inline: auto; padding: 22px 24px 48px; }
.view-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; flex-wrap: wrap; margin-block-end: 16px; }
.view-head-text { flex: 1; min-width: 280px; }
/* Leading tightens as size grows and tracking goes negative with it; the sub
   sits near 0 tracking at a comfortable measure. One value for every size
   would be wrong at one end or the other. */
.view-head h1 {
  margin: 0 0 5px;
  font-size: 23px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: var(--track-display);
  color: var(--ink-900);
}
.view-sub { margin: 0; color: var(--ink-muted); font-size: 13.5px; line-height: 1.6; max-width: 68ch; }

/* ---------- generic error / empty / loading states ----------
   Amber is this app's "the system could not answer" colour and red is "your
   input was refused". They are different messages and were sharing one style:
   a rejected password rendered in the same caution amber as an unbuilt
   endpoint. `.is-refusal` names the second case. */
.err-banner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  background: var(--amber-tint);
  border: 1px solid var(--amber);
  color: #7c3f07;
  border-radius: var(--r-panel);
  padding: 11px 14px;
  font-size: 13px;
  line-height: 1.5;
  margin-block-end: 14px;
}
.err-banner b { display: block; margin-block-end: 2px; }
.err-banner.is-refusal {
  background: var(--neg-tint);
  border-color: var(--neg);
  color: #8d1616;
}

/* An empty state is a composed answer, not grey text left on the floor. */
.empty-note {
  margin: 0;
  color: var(--ink-muted);
  font-size: 13px;
  line-height: 1.6;
  text-align: center;
  padding: 30px 24px;
  background: var(--panel-soft);
  border: 1px dashed var(--line);
  border-radius: var(--r-panel);
}
/* Loading reserves the shape the content will take, so nothing jumps when the
   answer lands. The bar carries the motion; the text stays readable. */
.loading-note {
  position: relative;
  margin: 0;
  color: var(--ink-muted);
  font-size: 13px;
  padding: 18px 2px 22px;
}
.loading-note::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 8px;
  block-size: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--line-soft) 0%, var(--accent) 50%, var(--line-soft) 100%);
  background-size: 200% 100%;
  animation: sweep 1.1s linear infinite;
}

/* ---------- login ----------
   `.login-shell` is the element index.html actually renders. It previously had
   no rules at all: the centring lived on `.login-wrap`, a class the markup
   stopped using, so the card rendered flush to the top-left corner. The
   stylesheet had drifted from the markup and nothing failed loudly.
   `.login-wrap`, `.login-brand` and `.login-tag` are deleted rather than kept
   as dead weight — the live class names are `.login-shell`, `.wordmark` and
   `.login-sub`. */
.login-shell {
  flex: 1;
  min-height: 100dvh;
  display: grid;
  /* Optically centred, not mathematically: a form reads as centred when it
     sits slightly above the true middle, so the top row is the smaller one. */
  grid-template-rows: 0.85fr auto 1fr;
  justify-items: center;
  padding: 24px;
}
.login-card {
  grid-row: 2;
  width: min(400px, 100%);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-panel);
  padding: 32px 30px;
  box-shadow: var(--shadow-card);
}
.login-card .wordmark { font-size: 20px; }
.login-sub {
  margin: 10px 0 24px;
  font-size: 13.5px;
  color: var(--ink-muted);
}
.login-form { display: flex; flex-direction: column; }
/* The submit is the only action on the screen, so it spans the card. */
.login-form .primary-btn { margin-block-start: 4px; }
/* A pilot footnote, not a hazard. It used to carry `.gov-note`, which paints
   an amber warning panel — the loudest element on a sign-in screen, saying
   nothing a signing-in user must act on. */
.login-note {
  margin: 18px 0 0;
  padding-block-start: 16px;
  border-block-start: 1px solid var(--line-soft);
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--ink-muted);
}
.field { display: flex; flex-direction: column; gap: 6px; margin-block-end: 14px; }
/* Two label idioms exist in this app: `<div class="field"><label>` in the
   mapping picker, and `<label class="field"><span class="field-k">` on the
   login form. Only the first matched, so the login labels rendered at body
   size and weight. Both are named here. */
.field label,
.field-k {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-700);
  letter-spacing: 0.005em;
}
.field input, .field select {
  border: 1px solid var(--line);
  border-radius: var(--r-ctl);
  padding: 9px 11px;
  font-size: 14px;
  background: var(--panel);
  color: var(--ink-900);
}
.field input:hover, .field select:hover { border-color: var(--ink-400); }
/* The typed-into field gets the accent; the keyboard ring is separate and
   still wins, because a sighted keyboard user needs both signals. */
.field input:focus, .field select:focus { border-color: var(--accent); }
.field input:focus-visible, .field select:focus-visible { outline-offset: 1px; }
/* :user-invalid, not :invalid. A `required` empty input is :invalid from the
   moment it renders, so :invalid paints an untouched form red. :user-invalid
   waits until the user has actually interacted or submitted. These inputs
   carry no placeholder, so the :not(:placeholder-shown) idiom would not have
   worked either: with no placeholder attribute that selector always matches. */
.field input:user-invalid { border-color: var(--neg); }

.primary-btn {
  width: 100%;
  border: 0;
  background: var(--accent-text);
  color: #ffffff;
  font-size: 14.5px;
  font-weight: 600;
  border-radius: var(--r-ctl);
  padding: 11px 16px;
  cursor: pointer;
  transition: background 0.15s var(--ease-out), transform 0.1s var(--ease-out);
}
/* #00737a on white is 5.63:1. The lighter --accent is 3.32:1, which is below
   AA for label text this size, so the button darkens rather than brightens. */
.primary-btn:hover:not(:disabled) { background: #005f66; }
.primary-btn:active:not(:disabled) { transform: scale(0.985); }
.primary-btn:disabled { opacity: 0.55; cursor: default; }

/* ---------- filter chips / KPI tiles ---------- */
.filter-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-block-end: 14px; }
.chip {
  border: 1px solid var(--line);
  background: var(--panel);
  border-radius: 999px;
  padding: 4px 12px;
  font-size: 12.5px;
  color: var(--ink-600);
  cursor: pointer;
  transition: border-color 0.15s var(--ease-out), color 0.15s var(--ease-out), background 0.15s var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .chip:hover { border-color: var(--accent); color: var(--accent-text); }
}
.chip:active { transform: scale(0.98); }
.chip.is-active { background: var(--accent-tint); border-color: var(--accent); color: var(--accent-text); }

.kpi-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-block-end: 18px; }
.kpi-tile { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-panel); padding: 12px 14px; }
.kpi-value { font-size: 21px; font-weight: 600; color: var(--ink-900); font-variant-numeric: tabular-nums; direction: ltr; unicode-bidi: isolate; display: block; }
.kpi-label { font-size: 12px; color: var(--ink-500); margin-block-start: 2px; }

/* ---------- findings list ---------- */
.findings-list { display: flex; flex-direction: column; gap: 10px; }
.finding-card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-panel);
  padding: 14px 16px;
  /* `backwards` matters: with a delay and no fill mode the card paints at full
     opacity, waits, then blinks to opacity 0 to start rising. */
  animation: rise 0.24s var(--ease-out-quart) backwards;
  cursor: pointer;
  transition: border-color 0.15s var(--ease-out), box-shadow 0.15s var(--ease-out), transform 0.1s var(--ease-out);
}
/* Stagger only the first rows: 8 x 35ms = 280ms total, so the list is
   readable almost immediately. Rows past the fold appear with the list. */
.finding-card:nth-child(-n+8) { animation-delay: calc((var(--i, 0)) * 35ms); }
.finding-card:nth-child(2) { --i: 1; }
.finding-card:nth-child(3) { --i: 2; }
.finding-card:nth-child(4) { --i: 3; }
.finding-card:nth-child(5) { --i: 4; }
.finding-card:nth-child(6) { --i: 5; }
.finding-card:nth-child(7) { --i: 6; }
.finding-card:nth-child(8) { --i: 7; }
@media (hover: hover) and (pointer: fine) {
  .finding-card:hover { border-color: var(--accent); box-shadow: var(--shadow-raised); }
}
.finding-card:active { transform: scale(0.997); }
.f-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-block-end: 8px; }
.f-rank { font-family: var(--mono); font-size: 12px; font-weight: 600; color: var(--accent-text); }
.f-rule {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-500);
  background: var(--panel-soft);
  border: 1px solid var(--line-soft);
  border-radius: 4px;
  padding: 2px 7px;
  font-family: var(--mono);
}
.f-sev, .f-conf {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.05em;
  border-radius: 4px;
  padding: 2px 7px;
}
.f-sev.high { background: var(--neg-tint); color: var(--neg); }
.f-sev.med  { background: var(--amber-tint); color: var(--amber); }
.f-sev.low  { background: #f4f4f5; color: var(--ink-600); }
.f-conf { background: var(--panel); border: 1px solid var(--line); color: var(--ink-500); }
.f-title { margin: 0 0 11px; font-size: 14.5px; font-weight: 600; color: var(--ink-900); line-height: 1.45; letter-spacing: var(--track-title); }
.f-figs { display: flex; flex-wrap: wrap; gap: 8px 22px; }
.fig { display: flex; flex-direction: column; gap: 2px; }
.fig-k { font-size: 11px; color: var(--ink-muted); }
.fig-v { font-size: 13.5px; font-weight: 600; color: var(--ink-800); font-variant-numeric: tabular-nums; direction: ltr; unicode-bidi: isolate; }
.fig-v.neg { color: var(--neg); }
.f-select { margin-inline-end: 4px; }
.list-note { color: var(--ink-muted); font-size: 12px; margin: 14px 2px 0; }
.list-toolbar { display: flex; align-items: center; gap: 10px; margin-block-end: 14px; flex-wrap: wrap; }
.pager { display: flex; align-items: center; gap: 8px; margin-block-start: 16px; }
.pager button {
  border: 1px solid var(--line);
  background: var(--panel);
  border-radius: var(--r-ctl);
  padding: 6px 12px;
  font-size: 12.5px;
  cursor: pointer;
}
.pager button { transition: border-color 0.15s var(--ease-out), color 0.15s var(--ease-out), transform 0.1s var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .pager button:hover:not(:disabled) { border-color: var(--accent); color: var(--accent-text); }
}
.pager button:active:not(:disabled) { transform: scale(0.98); }
.pager button:disabled { opacity: 0.4; cursor: default; }
.pager-info { font-size: 12px; color: var(--ink-muted); font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* ---------- action buttons ---------- */
.action-btn, .export-btn, .demo-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink-700);
  font-size: 12.5px;
  font-weight: 500;
  border-radius: var(--r-ctl);
  padding: 6px 12px;
  cursor: pointer;
  transition: border-color 0.15s var(--ease-out), color 0.15s var(--ease-out), transform 0.15s var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .action-btn:hover:not(:disabled), .export-btn:hover:not(:disabled), .demo-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent-text); }
}
.action-btn:active, .export-btn:active, .demo-btn:active { transform: scale(0.98); }
.action-btn:disabled, .export-btn:disabled, .demo-btn:disabled { opacity: 0.5; cursor: default; }
.approve-btn {
  border: 0;
  /* --accent behind white text is 3.32:1, under AA for 13px. --accent-text is
     5.63:1 and reads as the same colour family. */
  background: var(--accent-text);
  color: #ffffff;
  border-radius: var(--r-ctl);
  padding: 7px 16px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.15s var(--ease-out), background 0.15s var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .approve-btn:hover:not(:disabled) { background: #005f66; }
}
.approve-btn:active:not(:disabled) { transform: scale(0.98); }
.approve-btn:disabled { opacity: 0.5; cursor: default; }
.dec-btn {
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--ink-700);
  border-radius: 4px;
  padding: 4px 9px;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  transition: border-color 0.15s var(--ease-out), color 0.15s var(--ease-out);
}
.dec-btn:hover { border-color: var(--accent); }
.dec-btn.accept.is-on { background: var(--accent-tint); border-color: var(--accent); color: var(--accent-text); }
.dec-btn.reject.is-on { background: var(--neg-tint); border-color: var(--neg); color: var(--neg); }
.decision { display: inline-flex; gap: 4px; }

/* ---------- finding detail ---------- */
.detail-back {
  border: 0;
  background: none;
  color: var(--accent-text);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  padding: 0 0 12px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.detail-back:hover { text-decoration: underline; }
.detail-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-panel); padding: 18px 20px; }
.detail-meta { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-block-end: 10px; }
/* 600 rather than 700: at 19px the bold weight shouts next to the metadata
   row above it, and weight is doing hierarchy work that size already did. */
.detail-title { margin: 0 0 16px; font-size: 19px; font-weight: 600; line-height: 1.3; letter-spacing: var(--track-title); color: var(--ink-900); }
.detail-figs { display: flex; flex-wrap: wrap; gap: 8px 26px; margin-block-end: 14px; }

.narrative { margin-block-start: 6px; background: var(--accent-tint); border-inline-start: 3px solid var(--accent); border-radius: var(--r-ctl); padding: 10px 14px; }
.narrative-tag { display: block; font-size: 11px; font-weight: 600; letter-spacing: 0.07em; text-transform: uppercase; color: var(--accent-text); margin-block-end: 4px; }
.narrative-body { margin: 0; color: var(--ink-700); white-space: pre-wrap; }
.disclaimer {
  margin-block-start: 8px;
  display: flex;
  gap: 7px;
  align-items: flex-start;
  font-size: 12px;
  color: #7c3f07;
  background: var(--amber-tint);
  border: 1px solid var(--amber);
  border-radius: var(--r-ctl);
  padding: 7px 10px;
}

.section-title {
  margin: 20px 0 8px;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* ---------- tables (evidence, mappings, ledger) ---------- */
.table-scroll { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r-panel); }
.data-table { width: 100%; border-collapse: collapse; font-size: 12.5px; background: var(--panel); }
/* The header was solid --accent with white text: 3.32:1, below WCAG AA's
   4.5:1 for text this size, and a saturated band across every table on a
   screen whose job is reading figures. A quiet header lets the data carry the
   colour, and the label row still reads as a header through weight, case and
   the rule beneath it. */
.data-table th {
  background: var(--panel-soft);
  color: var(--ink-700);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  text-align: start;
  padding: 9px 10px;
  border-block-end: 1px solid var(--line);
  white-space: nowrap;
}
.data-table td { padding: 9px 10px; border-block-end: 1px solid var(--line-soft); color: var(--ink-700); vertical-align: top; }
.data-table tr:last-child td { border-block-end: 0; }
.data-table tbody tr:hover td { background: var(--panel-soft); }
/* Zebra at 40% strength: enough to track a row across eight columns of
   provenance, not enough to read as a second border system. */
.data-table tbody tr:nth-child(even) td { background: #fcfcfd; }
.data-table tbody tr:nth-child(even):hover td { background: var(--panel-soft); }
.mono-cell { font-family: var(--mono); font-size: 11.5px; direction: ltr; unicode-bidi: isolate; }
.num { direction: ltr; unicode-bidi: isolate; text-align: right; font-variant-numeric: tabular-nums; }
.num.neg { color: var(--neg); }

.evi-summary { color: var(--ink-800); font-weight: 500; }
.evi-lineage { font-family: var(--mono); font-size: 11px; color: var(--ink-500); margin-block-start: 3px; }

/* provenance chain */
.provenance { margin-block-start: 4px; display: flex; flex-wrap: wrap; align-items: center; gap: 4px; font-family: var(--mono); font-size: 11px; color: var(--ink-muted); direction: ltr; unicode-bidi: isolate; }
.provenance .p-chip { background: var(--panel); border: 1px solid var(--line-soft); border-radius: 4px; padding: 2px 6px; color: var(--ink-600); white-space: nowrap; }
.provenance .p-arrow { color: var(--ink-400); }

.raw-wb-card { display: flex; flex-wrap: wrap; gap: 6px 20px; background: var(--panel-soft); border: 1px solid var(--line-soft); border-radius: var(--r-ctl); padding: 10px 12px; margin-block-end: 8px; }
.raw-wb-card .fig-k { text-transform: uppercase; letter-spacing: 0.05em; }

/* ---------- mapping proposals ---------- */
.props-wrap { margin-block-start: 10px; }
.conf {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.05em;
  border-radius: 4px;
  padding: 2px 7px;
  white-space: nowrap;
}
.conf.high { background: var(--accent-tint); color: var(--accent-text); }
.conf.med { background: #f4f4f5; color: var(--ink-600); }
.conf.low { background: var(--amber-tint); color: var(--amber); }
.approve-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-block-start: 14px; }
.approve-hint { font-size: 11.5px; color: var(--ink-muted); }
/* Amber is a caution: a read-only role, a missing digest, a self-approval the
   server will refuse. Some notes wearing this class are not cautions at all,
   they are statements of fact (which run you are looking at, that a profile
   job is queued). `.is-info` gives those a neutral surface so the amber keeps
   meaning something. */
.gov-note {
  display: flex;
  gap: 8px;
  align-items: center;
  border: 1px solid var(--amber);
  background: var(--amber-tint);
  color: #7c3f07;
  border-radius: var(--r-ctl);
  padding: 8px 12px;
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.5;
  margin-block: 2px 12px;
}
.gov-note.is-info {
  border-color: var(--line);
  background: var(--panel);
  color: var(--ink-700);
  font-weight: 400;
}
.gov-note.is-info code { font-family: var(--mono); color: var(--accent-text); }

/* ---------- upload / ingest ---------- */
/* `<label>` is inline by default and this one has no `display` of its own, so
   its block child fragmented the inline box: the dashed border painted around
   a narrow sliver instead of the drop area. It has looked like this the whole
   time. */
.upload-drop {
  display: block;
  position: relative;
  border: 1.5px dashed var(--line);
  border-radius: var(--r-panel);
  background: var(--panel);
  padding: 40px 20px;
  text-align: center;
  color: var(--ink-muted);
  font-size: 13.5px;
  cursor: pointer;
  transition: border-color 0.15s var(--ease-out), background 0.15s var(--ease-out), color 0.15s var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .upload-drop:hover { border-color: var(--accent); background: var(--accent-tint); color: var(--accent-text); }
}
.upload-drop.is-drag { border-color: var(--accent); background: var(--accent-tint); color: var(--accent-text); }
/* `display: none` removed the file input from the tab order, so Ingest could
   not be reached by keyboard at all — on a product whose audit trail asserts a
   person did the work. Clipped instead of hidden: invisible, zero layout, and
   still focusable. The ring is drawn on the label, since the input has no box
   worth outlining. */
.upload-drop input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}
.upload-drop:has(input[type="file"]:focus-visible) {
  border-color: var(--accent);
  border-style: solid;
  outline: 2px solid var(--ink-900);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px var(--accent-tint);
}
.upload-result { margin-block-start: 14px; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-panel); padding: 14px 16px; }
.upload-result-title { margin: 0 0 6px; font-weight: 600; color: var(--ink-900); font-size: 13.5px; }
.sheet-picker { display: flex; flex-wrap: wrap; gap: 8px; align-items: stretch; margin-block: 12px 4px; }
.sheet-chip {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  border: 1px solid var(--line-soft);
  background: var(--panel);
  border-radius: 8px;
  padding: 6px 10px;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  color: var(--ink-800);
}
.sheet-chip small { font-size: 10.5px; font-weight: 400; color: var(--ink-muted); }
.sheet-chip:hover { border-color: var(--accent); }
.sheet-chip.is-on { border-color: var(--accent); background: var(--accent-tint); color: var(--accent-text); box-shadow: 0 0 0 2px var(--accent-tint); }

/* ---------- chain / ledger view ---------- */
.chain-stats { display: flex; gap: 10px; flex-wrap: wrap; margin-block-start: 4px; }
.chain-stat { font-size: 12px; border: 1px solid var(--line); background: var(--panel); border-radius: 999px; padding: 4px 12px; color: var(--ink-600); }
.chain-stat.ok { border-color: var(--green); background: var(--green-tint); color: var(--green); }
.chain-stat.bad { border-color: var(--neg); background: var(--neg-tint); color: var(--neg); }
.chain-stat code { font-family: var(--mono); }

.ledger-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-block: 12px 14px; }
.verify-result {
  margin-block-end: 14px;
  border-radius: var(--r-panel);
  padding: 10px 14px;
  font-size: 13px;
  border: 1px solid var(--line);
}
.verify-result.ok { border-color: var(--green); background: var(--green-tint); color: var(--green); }
.verify-result.bad { border-color: var(--neg); background: var(--neg-tint); color: var(--neg); }

.ledger-chain { list-style: none; margin: 0; padding: 0; }
.ledger-block {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-panel);
  background: var(--panel);
  margin-block-end: 8px;
  position: relative;
}
.ledger-block:hover { background: var(--panel-soft); }
.lb-idx { font-family: var(--mono); font-size: 11.5px; color: var(--ink-muted); min-width: 42px; padding-block-start: 2px; font-variant-numeric: tabular-nums; }
.lb-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.lb-line1, .lb-line2 { display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.lb-event { font-weight: 600; color: var(--ink-800); font-size: 13.5px; }
.lb-actor { font-family: var(--mono); font-size: 11.5px; color: var(--accent-text); background: var(--accent-tint); border-radius: 4px; padding: 1px 7px; direction: ltr; unicode-bidi: isolate; }
.lb-time { font-size: 12px; color: var(--ink-500); font-family: var(--mono); direction: ltr; unicode-bidi: isolate; font-variant-numeric: tabular-nums; }
.lb-seal { font-family: var(--mono); font-size: 10.5px; color: var(--ink-muted); word-break: break-all; direction: ltr; unicode-bidi: isolate; }
.lb-seal b { color: var(--ink-600); font-weight: 600; }
.lb-payload { font-family: var(--mono); font-size: 10.5px; color: var(--ink-500); word-break: break-all; }

/* ---------- footer ---------- */
.app-footer {
  position: sticky;
  bottom: 0;
  z-index: var(--z-footer);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  padding: 10px 20px;
  background: var(--navy);
  color: #c7d2dd;
  font-size: 12px;
}
.footer-zone { display: flex; align-items: center; gap: 8px; min-width: 0; }
.status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); display: inline-block; box-shadow: 0 0 0 3px rgba(21, 128, 61, 0.25); flex: none; }
.status-dot.bad { background: var(--neg); box-shadow: 0 0 0 3px rgba(185, 28, 28, 0.25); }
.footer-brand .wm-name { font-weight: 700; color: #ffffff; letter-spacing: 0.02em; }
.footer-brand .wm-divider { width: 1px; height: 12px; background: var(--navy-soft); margin-inline: 6px; display: inline-block; }
.footer-brand .wm-rest { color: #c7d2dd; }
.footer-brand .wm-accent { color: #4fd1c5; }
.footer-note { color: #8fa3b7; }

.raw-json {
  margin: 8px 0 0;
  background: var(--panel-soft);
  border: 1px dashed var(--line);
  border-radius: var(--r-ctl);
  padding: 8px 10px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-600);
  max-height: 220px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-all;
}
.raw-json summary { cursor: pointer; font-family: var(--font-en); font-size: 11.5px; color: var(--ink-500); font-weight: 600; }
.field-row { display: flex; gap: 10px; flex-wrap: wrap; }
.field-row .field { flex: 1; min-width: 160px; }
.checkbox-cell { text-align: center; }

/* ---------- misc ---------- */
@keyframes rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes sweep { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.hidden { display: none !important; }

/* ---------- responsive ---------- */
@media (max-width: 900px) {
  .kpi-row { grid-template-columns: repeat(2, 1fr); }
  .header-row { padding: 12px 16px; }
  .view-inner { padding: 18px 16px 40px; }
}
/* Reduced motion means gentler, not absent. Opacity and colour changes carry
   meaning here — a button confirming a press, a row confirming a hover — so
   they stay. What goes is translation, scaling and the looping loader sweep,
   which are the vestibular half. The previous rule flattened every transition
   to 0.01ms, which removed the feedback along with the movement. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-property: opacity, color, background-color, border-color, box-shadow !important;
    transition-duration: 0.15s !important;
  }
  .finding-card { animation: none; }
  .finding-card:active, .chip:active, .tab:active,
  .primary-btn:active, .approve-btn:active,
  .action-btn:active, .export-btn:active, .demo-btn:active,
  .pager button:active, .logout-btn:active { transform: none; }
  /* The loader keeps a static bar so the state is still legible. */
  .loading-note::after { animation: none; background: var(--line); }
}

/* A user who has asked for more contrast gets defined edges, not tints. */
@media (prefers-contrast: more) {
  :root { --line: #b4b4bb; --line-soft: #c4c4cb; --ink-muted: #4b4b53; }
  .data-table th { background: #ececed; color: var(--ink-900); }
  .empty-note { border-style: solid; border-color: var(--ink-400); }
  :focus-visible { outline-width: 3px; }
}
