/* ==========================================================================
   BizScore MVP console.

   Same design tokens as the prototype's css/app.css, deliberately duplicated
   rather than shared across the directory boundary: mvp/ is excluded from the
   Vercel deploy, and a stylesheet reaching up into the deployed prototype would
   couple the two so that editing one could break the other. The tokens are
   stable; the coupling would not be worth the twenty lines it saves.

   This is a console, not a marketing page. Dense, quiet, and legible at a
   glance — a credit officer reads it all day.
   ========================================================================== */

:root {
  color-scheme: dark;

  --plane:          #0d0d0d;
  --surface-1:      #1a1a19;
  --surface-2:      #212120;
  --surface-3:      #2a2a28;
  --text-primary:   #ffffff;
  --text-secondary: #c3c2b7;
  --text-muted:     #898781;
  --hairline:       rgba(255,255,255,0.10);
  --hairline-2:     rgba(255,255,255,0.06);

  /* The prototype's categorical series, validated against #1a1a19. The console
     previously carried only 1, 3 and 7 — the three it happened to name — while
     charts.js and the score gauge referenced others. An undefined custom
     property makes an SVG `fill` invalid, which falls back to BLACK, and an
     invalid `stroke` falls back to NONE. On this ground that is an invisible
     chart, not a broken-looking one, which is why it survived: every headless
     suite passes and nothing renders wrong, it just renders nothing. */
  --series-1: #3987e5;  /* blue    */
  --series-2: #d95926;  /* orange  */
  --series-3: #199e70;  /* aqua    */
  --series-4: #c98500;  /* yellow  */
  --series-5: #d55181;  /* magenta */
  --series-6: #008300;  /* green   */
  --series-7: #9085e9;  /* violet  */
  --series-8: #e66767;  /* red     */

  --grid: #2c2c2a;
  --axis: #383835;

  --good:     #0ca30c;
  --warning:  #fab219;
  --serious:  #ec835a;
  --critical: #d03b3b;

  /* Aliases. charts.js was written against these shorter names; they are
     defined rather than renamed so the chart code keeps reading the way its
     author meant it to. */
  --accent: var(--series-1);
  --warn:   var(--warning);
  --fail:   var(--critical);
  --muted:  var(--text-muted);
  --rule:   var(--grid);

  --radius: 10px;
  --radius-sm: 7px;
  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 28px rgba(0,0,0,.28);
  --font: system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

/* `hidden` must win, and without this it frequently does not.

   The UA stylesheet says [hidden] { display: none }, and ANY author rule that
   sets `display` beats it — so an element styled `display: flex` stays on
   screen when its `hidden` property is set, silently. The console had already
   been bitten twice and patched it twice, per element: `.app[hidden]` and
   `#public[hidden]` were both this bug.

   The third time was the approval form. Setting `hidden` on the actions row was
   meant to take the buttons away and put the form in their place; `.actions`
   carries `display: flex`, so the buttons stayed and the form rendered
   underneath them — two sets of controls, one of them stale, on a card that
   commits credit.

   One rule, at the top, applying to everything. The two per-element patches are
   gone because this replaces them. */
[hidden] { display: none !important; }

html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-primary);
  background: var(--plane);
  -webkit-font-smoothing: antialiased;
}
button, input, select, textarea { font: inherit; color: inherit; }
a { color: var(--series-1); }

/* ---------------------------------------------------------------- shell */

.app { display: grid; grid-template-columns: 244px minmax(0, 1fr); min-height: 100vh; }

/* Sticky and exactly one viewport tall, so a long screen scrolls under a rail
   that stays put. Without the explicit height the rail is stretched to the
   grid row — which is the height of the whole page — and the officer scrolls
   past the navigation on any screen longer than the window. */
.rail {
  background: #111110;
  border-right: 1px solid var(--hairline);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh;
}
.brand { padding: 20px 18px 16px; border-bottom: 1px solid var(--hairline); }
.brand-mark { display: flex; align-items: center; gap: 10px; }
.brand-logo {
  width: 32px; height: 32px; border-radius: 8px; flex: 0 0 32px;
  background: linear-gradient(135deg, var(--series-1), #1c5cab);
  display: grid; place-items: center; font-weight: 700; font-size: 15px; letter-spacing: -.5px;
}
.brand-name { font-weight: 650; letter-spacing: -.2px; font-size: 15px; }
.brand-sub { font-size: 11px; color: var(--text-muted); margin-top: 1px; }
.brand-tag { margin-top: 12px; font-size: 11px; color: var(--text-secondary); }

/* flex: 1 so the nav takes the slack and `whoami` stays pinned to the bottom of
   the viewport; overflow-y so a longer menu scrolls inside the rail rather than
   pushing the sign-out block off the screen. */
.nav { padding: 12px 10px; display: flex; flex-direction: column; gap: 2px;
       flex: 1; overflow-y: auto; scrollbar-width: thin; }
.nav-label {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .09em;
  color: var(--text-muted); padding: 12px 8px 6px;
}
.nav button {
  position: relative;
  display: flex; align-items: center; gap: 10px; width: 100%;
  text-align: left; background: transparent; border: 0; cursor: pointer;
  padding: 8px 10px; border-radius: var(--radius-sm);
  color: var(--text-secondary); font-size: 13.5px;
}
.nav button .ico { width: 16px; text-align: center; opacity: .85; font-size: 13px; flex: none; }
.nav-badge {
  margin-left: auto; font-size: 11px; background: var(--surface-3);
  color: var(--text-secondary); border-radius: 20px; padding: 1px 7px;
  font-variant-numeric: tabular-nums;
}
.nav-badge:empty { display: none; }
.nav button:hover { background: var(--surface-2); color: var(--text-primary); }
.nav button[aria-current="true"] {
  background: var(--surface-3); color: var(--text-primary); font-weight: 550;
}
.nav button[aria-current="true"] .nav-badge { background: var(--series-1); color: #fff; }
/* The active bar itself. A tint alone is easy to miss against a dark rail at
   presentation distance, so the current screen also carries an accent edge. */
.nav button[aria-current="true"]::before {
  content: ''; position: absolute; left: 0; top: 6px; bottom: 6px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--series-1);
}

.whoami {
  margin-top: auto; padding: 12px 14px; border-top: 1px solid var(--hairline);
  font-size: 11px; color: var(--text-muted);
}
.whoami .residency { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; color: var(--text-secondary); }
.whoami .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--good); flex: 0 0 7px; }
.whoami .name { color: var(--text-primary); font-size: 12px; }
.whoami .role { color: var(--text-muted); font-family: var(--mono); font-size: 11px; }
.whoami button {
  margin-top: 8px; background: none; border: 1px solid var(--hairline);
  border-radius: var(--radius-sm); padding: 4px 10px; cursor: pointer;
  color: var(--text-secondary); font-size: 12px;
}

/* The main column is a flex column so the topbar sits flush against the top of
   it and only the content below scrolls. */
.main { min-width: 0; display: flex; flex-direction: column; }

.topbar {
  display: flex; align-items: center; gap: 12px;
  padding: 0 26px; height: 56px; flex: none;
  border-bottom: 1px solid var(--hairline);
  background: var(--plane); position: sticky; top: 0; z-index: 10;
}
.topbar h1 { font-size: 15px; font-weight: 600; margin: 0; letter-spacing: -.2px; }
.topbar .crumb { color: var(--text-muted); font-size: 13px; }
.topbar h1, .topbar .crumb { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 10px; font-size: 12px; }
.topbar-right .tenant { display: flex; align-items: center; gap: 6px; color: var(--text-muted); }
.topbar-right .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--good); flex: 0 0 7px; }

.content { padding: 24px 26px 64px; max-width: 1420px; width: 100%; margin-inline: auto; }

.head { margin-bottom: 20px; }
.head h1 { margin: 0 0 4px; font-size: 21px; font-weight: 620; letter-spacing: -.4px; }
.head p { margin: 0; color: var(--text-secondary); font-size: 13.5px; max-width: 74ch; }

/* ---------------------------------------------------------------- shell, narrow
   Below 1000px the rail stops being a column and becomes a sticky top bar with
   the navigation scrolling horizontally. No drawer, no hamburger, no open/close
   state: five destinations fit in a scrolling row, and a disclosure widget is a
   thing to get wrong for no benefit at this size.

   The rail keeps its DOM order, so tab order still runs brand -> navigation ->
   account, and nothing depends on JavaScript to become reachable. */

@media (max-width: 1000px) {
  /* Flex rather than a single-column grid, because `position: sticky` on a grid
     item is measured against its own grid area — which here is one row the
     height of the bar itself, giving it nothing to stick within. A flex item is
     measured against the container, which spans the page. */
  .app { display: flex; flex-direction: column; }
  .main { flex: 1; }

  .rail {
    position: sticky; top: 0; z-index: 20;
    /* Undo the full-height column: here the rail is a bar as tall as its own
       contents, and 100vh would hand it the whole screen. */
    height: auto;
    flex-direction: row; align-items: center; gap: 12px;
    padding: 9px 14px;
    border-right: 0; border-bottom: 1px solid var(--hairline-2);
  }

  .brand {
    flex: none; padding: 0 12px 0 0;
    border-bottom: 0; border-right: 1px solid var(--hairline-2);
  }
  .brand-logo { width: 26px; height: 26px; flex-basis: 26px; font-size: 12px; border-radius: 7px; }
  .brand-name { font-size: 14px; }
  .brand-sub, .brand-tag, .nav-label { display: none; }
  /* The count badges go with the labels: a row of pills in a scrolling strip
     costs more width than the number is worth at this size. */
  .nav-badge { display: none; }

  .nav {
    flex: 1; flex-direction: row; padding: 0; gap: 2px;
    overflow-x: auto; overflow-y: visible; scrollbar-width: thin;
    /* Fades the cut edge so a scrolled-off destination looks scrollable rather
       than absent. */
    mask-image: linear-gradient(to right, transparent 0, #000 12px,
                                #000 calc(100% - 12px), transparent 100%);
  }
  .nav button { white-space: nowrap; flex: none; }
  /* Horizontal bar: the accent moves from the left edge to the underside, which
     is where a row of tabs reads it. */
  .nav button[aria-current="true"]::before {
    left: 6px; right: 6px; top: auto; bottom: 0; width: auto; height: 2px;
    border-radius: 2px 2px 0 0;
  }

  .whoami {
    flex: none; margin-top: 0; display: flex; align-items: center; gap: 10px;
    padding: 0 0 0 12px; border-top: 0; border-left: 1px solid var(--hairline-2);
  }
  .whoami .cannot, .whoami .residency { display: none; }
  .whoami button { margin-top: 0; }

  /* The topbar has the rail directly above it now, so it loses its own border
     and its sticky offset — two stacked sticky bars would eat a third of a
     phone screen. */
  .topbar { position: static; height: auto; padding: 12px 16px 0; border-bottom: 0; }
  .content { padding: 16px 16px 60px; }
}

/* Phone. The account block keeps only what identifies the session and the way
   out of it; the display name is the first thing that can go, because the role
   is what governs what the buttons will let you do. */
@media (max-width: 620px) {
  .rail { gap: 8px; padding: 8px 12px; }
  .brand { padding-right: 8px; }
  .brand-name { font-size: 13px; }
  .whoami { padding-left: 8px; }
  .whoami .name { display: none; }
  .nav button { padding: 7px 9px; font-size: 12.5px; }
  .topbar { padding: 10px 12px 0; }
  .topbar-right .tenant { display: none; }
  .content { padding: 14px 12px 48px; }
  .head h1 { font-size: 17px; }
}

/* ---------------------------------------------------------------- cards */

.card {
  background: var(--surface-1); border: 1px solid var(--hairline);
  border-radius: var(--radius); padding: 18px 20px; margin-bottom: 14px;
}
/* The mock's card head: a sentence-case title with an optional muted hint
   beside it, not an uppercase label. `h2` is the console's existing element and
   `.card-head h3` is the mock's; both render identically so screens can be
   migrated one at a time without the page looking half-dressed. */
.card > h2, .card-head h3 {
  margin: 0 0 14px; font-size: 14px; font-weight: 600;
  letter-spacing: -.1px; color: var(--text-primary); text-transform: none;
}
.card-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 14px; }
.card-head h3 { margin: 0; }
.card-head .hint { font-size: 12px; color: var(--text-muted); }
.card-head .spacer { flex: 1; }

.grid { display: grid; gap: 14px; }
.grid.two { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.grid.g-2-1 { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.grid.g-1-2 { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
@media (max-width: 1180px) {
  .grid.g-2-1, .grid.g-1-2 { grid-template-columns: minmax(0, 1fr); }
}

.stats { display: flex; flex-wrap: wrap; gap: 26px; }
.stat .v { font-size: 22px; font-variant-numeric: tabular-nums; }
.stat .k { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: .05em; }
.stat .n { font-size: 11px; color: var(--text-muted); }

/* Definition list, the mock's `kv`. Used wherever a screen states a set of
   recorded facts rather than tabulating rows. */
.kv { display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: 7px 16px; font-size: 13px; margin: 0; }
.kv dt { color: var(--text-muted); }
.kv dd { margin: 0; }
.kv dd b { font-weight: 600; }
@media (max-width: 620px) { .kv { grid-template-columns: minmax(0, 1fr); gap: 2px 0; } .kv dd { margin-bottom: 8px; } }

/* ---------------------------------------------------------------- tables */

table { width: 100%; border-collapse: collapse; font-size: 13px; }
th {
  text-align: left; font-weight: 550; font-size: 11.5px; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: .05em;
  padding: 9px 12px; border-bottom: 1px solid var(--hairline);
}
td { padding: 11px 12px; border-bottom: 1px solid var(--hairline-2); vertical-align: middle; }
td.strong { font-weight: 550; }
tr:last-child td { border-bottom: 0; }
tbody tr.clickable { cursor: pointer; }
tbody tr.clickable:hover { background: var(--surface-2); }

/* A row from a stored scan whose consent has lapsed since the run. Dimmed and
   captioned, never removed: it is the record of something that did happen, and
   deleting it to tidy the screen would be editing history. The caption under
   the name is what stops the dimming from reading as a rendering fault. */
tbody tr.lapsed { opacity: .6; }
.warn-text { color: var(--warning); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--mono); }
.scroll { overflow-x: auto; }

/* ---------------------------------------------------------------- bits */

/* The mock's pill: a filled tint rather than an outline, because at a glance
   across a table of forty rows the fill is what carries.

   Set in caps, and set here rather than at each of the forty call sites. A
   status badge is a label, not a word in a sentence: the outcome pills arrived
   from the engine already shouting (APPROVE, REFER, DECLINE) while the ones
   written by hand in the templates did not (paid, granted, pass), so the same
   table carried two different conventions and read as though one of them was a
   mistake. Caps at the stylesheet means no call site can get it wrong, and the
   size and tracking are dropped to match — 11px letter-spaced reads as a
   label, 11.5px unspaced in caps reads as shouting. */
.pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: 999px;
  font-size: 11px; font-weight: 600; border: 1px solid var(--hairline);
  text-transform: uppercase; letter-spacing: .055em;
  background: var(--surface-3); color: var(--text-secondary);
}
.pill.good, .pill.approve {
  background: rgba(12,163,12,.14); color: #4ade4a; border-color: rgba(12,163,12,.4);
}
.pill.warn, .pill.refer {
  background: rgba(250,178,25,.14); color: #fbc85a; border-color: rgba(250,178,25,.38);
}
.pill.bad, .pill.decline {
  background: rgba(208,59,59,.15); color: #f08585; border-color: rgba(208,59,59,.42);
}
.pill.info {
  background: rgba(57,135,229,.14); color: #7fb3f0; border-color: rgba(57,135,229,.4);
}
/* Muted is still the quiet one, but it was quiet to the point of vanishing:
   --text-muted on --surface-3 sits at roughly 3:1 and reads as disabled text
   rather than as a badge. Lifted to --text-secondary on a slightly warmer
   ground with a visible edge, so every pill on the screen reads as the same
   kind of object and the difference between them is meaning, not presence. */
.pill.muted {
  background: color-mix(in srgb, var(--text-secondary) 10%, var(--surface-3));
  color: var(--text-secondary);
  border-color: color-mix(in srgb, var(--text-secondary) 22%, transparent);
}
/* Used for the "✦ AI" mark on the opportunity scan. It had no rule at all, so
   it fell through to the default grey and the one badge on the page that was
   meant to stand out was the one that did not. */
.pill.acc {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent); border-color: color-mix(in srgb, var(--accent) 30%, transparent);
}

.band { font-family: var(--mono); font-weight: 600; }
.band.A, .band.B { color: var(--good); }
.band.C { color: var(--warning); }
.band.D { color: var(--serious); }
.band.E { color: var(--critical); }

/* The mock's band chip — a square, not a letter in running text. */
.band-chip {
  display: inline-grid; place-items: center; width: 26px; height: 26px;
  border-radius: 7px; font-weight: 700; font-size: 13px; flex: none;
  background: var(--surface-3); color: var(--text-primary);
}
.band-chip.A, .band-chip.B { background: rgba(12,163,12,.18); color: #4ade4a; }
.band-chip.C { background: rgba(250,178,25,.18); color: #fbc85a; }
.band-chip.D { background: rgba(236,131,90,.2); color: #f0a582; }
.band-chip.E { background: rgba(208,59,59,.2); color: #f08585; }

.mono { font-family: var(--mono); font-size: 12px; }
.muted { color: var(--text-muted); }
.small { font-size: 12px; }
.wrap { max-width: 78ch; }

/* The mock's button family. `.action` is the console's existing class and
   `.btn` is the mock's; both are styled here so screens can move over one at a
   time. Default is the quiet surface button — a screen with six equally loud
   blue buttons tells the officer nothing about which one is the point. */
button.action, .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px 15px; border-radius: var(--radius-sm);
  border: 1px solid var(--hairline); background: var(--surface-2);
  color: var(--text-primary); cursor: pointer; font-size: 13px; font-weight: 500;
  transition: background .12s, border-color .12s;
}
button.action:hover, .btn:hover { background: var(--surface-3); }
button.action.primary, .btn-primary {
  background: var(--series-1); border-color: transparent; color: #fff; font-weight: 560;
}
button.action.primary:hover, .btn-primary:hover { background: #2a78d6; }
button.action.ghost, .btn-ghost { background: transparent; color: var(--text-secondary); }

/* The callback the bank's loan system would post, standing in for a system this
   build is not connected to.

   Violet, not the credit blue: approve and release are this product's own
   decisions and they own the primary colour. This one is somebody else's event
   being reported, and it must not read as one more step the officer is
   authorising. It matches the left rule on `.note`, which is the same violet,
   so the block and its button read as one thing.

   Filled rather than ghosted because a ghost button on this ground is quiet
   enough to read as disabled — which is exactly the wrong thing to say about
   the control that carries the walkthrough to its end. Dark ink on it: white on
   this violet is about 3:1 and fails at 13px, where #16141f is about 6:1. */
button.action.external {
  background: var(--series-7); border-color: transparent; color: #16141f; font-weight: 560;
}
button.action.external:hover { background: #a49bef; }
.btn-lg { padding: 11px 20px; font-size: 14px; }
.btn-sm { padding: 5px 11px; font-size: 12.5px; }
.btn-approve { background: var(--good); border-color: transparent; color: #fff; }
.btn-decline { background: var(--critical); border-color: transparent; color: #fff; }
button.action:disabled, .btn:disabled { opacity: .45; cursor: not-allowed; }
.actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

/* ---------------------------------------------------- customer detail page */

.appbar {
  display: flex; align-items: center; gap: 14px; padding: 16px 18px; margin-bottom: 16px;
  background: var(--surface-1); border: 1px solid var(--hairline); border-radius: var(--radius);
}
.appbar h2 { margin: 0; font-size: 18px; letter-spacing: -.3px; }
.appbar .meta { font-size: 12.5px; color: var(--text-muted); margin-top: 2px; }
.appbar .spacer { flex: 1; }
.appbar .right { text-align: right; }
.appbar .right .sub { font-size: 11px; color: var(--text-muted); margin-bottom: 3px; }
@media (max-width: 760px) {
  .appbar { flex-wrap: wrap; }
  .appbar .spacer { flex-basis: 100%; height: 0; }
}

.tabs {
  display: flex; gap: 2px; border-bottom: 1px solid var(--hairline);
  margin-bottom: 18px; overflow-x: auto; scrollbar-width: thin;
}
.tab {
  padding: 9px 14px; border: 0; background: transparent; color: var(--text-secondary);
  cursor: pointer; font-size: 13.5px; border-bottom: 2px solid transparent; white-space: nowrap;
}
.tab:hover { color: var(--text-primary); }
.tab.on { color: var(--text-primary); border-bottom-color: var(--series-1); font-weight: 550; }
.tab .cnt { font-size: 11px; color: var(--text-muted); margin-left: 5px; }

.note {
  border-left: 2px solid var(--series-7); padding: 8px 0 8px 12px;
  color: var(--text-secondary); font-size: 12.5px; max-width: 82ch;
}
.note.warn { border-color: var(--warning); }
.note.bad { border-color: var(--critical); }

.banner {
  background: color-mix(in srgb, var(--warning) 12%, var(--surface-1));
  border: 1px solid color-mix(in srgb, var(--warning) 35%, transparent);
  border-radius: var(--radius-sm); padding: 8px 12px; font-size: 12.5px;
  margin-bottom: 14px;
}
.banner.bad {
  background: color-mix(in srgb, var(--critical) 12%, var(--surface-1));
  border-color: color-mix(in srgb, var(--critical) 40%, transparent);
}

/* ================================================================ landing
   The public page, matching the prototype at bizscore-ai.vercel.app. Same
   structure, same rhythm, same containers — a visitor who has seen one should
   not be able to tell which they are looking at.

   The one deliberate difference is in the copy, not the design: see the note in
   landing.js about which figures this build is willing to assert. */


.lp-nav {
  position: sticky; top: 0; z-index: 50;
  background: rgba(13,13,13,.88); backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--hairline);
}
.lp-nav-in, .lp-hero-in, .lp-sec-in, .lp-band-in, .lp-final-in, .lp-foot-in {
  max-width: 1140px; margin-inline: auto; padding-inline: 26px;
}
.lp-nav-in { display: flex; align-items: center; gap: 26px; height: 62px; }
.lp-brand { display: flex; align-items: center; gap: 10px; }
.lp-links { display: flex; gap: 22px; margin-left: 14px; }
.lp-links a { color: var(--text-secondary); text-decoration: none; font-size: 13.5px; }
.lp-links a:hover { color: var(--text-primary); }
.lp-nav-cta { margin-left: auto; display: flex; gap: 8px; }

.lp-hero {
  padding: 84px 0 68px;
  background:
    radial-gradient(900px 420px at 12% -10%, rgba(57,135,229,.16), transparent 62%),
    radial-gradient(760px 380px at 88% 0%, rgba(144,133,233,.12), transparent 60%);
}
.lp-eyebrow {
  display: inline-flex; align-items: center; gap: 7px; font-size: 12px; color: var(--series-7);
  background: rgba(144,133,233,.12); border: 1px solid rgba(144,133,233,.3);
  padding: 4px 12px; border-radius: 20px;
}
.lp-hero h1 {
  font-size: clamp(30px, 4.4vw, 50px); line-height: 1.1; letter-spacing: -1.6px;
  font-weight: 660; margin: 20px 0 0; max-width: 20ch;
}
.lp-hl { color: var(--series-1); }
.lp-lede { margin: 20px 0 0; font-size: 16px; line-height: 1.65; color: var(--text-secondary); max-width: 66ch; }
.lp-cta { display: flex; gap: 12px; margin-top: 28px; flex-wrap: wrap; }
.lp-trust {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 34px; font-size: 12px; color: var(--text-muted);
}
.lp-trust i { width: 3px; height: 3px; border-radius: 50%; background: var(--axis); display: inline-block; }

.lp-band { border-block: 1px solid var(--hairline); background: var(--surface-1); }
.lp-band-in { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 20px; padding-block: 26px; }
.lp-band-in > div { display: flex; flex-direction: column; gap: 4px; }
.lp-band-in b { font-size: 26px; font-weight: 660; letter-spacing: -.9px; }
.lp-band-in span { font-size: 12.5px; color: var(--text-secondary); line-height: 1.45; }

.lp-sec { padding: 78px 0; }
.lp-alt { background: var(--surface-1); border-block: 1px solid var(--hairline); }
.lp-sec-head { max-width: 76ch; margin-bottom: 36px; }
.lp-kicker { font-size: 11.5px; text-transform: uppercase; letter-spacing: .1em; color: var(--series-1); font-weight: 600; }
.lp-sec-head h2 { font-size: clamp(23px, 2.7vw, 32px); letter-spacing: -1px; margin: 10px 0 0; font-weight: 640; }
.lp-sec-head p { color: var(--text-secondary); font-size: 14.5px; line-height: 1.65; margin: 12px 0 0; }

.lp-grid4 { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 16px; }
.lp-grid3 { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 16px; }
.lp-card {
  background: var(--surface-2); border: 1px solid var(--hairline);
  border-radius: var(--radius); padding: 20px;
}
.lp-alt .lp-card { background: var(--plane); }
.lp-ico {
  width: 34px; height: 34px; border-radius: 9px; display: grid; place-items: center; font-size: 15px;
  background: rgba(57,135,229,.14); color: #7fb3f0; border: 1px solid rgba(57,135,229,.3);
}
.lp-card h4 { margin: 14px 0 6px; font-size: 14.5px; font-weight: 620; letter-spacing: -.2px; }
.lp-card p { margin: 0; font-size: 13px; line-height: 1.62; color: var(--text-secondary); }

.lp-steps { display: grid; gap: 14px; }
.lp-step {
  display: flex; gap: 16px; background: var(--plane); border: 1px solid var(--hairline);
  border-radius: var(--radius); padding: 18px 20px;
}
.lp-step-n {
  flex: 0 0 30px; width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  background: var(--series-1); color: #fff; font-weight: 680; font-size: 13px;
}
.lp-step h4 { margin: 3px 0 6px; font-size: 15px; font-weight: 620; letter-spacing: -.2px; }
.lp-step p { margin: 0; font-size: 13.5px; line-height: 1.62; color: var(--text-secondary); }
.lp-step-detail {
  margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--hairline-2);
  font-size: 12.5px; color: var(--text-muted); line-height: 1.55;
}

.lp-value { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 16px; margin-bottom: 30px; }
.lp-val { background: var(--plane); border: 1px solid var(--hairline); border-radius: var(--radius); padding: 20px; }
.lp-val b { display: block; font-size: 32px; font-weight: 680; letter-spacing: -1.4px; color: var(--series-1); }
.lp-val span { display: block; font-size: 13px; font-weight: 560; margin-top: 4px; }
.lp-val i { display: block; font-style: normal; font-size: 12px; color: var(--text-muted); margin-top: 7px; line-height: 1.5; }

.lp-two { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 28px; }
.lp-two h3 { font-size: 15.5px; margin: 0 0 12px; font-weight: 620; }
.lp-two ul { margin: 0; padding-left: 18px; }
.lp-two li { font-size: 13.5px; line-height: 1.65; color: var(--text-secondary); margin-bottom: 11px; }
.lp-two li b { color: var(--text-primary); font-weight: 600; }

.lp-final {
  padding: 76px 0; text-align: center;
  background: radial-gradient(700px 300px at 50% 0%, rgba(57,135,229,.14), transparent 65%);
}
.lp-final h2 { font-size: clamp(22px, 3vw, 32px); letter-spacing: -1px; margin: 0; font-weight: 640; }
.lp-final p { color: var(--text-secondary); font-size: 14.5px; max-width: 62ch; margin: 14px auto 26px; line-height: 1.6; }

.lp-foot { border-top: 1px solid var(--hairline); background: var(--surface-1); }
.lp-foot-in { display: grid; grid-template-columns: minmax(0,1.4fr) minmax(0,1fr); gap: 30px; padding-block: 34px; }
/* The console's `.note` carries an accent rail, which belongs beside a finding
   in the product and looks like a mistake in a footer. Reset here rather than
   inventing a second class for the same words. */
.lp-foot .note {
  border-left: 0; padding: 0; max-width: 60ch;
  font-size: 12.5px; color: var(--text-muted); line-height: 1.62;
}
.lp-foot b { color: var(--text-secondary); }

@media (max-width: 1000px) {
  .lp-grid4, .lp-band-in, .lp-value { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .lp-grid3, .lp-two, .lp-foot-in { grid-template-columns: minmax(0,1fr); }
  .lp-links { display: none; }
}
@media (max-width: 620px) {
  .lp-grid4, .lp-band-in, .lp-value { grid-template-columns: minmax(0,1fr); }
  .lp-sec { padding: 52px 0; }
  .lp-hero { padding: 52px 0 44px; }
}

/* ---------------------------------------------------------------- sign in */

/* `.wide` was referenced by both buttons on this card and defined by neither,
   so each one sized to its own text — a small blue "Sign in" beside a wider
   "Back to the overview". Two buttons doing the same job at two different
   widths is the sort of thing that reads as unfinished long before anyone can
   say why. */
.action.wide, .btn.wide { width: 100%; }

.signin-page { display: grid; place-items: center; min-height: 100vh; padding: 40px 20px; }
.signin-card {
  background: var(--surface-1); border: 1px solid var(--hairline);
  border-radius: var(--radius); padding: 30px 30px 26px; width: min(430px, 100%);
  box-shadow: var(--shadow);
}
.signin-head { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.signin-head b { display: block; font-size: 15px; font-weight: 650; letter-spacing: -.2px; }
.signin-head i { display: block; font-style: normal; font-size: 11.5px; color: var(--text-muted); margin-top: 1px; }
.signin-lede { margin: 0 0 20px; font-size: 13px; color: var(--text-secondary); line-height: 1.6; }

.personas { display: flex; flex-direction: column; gap: 8px; margin-bottom: 22px; }
.persona {
  text-align: left; background: var(--surface-2); border: 1px solid var(--hairline);
  border-radius: var(--radius-sm); padding: 12px 14px; cursor: pointer;
  display: grid; gap: 3px; transition: background .12s, border-color .12s;
}
.persona:hover { background: var(--surface-3); }
.persona.on {
  border-color: var(--series-1);
  background: color-mix(in srgb, var(--series-1) 10%, var(--surface-2));
}
.p-role { font-size: 10px; letter-spacing: .09em; text-transform: uppercase; color: var(--series-1); font-weight: 600; }
.p-name { font-size: 14px; font-weight: 550; }
.p-can { font-size: 12.5px; color: var(--text-secondary); }
.p-cannot { font-size: 11.5px; color: var(--warning); }

/* The two fields sit closer to each other than to the button, so the form reads
   as one block with an action under it rather than three loose rows. */
.signin-card form { display: flex; flex-direction: column; gap: 12px; }
.field { display: flex; flex-direction: column; gap: 5px; }
.field label {
  font-size: 10.5px; color: var(--text-muted); text-transform: uppercase;
  letter-spacing: .07em; font-weight: 500;
}
.field input {
  width: 100%; padding: 9px 11px; background: var(--surface-2);
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  font-size: 13.5px;
}
.field input:focus-visible {
  outline: 2px solid var(--series-1); outline-offset: 1px; border-color: transparent;
}
.signin-card form .action { margin-top: 4px; }
.signin-card .error { color: var(--critical); font-size: 12.5px; min-height: 18px; }

/* A rule before the way out, so leaving is plainly not part of signing in. */
.signin-card .action.ghost.wide {
  margin-top: 18px; padding-top: 14px;
  border-top: 1px solid var(--hairline-2); border-radius: 0;
  color: var(--text-muted);
}
.signin-card .action.ghost.wide:hover { background: none; color: var(--text-primary); }

/* ---------------------------------------------------------------- tiles */

.tiles {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(186px, 1fr));
  gap: 1px; background: var(--hairline-2); border: 1px solid var(--hairline-2);
  border-radius: var(--radius); overflow: hidden; margin-bottom: 14px;
}
.tile { background: var(--surface-1); padding: 15px 17px; }
.tile .k { font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted); }
.tile .v { font-size: 25px; line-height: 1.15; margin: 5px 0 3px; font-variant-numeric: tabular-nums; }
.tile .d { font-size: 11.5px; color: var(--text-muted); line-height: 1.5; }

.card.hero { display: flex; flex-wrap: wrap; gap: 24px; align-items: center; justify-content: space-between; }
.card.hero .hero-copy { flex: 1; min-width: 320px; }
.card.hero .hero-copy h2 { margin: 0 0 8px; text-transform: none; letter-spacing: 0; font-size: 15px; color: var(--text-primary); }
.card.hero .hero-copy p { margin: 0; font-size: 13.5px; color: var(--text-secondary); line-height: 1.65; max-width: 74ch; }
.card.hero .hero-copy b { color: var(--text-primary); }
.card.hero .hero-act { text-align: right; }

/* ---------------------------------------------------------------- ladder */

.rung { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--hairline-2); }
.rung:last-child { border-bottom: 0; }
.rung .label { font-size: 13px; }
.rung .why { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; max-width: 70ch; }
.rung .value { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.rung.binding .label { color: var(--warning); }
.rung.binding .value { color: var(--warning); }

.bar { height: 4px; background: var(--surface-3); border-radius: 2px; overflow: hidden; margin-top: 6px; }
.bar > i { display: block; height: 100%; background: var(--series-1); }
.rung.binding .bar > i { background: var(--warning); }

.reason { display: grid; grid-template-columns: 54px minmax(0,1fr); gap: 10px; padding: 6px 0; }
.reason .pts { font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: right; }
.reason.up .pts { color: var(--good); }
.reason.down .pts { color: var(--critical); }
.reason .txt { font-size: 12.5px; color: var(--text-secondary); }

.empty { color: var(--text-muted); font-size: 13px; padding: 10px 0; }
.spinner { color: var(--text-muted); font-size: 13px; padding: 10px 0; }

/* ---------------------------------------------------------------- stages
   The acquisition sequence. Nine sources, each able to fail on its own — the
   product's whole argument is about where the data comes from, so it is shown
   arriving rather than hidden behind a spinner. */

.stages { display: flex; flex-direction: column; gap: 2px; }
.stage {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border-radius: var(--radius-sm);
  font-size: 13px; color: var(--text-muted); border: 1px solid transparent;
}
.stage.active { background: var(--surface-2); color: var(--text-primary); border-color: var(--hairline); }
.stage.done { color: var(--text-secondary); }
.stage .st-ico {
  width: 18px; height: 18px; flex: 0 0 18px; display: grid; place-items: center;
  border-radius: 50%; border: 1.5px solid var(--axis, #383835); font-size: 10px;
}
.stage.done .st-ico { background: var(--good); border-color: var(--good); color: #fff; }
.stage.active .st-ico {
  border-color: var(--series-1); border-right-color: transparent;
  animation: stage-spin .7s linear infinite;
}
@keyframes stage-spin { to { transform: rotate(360deg); } }
.stage .st-name { flex: 1; }
.stage .st-detail { color: var(--text-muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.stage .st-ms {
  color: var(--text-muted); font-size: 11.5px; width: 56px; text-align: right;
  font-variant-numeric: tabular-nums;
}
@media (prefers-reduced-motion: reduce) { .stage.active .st-ico { animation: none; } }

/* ---------------------------------------------------------------- tabs */

.tabs {
  display: flex; flex-wrap: wrap; gap: 2px; margin-bottom: 14px;
  border-bottom: 1px solid var(--hairline); padding-bottom: 0;
}
.tab {
  background: none; border: 0; border-bottom: 2px solid transparent;
  padding: 8px 13px; cursor: pointer; color: var(--text-secondary); font-size: 13px;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.tab:hover { color: var(--text-primary); background: var(--surface-2); }
.tab.on { color: var(--text-primary); border-bottom-color: var(--series-1); }

h3.grp {
  margin: 18px 0 6px; font-size: 11px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-muted);
}
h3.grp:first-child { margin-top: 0; }

/* ---------------------------------------------------------------- charts */

.legend { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 8px; font-size: 11.5px; color: var(--text-muted); }
.legend i { display: inline-block; width: 10px; height: 3px; border-radius: 2px; margin-right: 6px; vertical-align: middle; }

.bars { display: flex; flex-direction: column; gap: 6px; }
.bar-row { display: grid; grid-template-columns: minmax(0, 210px) minmax(0, 1fr) 56px; gap: 12px; align-items: center; }
.bar-name { font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bar-track { height: 8px; background: var(--surface-3); border-radius: 4px; overflow: hidden; }
.bar-track > i { display: block; height: 100%; border-radius: 4px; }
.bar-val { font-family: var(--mono); font-size: 12px; text-align: right; font-variant-numeric: tabular-nums; }

td.num.bad { color: var(--critical); }

/* ---------------------------------------------------------------- reasons */

.reasons { display: flex; flex-direction: column; gap: 2px; }
.reason-row {
  display: grid; grid-template-columns: 46px 110px minmax(0, 1fr);
  gap: 12px; align-items: center; padding: 7px 0;
  border-bottom: 1px solid var(--hairline-2);
}
.reason-row:last-child { border-bottom: 0; }
.reason-pts { font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: right; font-size: 13px; }
.reason-row.up .reason-pts { color: var(--good); }
.reason-row.down .reason-pts { color: var(--critical); }
.reason-bar { height: 6px; background: var(--surface-3); border-radius: 3px; overflow: hidden; }
.reason-bar > i { display: block; height: 100%; border-radius: 3px; }
.reason-row.up .reason-bar > i { background: var(--good); }
.reason-row.down .reason-bar > i { background: var(--critical); }
.reason-txt { font-size: 12.5px; }

.mini {
  border-left: 2px solid var(--hairline); padding: 6px 0 6px 10px;
  margin-bottom: 8px; font-size: 12.5px; color: var(--text-secondary);
}
.mini.good { border-color: var(--good); }
.mini.bad { border-color: var(--critical); }

/* ---------------------------------------------------------------- cgc */

.schemes { display: flex; flex-direction: column; gap: 14px; }
.scheme { border: 1px solid var(--hairline-2); border-radius: var(--radius-sm); overflow: hidden; }
.scheme.eligible { border-color: color-mix(in srgb, var(--good) 40%, transparent); }
.scheme > header {
  display: flex; flex-wrap: wrap; gap: 10px; justify-content: space-between;
  align-items: center; padding: 11px 14px; background: var(--surface-2);
  border-bottom: 1px solid var(--hairline-2);
}
.scheme .name { font-size: 13.5px; font-weight: 600; }
.rule {
  display: grid; grid-template-columns: 20px minmax(0, 1fr); gap: 10px;
  padding: 10px 14px; border-bottom: 1px solid var(--hairline-2);
}
.rule:last-child { border-bottom: 0; }
.rule-mark { font-family: var(--mono); font-size: 13px; text-align: center; }
.rule-mark.ok { color: var(--good); }
.rule-mark.no { color: var(--critical); }
.rule-t { font-size: 13px; }
.rule .ev {
  margin-top: 7px; display: flex; flex-direction: column; gap: 3px;
  border-left: 2px solid var(--hairline); padding-left: 10px;
}
.rule .ev > div { display: grid; grid-template-columns: minmax(0, 190px) minmax(0, 1fr); gap: 10px; font-size: 11.5px; }
.ev-k { color: var(--text-muted); }
.ev-v { font-family: var(--mono); }
.rule .src { margin-top: 6px; font-size: 11px; }

/* ---------------------------------------------------------------- content, narrow
   The fixed-ish columns inside cards. Each of these was sized for a desktop
   console and squeezes its text column to nothing before the viewport itself
   looks cramped, so they give way earlier than the shell does. */

@media (max-width: 860px) {
  /* Acquisition stages: the detail drops under the label rather than fighting
     it for width. */
  .stage { grid-template-columns: 18px minmax(0, 1fr); row-gap: 1px; padding: 7px 0; }
  .stage .det { grid-column: 2; }

  /* Reason codes: the proportional bar is the first thing to go — the points
     and the sentence are what the officer reads. */
  .reason-row { grid-template-columns: 46px minmax(0, 1fr); }
  .reason-bar { display: none; }

  .bar-row { grid-template-columns: minmax(0, 130px) minmax(0, 1fr) 50px; gap: 9px; }

  .rule .ev > div { grid-template-columns: minmax(0, 1fr); gap: 1px; }
  .ev-k { font-size: 10.5px; }

  .card.hero .hero-act { text-align: left; }
  .card.hero .hero-copy { min-width: 0; }

  .tile .v { font-size: 22px; }
}

@media (max-width: 620px) {
  .card { padding: 14px 15px; }
  .stats { gap: 18px; }
  .rung { grid-template-columns: minmax(0, 1fr); row-gap: 4px; }
  .rung .value { text-align: left; font-size: 14px; }
  .bar-row { grid-template-columns: minmax(0, 1fr) 50px; }
  .bar-track { display: none; }
}

/* ------------------------------------------------------------ decision hero
   The mock's Decision tab: the score on its band scale, the verdict beside it,
   and the six terms of the deal underneath. Six numbers an officer reads in one
   pass, rather than a wall of equal-weight stats. */

.decision-hero { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: 24px; align-items: center; }
@media (max-width: 900px) { .decision-hero { grid-template-columns: minmax(0, 1fr); } }

.gauge { width: 100%; max-width: 300px; height: auto; display: block; margin: 0 auto; }
.gauge-value {
  fill: var(--text-primary); font-size: 40px; font-weight: 650;
  letter-spacing: -1.5px; font-family: var(--font);
}
.gauge-sub { fill: var(--text-secondary); font-size: 12px; font-family: var(--font); }
.gauge-axis { fill: var(--text-muted); font-size: 10.5px; font-family: var(--font); }

.verdict { display: flex; align-items: center; gap: 10px; font-size: 26px; font-weight: 650; letter-spacing: -.5px; }
.verdict-APPROVE { color: var(--good); }
.verdict-REFER   { color: var(--warning); }
.verdict-DECLINE { color: var(--critical); }

.terms {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 14px 20px; margin-top: 18px;
}
.term .k { font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted); }
.term .v { font-size: 19px; font-weight: 600; margin: 3px 0 2px; font-variant-numeric: tabular-nums; }
.term .n { font-size: 11.5px; color: var(--text-muted); line-height: 1.45; }

/* An analysis tab before the engine has run. Visible, so the officer can see
   what the run will produce, but plainly not yet reachable. */
.tab:disabled { opacity: .38; cursor: not-allowed; }
.tab:disabled:hover { color: var(--text-secondary); }

/* ============================================================================
   The AI credit briefing, the reason-code pair, and the affordability ladder.

   All three live on the Decision tab. The briefing is the only thing in the
   console whose words are not computed, so it is the only thing that carries a
   provenance line saying so.
   ========================================================================== */

/* The card is about twice as wide as prose should ever be set, so a single
   column leaves half of it empty and reads as a rendering fault. Two columns:
   the briefing at a proper measure, and a rail carrying the one thing a reader
   of machine-written prose actually needs — who wrote which part of it. */
/* The card is narrower than its siblings, on purpose.

   This is the one card on the tab whose content is prose, and prose has a
   width whatever the screen has. The rest of the Decision tab is tables and
   rows, which use every pixel they are given; a briefing does not.

   The alternative was tried and is what the sections exposed. Left full width
   with the paragraphs capped at a reading measure, the card had a 400px hole
   down its middle — text stopping short, then nothing, then the provenance
   rail against the far edge. Worse once sections arrived: the emphasis block
   had no cap, so it ran the full column and stood 60% wider than every
   paragraph above it. Two different widths in one column reads as a rendering
   fault, which is exactly what it was.

   So the measure is set ONCE, by the grid column, and everything inside
   inherits it. Nothing in this card carries a max-width of its own. */
/* THREE columns: the narrative, the argument for the amount, and provenance.

   Two earlier attempts and what each got wrong, because the third only makes
   sense against them.

   Full width with the paragraphs capped at a reading measure: a 400px hole
   down the middle of the card, and — once the emphasis block arrived, which
   had no cap — an accent panel standing 60% wider than every paragraph above
   it. Two widths in one column.

   Then the card itself capped at 880px: correct in isolation, wrong on the
   page. It became the only narrow card on a Decision tab of full-width ones,
   which reads as a mistake rather than as a choice.

   So the width is USED rather than avoided. The emphasis section moves out of
   the prose column into one of its own, which fixes the measure (about 60
   characters a column, better than the 75 it had) and gives the section an
   officer defends to a credit committee a whole column instead of a slab
   inside somebody else's. Nothing carries a max-width; the columns are the
   measure. */
.briefing-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 36px;
  align-items: start;
}

/* The provenance is a footer, not a third column.

   As a column it cost the prose 240px plus a gap — a quarter of the card — and
   the argument for the amount is the longest thing on it. Squeezed into 440px
   that section ran to sixteen lines of dense numeric prose, which is not a
   measure problem so much as a room problem: figures like "RM 1,500,000" do
   not break, so a narrow column spends its width on them and wraps everything
   else around them.

   The rail is four label/value pairs and two notes. It reads perfectly well as
   a strip along the bottom, and the two prose columns gain about 27% each. */
.briefing-rail {
  display: flex;
  grid-column: 1 / -1;
  border-left: 0;
  border-top: 1px solid var(--hairline);
  padding-left: 0;
  padding-top: 16px;
  margin-top: 6px;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px 30px;
}
.briefing-rail .br-title { width: 100%; }
.br-list { flex-direction: row; flex-wrap: wrap; gap: 8px 30px; }
.br-note { max-width: 62ch; }

/* A decline has no amount to argue, so there is no emphasis section. Rather
   than let one prose column run to twice the measure, the narrative takes both
   — as two columns of text, not one wide one. `break-inside` keeps a section
   and its heading together. */
.briefing-grid:not(.with-key) .briefing-key { display: none; }
.briefing-grid:not(.with-key) .briefing-body {
  grid-column: span 2;
  columns: 2;
  column-gap: 32px;
}
.briefing-grid:not(.with-key) .bsec { break-inside: avoid; }

.briefing-body { display: flex; flex-direction: column; }
.briefing-body p {
  margin: 0;
  line-height: 1.7;
  color: var(--text-secondary);
  font-size: 14.5px;
}
.briefing-body p + p { margin-top: 12px; }

/* Subordinate to the heading, not competing with it. The previous version set
   this in monospace at full opacity, which read as a code token rather than a
   label. */
.ai-badge {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .01em;
  padding: 2px 9px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  white-space: nowrap;
  position: relative;
  top: -1px;
}
/* A composed briefing is not a failure, but it is a different thing, and the
   badge must not claim a model wrote it.

   It must also not be invisible. This was grey-on-grey, which made the one
   label on the card that says who wrote the words the hardest thing on the
   card to read — exactly backwards. It now carries the same weight as the
   model badge in a different colour: violet for the engine's own prose, accent
   blue for a model's, so the distinction is legible at a glance instead of
   being a difference between "visible" and "not". */
.ai-badge.composed {
  background: color-mix(in srgb, var(--series-7) 14%, transparent);
  color: #b3abf2;
  border-color: color-mix(in srgb, var(--series-7) 38%, transparent);
}

/* ---- the provenance rail ---- */

.br-title {
  margin: 0;
  font-size: 10.5px;
  font-family: var(--mono);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 500;
}
.br-list { margin: 0; display: flex; flex-direction: column; gap: 8px; }
.br-row { display: flex; flex-direction: column; gap: 1px; }
.br-row dt { font-size: 11px; color: var(--text-muted); }
.br-row dd {
  margin: 0;
  font-size: 12.5px;
  color: var(--text-secondary);
  line-height: 1.4;
}
.br-note {
  margin: 0;
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--text-secondary);
}
.br-note.strong { color: var(--text-secondary); }

/* Why the deterministic path was taken. This was --text-muted, which put the
   one line on the card explaining that a model was NOT involved — and, when
   the key is rejected rather than absent, that something is misconfigured — at
   the lowest contrast on the screen. It is the opposite of a footnote. */
.br-note.why {
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 10%, transparent);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
}

/* Four lines of grey while the server writes. Not a spinner: the card has a
   known shape, and showing it stops the tab reflowing when the prose lands. */
.skeleton {
  height: 12px;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--surface-3) 25%, var(--surface-2) 37%, var(--surface-3) 63%);
  background-size: 400% 100%;
  animation: skeleton 1.4s ease-in-out infinite;
}
.skeleton.short { width: 62%; }
@keyframes skeleton { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) { .skeleton { animation: none; } }

/* Below this the rail has nowhere to go, so it becomes a footer block with a
   rule above it rather than a border down its side. */
/* One column of everything on a narrow screen. The two prose columns are the
   layout rather than a luxury, so they survive as long as there is room for
   them to be prose. */
@media (max-width: 940px) {
  .briefing-grid { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .briefing-grid:not(.with-key) .briefing-body { grid-column: auto; columns: 1; }
}

/* ---------------------------------------------------------- reason codes */

.rc-grid { gap: 22px; }
.rc {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 10px;
  align-items: baseline;
  padding: 9px 11px;
  margin-bottom: 7px;
  border-radius: 5px;
  background: var(--surface-2);
  border-left: 3px solid var(--hairline);
}
.rc-good { border-left-color: var(--good); }
.rc-bad  { border-left-color: var(--critical); }
.rc-id {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .06em;
  color: var(--text-muted);
  background: var(--surface-3);
  padding: 2px 6px;
  border-radius: 3px;
  white-space: nowrap;
}
.rc-txt { font-size: 13px; line-height: 1.45; }
.rc-w {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 12.5px;
  white-space: nowrap;
}
.rc-good .rc-w { color: var(--good); }
.rc-bad  .rc-w { color: var(--critical); }

/* ---------------------------------------------------------- affordability */

.aff { display: flex; flex-direction: column; }
.afr {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: baseline;
  padding: 9px 0;
  border-bottom: 1px solid var(--hairline-2);
}
.afr:last-child { border-bottom: 0; }
.afr-k { font-size: 13px; }
.afr-n { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; max-width: 74ch; line-height: 1.45; }
.afr-v {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 13.5px;
  text-align: right;
}
.afr.binding .afr-k, .afr.binding .afr-v { color: var(--warning); }
.afr.total { border-top: 1px solid var(--hairline); font-weight: 600; }

@media (max-width: 720px) {
  .rc { grid-template-columns: auto minmax(0, 1fr); }
  .rc-w { grid-column: 2; text-align: right; }
  .afr { grid-template-columns: minmax(0, 1fr); row-gap: 3px; }
  .afr-v { text-align: left; }
}

/* ============================================================================
   The scenario simulator.

   The tab the MVP was missing. Its shape is the prototype's — a narrow column
   of controls against a wide column of consequences — because that is the
   reading order the demo depends on: set something, then watch four cards
   explain what it did.
   ========================================================================== */

/* ---- the flow strip ----
   Six steps, and the officer is somewhere in them. Not decoration: it is the
   only thing on the tab that says the credit decision is settled HERE rather
   than back on the Decision tab. */

.wf-flow {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px;
  padding: 11px 14px; margin-bottom: 14px;
  background: var(--surface-1); border: 1px solid var(--hairline);
  border-radius: var(--radius); font-size: 12.5px; color: var(--text-muted);
}
.wf-arr { color: var(--axis); margin: 0 4px; }
.wf-s { display: inline-flex; align-items: center; gap: 7px; padding: 3px 9px; border-radius: 999px; }
.wf-s.done { color: var(--text-secondary); }
.wf-s.on { color: var(--text-primary); background: var(--surface-3); font-weight: 550; }
.wf-n {
  display: inline-grid; place-items: center; width: 17px; height: 17px; flex: none;
  border-radius: 50%; font-size: 10.5px; font-family: var(--mono);
  background: var(--surface-3); color: var(--text-muted);
}
.wf-s.done .wf-n { background: var(--good); color: #fff; }
.wf-s.on .wf-n { background: var(--series-1); color: #fff; }

/* ---- one-click scenarios ---- */

.preset-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; }
.preset {
  display: flex; flex-direction: column; gap: 3px; text-align: left;
  padding: 11px 13px; border-radius: var(--radius-sm); cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--hairline);
  color: var(--text-secondary); font: inherit;
}
.preset:hover { background: var(--surface-3); color: var(--text-primary); }
.preset.on { border-color: var(--series-1); background: color-mix(in srgb, var(--series-1) 12%, var(--surface-2)); }
.preset b { font-size: 13px; font-weight: 600; color: var(--text-primary); }
.preset span { font-size: 11.5px; color: var(--text-muted); }

/* ---- the sliders ---- */

.control { margin-bottom: 18px; }
.control:last-of-type { margin-bottom: 14px; }
.control label {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  font-size: 12.5px; color: var(--text-secondary); margin-bottom: 7px;
}
.control label b {
  font-weight: 600; color: var(--text-primary);
  font-variant-numeric: tabular-nums; font-size: 13px;
}
.control input[type=range] {
  width: 100%; accent-color: var(--series-1); background: transparent; cursor: pointer;
}

/* ---- where it breaks ---- */

.feat {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 14px;
  padding: 9px 0; border-bottom: 1px solid var(--hairline-2);
}
.feat:last-of-type { border-bottom: 0; }
.fl { font-size: 13px; }
.fv { font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: 13px; text-align: right; }
.fb { grid-column: 1 / -1; font-size: 11.5px; color: var(--text-muted); line-height: 1.5; max-width: 70ch; }

/* ---- the outcome tiles and the strip under them ---- */

.tiles.t4 { grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); }
.tile .d.up { color: var(--good); }
.tile .d.down { color: var(--critical); }
.tile .d .down { color: var(--critical); }

.delta-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: 14px;
  padding-top: 14px; border-top: 1px solid var(--hairline);
}
.delta-strip .d { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); }
.delta-strip .d b {
  display: block; margin-top: 4px; font-size: 16px; font-weight: 600;
  letter-spacing: 0; text-transform: none; color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

/* ---- severity ----
   The colour and the words come from the same object in the engine, so the
   card cannot say "stable" in green over a scenario that broke the facility. */

.sev-card { border-left: 3px solid var(--hairline); }
.sev-danger   { border-left-color: var(--critical); background: color-mix(in srgb, var(--critical) 7%, var(--plane)); }
.sev-warning  { border-left-color: var(--warning);  background: color-mix(in srgb, var(--warning) 7%, var(--plane)); }
.sev-positive { border-left-color: var(--good);     background: color-mix(in srgb, var(--good) 8%, var(--plane)); }
.sev-neutral  { border-left-color: var(--good);     background: color-mix(in srgb, var(--good) 5%, var(--plane)); }

.sev-head { display: flex; align-items: flex-start; gap: 12px; }
.sev-icon { font-size: 15px; line-height: 1.3; }
.sev-danger   .sev-icon { color: var(--critical); }
.sev-warning  .sev-icon { color: var(--warning); }
.sev-positive .sev-icon, .sev-neutral .sev-icon { color: var(--good); }
.sev-head > div { flex: 1; min-width: 0; }
.sev-label {
  font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-muted); font-family: var(--mono);
}
.sev-headline { font-size: 14.5px; font-weight: 600; margin-top: 3px; line-height: 1.45; }
.sev-why { margin-top: 10px; font-size: 12.5px; color: var(--text-secondary); line-height: 1.6; }

/* ---- the analysis blocks ---- */

.sblock { padding: 13px 0; border-bottom: 1px solid var(--hairline-2); }
.sblock:last-child { border-bottom: 0; padding-bottom: 0; }
.sblock-k {
  font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-muted); font-family: var(--mono);
}
.sblock-v { margin-top: 6px; font-size: 13.5px; line-height: 1.68; color: var(--text-secondary); max-width: 78ch; }

td.num.up { color: var(--good); }
td.num.down { color: var(--critical); }

/* ---- which drivers moved ----
   A diverging bar per driver, drawn in CSS rather than SVG: the rows are a
   fixed height and the only geometry is a percentage either side of a centre
   line, which is less machinery than a chart for the same picture. */

.dv { display: flex; flex-direction: column; gap: 5px; }
.dv-row { display: grid; grid-template-columns: minmax(0, 200px) minmax(0, 1fr) 60px; gap: 12px; align-items: center; }
.dv-name { font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dv-track { position: relative; height: 14px; background: var(--surface-2); border-radius: 3px; }
.dv-mid { position: absolute; left: 50%; top: 0; bottom: 0; width: 1px; background: var(--axis); }
.dv-bar { position: absolute; top: 3px; bottom: 3px; border-radius: 2px; }
.dv-bar.good { background: var(--good); }
.dv-bar.bad { background: var(--critical); }
.dv-val { font-family: var(--mono); font-size: 12px; text-align: right; font-variant-numeric: tabular-nums; }
.dv-val.up { color: var(--good); }
.dv-val.down { color: var(--critical); }

/* ---- the credit decision, priced on the scenario ---- */

.infobox {
  background: var(--surface-1); border: 1px solid var(--hairline);
  border-radius: var(--radius-sm); padding: 16px 18px; margin-top: 14px;
}
.ir-head { display: flex; align-items: center; gap: 10px; }
.ir-amount { font-size: 30px; font-weight: 660; letter-spacing: -1px; margin: 10px 0 2px; font-variant-numeric: tabular-nums; }
.ir-terms { font-size: 13.5px; color: var(--text-secondary); }
.ir-sub { font-size: 11.5px; color: var(--text-muted); margin-top: 8px; line-height: 1.55; }
.ir-scen { font-size: 12px; color: var(--text-secondary); margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--hairline-2); }

/* Below a laptop the two columns stop being two columns — the controls belong
   above the consequences, not squeezed beside them. */
@media (max-width: 1100px) {
  .grid.g-1-2, .grid.g-2-1 { grid-template-columns: minmax(0, 1fr); }
  .dv-row { grid-template-columns: minmax(0, 140px) minmax(0, 1fr) 54px; }
}

/* ============================================================================
   The opportunity scan's progress bar.

   Every value it shows is a count the server sent after finishing a customer,
   so the only thing eased here is the travel between two real widths. There is
   no indeterminate state and no animation towards a target: if the scan stalls,
   the bar stalls, which is the whole reason it replaced a self-ticking
   checklist.
   ========================================================================== */

.progress {
  height: 8px; border-radius: 4px; overflow: hidden;
  background: var(--surface-3); border: 1px solid var(--hairline-2);
}
.progress > i {
  display: block; height: 100%; width: 0;
  background: var(--series-1); border-radius: 4px;
  transition: width .25s ease-out;
}
@media (prefers-reduced-motion: reduce) { .progress > i { transition: none; } }

/* The one tile on the card that is the answer rather than the working. */
.tile .v.good { color: var(--good); }

/* The pacing disclosure under the scan bar. Quiet, but present: it is the one
   invented duration in the product and it says so where it happens. */
.pace-note {
  margin-top: 8px; font-size: 11.5px; color: var(--text-muted); line-height: 1.5;
}

/* ============================================================================
   The chart tooltip.

   Fixed to the viewport and pointer-events:none, so it follows the cursor and
   can never sit between the cursor and the mark it describes. Two lines: a
   heading and a note, both text nodes — see the comment in charts.js for why
   that is a security property and not a styling choice.
   ========================================================================== */

.viz-tip {
  position: fixed; top: 0; left: 0; z-index: 200; pointer-events: none;
  background: var(--plane); border: 1px solid var(--hairline); border-radius: 8px;
  padding: 8px 11px; font-size: 12px; color: var(--text-primary);
  box-shadow: var(--shadow); max-width: 300px; line-height: 1.55;
  opacity: 0; transition: opacity .1s;
}
.viz-tip.on { opacity: 1; }
.viz-tip b { display: block; font-weight: 600; }
.viz-tip span { color: var(--text-secondary); }
.viz-tip span:empty { display: none; }
@media (prefers-reduced-motion: reduce) { .viz-tip { transition: none; } }

/* ============================================================================
   The briefing's sections.

   Five labelled parts rather than one run of prose. The reason is not tidiness:
   "Why this amount" is the part an officer defends to a credit committee, and
   in an unbroken column it was the fourth paragraph down and looked exactly
   like the company background above it.

   Exactly one section is emphasised. Two would be none.
   ========================================================================== */

.bsec { display: block; }
.bsec + .bsec { margin-top: 26px; }

/* Close to the prose it labels, not floating between two sections. A heading
   equidistant from the paragraph above and the one below belongs to neither. */
.bsec-h {
  margin: 0 0 9px;
  font-size: 11px;
  font-family: var(--mono);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 600;
}
.bsec p { margin: 0; }
.bsec p + p { margin-top: 12px; }

/* The argument for the amount, set apart rather than shouted.

   It was a saturated blue panel, which on this ground reads as an alert — the
   colour a console uses for something being wrong. This is not a warning; it
   is the paragraph the officer will be asked about. So: the card's own raised
   surface, an accent rule down the side, an accent heading, and body text at
   full strength against the secondary grey above it. Present at a glance,
   without pretending to be an error. */
.briefing-key {
  border-left: 3px solid var(--accent);
  background: var(--surface-2);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: 18px 20px 20px;
}
.briefing-key .bsec-h { color: var(--accent); }
.briefing-key p {
  margin: 0;
  color: var(--text-primary);
  line-height: 1.72;
  font-size: 14.5px;
}
.briefing-key p + p { margin-top: 12px; }

/* ============================================================================
   The facility lifecycle.

   Four steps with a named person against each one. The card a second officer
   opens to decide whether to release has to answer 'who approved this, and
   when' before it answers anything else.

   The last two steps are drawn differently on purpose: customer acceptance and
   disbursement do not exist in this product and belong to the bank's loan
   system. Shown, so an officer sees where the decision goes next; dimmed and
   labelled, so nobody reads them as a queue this system is working through.
   ========================================================================== */

.flow {
  display: flex; flex-direction: column; gap: 2px;
  margin: 16px 0 4px; padding-top: 16px;
  border-top: 1px solid var(--hairline);
}
.flow-step {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 9px 12px; border-radius: var(--radius-sm);
  border: 1px solid transparent;
}
.flow-step .fs-dot {
  display: inline-grid; place-items: center; width: 22px; height: 22px; flex: none;
  border-radius: 50%; font-size: 11px; font-family: var(--mono);
  background: var(--surface-3); color: var(--text-muted); margin-top: 1px;
}
.flow-step .fs-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.flow-step b { font-size: 13.5px; font-weight: 550; color: var(--text-secondary); }
.fs-sub { font-size: 11.5px; color: var(--text-muted); }

.flow-step.done .fs-dot { background: var(--good); color: #fff; }
.flow-step.done b { color: var(--text-primary); }
.flow-step.done .fs-sub { color: var(--text-secondary); }

.flow-step.now {
  background: var(--surface-2); border-color: var(--hairline);
}
.flow-step.now .fs-dot { background: var(--series-1); color: #fff; }
.flow-step.now b { color: var(--text-primary); }

/* Somebody else's step. */
.flow-step.away { opacity: .62; }
.flow-step.away .fs-dot { background: transparent; border: 1px dashed var(--hairline); }

/* ============================================================================
   Inline forms, and the replay verdict.

   Nothing in this console opens a browser dialog. A justification that goes on
   a credit file wants a paragraph, wants to be pre-filled with the engine's own
   rationale, and must not block the page — window.prompt fails all three, and
   on this machine it also blocks the tooling used to look at the page at all.
   ========================================================================== */

.inline-form {
  margin-top: 14px; padding: 16px 18px;
  background: var(--surface-2); border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  display: flex; flex-direction: column; gap: 8px;
}
.inline-form label { font-size: 12.5px; color: var(--text-secondary); }
.inline-form textarea {
  width: 100%; resize: vertical; min-height: 66px;
  background: var(--plane); border: 1px solid var(--hairline);
  border-radius: var(--radius-sm); padding: 10px 12px;
  font-size: 13.5px; line-height: 1.6; color: var(--text-primary);
}
.inline-form textarea:focus-visible {
  outline: none; border-color: var(--series-1);
}
.inline-err { font-size: 12.5px; color: var(--critical); min-height: 0; }
.inline-err:empty { display: none; }

/* The replay verdict sits between the lifecycle and the actions: the last thing
   read before a decision is released. */
.replay {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px 12px;
  margin: 14px 0 4px; padding-top: 14px;
  border-top: 1px solid var(--hairline-2);
}
.replay .small { line-height: 1.55; }
.replay .note { flex: 1; margin: 0; }

/* The standing-decision banner carries an action, so it is a row rather than a
   paragraph. It sits above the tab strip because the facility card lives on the
   scenario simulator and an officer arriving to release something lands on
   Intake — reachable and invisible is the same as missing. */
#standing-banner {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 12px 14px; line-height: 1.55;
}
#standing-banner > div { flex: 1; min-width: 260px; }
