/* ==========================================================================
   Positka SOC Entitlements
   ---------------------------------------------------------------------------
   Application shell: fixed sidebar + scrolling content, the standard SaaS
   layout. Two rules from the data-viz method are load-bearing here:

     1. Status colour NEVER carries meaning alone. Every dot ships with its
        text label, which is the required mitigation for the warning and
        serious steps sitting below 3:1 on a light surface.
     2. Numbers wear text tokens, not series colour. A count is ink; the
        coloured dot beside it carries identity.
   ========================================================================== */

/* ------------------------------------------------------------------ tokens */

:root {
  color-scheme: light;

  /* Surfaces, from furthest back to nearest front */
  --canvas: #f6f7f9;
  --surface: #ffffff;
  --surface-2: #f9fafb;
  --sidebar: #101a2f;
  --sidebar-2: #1b2942;

  /* Brand */
  --brand: #1f3864;
  --brand-ink: #2c4f8f;
  --accent: #2a78d6;

  /* Ink */
  --ink: #101828;
  --ink-2: #475467;
  --muted: #8a93a3;
  --on-dark: #eaeef6;
  --on-dark-dim: #9aa8c2;

  /* Lines */
  --line: #e6e8ee;
  --line-2: #eff1f5;
  --ring: rgba(16, 24, 40, .08);

  /* Status (fixed, never themed) */
  --good: #0ca30c;
  --warning: #fab219;
  --serious: #ec835a;
  --critical: #d03b3b;
  --neutral: #8a93a3;

  /* Tints for status backgrounds */
  --good-bg: #e9f7e9;
  --warning-bg: #fef4e0;
  --serious-bg: #fdeee7;
  --critical-bg: #fbeaea;
  --neutral-bg: #f1f2f4;

  /* Sequential (meters) */
  --seq: #2a78d6;
  --seq-track: #e6e8ee;

  --input-tint: #fffdf5;

  --r-sm: 6px;
  --r: 10px;
  --r-lg: 14px;
  --shadow: 0 1px 2px rgba(16, 24, 40, .05);
  --shadow-lg: 0 4px 16px rgba(16, 24, 40, .08);
  --sans: "Inter var", system-ui, -apple-system, "Segoe UI", sans-serif;
  --sidebar-w: 232px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --canvas: #0d1117;
    --surface: #161b22;
    --surface-2: #1c2230;
    --sidebar: #0a0f1a;
    --sidebar-2: #141c2c;
    --brand: #2c4f8f;
    --brand-ink: #7fa9e8;
    --ink: #e9edf4;
    --ink-2: #a9b4c6;
    --muted: #7d8798;
    --line: #262d3a;
    --line-2: #1f2530;
    --ring: rgba(255, 255, 255, .08);
    --good-bg: #102a12;
    --warning-bg: #2e2410;
    --serious-bg: #2d1c14;
    --critical-bg: #2c1416;
    --neutral-bg: #1f2530;
    --seq: #3987e5;
    --seq-track: #262d3a;
    --input-tint: #1e2331;
    --shadow: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-lg: 0 4px 16px rgba(0, 0, 0, .5);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --canvas: #0d1117; --surface: #161b22; --surface-2: #1c2230;
  --sidebar: #0a0f1a; --sidebar-2: #141c2c;
  --brand: #2c4f8f; --brand-ink: #7fa9e8;
  --ink: #e9edf4; --ink-2: #a9b4c6; --muted: #7d8798;
  --line: #262d3a; --line-2: #1f2530; --ring: rgba(255,255,255,.08);
  --good-bg: #102a12; --warning-bg: #2e2410; --serious-bg: #2d1c14;
  --critical-bg: #2c1416; --neutral-bg: #1f2530;
  --seq: #3987e5; --seq-track: #262d3a; --input-tint: #1e2331;
  --shadow: 0 1px 2px rgba(0,0,0,.4); --shadow-lg: 0 4px 16px rgba(0,0,0,.5);
}

/* ------------------------------------------------------- appearance choices */

/* Written onto the root element server-side by `app.appearance`. Each block is
   the whole of what one preference does, which is what lets a new option be a
   value plus a rule rather than a change to the page.

   Only the non-default values appear here. The default case is the bare :root
   above, so an ordinary page carries no attributes and no extra cascade. */

/* Typeface. System stacks only — this tool makes zero external requests, so
   there are no web fonts to load. Each stack ends in a generic family, so a
   machine missing every named face still lands somewhere deliberate. */
:root[data-font="humanist"] {
  --sans: "Segoe UI", Tahoma, Verdana, Geneva, sans-serif;
}
:root[data-font="serif"] {
  --sans: Georgia, Cambria, "Times New Roman", Times, serif;
}
:root[data-font="mono"] {
  --sans: "Cascadia Mono", Consolas, "SF Mono", Menlo, monospace;
}

/* Text size. Everything is in rem — all 122 font sizes in this file were
   converted from px for exactly this — so one root value moves the whole page
   together, including the 11px metadata that a partial scale would leave behind.
   16px is the browser's own default, so a reader who has already raised it keeps
   that raise and this multiplies it rather than overriding it. */
:root { font-size: 16px; }
:root[data-text="s"]  { font-size: 14.5px; }
:root[data-text="l"]  { font-size: 17.5px; }
:root[data-text="xl"] { font-size: 19.5px; }

/* Row height. The matrix is 79 rows and the implementation table is 45, so this
   is the difference between two screens and three.

   Done with tokens the existing table rules read, rather than with an override
   block. An override would have to out-specify `.matrix tbody td`, and a rule
   written to win a specificity fight is a rule the next person edits by
   accident. Spacing only: shrinking the type as well is what the text size
   control is for, and no information is hidden — a row you cannot see the
   evidence for is not a denser table, it is a different one. */
:root {
  --cell-y: .6rem;
  --cell-y-tight: .45rem;
  --cell-line: 1.5;
}
:root[data-density="compact"] {
  --cell-y: .3rem;
  --cell-y-tight: .22rem;
  --cell-line: 1.34;
}

/* Animation. The operating system's own request is honoured whatever is chosen
   here — hence two selectors saying the same thing rather than one. Transitions
   are cut to 1ms rather than 0 so anything listening for transitionend still
   fires; a handler that never runs is a worse bug than a fast animation. */
:root[data-motion="reduced"] *,
:root[data-motion="reduced"] *::before,
:root[data-motion="reduced"] *::after {
  animation-duration: 1ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 1ms !important;
  scroll-behavior: auto !important;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}

*, *::before, *::after { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  font-family: var(--sans);
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--ink);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--brand-ink); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { margin: 0; line-height: 1.3; font-weight: 600; letter-spacing: -.01em; }
h1 { font-size: 1.4rem; }
h2 { font-size: 1rem; }
h3 { font-size: .875rem; }

p { margin: 0; }

.muted { color: var(--muted); }
.dim { color: var(--ink-2); }
.small { font-size: 0.78125rem; }
.xs { font-size: 0.71875rem; }
.tabular { font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }
.right { text-align: right; }
.grow { flex: 1; min-width: 0; }
.stack { display: flex; flex-direction: column; gap: .4rem; }
.row { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }
.between { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; }
.divider { height: 1px; background: var(--line); margin: 1rem 0; }

/* ------------------------------------------------------------------- shell */

.app { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 100vh; }

.sidebar {
  background: var(--sidebar);
  color: var(--on-dark);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh;
  padding: 1rem .75rem;
  gap: .25rem;
}
.sidebar .logo {
  display: flex; align-items: center; gap: .6rem;
  padding: .3rem .5rem 1.1rem;
}
.sidebar .logo .mark {
  width: 30px; height: 30px; border-radius: 8px; flex: 0 0 auto;
  background: linear-gradient(135deg, #2a78d6, #1f3864);
  display: grid; place-items: center;
  color: #fff; font-weight: 700; font-size: 0.8125rem; letter-spacing: -.02em;
}
.sidebar .logo .name { font-weight: 650; font-size: 0.84375rem; letter-spacing: .01em; }
.sidebar .logo .sub { font-size: 0.65625rem; color: var(--on-dark-dim); letter-spacing: .04em; text-transform: uppercase; }

.sidebar .group-label {
  font-size: 0.625rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--on-dark-dim); padding: .9rem .6rem .3rem;
}
.sidebar nav { display: flex; flex-direction: column; gap: 1px; }
.sidebar nav a {
  display: flex; align-items: center; gap: .55rem;
  padding: .5rem .6rem; border-radius: var(--r-sm);
  color: var(--on-dark-dim); font-size: 0.8125rem; font-weight: 500;
}
.sidebar nav a:hover { background: var(--sidebar-2); color: var(--on-dark); text-decoration: none; }
.sidebar nav a[aria-current] { background: var(--sidebar-2); color: #fff; font-weight: 600; }
.sidebar nav a[aria-current] .ico { color: var(--accent); }
.sidebar nav a .ico { width: 16px; height: 16px; flex: 0 0 auto; }
.sidebar nav a .badge {
  margin-left: auto; font-size: 0.65625rem; font-weight: 700;
  background: var(--critical); color: #fff;
  border-radius: 999px; padding: .05rem .38rem; font-variant-numeric: tabular-nums;
}
.sidebar .spacer { flex: 1; }
.sidebar .foot {
  border-top: 1px solid rgba(255, 255, 255, .09);
  padding-top: .7rem; margin-top: .7rem;
}
/* Now a link to the profile, so it needs the affordances of one: no underline,
   a hover surface, and the current-page state the nav rows use. */
.sidebar .who {
  display: flex; align-items: center; gap: .55rem;
  padding: .3rem .6rem .5rem;
  color: inherit; text-decoration: none; border-radius: var(--r-sm);
}
.sidebar a.who { padding: .4rem .6rem; }
.sidebar a.who:hover { background: var(--sidebar-2); text-decoration: none; }
.sidebar a.who.is-current { background: var(--sidebar-2); }
.sidebar a.who .ico { width: 15px; height: 15px; color: var(--on-dark-dim); flex: 0 0 auto; }
.sidebar a.who:hover .ico { color: var(--on-dark); }
.sidebar .who .avatar {
  width: 28px; height: 28px; border-radius: 50%; flex: 0 0 auto;
  background: var(--sidebar-2); color: var(--on-dark);
  display: grid; place-items: center; font-size: 0.6875rem; font-weight: 700;
  border: 1px solid rgba(255, 255, 255, .12);
}
.sidebar .who .n { font-size: 0.78125rem; font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sidebar .who .r { font-size: 0.65625rem; color: var(--on-dark-dim); text-transform: uppercase; letter-spacing: .05em; }
.sidebar .signout {
  width: 100%; justify-content: center;
  background: transparent; border: 1px solid rgba(255, 255, 255, .16); color: var(--on-dark);
}
.sidebar .signout:hover { background: var(--sidebar-2); }

/* ------------------------------------------------ approving from an email */

/* Its own page, reached by somebody not signed in, so it borrows nothing from
   the app shell. Centred column, generous type: this is read on a phone at the
   weekend more often than at a desk. */
.approve-page {
  min-height: 100vh; padding: 2rem 1rem;
  background: var(--canvas);
  display: flex; justify-content: center; align-items: flex-start;
}
.approve-card {
  width: 100%; max-width: 720px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg);
  padding: 1.6rem 1.8rem 2rem;
}
.approve-card.narrow { max-width: 560px; }
.approve-head { display: flex; align-items: center; gap: .7rem; margin-bottom: 1.4rem; }
.approve-head .mark {
  width: 34px; height: 34px; border-radius: 9px; flex: 0 0 auto;
  background: linear-gradient(135deg, #2a78d6, #1f3864);
  display: grid; place-items: center; color: #fff; font-weight: 700;
}
.approve-head .who { font-weight: 650; font-size: 0.84375rem; }
.approve-head .sub {
  font-size: 0.65625rem; color: var(--muted);
  text-transform: uppercase; letter-spacing: .05em;
}
.approve-card h1 { font-size: 1.3rem; margin-bottom: .2rem; }
.approve-card > .sub { color: var(--muted); font-size: 0.78125rem; margin-bottom: 1.1rem; }

.approve-you {
  display: flex; gap: .6rem; align-items: flex-start;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r); padding: .8rem .9rem; margin-bottom: 1.2rem;
  font-size: 0.8125rem;
}
.approve-you .ico { flex: 0 0 auto; margin-top: .15rem; color: var(--brand-ink); }

.approve-section {
  font-size: 0.6875rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--brand-ink);
  margin: 1.4rem 0 .5rem; padding-bottom: .3rem;
  border-bottom: 1px solid var(--line);
}
.approve-facts, .approve-body { margin: 0; }
.approve-facts dt, .approve-body dt {
  font-size: 0.6875rem; font-weight: 650; text-transform: uppercase;
  letter-spacing: .04em; color: var(--muted); margin-top: .7rem;
}
.approve-facts dd, .approve-body dd {
  margin: .15rem 0 0; font-size: 0.8125rem; white-space: pre-line;
}

.approve-signers { width: 100%; border-collapse: collapse; font-size: 0.8125rem; }
.approve-signers td { padding: .5rem 0; border-bottom: 1px solid var(--line-2); }
.approve-signers tr.is-you td { background: var(--surface-2); }

.approve-act { margin-top: 1.6rem; padding-top: 1.2rem; border-top: 1px solid var(--line); }
.approve-buttons { display: flex; gap: .6rem; flex-wrap: wrap; margin: .8rem 0 .5rem; }

.approve-result { display: flex; align-items: center; gap: .7rem; margin-bottom: 1rem; }
.approve-result .ico { width: 26px; height: 26px; flex: 0 0 auto; }
.approve-result.good .ico { color: var(--good); }
.approve-result.bad .ico { color: var(--critical); }
.approve-result h1 { font-size: 1.2rem; }

.ok-text { color: var(--good); font-weight: 600; }
.warn-text { color: var(--serious); }

/* ------------------------------------------------------------------- tabs */

/* The four sections of an account. Underline rather than boxes: the page below is
   already a stack of cards, and a second set of boxes around them reads as
   clutter. The numbers are there because the order is the order the work happens
   in, which is worth saying once on the page rather than in a manual. */
.tabs {
  display: flex; gap: .15rem; flex-wrap: wrap;
  border-bottom: 1px solid var(--line);
  margin: -.25rem 0 1.1rem;
}
.tab {
  display: flex; align-items: center; gap: .45rem;
  padding: .55rem .85rem; margin-bottom: -1px;
  font-size: 0.8125rem; font-weight: 550; color: var(--muted);
  border-bottom: 2px solid transparent;
  border-radius: var(--r-sm) var(--r-sm) 0 0;
}
.tab:hover { color: var(--ink); background: var(--surface-2); text-decoration: none; }
.tab.is-current {
  color: var(--brand-ink); font-weight: 650;
  border-bottom-color: var(--brand-ink);
  background: var(--surface);
}
.tab-n {
  width: 18px; height: 18px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center;
  font-size: 0.625rem; font-weight: 700; font-variant-numeric: tabular-nums;
  background: var(--surface-2); color: var(--muted); border: 1px solid var(--line);
}
.tab.is-current .tab-n {
  background: var(--brand-ink); color: #fff; border-color: var(--brand-ink);
}
.tab-count {
  font-size: 0.65625rem; font-weight: 700; font-variant-numeric: tabular-nums;
  background: var(--critical); color: #fff;
  border-radius: 999px; padding: .05rem .35rem;
}

@media (max-width: 700px) {
  .tab { padding: .5rem .55rem; font-size: 0.75rem; }
  .tab-n { display: none; }
}

/* ---------------------------------------------------------- implementation */

/* A table now, not two lists. The rows are a fixed catalogue, so the interesting
   states are "answered", "not answered yet", and "needs attention" — and the first
   two have to be distinguishable at a glance down a column of forty-five. */
.impl-table td.param { width: 26%; }
.impl-table .cell-input { min-height: 2rem; }

/* A row nothing has been said about. Dimmed, not coloured: it is not a problem,
   it is an absence, and forty-five red rows on a new account would be noise. The
   left edge is what carries it, so the dimming does not have to be heavy enough
   to make the text hard to read. */
tr.row-blank { background: var(--surface-2); }
tr.row-blank td.param .name { color: var(--ink-2); }
tr.row-blank td.param { box-shadow: inset 3px 0 0 var(--line); }
tr.row-blank .cell-input::placeholder { color: var(--muted); font-style: italic; }

/* A critical source that is not integrated. The one thing on this page worth a
   colour, and it gets a label in the Integrated column too — never colour alone. */
tr.row-attention td:first-child { box-shadow: inset 3px 0 0 var(--critical); }
tr.row-attention { background: var(--critical-bg); }

/* The group header carries its own count, so you can see which part of the scope
   is thin without adding a column to every row. */
.group-count {
  display: inline-block; margin-left: .5rem;
  font-size: 0.6875rem; font-variant-numeric: tabular-nums;
  color: var(--ink-2); background: var(--surface);
  border: 1px solid var(--line); border-radius: 999px;
  padding: .05rem .4rem; font-weight: 600;
}
.group-meaning {
  display: block; margin-top: .2rem;
  font-size: 0.71875rem; font-weight: 400; color: var(--muted);
  text-transform: none; letter-spacing: 0;
}

/* Under a value: the yardstick, the evidence, and where the value came from. All
   small, all optional, and none of it competing with the value itself. */
.cell-meta { display: flex; flex-direction: column; gap: .18rem; margin-top: .25rem; }
.cell-meta .chip { align-self: flex-start; }

/* One number, big, with a bar beside it. This is the whole summary — there were
   five stat tiles and a per-group table here before and none of them answered the
   question faster than "31 of 45 answered". */
.impl-headline {
  display: flex; align-items: center; gap: 1.6rem; flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow);
  padding: 1.2rem 1.5rem; margin-bottom: 1.4rem;
}
.impl-figure { display: flex; flex-direction: column; line-height: 1; }
.impl-pct {
  font-size: 2.6rem; font-weight: 680; letter-spacing: -.03em;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.impl-pct-label {
  font-size: 0.65625rem; text-transform: uppercase; letter-spacing: .09em;
  color: var(--muted); margin-top: .3rem;
}
.impl-bar-wrap { flex: 1 1 260px; min-width: 0; }
.impl-bar {
  height: 8px; border-radius: 999px; overflow: hidden;
  background: var(--seq-track);
}
.impl-bar-fill {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), var(--good));
  transition: width .28s ease;
}
.impl-bar-note { font-size: 0.78125rem; color: var(--ink-2); margin-top: .55rem; }

/* Add one inventory line. Sits under the table it adds to. */
.row-form {
  display: flex; gap: .45rem; flex-wrap: wrap; align-items: center;
}
.row-form input[type="text"] { flex: 1 1 200px; min-width: 0; }
.row-form input.narrow { flex: 0 1 90px; }
.row-form input, .row-form select {
  font: inherit; font-size: 0.78125rem;
  padding: .4rem .55rem; border: 1px solid var(--line);
  border-radius: var(--r-sm); background: var(--surface); color: var(--ink);
}
.row-form input:focus, .row-form select:focus {
  border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--ring);
}

@media (max-width: 760px) {
  .group-meaning { display: none; }
}

/* --------------------------------------------------------- the flow diagram */

/* Six labelled nodes on one line, with the connector drawn as a border on the
   node rather than a separate element — one box per stage, so nothing can get out
   of step with anything else. Wraps to two rows on a narrow screen instead of
   scrolling, because a process diagram you have to scroll to see the end of is not
   telling you where you are. */
.flow {
  list-style: none; display: flex; flex-wrap: wrap;
  margin: 0; padding: 0; gap: .2rem;
}
.flow-node {
  flex: 1 1 120px; min-width: 0;
  display: flex; flex-direction: column; align-items: center;
  text-align: center; padding: .7rem .4rem .6rem;
  border-top: 3px solid var(--line);
  position: relative;
}
.flow-dot {
  width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 0.6875rem; font-weight: 700; font-variant-numeric: tabular-nums;
  background: var(--surface-2); color: var(--muted);
  border: 1px solid var(--line);
  margin-bottom: .35rem;
}
.flow-label {
  font-size: 0.71875rem; font-weight: 600; line-height: 1.25;
  color: var(--ink-2);
}
.flow-note {
  font-size: 0.65625rem; color: var(--muted); margin-top: .1rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}

/* Done, current, pending, stopped. Colour is never the only signal — the tick,
   the ring and the cross say the same thing, which is the rule the verdict chips
   follow and it matters as much here. */
.flow-node.is-done { border-top-color: var(--good); }
.flow-node.is-done .flow-dot {
  background: var(--good-bg); border-color: var(--good); color: var(--good);
}
.flow-node.is-done .flow-label { color: var(--ink); }

.flow-node.is-current { border-top-color: var(--accent); }
.flow-node.is-current .flow-dot {
  background: var(--accent); border-color: var(--accent); color: #fff;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
.flow-node.is-current .flow-label { color: var(--ink); font-weight: 700; }
.flow-node.is-current .flow-note { color: var(--accent); font-weight: 650; }

.flow-node.is-failed { border-top-color: var(--critical); }
.flow-node.is-failed .flow-dot {
  background: var(--critical-bg); border-color: var(--critical); color: var(--critical);
}
.flow-node.is-failed .flow-label { color: var(--critical); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* ------------------------------------------------------- change requests */

/* The change request page as three numbered steps. The old page was one flat
   stack of cards and nobody could tell what to do next; numbering the sequence
   and dimming the steps that are not yet reachable is most of the fix. */
.cr-step { position: relative; margin-bottom: 1rem; }
.cr-step > .card { margin-bottom: 0; }
.cr-step-head {
  display: flex; align-items: baseline; gap: .6rem;
  margin: 0 0 .5rem;
}
.cr-step-num {
  flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 0.6875rem; font-weight: 700; font-variant-numeric: tabular-nums;
  background: var(--brand); color: #fff;
}
.cr-step.is-done .cr-step-num { background: var(--good); }
.cr-step.is-waiting .cr-step-num { background: var(--muted); }
.cr-step-title { font-size: 0.84375rem; font-weight: 650; }
.cr-step-note { font-size: 0.75rem; color: var(--muted); }
.cr-step.is-waiting > .card { opacity: .72; }

/* A disclosure sitting inside a card, so it needs no border of its own. */
.disclose.flush {
  border: 0; border-top: 1px solid var(--line);
  border-radius: 0; margin: 0; box-shadow: none;
}

/* A lettered sub-step inside a step: 2a download, 2b send, 2c upload, 2d record.
   The order was the actual complaint — "mark as sent" was sitting below the upload
   that comes after it — so the sequence is now numbered on the page rather than
   implied by position. */
.cr-substep { display: flex; gap: .7rem; padding: .8rem 0; border-top: 1px solid var(--line); }
.cr-substep:first-child { border-top: 0; padding-top: .2rem; }
.cr-substep.is-done .cr-substep-tag { background: var(--good); color: #fff; border-color: var(--good); }
.cr-substep.is-now .cr-substep-tag { background: var(--accent); color: #fff; border-color: var(--accent); }
.cr-substep-tag {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center; font-size: 0.65625rem; font-weight: 700;
  background: var(--surface-2); color: var(--muted); border: 1px solid var(--line);
}
.cr-substep-body { flex: 1 1 auto; min-width: 0; }
.cr-substep-title { font-size: 0.8125rem; font-weight: 600; }
.cr-substep.is-waiting { opacity: .6; }

/* One row per seat in the approval block. */
.cr-seat { border-top: 1px solid var(--line); padding: .8rem 0; }
.cr-seat:first-child { border-top: 0; padding-top: 0; }
.cr-seat-head { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
.cr-seat-role {
  font-size: 0.65625rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--brand-ink);
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 999px; padding: .1rem .45rem;
}
.cr-seat-who { font-size: 0.84375rem; font-weight: 600; }
.cr-seat-empty { font-size: 0.8125rem; color: var(--serious); }
.cr-seat-meaning { font-size: 0.71875rem; color: var(--muted); flex: 1 1 100%; }

/* The three steps of the process, shown as a checklist so the current position
   is visible without reading the status label twice. */
.cr-steps { list-style: none; margin: 0; padding: 0; font-size: 0.78125rem; }
.cr-steps li {
  display: flex; align-items: center; gap: .4rem;
  padding: .15rem 0; color: var(--muted);
}
.cr-steps li.done { color: var(--ink); }
.cr-steps li.done .ico { color: var(--good); }
.cr-steps li.todo .ico { opacity: .5; }

/* One form per available step. Separated by a rule rather than a card each:
   they are alternatives at the same point in the process, not a sequence. */
.cr-action { padding: .7rem 0; border-top: 1px solid var(--line); }
.cr-action:first-child { border-top: 0; padding-top: 0; }
.cr-action.is-blocked { opacity: .62; }

/* The (A) / (B) headings inside the change request form, which is one long
   document rather than a set of cards. */
.section-sub {
  font-size: 0.75rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--brand-ink);
  margin: 1.2rem 0 .5rem; padding-bottom: .3rem;
  border-bottom: 1px solid var(--line);
}
.card-body > .section-sub:first-child { margin-top: 0; }

/* The read-only view of a CR that has been issued. */
.cr-read { margin: 0; }
.cr-read dt {
  font-size: 0.6875rem; font-weight: 650; text-transform: uppercase;
  letter-spacing: .045em; color: var(--muted); margin-top: .85rem;
}
.cr-read dt:first-child { margin-top: 0; }
.cr-read dd {
  margin: .2rem 0 0; font-size: 0.8125rem; color: var(--ink);
  white-space: pre-line;    /* the textareas keep their line breaks */
}

/* A row in the trail that has not happened yet. */
tr.dim > * { opacity: .55; }

/* What a row says today, next to what the scan proposes to put there. Struck
   through, because "will be replaced" underneath it is the caption and the value
   itself should read as the old one at a glance. */
.was { text-decoration: line-through; color: var(--ink-2); }

/* Appearance switch. In the sidebar, which is dark in both themes — so these
   colours are the sidebar's own, not the page's, and do not swap with the
   theme they set. */
.theme-switch {
  display: flex; gap: 2px; margin: 0 .6rem .55rem;
  padding: 2px; border-radius: var(--r-sm);
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .09);
}
.theme-opt {
  flex: 1 1 0; min-width: 0;
  display: flex; align-items: center; justify-content: center; gap: .3rem;
  padding: .3rem .2rem; border: 0; border-radius: calc(var(--r-sm) - 1px);
  background: transparent; color: var(--on-dark-dim);
  font: inherit; font-size: 0.65625rem; cursor: pointer;
}
.theme-opt .ico { width: 13px; height: 13px; flex: 0 0 auto; }
.theme-opt:hover { color: var(--on-dark); background: rgba(255, 255, 255, .07); }
.theme-opt[aria-current="true"] {
  background: var(--sidebar-2); color: var(--on-dark);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .25);
}
/* The label is the affordance at this size, but three of them do not fit a
   narrow sidebar — so below that, the icon carries it and `title` explains. */
@media (max-width: 1100px) {
  .theme-opt span { display: none; }
}

.content { min-width: 0; display: flex; flex-direction: column; }

.topbar {
  position: sticky; top: 0; z-index: 30;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
  padding: .55rem 1.5rem;
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
}
.topbar .crumbs { font-size: 0.78125rem; color: var(--muted); display: flex; gap: .4rem; align-items: center; }
.topbar .crumbs a { color: var(--muted); }
.topbar .crumbs .sep { opacity: .5; }

.page { padding: 1.5rem; max-width: 1720px; width: 100%; }
.page-head { display: flex; align-items: flex-start; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.25rem; }
.page-head h1 + .sub { margin-top: .3rem; color: var(--ink-2); font-size: 0.8125rem; max-width: 78ch; }
.actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }

@media (max-width: 900px) {
  .app { grid-template-columns: 1fr; }
  .sidebar {
    position: static; height: auto; flex-direction: row; align-items: center;
    flex-wrap: wrap; gap: .5rem; padding: .6rem .9rem;
  }
  .sidebar .logo { padding: 0 .5rem 0 0; }
  .sidebar .logo .sub, .sidebar .group-label, .sidebar .who .r { display: none; }
  .sidebar nav { flex-direction: row; flex-wrap: wrap; }
  .sidebar .foot { border: 0; margin: 0; padding: 0; }
  .sidebar .spacer { flex: 1; }
  .page { padding: 1rem; }
}

/* ------------------------------------------------------------------- cards */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow);
  margin-bottom: 1rem;
}
.card > .card-head {
  padding: .85rem 1.1rem;
  border-bottom: 1px solid var(--line-2);
  display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap;
}
.card > .card-head h2 { font-size: .95rem; }
.card > .card-head .hint { font-size: 0.75rem; color: var(--muted); }
.card > .card-head .actions { margin-left: auto; }
.card > .card-body { padding: 1.1rem; }
.card > .card-foot {
  padding: .7rem 1.1rem; border-top: 1px solid var(--line-2);
  font-size: 0.75rem; color: var(--muted); background: var(--surface-2);
  border-radius: 0 0 var(--r) var(--r);
}

.grid { display: grid; gap: 1rem; align-items: start; }
.grid.two { grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); }
.grid.three { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

/* ----------------------------------------------------- hero, tiles, meters */

.hero { display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap; }
.hero .figure {
  font-size: 3rem; font-weight: 700; line-height: 1; letter-spacing: -.03em;
  color: var(--ink);
}
.hero .figure-label {
  font-size: 0.6875rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted); margin-top: .3rem;
}
.hero .caption { flex: 1 1 30ch; max-width: 64ch; color: var(--ink-2); font-size: 0.8125rem; }

.meter { display: block; height: 7px; border-radius: 999px; background: var(--seq-track); overflow: hidden; }
.meter > span { display: block; height: 100%; border-radius: 999px; background: var(--seq); }
.meter.slim { height: 5px; }

.tiles { display: grid; gap: .75rem; grid-template-columns: repeat(auto-fit, minmax(178px, 1fr)); margin-bottom: 1rem; }
.tile {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--shadow);
  padding: .8rem .9rem; position: relative; overflow: hidden;
}
/* A 3px status rail: redundant with the label, never the only cue. */
.tile::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px; background: var(--neutral);
}
.tile.t-gap::before { background: var(--critical); }
.tile.t-conflict::before { background: var(--serious); }
.tile.t-over::before { background: var(--warning); }
.tile.t-match::before { background: var(--good); }
.tile.t-na::before, .tile.t-plain::before { background: var(--line); }
.tile .label { display: flex; align-items: center; gap: .4rem; font-size: 0.75rem; color: var(--ink-2); font-weight: 550; }
.tile .value { font-size: 1.75rem; font-weight: 700; line-height: 1.15; margin-top: .2rem; letter-spacing: -.02em; }
.tile .hint { font-size: 0.6875rem; color: var(--muted); margin-top: .15rem; line-height: 1.35; }
.tile.is-zero .value { color: var(--muted); font-weight: 600; }

/* ------------------------------------------------------- dashboard blocks */

/* Health strip: four panels, the first one twice the width for the hero figure. */
.kpis {
  display: grid; gap: 1rem; margin-bottom: 1rem;
  grid-template-columns: 1.5fr 1fr 1fr 1fr;
}
@media (max-width: 1180px) { .kpis { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); } }

.kpi {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--shadow); padding: 1rem 1.1rem;
  display: flex; flex-direction: column; gap: .5rem;
}
.kpi .k-label {
  font-size: 0.6875rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted); display: flex; align-items: center; gap: .4rem;
}
.kpi .k-value { font-size: 2.1rem; font-weight: 700; line-height: 1; letter-spacing: -.025em; }
.kpi.lead .k-value { font-size: 3rem; }
.kpi .k-sub { font-size: 0.75rem; color: var(--ink-2); }
.kpi .k-foot { margin-top: auto; }
.kpi.is-zero .k-value { color: var(--muted); }
.kpi.flagged .k-value { color: var(--critical); }

/* Five metrics fit at desktop width; the hero figure keeps a little extra. */
.kpis.five { grid-template-columns: 1.35fr 1fr 1fr 1fr 1fr; }
.kpis.five .kpi.lead .k-value { font-size: 2.6rem; }
@media (max-width: 1240px) {
  .kpis.five { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
}

/* By customer: the two rate columns carry a meter under the figure, so the
   comparison across accounts reads without doing arithmetic. */
.by-customer thead th.num .dot { margin-right: .25rem; vertical-align: middle; }
.by-customer td.num .meter { margin-top: .35rem; min-width: 54px; }

/* Horizontal bars: magnitude comparison, so one hue, not five. The status dot
   beside each label keeps the verdict identity without a five-way colour
   adjacency the palette cannot pass. */
.bars { display: flex; flex-direction: column; gap: .55rem; }
.bar-row { display: grid; grid-template-columns: minmax(140px, 15rem) 1fr auto; gap: .7rem; align-items: center; }
.bar-row .b-label { display: flex; align-items: center; gap: .4rem; font-size: 0.78125rem; color: var(--ink-2); }
.bar-track { background: var(--seq-track); border-radius: 0 4px 4px 0; height: 12px; overflow: hidden; }
.bar-fill {
  display: block; height: 100%; background: var(--seq);
  border-radius: 0 4px 4px 0;   /* rounded data-end, square at the baseline */
  min-width: 2px;
}
.bar-row .b-value { font-size: 0.8125rem; font-weight: 650; font-variant-numeric: tabular-nums; min-width: 2.5rem; text-align: right; }
.bar-row.is-zero .b-value { color: var(--muted); font-weight: 500; }

/* Heat-tinted counts. The number is always ink; the tint is a second channel. */
td.heat { position: relative; text-align: right; font-variant-numeric: tabular-nums; }
td.heat > span { position: relative; z-index: 1; }
td.heat::before {
  content: ""; position: absolute; inset: 2px; border-radius: 3px;
  background: var(--heat, transparent);
}

/* Compact action list — one line per thing to do. */
.todo { display: flex; flex-direction: column; }
.todo-item {
  display: grid; grid-template-columns: auto 1fr auto; gap: .7rem;
  align-items: baseline; padding: .6rem 1.1rem;
  border-bottom: 1px solid var(--line-2);
}
.todo-item:last-child { border-bottom: 0; }
.todo-item:hover { background: var(--surface-2); }
.todo-item .t-what { min-width: 0; }
.todo-item .t-name { font-weight: 550; font-size: 0.8125rem; }
.todo-item .t-meta { font-size: 0.71875rem; color: var(--muted); margin-top: .1rem; }
.todo-item .t-where { font-size: 0.71875rem; white-space: nowrap; }

.all-clear {
  display: flex; align-items: center; gap: .5rem;
  padding: 1.1rem; font-size: 0.8125rem; color: var(--ink-2);
}
.all-clear .ico { color: var(--good); width: 18px; height: 18px; }

/* ------------------------------------------------------------------- icons */

/* A base size for every icon. Without this, an icon used anywhere that has no
   context rule of its own inherits nothing and draws at the SVG's natural size —
   a 24px glyph stretched to fill its box, which is how a ladder ended up the
   height of a paragraph in the escalation heading. Context rules below still
   win on specificity. */
.ico { width: 16px; height: 16px; flex: 0 0 auto; vertical-align: -3px; }

/* ------------------------------------------------------------ status atoms */

.dot {
  width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex: 0 0 auto;
  box-shadow: 0 0 0 1px var(--ring);
}
.dot.match, .dot.good { background: var(--good); }
.dot.over { background: var(--warning); }
.dot.conflict { background: var(--serious); }
.dot.gap { background: var(--critical); }
.dot.na { background: var(--neutral); }
.dot.blank { background: transparent; box-shadow: inset 0 0 0 1.5px var(--muted); }

.verdict { display: inline-flex; align-items: center; gap: .4rem; white-space: nowrap; }

/* Chip = dot + label + tint. The label is what carries meaning. */
.chip {
  display: inline-flex; align-items: center; gap: .35rem;
  font-size: 0.71875rem; font-weight: 600; white-space: nowrap;
  padding: .15rem .5rem; border-radius: 999px;
  background: var(--neutral-bg); color: var(--ink-2);
  border: 1px solid transparent;
}
.chip.match { background: var(--good-bg); color: #0a6b0a; }
.chip.over { background: var(--warning-bg); color: #8a5d00; }
.chip.conflict { background: var(--serious-bg); color: #9c4a24; }
.chip.gap { background: var(--critical-bg); color: #a12727; }
.chip.na, .chip.blank { background: var(--neutral-bg); color: var(--muted); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .chip.match { color: #6ede6e; }
  :root:not([data-theme="light"]) .chip.over { color: #f5c65c; }
  :root:not([data-theme="light"]) .chip.conflict { color: #f0a17e; }
  :root:not([data-theme="light"]) .chip.gap { color: #f08b8b; }
}
:root[data-theme="dark"] .chip.match { color: #6ede6e; }
:root[data-theme="dark"] .chip.over { color: #f5c65c; }
:root[data-theme="dark"] .chip.conflict { color: #f0a17e; }
:root[data-theme="dark"] .chip.gap { color: #f08b8b; }

.pill {
  display: inline-flex; align-items: center; gap: .25rem;
  font-size: 0.65625rem; font-weight: 650; letter-spacing: .02em;
  padding: .1rem .4rem; border-radius: var(--r-sm);
  border: 1px solid var(--line); color: var(--ink-2); background: var(--surface-2);
}
.pill.core { border-color: #f0c9c9; color: #a12727; background: var(--critical-bg); }
.pill.on { border-color: #bfe6bf; color: #0a6b0a; background: var(--good-bg); }
.pill.off { color: var(--muted); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pill.core { border-color: #5a2b2b; color: #f08b8b; }
  :root:not([data-theme="light"]) .pill.on { border-color: #2a5a2a; color: #6ede6e; }
}

/* ------------------------------------------------------------------ tables */

table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 0.8125rem; }
thead th {
  background: var(--surface-2); color: var(--ink-2);
  font-weight: 600; font-size: 0.65625rem; letter-spacing: .06em; text-transform: uppercase;
  text-align: left; padding: .55rem .7rem;
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 2; white-space: nowrap;
}
tbody td, tbody th {
  padding: var(--cell-y) .7rem; border-bottom: 1px solid var(--line-2);
  line-height: var(--cell-line);
  text-align: left; vertical-align: top; font-weight: 400;
}
tbody tr:last-child td, tbody tr:last-child th { border-bottom: 0; }
tbody tr:hover td, tbody tr:hover th { background: var(--surface-2); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
td.mid, th.mid { text-align: center; }
tfoot td {
  padding: .55rem .7rem; font-weight: 650; background: var(--surface-2);
  border-top: 1px solid var(--line); font-size: 0.78125rem;
}
.table-scroll { overflow-x: auto; }
.table-scroll table.matrix { min-width: max-content; }
td.prose { white-space: normal; max-width: 46ch; }
td.prose-wide { white-space: normal; max-width: 62ch; }
.zero { color: var(--muted); }
.flag { color: var(--critical); font-weight: 650; }
.strong { font-weight: 650; }
.cell-title { font-weight: 550; color: var(--ink); }
.cell-sub { font-size: 0.71875rem; color: var(--muted); margin-top: .1rem; }

/* ---------------------------------------------------------------- controls */

.btn {
  display: inline-flex; align-items: center; gap: .4rem;
  font: inherit; font-size: 0.8125rem; font-weight: 600; line-height: 1.2;
  padding: .48rem .85rem; border-radius: var(--r-sm); cursor: pointer;
  border: 1px solid var(--brand); background: var(--brand); color: #fff;
  transition: background .12s ease, border-color .12s ease;
  white-space: nowrap;
}
.btn:hover { background: var(--brand-ink); border-color: var(--brand-ink); text-decoration: none; }
.btn .ico { width: 15px; height: 15px; }
.btn.ghost { background: var(--surface); color: var(--ink); border-color: var(--line); box-shadow: var(--shadow); }
.btn.ghost:hover { background: var(--surface-2); border-color: var(--muted); }
.btn.danger { background: var(--critical); border-color: var(--critical); }
.btn.danger:hover { background: #b02f2f; border-color: #b02f2f; }
.btn.small { padding: .3rem .6rem; font-size: 0.75rem; }
.btn.link { background: none; border: 0; color: var(--brand-ink); box-shadow: none; padding: .2rem .3rem; }
.btn.link:hover { background: var(--surface-2); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible,
textarea:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

label.field { display: block; margin-bottom: .9rem; font-size: 0.78125rem; color: var(--ink-2); font-weight: 600; }
label.field > span { display: block; margin-bottom: .3rem; }
label.field .hint { font-weight: 400; color: var(--muted); }

input[type="text"], input[type="email"], input[type="password"], input[type="date"],
select, textarea {
  width: 100%; font: inherit; font-size: 0.8125rem; color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: .45rem .6rem;
  box-shadow: var(--shadow);
}
input:focus, select:focus, textarea:focus { border-color: var(--accent); }
textarea { min-height: 72px; resize: vertical; }
select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2 4.5l4 3 4-3' fill='none' stroke='%238a93a3' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .5rem center;
  padding-right: 1.7rem;
}

/* Drop zone for the document uploads */
.dropzone {
  border: 1.5px dashed var(--line); border-radius: var(--r);
  background: var(--surface-2); padding: 1rem;
  display: flex; gap: .8rem; align-items: flex-start;
  transition: border-color .12s ease, background .12s ease;
}
.dropzone:hover, .dropzone.has-file { border-color: var(--accent); background: var(--surface); }
.dropzone .ico { width: 22px; height: 22px; color: var(--muted); flex: 0 0 auto; margin-top: .1rem; }
.dropzone.has-file .ico { color: var(--good); }
.dropzone .dz-body { min-width: 0; flex: 1; }
.dropzone .dz-title { font-weight: 600; font-size: 0.8125rem; color: var(--ink); }
.dropzone .dz-hint { font-size: 0.71875rem; color: var(--muted); margin-top: .1rem; }
.dropzone .dz-file { font-size: 0.75rem; color: var(--good); font-weight: 600; margin-top: .3rem; word-break: break-all; }
.dropzone input[type="file"] { margin-top: .5rem; font-size: 0.75rem; width: 100%; }

.filters {
  display: flex; gap: .6rem; align-items: flex-end; flex-wrap: wrap;
  padding: .85rem 1.1rem; border-bottom: 1px solid var(--line-2);
  background: var(--surface-2); border-radius: var(--r) var(--r) 0 0;
}
.filters label.field { margin: 0; min-width: 155px; }
.filters .check { display: flex; align-items: center; gap: .35rem; font-size: 0.78125rem; font-weight: 500; color: var(--ink-2); }
.filters .check input { width: auto; box-shadow: none; }
.filters .sep { flex: 1; }

/* ---------------------------------------------------------------- notices */

.notice {
  display: flex; gap: .65rem; align-items: flex-start;
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  background: var(--surface); box-shadow: var(--shadow);
  padding: .75rem .9rem; border-radius: var(--r-sm);
  margin-bottom: 1rem; font-size: 0.8125rem;
}
.notice .ico { width: 17px; height: 17px; flex: 0 0 auto; margin-top: .1rem; color: var(--accent); }
.notice.ok { border-left-color: var(--good); background: var(--good-bg); }
.notice.ok .ico { color: var(--good); }
.notice.warn { border-left-color: var(--serious); background: var(--serious-bg); }
.notice.warn .ico { color: var(--serious); }
.notice.error { border-left-color: var(--critical); background: var(--critical-bg); }
.notice.error .ico { color: var(--critical); }
.notice strong { display: block; margin-bottom: .1rem; }
.notice code { font-size: 0.75rem; }
.notice pre { white-space: pre-wrap; margin: .4rem 0 0; font-size: 0.75rem; }

/* ----------------------------------------------------------------- matrix */

.matrix { font-size: 0.78125rem; }
.matrix tbody td { vertical-align: top; padding: var(--cell-y-tight) .55rem; }
.matrix tbody tr.group-head td {
  background: var(--sidebar); color: #fff; font-weight: 650;
  font-size: 0.65625rem; letter-spacing: .07em; text-transform: uppercase;
  padding: .4rem .7rem; border-bottom: 0;
}
.matrix tbody tr.group-head:hover td { background: var(--sidebar); }
/* Seven columns is a lot. Widths are tight on purpose so the whole row fits a
   1600px screen without the last column falling off the edge. */
.matrix td.param { min-width: 190px; max-width: 240px; white-space: normal; }
.matrix td.param .name { font-weight: 600; color: var(--ink); }
.matrix td.param .ref { color: var(--muted); font-size: 0.6875rem; margin-top: .1rem; }
.matrix td.cell { min-width: 148px; max-width: 172px; }
.matrix td.note-cell { min-width: 210px; max-width: 260px; white-space: normal; }
.matrix td.why-cell { min-width: 218px; max-width: 268px; white-space: normal; }

/* A row that is not a deviation has nothing to explain and nobody to agree it
   with, so it carries no controls at all — just a note saying so. Four inert
   dropdowns on every Match row was most of what made this table hard to read.
   The script clones the controls in if an edit turns the row into a deviation. */
.matrix td.why-cell.not-deviation::before {
  content: "no deviation"; font-size: 0.6875rem; color: var(--muted);
}
.matrix td.why-cell.not-deviation:has(.agree-grid)::before { content: none; }
.disposition-cell { margin-bottom: .3rem; }
.agree-grid { display: grid; grid-template-columns: 1.15fr 1fr 1fr; gap: .25rem; margin-top: .3rem; }
.agree-grid .cell-select { padding-right: 1.1rem; background-position: right .25rem center; }
.agree { display: block; font-size: 0.625rem; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); }
.agree > span { display: block; margin-bottom: .1rem; }
.matrix .standard { color: var(--muted); font-size: 0.71875rem; min-width: 110px; max-width: 150px; white-space: normal; }

.note-grid { display: grid; grid-template-columns: 1fr 1fr 1.6fr; gap: .25rem; margin-top: .25rem; }
.note-grid input { font-size: 0.71875rem; padding: .22rem .35rem; }

.cell-input, .cell-select {
  width: 100%; background: var(--input-tint);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: .32rem .45rem; font: inherit; font-size: 0.78125rem; color: var(--ink);
  box-shadow: none;
}
.cell-input:hover, .cell-select:hover { border-color: var(--muted); }
.cell-input:focus, .cell-select:focus { border-color: var(--accent); background: var(--surface); }
.cell-input.saved, .cell-select.saved { animation: flash-saved 1.1s ease-out; }
.cell-input.failed, .cell-select.failed { border-color: var(--critical); background: var(--critical-bg); }
@keyframes flash-saved {
  0% { background: var(--good-bg); border-color: var(--good); }
  100% { background: var(--input-tint); }
}
.note-input { background: var(--surface); min-height: 0; height: auto; field-sizing: content; resize: vertical; }
.cell-select.small { font-size: 0.71875rem; padding: .2rem .35rem; margin-top: .2rem; }
/* Evidence is the quote that makes a finding defensible, but a paragraph of it
   in every cell sets the height of every row. Three lines, and the full text on
   hover — the whole quote is still one gesture away, and rows stay comparable. */
.evidence {
  margin-top: .28rem; font-size: 0.6875rem; color: var(--muted);
  border-left: 2px solid var(--line); padding-left: .4rem; line-height: 1.4;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden;
}
.matrix tbody tr:hover .evidence { -webkit-line-clamp: unset; }
.readonly-cell { padding: .3rem .4rem; font-size: 0.78125rem; white-space: pre-wrap; }

/* ------------------------------------------------------------------- misc */

details.disclose {
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); box-shadow: var(--shadow); margin-bottom: 1rem;
}
details.disclose summary {
  cursor: pointer; font-weight: 600; font-size: 0.8125rem; padding: .8rem 1.1rem;
  list-style: none; display: flex; align-items: center; gap: .5rem;
}
details.disclose summary::-webkit-details-marker { display: none; }
details.disclose summary::before {
  content: ""; width: 0; height: 0; flex: 0 0 auto;
  border-left: 5px solid var(--muted); border-top: 4px solid transparent;
  border-bottom: 4px solid transparent; transition: transform .15s ease;
}
details.disclose[open] summary::before { transform: rotate(90deg) translateX(1px); }
details.disclose .disclose-body { padding: 0 1.1rem 1.1rem; border-top: 1px solid var(--line-2); padding-top: 1rem; }

.empty {
  text-align: center; padding: 3rem 1.5rem; color: var(--ink-2);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--shadow);
}
.empty .ico { width: 40px; height: 40px; color: var(--muted); margin-bottom: .75rem; }
.empty h2 { color: var(--ink); margin-bottom: .35rem; font-size: 1.05rem; }
.empty p { max-width: 52ch; margin: 0 auto 1.1rem; font-size: 0.8125rem; }

/* Sign-in is the one page without the shell. */
.auth {
  min-height: 100vh; display: grid; place-items: center; padding: 1.5rem;
  background:
    radial-gradient(1100px 500px at 50% -8%, color-mix(in srgb, var(--accent) 13%, transparent), transparent),
    var(--canvas);
}
.auth .box { width: 100%; max-width: 384px; }
.auth .brand { display: flex; align-items: center; gap: .65rem; justify-content: center; margin-bottom: 1.25rem; }
.auth .brand .mark {
  width: 34px; height: 34px; border-radius: 9px;
  background: linear-gradient(135deg, #2a78d6, #1f3864);
  display: grid; place-items: center; color: #fff; font-weight: 700; font-size: 0.875rem;
}
.auth .card { margin: 0; }
.auth .card > .card-body { padding: 1.5rem; }
.auth .legal { text-align: center; font-size: 0.71875rem; color: var(--muted); margin-top: 1rem; }

.foot-note { padding: 1.5rem; color: var(--muted); font-size: 0.71875rem; text-align: center; }

@media print {
  .sidebar, .topbar, .actions, .filters, .foot-note { display: none !important; }
  .app { grid-template-columns: 1fr; }
  body { background: #fff; }
  .card { break-inside: avoid; box-shadow: none; }
}

/* ------------------------------------------- escalation, contacts, perms */

/* A heading that separates page sections without pretending to be a card. */
.section-head { margin: 1.6rem 0 .7rem; }
.section-head h2 { font-size: 1.05rem; font-weight: 650; letter-spacing: -.01em; }
.section-head .sub { font-size: 0.78125rem; color: var(--muted); margin-top: .15rem; }
.card-head h2 .ico { width: 15px; height: 15px; vertical-align: -2px; margin-right: .3rem; color: var(--muted); }

/* Contact rows: inputs sit flush in the cell, like the matrix. */
table.contacts td { padding: .35rem .4rem; vertical-align: middle; }
table.contacts td .cell-input { width: 100%; }
table.contacts .readonly-cell { font-size: 0.78125rem; }

/* Add-a-row strip in the card footer: wraps rather than scrolling the page. */
.add-row { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
.add-row input { width: auto; }

/* Capability grid. The tick carries a text alternative, so the meaning does not
   depend on seeing a glyph or a colour. */
table.perms th[scope], table.perms tbody th { font-weight: 500; }
table.perms .yes { color: var(--good); display: inline-flex; }
table.perms .no { color: var(--muted); }
.ico-sm { width: 15px; height: 15px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Delete, in a row of otherwise safe actions. */
.btn.ghost.danger-link { color: var(--critical); }
.btn.ghost.danger-link:hover { border-color: var(--critical); background: var(--critical-bg); }

/* --------------------------------------------------------- alert volume */

/* A bar with a threshold marker on it. CSS, not SVG: a fluid SVG stretches its
   strokes, so a 2px marker becomes a smear at wide viewports. */
.cap-track {
  position: relative; display: block; width: 100%; height: 16px;
  border-radius: 0 4px 4px 0;
  /* .bar-track clips its fill, which would also clip the threshold marker —
     it deliberately overhangs the bar by 3px at each end. */
  overflow: visible;
}
.cap-marker {
  position: absolute; top: -3px; bottom: -3px; width: 0;
  border-left: 2px dashed var(--ink);
}
.volume td, .volume th { vertical-align: middle; }

/* Small multiples: one trend per account, all on the period the filter chose. */
.trend-grid {
  display: grid; gap: .9rem;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
.trend {
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface-2); padding: .7rem .8rem;
}
.trend-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.trend-head .t-name { font-weight: 600; font-size: 0.8125rem; color: var(--ink); }
.trend .chart { display: block; width: 100%; height: 56px; margin: .45rem 0 .25rem; }
.trend-foot {
  display: flex; justify-content: space-between; gap: .5rem;
  font-size: 0.65625rem; color: var(--muted);
}

/* A stacked row of segments. Named .mix, not .stack: .stack is already a
   vertical layout utility in this file, and redefining it here would silently
   turn every existing vertical stack into a horizontal one. */
.mix { display: flex; gap: 2px; height: 14px; width: 100%; }
.mix .seg { min-width: 2px; }
.mix .seg:first-child { border-radius: 3px 0 0 3px; }
.mix .seg:last-child { border-radius: 0 3px 3px 0; }

.leg { display: flex; flex-wrap: wrap; gap: .3rem 1rem; }
.leg-item { display: inline-flex; align-items: center; gap: .35rem; font-size: 0.75rem; color: var(--ink-2); }
.swatch { width: 10px; height: 10px; border-radius: 2px; display: inline-block; flex: 0 0 auto; }

.kpi .k-of { font-size: 0.9375rem; color: var(--muted); font-weight: 600; }

/* ------------------------------------------- SOC customer dashboard (mockup) */

.live-pill {
  display: inline-flex; align-items: center; gap: .45rem;
  font-size: 0.75rem; color: var(--good); background: var(--good-bg);
  padding: .35rem .7rem; border-radius: 999px; white-space: nowrap;
}
.live-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--good); flex: 0 0 auto; }
@media (prefers-reduced-motion: no-preference) {
  .live-dot { animation: live-pulse 1.8s ease-in-out infinite; }
}
@keyframes live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

.tabs-row {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  border-bottom: 1px solid var(--line); margin: 0 0 1.1rem;
}
/* Scoped to `.tabs-row`, which is the only place these appear.
   They were unscoped, and being later in the file they were quietly overriding
   the account tab bar's own padding, font size, gap and border — so the four
   account tabs had been rendering in the alert dashboard's dimensions rather than
   their own. Two rule sets with the same names is the kind of collision that
   never announces itself; it just makes one of the two look slightly wrong. */
.tabs-row .tabs { display: flex; gap: .25rem; }
.tabs-row .tab {
  appearance: none; background: none; border: 0; cursor: pointer;
  font: inherit; font-size: 0.84375rem; font-weight: 500; color: var(--muted);
  padding: .7rem 1.15rem; margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  border-radius: 0;
}
.tabs-row .tab:hover { color: var(--ink-2); background: none; }
.tabs-row .tab.is-on { color: var(--ink); border-bottom-color: var(--accent); font-weight: 600; }
.span-form { display: flex; align-items: center; gap: .5rem; padding-bottom: .5rem; }
.field.inline { display: flex; align-items: center; gap: .45rem; margin: 0; }
.field.inline > span {
  font-size: 0.6875rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted);
}
.field.inline select { width: auto; min-width: 132px; }

/* Panes: one at a time, and one is always on with JS off. */
.pane { display: none; }
.pane.is-on { display: block; }

.sum-grid {
  display: grid; gap: .85rem; margin-bottom: 1.4rem;
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
}
.sum-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); padding: .9rem 1rem; box-shadow: var(--shadow);
}
.sum-card.alert { background: var(--critical-bg); border-color: #f0c9c9; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .sum-card.alert { border-color: #5a2b2b; }
}
.sum-lbl { font-size: 0.75rem; color: var(--ink-2); }
.sum-val { font-size: 1.7rem; font-weight: 700; letter-spacing: -.02em; margin: .2rem 0 .1rem; }
.sum-val.crit { color: var(--critical); }
.sum-val .of { font-size: 0.875rem; color: var(--muted); font-weight: 600; }
.sum-sub { font-size: 0.71875rem; color: var(--muted); line-height: 1.35; }

.section-title { font-size: 0.875rem; font-weight: 600; margin: 0 0 .2rem; }
.section-title.mt { margin-top: 1.9rem; }
.section-sub { font-size: 0.75rem; color: var(--muted); margin-bottom: .8rem; }

.cmp-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--shadow); padding: 1rem 1.1rem;
}
.cmp-card.mt { margin-top: 1.9rem; }
.cmp-card .table-scroll { margin: .5rem -1.1rem -1rem; }
.cmp-card .card-head { padding: 0 0 .6rem; border: 0; }

.leg { display: flex; flex-wrap: wrap; gap: .35rem 1.1rem; margin-bottom: .9rem; }
.leg-item { display: inline-flex; align-items: center; gap: .4rem; font-size: 0.71875rem; color: var(--ink-2); }
.leg-dash { width: 15px; border-top: 2px dashed var(--ink); display: inline-block; }
.swatch { width: 11px; height: 11px; border-radius: 3px; display: inline-block; flex: 0 0 auto; }

/* Ranked horizontal bars with a threshold marker. */
.hbars { display: flex; flex-direction: column; gap: .45rem; }
.hbar-row {
  display: grid; gap: .7rem; align-items: center;
  grid-template-columns: minmax(104px, 14%) 1fr 3.4rem 5.6rem;
}
.hb-name { font-size: 0.78125rem; font-weight: 550; color: var(--ink); }
.hb-track {
  position: relative; display: block; height: 18px;
  background: var(--seq-track); border-radius: 0 4px 4px 0;
}
.hb-fill { display: block; height: 100%; border-radius: 0 4px 4px 0; min-width: 2px; }
.cap-marker {
  position: absolute; top: -3px; bottom: -3px; width: 0;
  border-left: 2px dashed var(--ink);
}
.hb-val { font-size: 0.8125rem; font-weight: 650; text-align: right; }
.hb-mult { font-size: 0.71875rem; color: var(--muted); text-align: right; }

/* Trend cards, each with its own period switch. */
.trend-grid {
  display: grid; gap: .85rem;
  grid-template-columns: repeat(auto-fill, minmax(330px, 1fr));
}
.trend-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--shadow); padding: .9rem 1rem;
}
.trend-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.trend-name { font-size: 0.84375rem; font-weight: 600; color: var(--ink); }
.seg { display: inline-flex; background: var(--surface-2); border-radius: 8px; padding: 3px; gap: 2px; flex: 0 0 auto; }
.seg button {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  font: inherit; font-size: 0.6875rem; font-weight: 500; color: var(--muted);
  padding: .28rem .55rem; border-radius: 6px; white-space: nowrap;
}
.seg button:hover { color: var(--ink-2); }
.seg button.is-on { background: var(--surface); color: var(--ink); box-shadow: var(--shadow); }
.trend-body { display: none; }
.trend-body.is-on { display: block; }
.trend-meta { font-size: 0.71875rem; color: var(--muted); margin: .55rem 0 .1rem; }
.trend-meta b { color: var(--ink); }
.trend-meta b.over { color: var(--critical); }
svg.area { display: block; width: 100%; height: auto; }
svg.area .ax { font-size: 0.5625rem; fill: var(--muted); }

/* Donut cards. */
.split-grid {
  display: grid; gap: .85rem;
  grid-template-columns: repeat(auto-fill, minmax(292px, 1fr));
}
.mini-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: var(--shadow); padding: .9rem 1rem;
}
.mini-card h4 {
  font-size: 0.8125rem; font-weight: 600; margin: 0 0 .7rem;
  display: flex; justify-content: space-between; align-items: baseline; gap: .5rem;
}
.mini-card h4 span { font-size: 0.6875rem; font-weight: 400; color: var(--muted); }
.chart-wrap { display: flex; align-items: center; gap: 1rem; }
.chart-donut { width: 104px; flex: 0 0 auto; }
svg.donut { display: block; width: 100%; height: auto; }
.chart-nums { flex: 1; display: flex; flex-direction: column; gap: .4rem; min-width: 0; }
.chart-num { display: flex; align-items: center; justify-content: space-between; gap: .5rem; font-size: 0.75rem; }
.chart-num .cn-lbl { display: inline-flex; align-items: center; gap: .45rem; color: var(--ink-2); min-width: 0; }
.chart-num .cn-val { font-weight: 650; }
.chart-num .cn-pct { font-size: 0.6875rem; color: var(--muted); margin-left: .35rem; }

/* A stacked mix inside a table cell. */
.mix { display: flex; gap: 2px; height: 14px; width: 100%; }
.mix .seg-bar { min-width: 2px; }
.mix .seg-bar:first-child { border-radius: 3px 0 0 3px; }
.mix .seg-bar:last-child { border-radius: 0 3px 3px 0; }

/* Live refresh: hold the last good render, never blank it. */
.live-dot.is-off { background: var(--muted); animation: none; }
[data-live-refresh].is-stale .sum-val { opacity: .55; transition: opacity .2s ease; }
[data-live-refresh].is-stale .live-pill { color: var(--muted); background: var(--neutral-bg); }
[data-live-refresh].is-stale .live-dot { background: var(--muted); animation: none; }
.just-changed { animation: just-changed 1.2s ease-out; }
@keyframes just-changed {
  0% { background: var(--warning-bg); }
  100% { background: transparent; }
}

/* Two-document coverage table: a hairline between the SOW block and the Manual
   block, so eight numeric columns read as two groups of four. */
.coverage th.group-start, .coverage td.group-start { border-left: 1px solid var(--line); }
.coverage thead tr:first-child th[colspan] { text-align: center; }
.coverage td.num .meter { margin-top: .3rem; min-width: 48px; }

/* ------------------------------------------------------------- your profile */

/* Three tabs, and only the appearance one needs a layout: controls on the left,
   a preview that stays put on the right. The other two are ordinary two-card
   grids and use `.grid.two` like every other page. */
.prof-layout {
  display: grid; gap: 1.2rem;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 26rem);
  align-items: start;
}
.prof-controls { display: grid; gap: .9rem; min-width: 0; }

/* The preview is the whole reason for the two columns, so it stays in view while
   the controls scroll past it. `top` clears the sticky topbar. */
.prof-aside { position: sticky; top: 4.2rem; min-width: 0; }

@media (max-width: 1080px) {
  .prof-layout { grid-template-columns: minmax(0, 1fr); }
  /* Stacked, the preview belongs above the controls — underneath it would be
     below the fold at the moment you are choosing. */
  .prof-aside { position: static; order: -1; }
}

/* A fieldset drawn as a card. `min-width: 0` because a fieldset defaults to
   min-content width in a grid and would refuse to shrink. */
.prof-set { border: 0; margin: 0; min-width: 0; padding: .9rem 1rem 1rem; }
.prof-legend {
  padding: 0; font-size: 0.875rem; font-weight: 600; color: var(--ink);
}
.prof-hint {
  margin: .25rem 0 .7rem; font-size: 0.75rem; color: var(--muted);
  max-width: 68ch;
}

.prof-opts { display: grid; gap: .45rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 620px) { .prof-opts { grid-template-columns: minmax(0, 1fr); } }

/* A radio drawn as a card. The native input is kept in the accessibility tree
   rather than replaced, so the group still arrows through from a keyboard and
   reads as a radio group — the label carries the styling, the input the meaning. */
.prof-opt {
  display: flex; gap: .55rem; align-items: flex-start;
  padding: .55rem .65rem; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); transition: border-color .12s, background .12s;
}
.prof-opt:hover { border-color: var(--brand-ink); }
.prof-opt input[type="radio"] { margin: .15rem 0 0; flex: 0 0 auto; accent-color: var(--accent); }
.prof-opt.is-on { border-color: var(--accent); background: var(--input-tint); }
.prof-opt:focus-within { outline: none; box-shadow: 0 0 0 3px var(--ring); }

.prof-opt-body { display: flex; flex-direction: column; min-width: 0; }
.prof-opt-name { font-size: 0.8125rem; font-weight: 600; color: var(--ink); }
.prof-opt-why { font-size: 0.6875rem; color: var(--muted); margin-top: .1rem; }

/* Save, pinned to the bottom of the window. Five settings is more than one
   screen at the larger text sizes, and a Save button you have to scroll back up
   to find is a Save button people stop pressing. */
.prof-bar {
  position: sticky; bottom: 0; z-index: 5;
  display: flex; gap: .55rem; align-items: center; flex-wrap: wrap;
  margin-top: 1.2rem; padding: .8rem 1rem;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg);
}

.prof-form { display: grid; gap: .9rem; max-width: 44ch; }
.field { display: flex; flex-direction: column; gap: .25rem; }
.field-label { font-size: 0.75rem; font-weight: 600; color: var(--ink-2); }
.field input {
  font: inherit; font-size: 0.8125rem; padding: .45rem .6rem;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink);
}
.field input:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--ring); }
.field-note { font-size: 0.6875rem; color: var(--muted); max-width: 52ch; }

/* Prose with a bold lead per point, for the "how this works" panels. */
.prose-list { margin: 0; padding-left: 1.15rem; }
.prose-list li { font-size: 0.78125rem; color: var(--ink-2); line-height: 1.55; margin-bottom: .55rem; }
.prose-list li:last-child { margin-bottom: 0; }
.prose-list strong { color: var(--ink); font-weight: 600; }

/* The preview panel.
   The appearance rules live on :root, and a :root selector cannot match a div —
   so the panel needs its own copy of each one. Kept next to the controls rather
   than beside the :root block, because these two lists have to be edited
   together and a reader needs to see that. */
.prof-preview {
  border: 1px solid var(--line); border-radius: var(--r);
  overflow: hidden; background: var(--surface);
  font-family: var(--sans);
}
.prof-preview-head {
  padding: .4rem .7rem; background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  font-size: 0.65625rem; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-2);
}
.prof-preview table { font-size: 0.8125rem; }
.prof-preview-prose {
  margin: 0; padding: .7rem;
  border-top: 1px solid var(--line-2);
  font-size: 0.75rem; color: var(--ink-2); line-height: 1.55;
}

.prof-preview[data-font="humanist"] { --sans: "Segoe UI", Tahoma, Verdana, Geneva, sans-serif; }
.prof-preview[data-font="serif"]    { --sans: Georgia, Cambria, "Times New Roman", Times, serif; }
.prof-preview[data-font="mono"]     { --sans: "Cascadia Mono", Consolas, "SF Mono", Menlo, monospace; }

/* Size is the one rule the panel cannot copy. Everything inside is in rem, and
   rem is root-relative by definition, so setting a font-size on the panel would
   do nothing at all. `zoom` scales the subtree instead — the ratios below are the
   root sizes over 16px, so the panel matches what saving would actually give. */
.prof-preview[data-text="s"]  { zoom: .906; }
.prof-preview[data-text="l"]  { zoom: 1.094; }
.prof-preview[data-text="xl"] { zoom: 1.219; }

.prof-preview[data-density="compact"] { --cell-y: .3rem; --cell-y-tight: .22rem; --cell-line: 1.34; }

.prof-preview[data-motion="reduced"] *,
.prof-preview[data-motion="reduced"] *::before,
.prof-preview[data-motion="reduced"] *::after {
  animation-duration: 1ms !important;
  transition-duration: 1ms !important;
}

/* The colour mode is previewed on the whole page rather than in the panel: it is
   the one choice that changes the surface the panel is drawn on, so a swatch of
   it inside a light page would be a lie. */
.prof-preview[data-theme] { color-scheme: unset; }

/* ------------------------------------------------------- how to read a chart */

/* A question mark beside a heading that explains the chart under it.
   A real <button>, not a span with a title: a title attribute is invisible to
   touch, slow to appear, and cannot hold two sentences legibly. This shows on
   hover AND on keyboard focus, and stays up while the pointer is over the bubble
   itself so a long explanation can be read to the end. No JavaScript. */
.explain { position: relative; display: inline-flex; vertical-align: middle; }

.explain-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.15rem; height: 1.15rem; padding: 0; margin-left: .35rem;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); color: var(--ink-2);
  font: inherit; font-size: 0.6875rem; font-weight: 700; line-height: 1;
  cursor: help; transition: border-color .12s, color .12s, background .12s;
}
.explain-btn:hover { border-color: var(--accent); color: var(--accent); }
.explain-btn:focus-visible {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--ring);
}

.explain-pop {
  position: absolute; z-index: 40; top: calc(100% + .45rem); left: 0;
  width: max-content; max-width: min(42ch, 80vw);
  padding: .6rem .7rem;
  background: var(--surface); color: var(--ink-2);
  border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: var(--shadow-lg);
  font-size: 0.75rem; font-weight: 400; line-height: 1.5;
  text-align: left; text-transform: none; letter-spacing: normal;
  opacity: 0; visibility: hidden; transition: opacity .12s;
}
.explain-btn:hover + .explain-pop,
.explain-btn:focus-visible + .explain-pop,
.explain-pop:hover {
  opacity: 1; visibility: visible;
}

.explain-pop strong { color: var(--ink); font-weight: 600; }
.explain-pop ul { margin: .4rem 0 0; padding-left: 1.1rem; }
.explain-pop li { margin-bottom: .22rem; }
.explain-pop li:last-child { margin-bottom: 0; }

/* Near the right edge the bubble would hang off the page. A heading that knows
   it is on the right says so, and the bubble anchors from that side instead. */
.explain.from-right .explain-pop { left: auto; right: 0; }

/* --------------------------------------------------------- two-factor */

/* A six-digit code, typed once and quickly. Wide tracking and a monospace face
   so a transposed pair is visible before it is submitted rather than after. */
.code-input {
  font-family: "Cascadia Mono", Consolas, "SF Mono", Menlo, monospace;
  font-size: 1.05rem; letter-spacing: .32em; text-align: center;
  padding: .5rem .6rem; max-width: 11rem;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink);
}
.code-input:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--ring); }
.code-input:disabled { background: var(--surface-2); color: var(--muted); }
.code-input::placeholder { letter-spacing: .32em; color: var(--muted); }

/* The QR code.

   It carries a viewBox and no intrinsic size — see `app.mfa.qr_svg` for why —
   so it scales to this box instead of being cropped by it. `width: 100%` with
   `height: auto` and a square aspect ratio is what makes that true at every
   text size and in every column width; a fixed pixel size here is what cropped
   it before, and a cropped QR is not a smaller QR, it is an unscannable one.

   Sized generously on purpose. A phone camera at arm's length wants around
   200px, and this is the one image in the app whose whole job is to be
   photographed. */
.qr-wrap {
  display: block; margin: .7rem 0 .3rem; padding: .8rem;
  width: fit-content; max-width: 100%;
  background: #ffffff; color: #101828;
  border: 1px solid var(--line); border-radius: var(--r);
}
.qr-wrap .qr {
  display: block;
  width: min(16rem, 60vw); height: auto; aspect-ratio: 1;
  /* No anti-aliasing between modules — a blurred edge is what makes a scan
     fail at the margins. */
  shape-rendering: crispEdges;
}

/* CSS beats the `stroke` attribute segno writes, so the code takes the colour of
   the panel it is drawn on. The attribute stays a dark hex, so a printed page or
   a missing stylesheet still gives a scannable black code.

   The panel is white in both themes rather than themed: phone cameras are much
   better at dark-on-light than the reverse, and this is the one thing in the app
   that has to work through a camera. */
.qr-wrap .qr .qr-line { stroke: currentColor; }

/* The key, for anyone who cannot scan. Selectable in one gesture, and grouped
   in fours by the template because 32 unbroken characters get miscopied. */
code.secret {
  display: inline-block; margin: .35rem 0; padding: .35rem .55rem;
  font-size: 0.8125rem; letter-spacing: .06em;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-sm); user-select: all;
}

.enrol { margin: 0; padding-left: 1.3rem; }
.enrol > li { font-size: 0.8125rem; color: var(--ink-2); line-height: 1.55; margin-bottom: 1rem; }
.enrol > li:last-child { margin-bottom: 0; }
.enrol strong { color: var(--ink); font-weight: 600; display: block; }
.enrol-form { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; margin-top: .6rem; }

/* Recovery codes, shown once. Bordered and monospace so a screenshot or a
   printout is legible, and two columns so ten of them fit without scrolling. */
.codes-card { border-color: var(--warning); }
.codes {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .3rem .9rem; margin: .8rem 0; padding-left: 1.4rem;
}
@media (max-width: 620px) { .codes { grid-template-columns: minmax(0, 1fr); } }
.codes li { font-size: 0.8125rem; color: var(--ink-2); }
.codes code {
  font-size: 0.875rem; letter-spacing: .04em; color: var(--ink);
  user-select: all;
}

/* Turning a protection off. Tinted, because the difference between this and the
   form above it is that one of them makes the account weaker. */
.danger-zone {
  border-top: 1px solid var(--line);
  background: var(--critical-bg);
}
.danger-zone .field-label { color: var(--ink); }

.prose-list.two-col { columns: 2; column-gap: 2rem; }
.prose-list.two-col li { break-inside: avoid; }
@media (max-width: 900px) { .prose-list.two-col { columns: 1; } }

/* ------------------------------------------------------- written documents */

/* The manual and the SOP, read in the app. Two columns: a contents list that
   stays put, and prose at a measured width — this is the one page in the tool
   that is genuinely a document, and long-form text at the full width of a 1440px
   screen is unreadable however good the typography is. */
.doc-layout {
  display: grid; gap: 1.4rem;
  grid-template-columns: minmax(200px, 17rem) minmax(0, 1fr);
  align-items: start;
}
@media (max-width: 1000px) {
  .doc-layout { grid-template-columns: minmax(0, 1fr); }
  /* Stacked, the contents goes first: it is how somebody finds the one section
     they came for without scrolling the whole document. */
  .doc-nav { position: static; }
}

.doc-nav { position: sticky; top: 4.2rem; min-width: 0; }
.doc-toc { display: flex; flex-direction: column; padding: .4rem; }
.doc-toc a {
  display: flex; gap: .55rem; align-items: baseline;
  padding: .4rem .5rem; border-radius: var(--r-sm);
  color: var(--ink-2); text-decoration: none;
}
.doc-toc a:hover { background: var(--surface-2); color: var(--ink); text-decoration: none; }
.doc-toc-n {
  flex: 0 0 auto; min-width: 1.15rem; text-align: right;
  font-size: 0.6875rem; font-weight: 700; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.doc-toc-t { display: block; font-size: 0.78125rem; font-weight: 550; }
.doc-toc-s { display: block; font-size: 0.6875rem; color: var(--muted); margin-top: .1rem; }

.doc-body { min-width: 0; max-width: 72ch; display: grid; gap: 1.1rem; }
.doc-intro { margin: 0; font-size: 0.9375rem; line-height: 1.65; color: var(--ink-2); }

.doc-section {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow);
  padding: 1.3rem 1.5rem 1.5rem;
  /* So an anchor link does not park the heading under the sticky topbar. */
  scroll-margin-top: 4.5rem;
}
.doc-section h2 {
  display: flex; gap: .6rem; align-items: baseline;
  font-size: 1.0625rem; margin-bottom: .2rem;
}
.doc-n {
  flex: 0 0 auto;
  font-size: 0.75rem; font-weight: 700; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.doc-section h3 {
  font-size: 0.875rem; margin: 1.3rem 0 .4rem; color: var(--ink);
}
.doc-summary {
  margin: 0 0 1rem; font-size: 0.78125rem; color: var(--muted);
  padding-bottom: .8rem; border-bottom: 1px solid var(--line-2);
}

.doc-p { margin: 0 0 .75rem; font-size: 0.84375rem; line-height: 1.68; color: var(--ink-2); }
.doc-p.is-lead { color: var(--ink); font-weight: 600; margin-bottom: .35rem; }
.doc-p.is-muted { font-size: 0.75rem; color: var(--muted); }
.doc-lead {
  margin: .9rem 0 .35rem; font-size: 0.84375rem; font-weight: 600; color: var(--ink);
}

.doc-ul, .doc-ol { margin: 0 0 .9rem; padding-left: 1.35rem; }
.doc-ul li, .doc-ol li {
  font-size: 0.84375rem; line-height: 1.62; color: var(--ink-2); margin-bottom: .35rem;
}
.doc-ul li:last-child, .doc-ol li:last-child { margin-bottom: 0; }
.doc-ol li::marker { font-weight: 600; color: var(--muted); }

.doc-table { margin-bottom: .9rem; font-size: 0.78125rem; }
.doc-table thead th { white-space: normal; }
.doc-table td { line-height: 1.55; }
.doc-table tbody td:first-child { font-weight: 550; color: var(--ink); }

/* Sparingly used — three or four per document — so it keeps meaning "read this
   even if you are skimming". */
.doc-callout {
  display: flex; flex-direction: column; gap: .2rem;
  margin: .3rem 0 1rem; padding: .7rem .85rem;
  border-left: 3px solid var(--accent); border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: var(--surface-2);
  font-size: 0.8125rem; line-height: 1.6; color: var(--ink-2);
}
.doc-callout strong { color: var(--ink); }
.doc-callout.is-warn { border-left-color: var(--critical); background: var(--critical-bg); }

@media print {
  /* Printing the page rather than the Word file is a legitimate thing to do. */
  .sidebar, .doc-nav, .topbar, .actions { display: none !important; }
  .doc-layout { display: block; }
  .doc-body { max-width: none; }
  .doc-section { break-before: page; box-shadow: none; border: 0; padding: 0 0 1rem; }
  .doc-section:first-of-type { break-before: auto; }
}

/* ------------------------------------------------ the analysis date filter */

/* Only on the analysis tab. The live tab has no date control at all, which is
   the distinction between the two — so this lives inside the pane rather than
   beside the tab bar where it would look like it scoped both. */
.period-form {
  display: flex; gap: .9rem; align-items: center; flex-wrap: wrap;
  padding: .7rem .9rem; margin-bottom: .7rem;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow);
}

/* Submit buttons rather than a select, so the current window is visible instead
   of having to be opened — and so it still works with no JavaScript, which a
   select relying on `onchange` does not. */
.period-choices { display: flex; gap: 2px; flex-wrap: wrap; }
.period-opt {
  appearance: none; cursor: pointer;
  font: inherit; font-size: 0.78125rem; font-weight: 550;
  padding: .35rem .7rem; border-radius: var(--r-sm);
  border: 1px solid transparent; background: none; color: var(--ink-2);
}
.period-opt:hover { background: var(--surface-2); color: var(--ink); }
.period-opt.is-on {
  background: var(--surface); color: var(--brand-ink);
  border-color: var(--line); box-shadow: var(--shadow); font-weight: 650;
}
.period-opt:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--ring); }

.period-custom {
  display: flex; gap: .45rem; align-items: center; flex-wrap: wrap;
  margin-left: auto; padding-left: .9rem; border-left: 1px solid var(--line);
}
.period-custom input[type="date"] {
  font: inherit; font-size: 0.75rem; padding: .3rem .4rem;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink);
}
.period-custom input:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--ring); }
@media (max-width: 820px) {
  .period-custom { margin-left: 0; padding-left: 0; border-left: 0; }
}

/* What the visible tab is scoped to, said once beside the tab bar. A reader who
   cannot tell the live tab from a windowed one will misread both. */
.tabs-note { font-size: 0.71875rem; color: var(--muted); padding-bottom: .5rem; max-width: 46ch; }

.window-note {
  font-size: 0.78125rem; color: var(--ink-2); margin: 0 0 1.1rem;
}
.window-note strong { color: var(--ink); }

.trend-foot {
  margin-top: .4rem; font-size: 0.6875rem; color: var(--muted);
}

/* ----------------------------------------------------------- renewal pack */

/* Four tiles, and they are the argument rather than the bookkeeping. Bigger than
   the alert dashboard's because this page is read across a meeting-room table. */
.ren-tiles {
  display: grid; gap: .8rem; margin-bottom: 1.2rem;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 980px) { .ren-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .ren-tiles { grid-template-columns: minmax(0, 1fr); } }

.ren-tile {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow);
  padding: .9rem 1.1rem 1rem;
}
.ren-tile-lbl {
  font-size: 0.65625rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--muted); font-weight: 600;
}
.ren-tile-val {
  font-size: 2rem; font-weight: 680; letter-spacing: -.03em; line-height: 1.1;
  color: var(--ink); font-variant-numeric: tabular-nums; margin: .3rem 0 .15rem;
}
.ren-tile-note { font-size: 0.71875rem; color: var(--ink-2); }
/* The tone tints the number only. The label and the note stay ink, so a tile is
   still readable printed in grey — which is how half of these get read. */
.ren-tile.is-crit { border-top: 3px solid var(--critical); }
.ren-tile.is-crit .ren-tile-val { color: var(--critical); }
.ren-tile.is-warn { border-top: 3px solid var(--warning); }
.ren-tile.is-warn .ren-tile-val { color: var(--warning); }

/* The asks. Each one is a claim plus its evidence, and the chip says whether it
   is evidenced or still a conversation — sales should know before leading. */
.ren-asks { display: grid; gap: .7rem; }
.ren-ask {
  padding: .7rem .9rem; border-radius: var(--r);
  border-left: 3px solid var(--line); background: var(--surface-2);
}
.ren-ask.is-strong { border-left-color: var(--critical); }
.ren-ask.is-soft { border-left-color: var(--accent); }
.ren-ask-head {
  display: flex; gap: .6rem; align-items: baseline; flex-wrap: wrap;
  margin-bottom: .25rem;
}
.ren-ask-head strong { font-size: 0.875rem; color: var(--ink); }
.ren-ask p { margin: 0; font-size: 0.78125rem; line-height: 1.6; color: var(--ink-2); }

/* One track split at the entitlement. Two separate bars made the reader do the
   subtraction; this draws the answer. */
.ren-overage {
  display: flex; height: 2.4rem; margin: .3rem 0 .8rem;
  border-radius: var(--r-sm); overflow: hidden; background: var(--surface-2);
}
.ren-seg {
  display: flex; align-items: center; justify-content: center;
  font-size: 0.6875rem; font-weight: 650; color: #fff;
  white-space: nowrap; overflow: hidden;
}
.ren-seg.is-within { background: var(--seq); }
.ren-seg.is-over { background: var(--critical); }

.ren-mix-head {
  display: flex; gap: .5rem; align-items: baseline; flex-wrap: wrap;
  font-size: 0.78125rem; font-weight: 600; color: var(--ink); margin-bottom: .45rem;
}
.ren-mix-keys { display: flex; gap: .9rem; flex-wrap: wrap; margin-top: .5rem; }
.ren-key {
  display: inline-flex; gap: .3rem; align-items: baseline;
  font-size: 0.71875rem; color: var(--ink-2);
}

/* Two integers, side by side, at a size worth reading. A bar chart of 2 against
   1 was the first version and it was decoration around two numbers. */
.ren-pair {
  display: flex; gap: .6rem; align-items: center; flex-wrap: wrap;
  margin: .2rem 0 .6rem;
}
.ren-pair-n {
  font-size: 1.75rem; font-weight: 680; letter-spacing: -.03em;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.ren-pair-n.crit { color: var(--critical); }
.ren-pair-lbl { font-size: 0.6875rem; color: var(--ink-2); line-height: 1.3; }
.ren-pair-vs {
  font-size: 0.6875rem; text-transform: uppercase; letter-spacing: .08em;
  color: var(--muted); padding: 0 .3rem;
}

.ren-grow {
  display: inline-block; width: 1.05rem; text-align: center;
  font-weight: 700; color: var(--warning);
}

/* The term, month by month. A column per month: volume as the bar, the
   entitlement as a line across it, change requests as marks underneath. The
   accumulation is the argument a table of totals cannot make. */
.ren-months {
  display: flex; gap: 3px; align-items: flex-end;
  overflow-x: auto; padding-bottom: .3rem;
}
.ren-month { flex: 1 1 0; min-width: 26px; text-align: center; }
.ren-month-bar {
  position: relative; height: 6rem;
  background: var(--surface-2); border-radius: 2px 2px 0 0;
}
.ren-month-fill {
  position: absolute; left: 0; right: 0; bottom: 0;
  background: var(--seq); border-radius: 2px 2px 0 0;
}
.ren-month-fill.is-over {
  /* Over the month's own entitlement. The bar is one colour rather than two
     stacked, because the entitlement line above it already says where the
     boundary is and two encodings of one fact is one too many. */
  background: var(--critical);
}
.ren-month-cap {
  position: absolute; left: -1px; right: -1px; height: 0;
  border-top: 2px dashed var(--ink);
}
.ren-month-cap.is-key {
  position: static; display: inline-block; width: 14px;
  border-top: 2px dashed var(--ink); height: 0; vertical-align: middle;
}
.ren-month-marks {
  display: flex; gap: 2px; justify-content: center; flex-wrap: wrap;
  min-height: .7rem; padding-top: .25rem;
}
.ren-cr {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--muted);
}
.ren-cr.is-agreed { background: var(--good); border-color: var(--good); }
.ren-month-lbl {
  font-size: 0.5625rem; color: var(--muted); margin-top: .15rem;
  white-space: nowrap;
}
.ren-months-key {
  display: flex; gap: 1rem; flex-wrap: wrap; margin-top: .7rem;
  font-size: 0.6875rem; color: var(--ink-2);
}

.ren-inline-stats {
  display: flex; gap: 1.4rem; flex-wrap: wrap; margin-bottom: .5rem;
  font-size: 0.84375rem; color: var(--ink-2);
}
.ren-inline-stats b {
  font-size: 1.15rem; color: var(--ink); font-variant-numeric: tabular-nums;
}

/* ------------------------------------------ what a change moves in the matrix */

.line-form { display: grid; gap: .6rem; }
.line-form-row {
  display: flex; gap: .6rem; align-items: flex-end; flex-wrap: wrap;
}
.line-form-row .field.inline { margin: 0; }
.line-form-row .field.inline.grow { flex: 1 1 220px; min-width: 0; }
.line-form-row .field.inline > span {
  font-size: 0.6875rem; font-weight: 600; color: var(--ink-2);
}
.line-form select, .line-form input[type="text"] {
  font: inherit; font-size: 0.78125rem; padding: .35rem .5rem;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink); width: 100%;
}
.line-form select:focus, .line-form input:focus {
  border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--ring);
}

/* ---------------------------------------------------- customer sentiment */
/* The grid is the spreadsheet this replaces: people or accounts down the side,
 * weeks across. Cells are fixed-width and square-ish so a row reads as a
 * sequence rather than as a set of differently sized blocks.
 *
 * Every cell carries its letter. That is not decoration: the green and the red
 * separate poorly under deutan vision (measured, see app/charts.py), so the
 * letter is what actually carries the reading and the colour is the second
 * signal. Never remove the mark to tidy the grid up. */

.heat-grid { border-collapse: separate; border-spacing: 3px; }
.heat-grid th { font-weight: 600; }
.heat-grid thead th {
  font-size: 0.6875rem; font-weight: 600; color: var(--ink-2);
  text-align: center; padding: 0 0 .2rem; white-space: nowrap;
}
.heat-grid tbody th {
  text-align: left; font-size: 0.8125rem; padding-right: .6rem;
  white-space: nowrap; font-weight: 500;
}
.heat-grid tbody th .cell-sub { font-weight: 400; }

.heat-cell {
  width: 2.1rem; height: 1.9rem; padding: 0;
  border-radius: var(--r-sm);
  text-align: center; vertical-align: middle;
  font-size: 0.75rem; font-weight: 700; letter-spacing: .02em;
  color: #fff;
  font-family: var(--sans);
}
/* No reading taken: a hatch, not a colour. It is not a fourth level, it is the
 * absence of one, and it should not look like a level. */
.heat-cell.no-reading {
  background: repeating-linear-gradient(
    -45deg, var(--surface-2), var(--surface-2) 3px, var(--line) 3px, var(--line) 5px
  );
  color: var(--ink-3);
}
/* Nobody was asked at all. Fainter still than a non-reading, and empty. */
.heat-cell.is-missing {
  background: var(--surface-2);
  border: 1px dashed var(--line);
  color: var(--ink-3);
  font-weight: 400;
}
.heat-cell.is-current { outline: 2px solid var(--accent); outline-offset: 1px; }

.heat-index {
  font-variant-numeric: tabular-nums; font-weight: 700;
  font-size: 0.9375rem;
}
.heat-index.none { font-weight: 400; color: var(--ink-3); font-size: 0.8125rem; }

/* Movement against the window before this one. A number and an arrow — the
 * arrow alone is a direction with no size. */
.move { font-variant-numeric: tabular-nums; font-size: 0.8125rem; white-space: nowrap; }
.move.up { color: var(--c-166b43, #166b43); }
.move.down { color: var(--c-b32c24, #b32c24); }
.move.flat, .move.none { color: var(--ink-3); }

/* The weekly entry form: one row per stakeholder, all saved together. */
.week-form { display: flex; flex-direction: column; gap: .5rem; }
.week-row {
  display: grid;
  grid-template-columns: minmax(9rem, 1.1fr) minmax(7rem, .8fr) minmax(6rem, .7fr) minmax(10rem, 2fr);
  gap: .5rem; align-items: start;
  padding: .6rem; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface);
}
@media (max-width: 52rem) {
  .week-row { grid-template-columns: 1fr 1fr; }
}
.week-row .who { font-size: 0.8125rem; font-weight: 600; }
.week-row select, .week-row input[type="text"] {
  font: inherit; font-size: 0.8125rem; padding: .3rem .45rem; width: 100%;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink);
}
.week-row .lvl-label {
  font-size: 0.625rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-3); display: block; margin-bottom: .15rem;
}
.week-nav { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap; }

/* Two panels side by side, stacking early — used by the sentiment dashboard. */
.two-up {
  display: grid; gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}

/* A stack segment for readings that were taken but say nothing. Hatched rather
 * than coloured, for the same reason the grid cell is: it is not a level. */
.seg-bar.no-reading {
  background: repeating-linear-gradient(
    -45deg, var(--surface-2), var(--surface-2) 3px, var(--line) 3px, var(--line) 5px
  );
}
