/* ==========================================================================
   DECIDE by LEAN OCM — V4 design tokens and application shell
   UX/UI source of truth: docs/canonical/07_UX_DESIGN_SYSTEM.md

   Three-zone enterprise shell: A. left application sidebar, B. top utility bar,
   C. main workspace. The DECIDE lifecycle stepper lives inside the workspace
   and is never the application navigation.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Inter — controlled application asset (design system §4.1).
   Self-hosted, so the isolated preview renders the approved typeface with no
   external runtime dependency. Only the three approved weights are bundled;
   provenance and per-file hashes are in src/fonts/PROVENANCE.md.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/Inter-Regular.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/Inter-Medium.woff2") format("woff2");
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/Inter-SemiBold.woff2") format("woff2");
}

:root {
  color-scheme: light;

  /* Typography — approved LEAN OCM scale */
  --font-family-base: "Inter", "Segoe UI", Arial, sans-serif;
  /* Owner instruction 2026-09-23: every text size drops by one step of the ladder.
     The token NAMES are unchanged so no call site had to be touched, and the whole
     reduction is this one block — reverting these seven values restores the original
     scale exactly. The original scale was 10/11/12/13/14/16/20 and is recorded, with
     the rendered census, in /opt/data/concepts/type-scale/BASELINE-original-2026-09-23.txt
     and in docs/specs/NEXT-WORK.md. */
  --font-size-10: 9px;      /* was 10px */
  --font-size-11: 10px;     /* was 11px */
  --font-size-12: 11px;     /* was 12px */
  --font-size-13: 12px;     /* was 13px */
  --font-size-14: 13px;     /* was 14px */
  --font-size-16: 14px;     /* was 16px */
  --font-size-20: 16px;     /* was 20px */

  /* Brand colour */
  --color-navy: #11284f;
  --color-navy-soft: #1c3a6b;
  --color-teal: #087f79;
  --color-teal-dark: #05635f;
  --color-teal-pale: #e6f4f2;
  --color-blue: #2870a8;
  --color-amber: #a65f00;
  --color-red: #a23333;
  --color-green: #236b3b;

  /* Neutral colour */
  --color-ink: #1b2a3a;
  --color-muted: #55677a;
  --color-line: #cfd9ea;
  --color-line-soft: #e4ebf6;
  --color-surface: #fff;
  --color-canvas: #f4f7fb;
  --color-soft: #eff3fa;

  /* LEAN OCM four colour bar brand treatment */
  --brand-bar-1: var(--color-navy);
  --brand-bar-2: var(--color-teal);
  --brand-bar-3: var(--color-blue);
  --brand-bar-4: var(--color-amber);

  /* Shape and elevation */
  --radius-card: 10px;
  --radius-control: 6px;
  --radius-pill: 999px;
  --border-card: 1px solid var(--color-line);
  --shadow-card: 0 1px 3px rgb(17 40 79 / 6%);
  --shadow-raised: 0 10px 28px rgb(17 40 79 / 14%);

  /* Compact spacing rhythm */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --gutter: clamp(0.75rem, 2.4vw, 2rem);

  /* Shell metrics (design system §3) */
  --sidebar-width: 256px;
  --sidebar-collapsed-width: 72px;
  --utility-bar-height: 56px;
  --brand-bar-height: 3px;
}

/* ==========================================================================
   Claude's design tokens — the off-app prototype's own values, copied verbatim.

   Source of truth: branch `design-v5-change-register` at b05c17a, file
   `offapp/change-register/register.css` (its `:root` and its two dark blocks),
   read with `git show`. Every value below comes from that file; none is read
   off a screenshot. Each property carries the prototype's own name with a
   `--ds-` prefix, so this block diffs 1:1 against the prototype and cannot
   collide with the app's own `--color-*`, `--space-*`, `--craft-*` or
   `--font-size-*` tokens. Nothing here replaces or re-points an existing token:
   `--color-navy` and its neighbours keep their own declared values, which the
   unit suite pins (tests/design-tokens.test.js).

   The nine text roles are the prototype's `.t-h1`, `.t-fig`, `.t-strong`,
   `.t-ctl`, `.t-body`, `.t-mute`, `.t-meta`, `.t-label` and `.t-chip` — the
   ladder 14/11/10px, each with its own line height and weight. They are carried
   here as data only: no rule in this stylesheet consumes them yet, because the
   unit suite requires every declared text size in the sheet to be one of the
   approved `--font-size-*` steps.

   Theme: light below; the prototype's dark values follow under both
   `prefers-color-scheme` and `[data-theme="dark"]`, exactly as the prototype
   declares them. The prototype re-declares only its colours for dark, so the
   type and geometry tokens are shared by both themes. The prototype's
   `color-scheme:dark` declaration is deliberately NOT carried over: it is not a
   token, and it would repaint the native controls of an app that is light-only.
   ========================================================================== */
:root {
  /* Palette — the prototype's `:root` */
  --ds-head: #11284f;
  --ds-text: #1b2a3a;
  --ds-muted: #55677a;
  --ds-line: #cfd9ea;
  --ds-line2: #e4ebf6;
  --ds-sb: #7f8da5;
  --ds-sb-h: #5f6f89;
  --ds-tint: #eff3fa;
  --ds-canvas: #f4f7fb;
  --ds-surface: #ffffff;
  --ds-primary: #11284f;
  --ds-on-primary: #ffffff;
  --ds-blue: #2870a8;
  --ds-teal: #087f79;
  --ds-green: #17663a;
  --ds-amber: #a65f00;
  --ds-red: #b3261e;
  --ds-purple: #5b4fa3;
  --ds-grey-seg: #7a8a9c;
  --ds-bar-off: #d9e2ee;
  --ds-faint: #5e6f84;
  --ds-dashed: #7f8da5;
  --ds-edge: #7f8da5;
  --ds-d-pe: #2870a8;
  --ds-d-pr: #087f79;
  --ds-d-te: #5b4fa3;
  --ds-d-da: #a65f00;
  --ds-on-fill: #ffffff;
  --ds-chip-green-bg: #e6f4ec;
  --ds-chip-green-fg: #17663a;
  --ds-chip-blue-bg: #eaf2f9;
  --ds-chip-blue-fg: #1f5f93;
  --ds-chip-amber-bg: #fdf6ea;
  --ds-chip-amber-fg: #8a5000;
  --ds-chip-grey-bg: #eef1f5;
  --ds-chip-grey-fg: #55677a;
  --ds-dis-bg: #eef1f5;
  --ds-dis-fg: #7a8a9c;
  --ds-danger-bg: #b3261e;
  --ds-scrim: rgba(10, 20, 40, .46);
  --ds-shadow: 0 8px 24px rgba(17, 40, 79, .16);
  --ds-font: Inter, 'Segoe UI', Arial, sans-serif;

  /* The prototype's three size steps, and the four facts it measures with:
     a text control and a select are 30px high in a 10px horizontal inset, its
     form popup is 760px wide, and every scroll area draws a 6px bar. */
  --ds-t14: 14px;
  --ds-t11: 11px;
  --ds-t10: 10px;
  --ds-control-height: 30px;
  --ds-control-pad-x: 10px;
  --ds-dialog-width: 760px;
  --ds-scrollbar-width: 6px;

  /* The nine text roles: size / weight / line height */
  --ds-role-h1-size: var(--ds-t14);     --ds-role-h1-weight: 600;     --ds-role-h1-line: 20px;
  --ds-role-fig-size: var(--ds-t14);    --ds-role-fig-weight: 600;    --ds-role-fig-line: 20px;
  --ds-role-strong-size: var(--ds-t11); --ds-role-strong-weight: 600; --ds-role-strong-line: 16px;
  --ds-role-ctl-size: var(--ds-t11);    --ds-role-ctl-weight: 500;    --ds-role-ctl-line: 16px;
  --ds-role-body-size: var(--ds-t11);   --ds-role-body-weight: 400;   --ds-role-body-line: 16px;
  --ds-role-mute-size: var(--ds-t11);   --ds-role-mute-weight: 400;   --ds-role-mute-line: 16px;
  --ds-role-meta-size: var(--ds-t11);   --ds-role-meta-weight: 400;   --ds-role-meta-line: 16px;
  --ds-role-label-size: var(--ds-t11);  --ds-role-label-weight: 600;  --ds-role-label-line: 16px;
  --ds-role-chip-size: var(--ds-t10);   --ds-role-chip-weight: 600;   --ds-role-chip-line: 14px;
}

/* The prototype's dark values, under both of its own selectors. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ds-head: #dbe6f8;
    --ds-text: #dbe4f2;
    --ds-muted: #9fb0c6;
    --ds-line: #2c3d5a;
    --ds-line2: #223049;
    --ds-sb: #607aa6;
    --ds-sb-h: #7f98c4;
    --ds-tint: #1b2a45;
    --ds-canvas: #0c1424;
    --ds-surface: #121d33;
    --ds-primary: #3b6fb8;
    --ds-on-primary: #ffffff;
    --ds-blue: #6aa7dc;
    --ds-teal: #4fc3bd;
    --ds-green: #5cc48a;
    --ds-amber: #e0a24a;
    --ds-red: #f0877f;
    --ds-purple: #a99cf0;
    --ds-grey-seg: #6f819a;
    --ds-bar-off: #2c3d5a;
    --ds-faint: #7f92ab;
    --ds-dashed: #607aa6;
    --ds-edge: #607aa6;
    --ds-d-pe: #2f6ea6;
    --ds-d-pr: #0b7f78;
    --ds-d-te: #6a5cc0;
    --ds-d-da: #a35f05;
    --ds-on-fill: #ffffff;
    --ds-chip-green-bg: #12301f;
    --ds-chip-green-fg: #8fdcb0;
    --ds-chip-blue-bg: #15304a;
    --ds-chip-blue-fg: #9cc8ee;
    --ds-chip-amber-bg: #3a2a10;
    --ds-chip-amber-fg: #f0c27a;
    --ds-chip-grey-bg: #1f2b40;
    --ds-chip-grey-fg: #a8b8cc;
    --ds-dis-bg: #1a263c;
    --ds-dis-fg: #6f819a;
    --ds-danger-bg: #c4382f;
    --ds-scrim: rgba(0, 0, 0, .6);
    --ds-shadow: 0 8px 24px rgba(0, 0, 0, .5);
  }
}
:root[data-theme="dark"] {
  --ds-head: #dbe6f8;
  --ds-text: #dbe4f2;
  --ds-muted: #9fb0c6;
  --ds-line: #2c3d5a;
  --ds-line2: #223049;
  --ds-sb: #607aa6;
  --ds-sb-h: #7f98c4;
  --ds-tint: #1b2a45;
  --ds-canvas: #0c1424;
  --ds-surface: #121d33;
  --ds-primary: #3b6fb8;
  --ds-on-primary: #ffffff;
  --ds-blue: #6aa7dc;
  --ds-teal: #4fc3bd;
  --ds-green: #5cc48a;
  --ds-amber: #e0a24a;
  --ds-red: #f0877f;
  --ds-purple: #a99cf0;
  --ds-grey-seg: #6f819a;
  --ds-bar-off: #2c3d5a;
  --ds-faint: #7f92ab;
  --ds-dashed: #607aa6;
  --ds-edge: #607aa6;
  --ds-d-pe: #2f6ea6;
  --ds-d-pr: #0b7f78;
  --ds-d-te: #6a5cc0;
  --ds-d-da: #a35f05;
  --ds-on-fill: #ffffff;
  --ds-chip-green-bg: #12301f;
  --ds-chip-green-fg: #8fdcb0;
  --ds-chip-blue-bg: #15304a;
  --ds-chip-blue-fg: #9cc8ee;
  --ds-chip-amber-bg: #3a2a10;
  --ds-chip-amber-fg: #f0c27a;
  --ds-chip-grey-bg: #1f2b40;
  --ds-chip-grey-fg: #a8b8cc;
  --ds-dis-bg: #1a263c;
  --ds-dis-fg: #6f819a;
  --ds-danger-bg: #c4382f;
  --ds-scrim: rgba(0, 0, 0, .6);
  --ds-shadow: 0 8px 24px rgba(0, 0, 0, .5);
}

[hidden] { display: none !important; }
* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--color-canvas);
  color: var(--color-ink);
  font-family: var(--font-family-base);
  font-size: var(--font-size-13);
  line-height: 1.45;
}
button, input, select, textarea { font: inherit; }
/* A button label is a single-line fact: it never wraps onto a second line. Every
   button — not only a header pair — is as wide as its own label on one line plus
   its padding, and a row that holds buttons makes room for them rather than
   compressing them (Owner correction, 2026-10-09; the field rule applied to a
   button). The browser gate measures every button the harness visits against its
   own label so a squeezed button fails wherever it appears. */
button { cursor: pointer; white-space: nowrap; }
button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible, a:focus-visible {
  outline: 2px solid var(--color-amber);
  outline-offset: 1px;
}
button:disabled { cursor: not-allowed; opacity: .6; }
a { color: var(--color-blue); }
/* Owner typography change (design system §4.1): the weight contract is 400 body /
   500 labels and navigation / 600 headings, key values and emphasis. Headings,
   inline emphasis and table headings carry an explicit rule so no element relies
   on the user agent's bold, which would request a weight the bundled family does
   not carry and be synthesised. */
h1 { margin: 0; font-weight: 600; font-size: var(--font-size-20); line-height: 1.2; }
h2 { margin: 0; font-weight: 600; font-size: var(--font-size-16); line-height: 1.25; }
h3 { margin: 0; font-weight: 600; font-size: var(--font-size-14); line-height: 1.3; }
h4 { margin: 0; font-weight: 600; font-size: var(--font-size-11); line-height: 1.3; letter-spacing: .06em; text-transform: uppercase; }
strong, b { font-weight: 600; }

.skip-link { position: fixed; left: var(--space-4); top: -5rem; z-index: 60; padding: var(--space-2) var(--space-3); background: var(--color-navy); color: var(--ds-on-primary); font-size: var(--font-size-13); }
.skip-link:focus { top: var(--space-2); }
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
.eyebrow { margin: 0 0 var(--space-1); color: var(--color-teal-dark); font-size: var(--font-size-10); font-weight: 600; letter-spacing: .1em; text-transform: uppercase; }

/* ================================================================ A. sidebar */

.app-frame { display: grid; grid-template-columns: var(--sidebar-width) minmax(0, 1fr); min-height: 100vh; }
.app-frame[data-sidebar="collapsed"] { grid-template-columns: var(--sidebar-collapsed-width) minmax(0, 1fr); }

/* The sidebar is deliberately two elements. `.app-sidebar` is the column
   *surface*: the grid item, never clamped, so the column background and its
   right edge are drawn for the full height of the shell however tall the
   workspace grows (design system §3A). `.sidebar-inner` carries the navigation
   itself and is pinned to the viewport, so the brand, the destinations and the
   sidebar footer never scroll away with the workspace. */
.app-sidebar {
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border-right: 1px solid var(--color-line);
}
.sidebar-inner {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  height: 100vh;
  padding: var(--space-3) 6px;
  overflow-y: auto;
}
.sidebar-brand { display: flex; flex: 0 0 auto; align-items: center; gap: var(--space-2); padding: 0 var(--space-2); }
.brand-mark {
  display: grid;
  flex: 0 0 auto;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 8px 8px 8px 2px;
  background: var(--color-teal);
  color: var(--ds-on-fill);
  font-size: var(--font-size-14);
  font-weight: 600;
}
.brand-lockup strong { display: block; font-size: var(--font-size-16); letter-spacing: .1em; line-height: 1.1; }
.brand-lockup small { display: block; color: var(--color-muted); font-size: var(--font-size-10); letter-spacing: .13em; text-transform: uppercase; }
.brand-bars { display: grid; flex: 0 0 auto; grid-template-columns: repeat(4, 1fr); height: var(--brand-bar-height); margin: 0 var(--space-2); border-radius: var(--radius-pill); overflow: hidden; }
.brand-bars span:nth-child(1) { background: var(--brand-bar-1); }
.brand-bars span:nth-child(2) { background: var(--brand-bar-2); }
.brand-bars span:nth-child(3) { background: var(--brand-bar-3); }
.brand-bars span:nth-child(4) { background: var(--brand-bar-4); }

.app-nav { flex: 1 0 auto; }
.app-nav-heading { margin: 0 0 var(--space-2); padding: 0 var(--space-2); color: var(--color-muted); font-size: var(--font-size-10); font-weight: 600; letter-spacing: .1em; text-transform: uppercase; }
.app-nav-list { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; }
.app-nav-list button {
  display: flex;
  align-items: center;
  gap: 4px;
  width: 100%;
  min-height: 34px;
  padding: 6px;
  border: 0;
  border-left: 3px solid transparent;
  border-radius: 0 var(--radius-control) var(--radius-control) 0;
  background: transparent;
  color: var(--color-muted);
  font-size: var(--font-size-13);
  font-weight: 500;
  text-align: left;
}
.app-nav-list button:hover { background: var(--color-soft); color: var(--color-navy); }
.app-nav-list button[aria-current="page"] { border-left-color: var(--color-teal); background: var(--color-soft); color: var(--color-navy); }
.app-nav-list button[aria-expanded="true"] { color: var(--color-navy); }
/* A destination that exists in the final information architecture but is not
   implemented in this slice stays reachable, is announced as planned, and says
   so in the content area — never a silent dead end or fake screen. */
.app-nav-list button[data-planned="true"] { border-left-style: dashed; border-left-color: var(--color-line); font-weight: 500; }
.app-nav-list button[data-planned="true"] .nav-icon { color: var(--color-muted); opacity: .75; }
.nav-icon { display: grid; flex: 0 0 auto; place-items: center; width: 20px; height: 20px; color: var(--color-navy); }
.nav-icon svg { width: 16px; height: 16px; }
.app-nav-text { min-width: 0; overflow: hidden; }
/* Owner UAT correction 1 — the primary navigation label is a destination name
   and never wraps: it is laid out on one line, and the label box shrinks so a
   state chip keeps its own width, with the ellipsis as the fallback rather than
   a second line. The longest destination (the current Project) fits at the
   expanded desktop width, which is measured rather than assumed:
   `scripts/browser-acceptance.js` asserts every rendered destination label is
   one line and untruncated at the desktop and expanded-tablet widths. */
/* A navigation destination is a label, so it carries the 500 rule even though it
   is marked up as `strong` (§4.1). */
.app-nav-text strong { display: block; font-weight: 500; overflow: hidden; font-size: var(--font-size-12); line-height: 1.35; text-overflow: ellipsis; white-space: nowrap; }
/* The only state wording the rail carries is the "Planned" chip on a destination
   that exists in the information architecture but is not implemented yet
   (design system §2.1, §12) — never explanatory subtext under the name. */
.app-nav-state { flex: 0 0 auto; margin-left: auto; padding: 0 3px; border: 1px solid var(--color-line); border-radius: var(--radius-pill); color: var(--color-muted); font-size: var(--font-size-10); font-weight: 600; }
.app-nav-current { flex: 0 0 auto; margin-left: auto; padding: 0 3px; border: 1px solid var(--color-teal); border-radius: var(--radius-pill); color: var(--color-teal-dark); font-size: var(--font-size-10); font-weight: 600; }
.app-nav-disclosure { flex: 0 0 auto; margin-left: auto; color: var(--color-muted); font-size: var(--font-size-11); }
.app-nav-group button[aria-expanded="true"] .app-nav-disclosure { transform: rotate(90deg); }
.app-nav-sublist { margin: 2px 0 var(--space-1); padding: 0 0 0 8px; list-style: none; }
/* A child destination is a text-only row: the destination name on one line, no
   icon and no state chip, so the longest name in the rail is never squeezed and
   the current location is carried by its own indicator and `aria-current`. */
.app-nav-sublist button { min-height: 28px; padding: var(--space-1) 6px; font-size: var(--font-size-12); font-weight: 500; }
.app-nav-sublist .app-nav-text strong { font-weight: 500; }

/* The open Project's own records (Owner's decision 2026-09-25, ADR-0013). One step
   in from the Project's row, because they are the Project's rather than a stage's:
   Project-level and cross-stage records (04_FUNCTIONAL_MODEL.md §4.5-§4.11) are
   not listed under any single stage. The caption names the list once, so the seven
   names need no explanation of their own, and every row keeps a child row's
   28px height — above the 24px pointer floor the navigation holds. */
.app-nav-caption { margin: var(--space-1) 0 2px; padding: 0 6px 0 14px; color: var(--color-muted); font-size: var(--font-size-12); font-weight: 500; }
.app-nav-records { margin-top: 0; padding-left: 14px; }
/* A planned destination is marked by its dashed edge, exactly as a planned
   top-level destination is (§2.1). A child row still carries no state chip. */
.app-nav-records button[data-planned="true"] { border-left-style: dashed; border-left-color: var(--color-line); }

.sidebar-footer { display: flex; flex: 0 0 auto; flex-direction: column; gap: var(--space-1); margin-top: auto; padding-top: var(--space-2); border-top: 1px solid var(--color-line-soft); }
.user-chip { display: flex; align-items: center; gap: var(--space-2); width: 100%; min-height: 36px; padding: var(--space-1) var(--space-2); border: 0; border-radius: var(--radius-control); background: transparent; color: var(--color-ink); text-align: left; }
.user-chip:hover { background: var(--color-soft); }
.avatar { display: grid; flex: 0 0 auto; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: var(--color-navy); color: var(--ds-on-primary); font-size: var(--font-size-10); font-weight: 600; }
.user-text strong { display: block; font-size: var(--font-size-12); }
.user-text small { display: block; color: var(--color-muted); font-size: var(--font-size-10); }
.build-identifier { padding: 0 var(--space-2); color: var(--color-muted); font-size: var(--font-size-10); font-variant-numeric: tabular-nums; }
.build-identifier[data-build-state="resolved"] { color: var(--color-teal-dark); font-weight: 600; }
.build-identifier[data-build-state="unavailable"] { color: var(--color-red); font-weight: 600; }

/* Collapsed rail (tablet default, or user-collapsed desktop): icons only, with
   the label text kept in the accessibility tree as the accessible name. */
.app-frame[data-sidebar="collapsed"] .app-nav-text,
.app-frame[data-sidebar="collapsed"] .app-nav-heading,
.app-frame[data-sidebar="collapsed"] .app-nav-state,
.app-frame[data-sidebar="collapsed"] .app-nav-current,
.app-frame[data-sidebar="collapsed"] .app-nav-disclosure,
.app-frame[data-sidebar="collapsed"] .brand-lockup,
.app-frame[data-sidebar="collapsed"] .user-text,
.app-frame[data-sidebar="collapsed"] .build-identifier,
.app-frame[data-sidebar="collapsed"] .environment-status {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.app-frame[data-sidebar="collapsed"] .app-nav-list button,
.app-frame[data-sidebar="collapsed"] .user-chip { justify-content: center; padding-left: 0; padding-right: 0; }
.app-frame[data-sidebar="collapsed"] .app-nav-sublist { display: none; }
.app-frame[data-sidebar="collapsed"] .sidebar-inner { padding-left: var(--space-1); padding-right: var(--space-1); }
.app-frame[data-sidebar="collapsed"] .sidebar-brand { justify-content: center; padding: 0; }

/* ------------------------------------------------------- Projects (issue #18) */

/* Owner correction 22: Projects is a table. The field names are column headers,
   stated once above the register, so no row repeats them and the space the
   repeated labels took carries the description — which puts every Project on a
   single line. Every cell is the record's own value, so the table cannot state a
   Project the model does not hold. */
.project-list { width: 100%; margin: 0; border-collapse: collapse; table-layout: fixed; text-align: left; }
.project-list thead th {
  padding: 0 var(--space-3) 6px;
  color: var(--color-muted);
  font-size: var(--font-size-10);
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  text-align: left;
  white-space: nowrap;
}
/* Owner instruction 2026-09-23: the description leaves the table; the name is capped at
   30 characters, so it carries the width the description gave up. */
.project-list th.col-project-id { width: 8%; }
.project-list th.col-project { width: 32%; }
/* Owner instruction 2026-10-04: 'From the projects register remove the column created
   and place it into the Project Information pop up screen, next to the Project ID
   field. This should provide enough space for the projects register to be displayed on
   one row.' The Created column is gone from the register and its 22% is shared out, so
   every remaining column states its whole content on one line. */
.project-list th.col-owner { width: 17%; }
.project-list th.col-target { width: 19%; }
.project-list th.col-changes { width: 12%; }
.project-list th.col-actions { width: 12%; }
.project-row { border-top: var(--border-card); }
.project-row:hover { background: var(--color-soft); }
/* The open Project is marked by a rail as well as by the chip, so the state does
   not rest on reading the row's text (design system §2.4). */
.project-row[aria-current="true"] { box-shadow: inset 3px 0 0 var(--color-teal); }
/* Owner instruction 2026-09-23: one list pattern. The Projects table carries the same
   head and cell metrics as the registers, so the four lists read identically. */
.project-cell { padding: 4px var(--space-3); color: var(--color-ink); font-size: var(--font-size-12); vertical-align: middle; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.project-cell-project { font-size: var(--font-size-14); }
/* The control that opens the Project, in the identity cell, so the row is
   operable from the keyboard as well as by pointer. */
/* The project name is a button label, so it never wraps (Owner correction, 2026-10-09):
   with the label held on one line the control is shorter than the pointer-target floor,
   so the floor is declared here rather than left to a wrap that no longer happens. */
.project-row-open { display: flex; align-items: center; gap: var(--space-2); width: 100%; min-height: 24px; border: 0; padding: 0; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.project-row-name { color: var(--color-navy); font-size: var(--font-size-14); font-weight: 600; }
.project-cell-changes { font-variant-numeric: tabular-nums; }
.project-cell-actions { text-align: right; }
/* The open Project's `Open` chip sits here, with the row's own control, rather than in a
   fact cell (ADR-0064: a cell holds one value). Its middle lines up with the 26px menu
   button so the two read as one row of controls. */
.project-cell-actions > * { vertical-align: middle; }
/* The three-dot control that corrects a Project's key information. */
.project-row-menu {
  width: 26px;
  height: 26px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--color-muted);
  font-size: var(--font-size-16);
  line-height: 1;
}
.project-row-menu:hover { background: var(--color-soft); color: var(--color-navy); }
/* The creation metadata of a Project being created: the same read-only treatment
   the Change form gives its own audit history, because it is generated from the
   record and the signed-in session rather than typed. */
.project-audit { margin: 0; padding: var(--space-1) var(--space-2); border-radius: var(--radius-control); background: var(--color-soft); color: var(--color-muted); font-size: var(--font-size-12); }

/* ------------------------------------------------ create Project popup (§6) */

/* Issue #18, item 2: the Create Project popup is the Change popup's design
   language — a compact centred modal sized to the fields it holds, never a side
   drawer, with no internal scrolling at the supported desktop viewport. */
#project-dialog {
  width: min(var(--craft-dialog-width), 100% - 48px);
  max-width: 100%;
  max-height: min(94vh, 820px);
  margin: auto;
  padding: 0;
  border: var(--border-card);
  border-radius: var(--radius-card);
  color: var(--color-ink);
  box-shadow: var(--shadow-raised);
  overflow: hidden;
}
#project-dialog[open] { display: flex; flex-direction: column; }
#project-dialog::backdrop { background: rgb(17 40 79 / 42%); }
#project-form { display: flex; flex: 1 1 auto; flex-direction: column; min-height: 0; max-height: 100%; padding: 0 var(--space-4) var(--space-2); overflow-y: auto; }

/* ============================================================= B. utility bar */

.app-body { display: flex; flex-direction: column; min-width: 0; }
.utility-bar {
  position: sticky;
  top: 0;
  z-index: 25;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--utility-bar-height);
  padding: 0 var(--gutter);
  background: var(--color-surface);
  /* Owner instruction 2026-09-23: a visible gap sits between the Project header bar and
     the stage bar, closed at its top by this rule. */
  border-bottom: 1px solid var(--color-line);
}
.sidebar-toggle { display: grid; flex: 0 0 auto; }
.sidebar-toggle svg { width: 16px; height: 16px; }
/* The off-canvas panel's own close control exists only at the off-canvas width,
   where the panel paints over the utility bar and therefore over the menu
   control (design system §9, §10). At desktop and tablet the sidebar is a
   persistent surface and needs no dismissal. */
.sidebar-close { display: none; margin-left: auto; flex: 0 0 auto; }
/* Owner review 2026-09-23: the glyph was pinned to the top of the round control
   (1px above, 11px below) because the control is a grid container with no alignment of
   its own. place-items centres it on both axes. */
.icon-button { place-items: center; width: 28px; height: 28px; border: 0; border-radius: 50%; background: var(--color-soft); color: var(--color-ink); font-size: var(--font-size-16); line-height: 1; }
.icon-button[aria-expanded="true"] { background: var(--color-teal-pale); color: var(--color-teal-dark); }
/* The page header (design system §2, §3B, §5). It is one statement of where the
   practitioner is: with a Project open, that Project's four facts — ID, name,
   Owner, Target date — and, with none open, the application area.
   Owner final Change Register page correction 1 (Issue #18 comment 5708151980),
   implemented literally per ChatGPT's review of 2026-09-17T07:49:38Z: this is
   the area that used to read `Projects`, and the four fields it now carries are
   not restated anywhere else on the page. */
.header-context { flex: 1 1 auto; min-width: 0; }
.header-area { margin: 0; color: var(--color-navy); font-size: var(--font-size-13); font-weight: 600; }
/* The four Project facts read as ONE line of context: the ID chip and the name,
   then Owner, then Target, separated by hairline rules (Owner correction 18).
   Owner instruction, recorded in docs/specs/NEXT-WORK.md item 1: the Project
   description takes the line directly beneath the Project title, so this block
   is a two-row grid rather than one wrapping flex line - the identity and the
   fact line share row 1, and the description spans row 2 in the same reading
   order the markup carries (title, description, facts). The line is spaced rather than
   packed at the left end: the identity, the Owner fact and the Target fact are separated
   by equal intervals, so the three read as distinct groups at a comfortable distance.
   Owner correction 1's guarantees are unchanged - every fact is still read from
   the Project record, each is still stated exactly once on the page, and no
   `Projects` wording returns. The name column may still shrink rather than
   clip, so the Project name is never the element that gets lost. */
.header-project {
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  grid-template-areas:
    "identity facts"
    "description description";
  align-items: baseline;
  column-gap: var(--space-6);
  min-width: 0;
}
/* Header pass 2026-09-23: the Project's own name is the identity of the page, and after
   the one-step reduction it rendered at 13px while the section heading beneath it
   ("Change Register", h2) rendered at 14px — the page's identity smaller than one of its
   own headings. It takes the 20 step (16px), so the order reads project name, then the
   screen heading, then everything else. Nothing else in the header moved. */
.header-identity { grid-area: identity; display: flex; align-items: center; gap: var(--space-3); margin: 0; min-width: 0; color: var(--color-navy); font-size: var(--font-size-20); font-weight: 600; }
.header-identity #project-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The fact line is spaced, not packed: one even rhythm the whole way across. Each of the
   two rules carries the same --space-6 on both sides of it - the row's column gap before
   the first rule and the line's own padding-left after it, then the pair gap before the
   second rule and the second pair's padding-left after it - so the title, the Owner fact
   and the Target fact read as three groups separated by equal intervals, and nothing
   stretches to fill the remaining width. */
.header-facts { grid-area: facts; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--space-6); margin: 0; min-width: 0; padding-left: var(--space-6); border-left: 1px solid var(--color-line); }
.header-facts > div { display: flex; align-items: baseline; gap: var(--space-1); min-width: 0; }
.header-facts > div + div { padding-left: var(--space-6); border-left: 1px solid var(--color-line); }
/* Sentence case with a colon, as the fact reads on the line - the label is not
   a field caption once it sits beside its value. The colon is presentational, so
   the label text itself stays exactly `Owner` and `Target`. */
.header-facts dt { color: var(--color-muted); font-size: var(--font-size-12); }
.header-facts dt::after { content: ':'; }
.header-facts dd { margin: 0; color: var(--color-ink); font-size: var(--font-size-12); font-weight: 500; }
/* The one surface allowed to state non-production status (design system §3B,
   §4.4). Its marker is amber - an environment indicator must not read as a
   success signal.
   Owner final Change Register page correction 2 (Issue #18 comment 5708151980):
   it sits in the sidebar footer's technical area, directly below the build
   identifier, and no longer in the utility bar, where environment wording
   competed with product-facing content. It is stated once, subordinate to the
   business content above it, and it is the same surface the copy standard
   exempts from the business-copy rule. */
.environment-status { margin: var(--space-1) 0 0; padding: 0 var(--space-2); color: var(--color-muted); font-size: var(--font-size-10); }
.environment-status span { margin-right: var(--space-1); color: var(--color-amber); }

/* ============================================================ C. workspace */

main { width: 100%; max-width: 1440px; margin: 0 auto; padding: var(--space-4) var(--gutter) var(--space-5); }

/* The Project description, on the line directly beneath the Project title
   (Owner instruction, recorded in docs/specs/NEXT-WORK.md item 1). It carries no
   band of its own any more - no bottom padding and no rule - because it is part
   of the header's single block of Project context, so the header states the
   Project once and nothing beneath the header repeats it. */
.project-context { grid-area: description; margin: 0; min-width: 0; }
/* Owner UAT correction 3 — the Project ID and the Project name are one identity
   treatment inside the page title, and the identifier is not repeated (§3B, §5).
   Owner final Change Register page correction 1 (Issue #18 comment 5708151980)
   puts that identity, with Owner and Target, in the header above; the description
   sits beneath the title in the same block, read from the record. */
.context-id { display: inline-block; margin-right: var(--space-2); padding: 1px var(--space-2); border: 1px solid var(--color-teal); border-radius: var(--radius-pill); color: var(--color-teal-dark); font-size: var(--font-size-11); font-weight: 600; letter-spacing: .06em; vertical-align: middle; white-space: nowrap; }
.header-identity .context-id { margin-right: 0; }
.context-description { margin: 0; color: var(--color-muted); font-size: var(--font-size-12); }

/* ADR-0010: the area row is gone. The Change Register, Impacted Groups and
   Stakeholders are DEFINE's own destinations, reached from DEFINE's list on the
   stage bar, so nothing steps the stage layer aside any more: the stage stays
   named on screen while a register is showing. */
.register-area-view { display: block; }
.register-area-view[hidden] { display: none; }
/* A register is a table, for the same reason the Projects list is: the field names
   are column headers stated once, so no row repeats them. */
.register-table { width: 100%; border-collapse: collapse; text-align: left; }
.register-table thead th { padding: 0 var(--space-3) 4px; color: var(--color-muted); font-size: var(--font-size-10); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; text-align: left; white-space: nowrap; }
/* The review's two acts belong on one line: a Confirm and a Dismiss that wrap onto
   two rows read as two different rows' actions. The cell states the pair, and the
   table is the register's own table, so nothing else about it moves. */
.proposal-actions { white-space: nowrap; }
.proposal-actions .secondary-button + .secondary-button { margin-left: var(--space-1); }
.register-table tbody tr { border-top: var(--border-card); }
.register-table tbody tr:hover { background: var(--color-soft); }
.register-table th, .register-table td { padding: 4px var(--space-3); color: var(--color-ink); font-size: var(--font-size-12); vertical-align: middle; }
.register-cell-name { color: var(--color-navy); font-size: var(--font-size-13); font-weight: 600; text-align: left; }
.register-cell-count { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* DECIDE lifecycle stepper: horizontal, inside the workspace, below Project
   context and above stage content — never the application navigation. */
/* The bar is frozen by sitting exactly where it already rests: the workspace's top
   padding is absorbed into the bar's own background, so its resting position and its
   sticky offset are the same number and it cannot move when the page scrolls
   (Owner, 2026-09-23). The Project header and this bar are two headers stacked, and a
   soft gradient separates them rather than a hairline (Owner's reference, 2026-09-23).
   The gradient belongs to the bar, so it travels with it and the separation never
   disappears while the page scrolls. */
/* The white gap between the Project header bar and this bar is 32px, double what it was
   (Owner, 2026-09-23), and it lives in this band's own padding so the frozen resting
   position (top: 56px, the header's bottom edge) does not move. */
/* The gap between the Project header bar and this bar is a grey band — the page's own
   canvas colour — standing in the bar's top padding (Owner, 2026-09-23: "create a gap
   like this, grey background, not increase the DECIDE row"). Keeping it as padding on
   the bar means the stage row keeps its own height and the frozen resting position
   (top: 56px, the header's bottom edge) does not move. */
.stage-nav { position: sticky; top: 56px; z-index: 24; margin: -16px calc(-1 * var(--gutter)) var(--space-3); padding: 16px var(--gutter) 0; border-bottom: 1px solid var(--color-line); background: var(--color-surface); }
.stage-nav::before { content: ''; position: absolute; inset: 0 0 auto 0; height: 16px; background: var(--color-canvas); pointer-events: none; }
/* Six stages always fit: the columns share the width rather than the bar scrolling
   sideways (Owner, 2026-09-23). The row is the full width of the header band above it,
   so the two share one left and one right edge (Owner, 2026-09-23). */
.stage-nav ol { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); min-width: 0; margin: 0; padding: 0; list-style: none; }
/* The stage cell stacks its own control and the control that opens its list, so the
   pair can never be wider than the column it shares with five siblings. */
.stage-nav li { position: relative; display: flex; flex-direction: column; align-items: flex-start; min-width: 0; padding: 0 var(--space-4); }
.stage-nav li:first-child { padding-left: 0; }
.stage-nav li:last-child { padding-right: 0; }
/* The divider between two stages is a short rule standing in the gap between them,
   centred on the cell's height, with the same gap either side of it (Owner's reference
   and review, 2026-09-23) — not a border running the full height and crowding the text. */
.stage-nav li + li::before { content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 1px; height: 34px; background: var(--color-line); }
.stage-nav button {
  position: relative;
  width: 100%;
  padding: var(--space-2) var(--space-2) var(--space-2) 0;
  border: 0;
  border-bottom: 3px solid transparent;
  background: transparent;
  color: var(--color-muted);
  font-size: var(--font-size-11);
  font-weight: 600;
  letter-spacing: .06em;
  text-align: left;
}
/* The numbered circle and the stage descriptor belong to the stage control itself,
   not to the control beside it that opens the stage's list (ADR-0010). */
.stage-nav button[data-stage] > span { display: inline-grid; place-items: center; width: 18px; height: 18px; margin-right: var(--space-1); border: 1px solid var(--color-line); border-radius: 50%; font-size: var(--font-size-10); }
.stage-nav button[data-stage] small { display: block; margin: 2px 0 0 24px; font-size: var(--font-size-10); font-weight: 400; letter-spacing: 0; }
/* Owner's pick from the four placements rendered on 2026-09-23 (option A): the caret
   sits on the stage name's own line at the right edge of that stage's cell, so it
   reads as that stage's menu and nothing new is added to the bar. The name keeps
   clear of it. */
.stage-nav button[data-stage] { padding-right: 30px; }
.stage-nav button[aria-current="step"] { border-color: var(--color-teal); color: var(--color-teal-dark); }
.stage-nav button[aria-current="step"] > span { border-color: var(--color-teal); background: var(--color-teal); color: var(--ds-on-fill); }
/* Unavailable stages are labelled and shaped as unavailable, not colour-only. */
.stage-nav button[aria-disabled="true"] { cursor: default; color: var(--color-muted); }
.stage-nav button[aria-disabled="true"] > span { border-style: dashed; }

/* ADR-0010 — each stage's own list. Everything under a stage is one click from
   anywhere: the control states what it opens, the panel is fixed so the bar's own
   scrolling box cannot clip it, and every entry clears the 24×24px minimum target. */
/* Owner's pick from the four placements rendered on 2026-09-23 (option A), then moved
   left of the cell edge at his instruction the same day: the caret sits on the stage
   name's own line, immediately after the name, so it belongs to that stage's name and
   not to the cell's corner. src/app.js measures the name and places it. */
.stage-nav .stage-menu-toggle { position: absolute; top: 0; left: 0; display: inline-flex; align-items: center; justify-content: center; width: auto; min-width: 30px; min-height: 30px; margin: 0; padding: 0 var(--space-1); border: 0; background: none; color: var(--color-muted); font-size: var(--font-size-16); line-height: 1; cursor: pointer; }
.stage-nav .stage-menu-toggle:hover { color: var(--color-navy); background: var(--color-soft); }
.stage-nav .stage-menu-toggle[aria-expanded="true"] { color: var(--color-teal-dark); background: var(--color-soft); }
.stage-nav .stage-menu-toggle:focus-visible { outline: 3px solid var(--color-teal-dark); outline-offset: 2px; }
.stage-menu { position: fixed; z-index: 40; max-height: 70vh; overflow-y: auto; padding: var(--space-2); border: var(--border-card); border-radius: var(--radius-control); background: var(--color-surface); box-shadow: 0 12px 28px rgba(17, 40, 79, .18); }
.stage-menu[hidden] { display: none; }
.stage-menu-heading { margin: var(--space-2) 0 var(--space-1); padding: 0 var(--space-2); color: var(--color-muted); font-size: var(--font-size-10); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }
/* The groups are separated by a rule rather than a tint, so the list stays flat and
   the panel does not become a box inside a box. */
.stage-menu-heading + .stage-menu-item ~ .stage-menu-heading,
.stage-menu-heading:not(:first-child) { margin-top: var(--space-3); padding-top: var(--space-2); border-top: 1px solid var(--color-line); }
.stage-menu-item { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3); width: 100%; min-height: 24px; padding: var(--space-1) var(--space-2); border: 0; border-radius: var(--radius-control); background: none; color: var(--color-navy); font: inherit; font-size: var(--font-size-12); font-weight: 400; letter-spacing: 0; text-align: left; cursor: pointer; }
.stage-menu-item:hover { background: var(--color-soft); }
.stage-menu-item[aria-current="true"] { background: var(--color-soft); font-weight: 600; }
.stage-menu-item:focus-visible { outline: 3px solid var(--color-teal-dark); outline-offset: -2px; }
.stage-menu-ref { color: var(--color-muted); font-size: var(--font-size-10); white-space: nowrap; }

/* A deliverable the model names and this release has not built: the stage's whole
   list is shown in place, with the chosen entry marked, so the practitioner sees
   where the deliverable sits without anything being invented for it.

   ADR-0064 — the Owner's register standard: one fact per column, one row per record,
   nothing stacked. The list's two facts — the reference and the label — take a column
   EACH (they were joined in one line), so it takes the register's own two-column shape
   while staying the list it is. The reference is a narrow muted column; the chosen
   deliverable's row keeps the emphasis it had. */
.stage-deliverable-table .col-deliverable-ref { width: 96px; white-space: nowrap; }
.stage-deliverable-table .stage-deliverable-ref { color: var(--color-muted); white-space: nowrap; }
.stage-deliverable-table tbody tr[aria-current="true"] { font-weight: 600; }
.stage-deliverable-table tbody tr[aria-current="true"] td { color: var(--color-navy); }

/* The bar freezes below the utility bar, which is sticky at the top (ADR-0010). At
   the off-canvas width the header is taller, so the bar follows it. */
@media (max-width: 767px) {
  .stage-nav { top: 70px; }
}

.page-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-3); }
.page-heading p:last-child { margin: var(--space-1) 0 0; color: var(--color-muted); font-size: var(--font-size-12); }
.page-actions { display: flex; align-items: center; gap: var(--space-2); flex: 0 0 auto; }

.primary-button, .secondary-button { min-height: 36px; padding: var(--space-2) var(--space-3); border-radius: var(--radius-control); font-size: var(--font-size-13); font-weight: 600; }
.primary-button { border: 1px solid var(--color-teal-dark); background: var(--color-teal); color: var(--ds-on-fill); }
.primary-button:hover { background: var(--color-teal-dark); }
.secondary-button { border: 1px solid var(--color-line); background: var(--color-surface); color: var(--color-navy); }
.secondary-button:hover { background: var(--color-soft); }
.danger-button { border-color: #d6b1b1; color: var(--color-red); }

/* ----------------------------------------------------- pressed state (§11) */

/* The authored, visible response to a press. It is deliberately distinct from
   the hover state — :active also matches :hover, so a press that only reused the
   hover colour would be invisible — and it is read back from the live engine
   with a real mouse button held down (scripts/browser-acceptance.js), so the
   state cannot silently disappear from the stylesheet and pass review unnoticed. */
.primary-button:active:not(:disabled) { background: var(--color-navy); transform: translateY(1px); }
.secondary-button:active:not(:disabled) { background: var(--color-line-soft); transform: translateY(1px); }
.icon-button:active:not(:disabled),
.row-menu-button:active:not(:disabled),
.user-chip:active:not(:disabled),
.app-nav-list button:active:not(:disabled) { background: var(--color-line-soft); transform: translateY(1px); }

/* ------------------------------------------------------ summary + register */

.summary-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--space-3); margin-bottom: var(--space-3); }
.summary-grid article { display: flex; flex-direction: column; justify-content: center; gap: 2px; padding: var(--space-3); border: var(--border-card); border-radius: var(--radius-card); background: var(--color-surface); }
/* Owner UAT correction 16 — one Total Changes figure, the status metrics grouped
   as status measures, and Criticality presented separately as an overlapping
   risk measure, so the summary can never be read as four additive peer totals. */
.summary-caption { margin: 0; color: var(--color-muted); font-size: var(--font-size-11); font-weight: 600; text-transform: uppercase; letter-spacing: .04em; }
/* Owner 2026-09-28: the network question is answered beside the member count, in this compact card.
   Its control keeps the shell's field height and a usable width, so it is a real pointer target
   (§10 measured it at 41x18, under the 24px minimum, before this). */
.summary-need { display: flex; flex-direction: column; gap: 6px; }
.summary-need-row { display: flex; align-items: center; gap: 8px; }
.summary-need select {
  min-width: 96px;
  min-height: 34px;
  padding: 0 8px;
  font-size: var(--font-size-11);
}
.summary-need .primary-button { min-height: 34px; }

.summary-caption small { display: block; margin-top: 1px; color: var(--color-muted); font-size: var(--font-size-10); font-weight: 400; text-transform: none; letter-spacing: 0; }
.summary-total-value { color: var(--color-navy); font-size: var(--font-size-20); font-weight: 600; line-height: 1.1; }
.summary-status-list { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); margin: 0; padding: 0; list-style: none; }
.summary-status-list li { display: flex; align-items: baseline; gap: var(--space-1); }
.summary-measure-value { color: var(--color-navy); font-size: var(--font-size-16); font-weight: 600; line-height: 1.1; }
.summary-measure-label { color: var(--color-muted); font-size: var(--font-size-12); }
.summary-overlap { margin: 0; color: var(--color-muted); font-size: var(--font-size-12); }

.workspace-card { border: var(--border-card); border-radius: var(--radius-card); background: var(--color-surface); }
.register-card { overflow: hidden; }
.register-toolbar { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); padding: var(--space-3); border-bottom: 1px solid var(--color-line); }
.card-title p { margin: var(--space-1) 0 0; color: var(--color-muted); font-size: var(--font-size-11); }
.register-tools { display: flex; gap: var(--space-2); }
.register-tools input, .register-tools select { min-height: var(--ds-control-height); padding: var(--space-1) var(--space-2); border: 1px solid var(--color-line); border-radius: var(--radius-control); background: var(--color-surface); font-size: var(--font-size-12); }
.table-wrap { max-height: min(60vh, 620px); overflow: auto; }
table { width: 100%; border-collapse: collapse; }
thead th { position: sticky; top: 0; z-index: 2; padding: var(--space-2) var(--space-3); background: var(--color-soft); color: var(--color-muted); font-size: var(--font-size-11); font-weight: 600; letter-spacing: .04em; text-align: left; text-transform: uppercase; }
td { padding: var(--space-2) var(--space-3); border-top: 1px solid var(--color-line-soft); font-size: var(--font-size-12); vertical-align: top; }
tbody tr:hover { background: #f8fafe; }
tbody tr:focus-within { background: var(--color-soft); }
/* The Change Register's own columns (ADR-0064, the Owner's register standard): the Change ID
   names its own column, the Change Title its own, the Owner its own and the Timing its own,
   together with the Classification and the Change it relates to — one fact per column, each on
   its own one line. This is the same treatment the Stakeholders register took on the Owner's
   correction of 2026-10-09: the cells do not wrap, and a register that carries a column per fact
   takes the tighter inline inset so its honest total width stays as narrow as it can.
   `.change-title .id-label` is kept for the DEFINE Relationship review's rows
   (`renderProposalRow`), which used to stack the ID over the title. The Owner's one-row cell
   rule of 2026-10-13 (ADR-0078) brings that register to the standard too: the scoped rule
   below keeps every cell to ONE row, clipped to its column, with the text that does not fit
   read on hover. */
.change-register-table thead th,
.change-register-table tbody td,
.change-register-table tbody th { white-space: nowrap; }
.register-card .change-register-table th,
.register-card .change-register-table td { padding-inline: var(--space-1); }
.change-register-table .change-title { min-width: 0; }
.change-title { min-width: 240px; }
.change-title strong { display: block; color: var(--color-navy); font-size: var(--font-size-13); }
.change-title .id-label { display: block; margin-bottom: 1px; color: var(--color-muted); font-size: var(--font-size-10); font-weight: 600; letter-spacing: .06em; }
.change-id .id-label { color: var(--color-muted); font-size: var(--font-size-10); font-weight: 600; letter-spacing: .06em; }
.owner-cell strong { display: block; font-size: var(--font-size-12); }
.timing-cell span { color: var(--color-muted); font-size: var(--font-size-11); line-height: 1.4; }
.relationship-cell, .related-change-cell { color: var(--color-muted); font-size: var(--font-size-11); }

/* The Owner's one-row cell rule, 2026-10-13 (ADR-0078). His words: *"Try and keep the text to
   1 row within the column restriction. If there is extra text allow a hover function."* So a
   register cell reads on ONE ROW, clipped at its column's own edge, and the text that does not
   fit is read on hover — never wrapped onto a second line, and never stacked. Applied here to
   the DEFINE Relationship review register (`#relationship-review-view`): the register whose
   "Why this is proposed" cell carries a wrapped prose explanation and whose identity cells
   stacked the ID over the title. `table-layout: fixed` gives every column a declared width, so
   the clip and the ellipsis resolve at the column's own edge rather than at the table's. */
#relationship-review-view .register-table { table-layout: fixed; }
#relationship-review-view .register-table th:nth-child(1) { width: 21%; }
#relationship-review-view .register-table th:nth-child(2) { width: 14%; }
#relationship-review-view .register-table th:nth-child(3) { width: 22%; }
#relationship-review-view .register-table th:nth-child(4) { width: 28%; }
#relationship-review-view .register-table th:nth-child(5) { width: 15%; }
#relationship-review-view .register-table th,
#relationship-review-view .register-table td {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* One row for the identity cells too: the ID and the title read on the same line, not stacked.
   Both read at the register's own cell size, so the line is one line box and the measurement
   that counts them agrees with the eye — a smaller ID over a larger title would be one line of
   text but two text heights, which is what "stacked" means here. */
#relationship-review-view .register-table .change-title .id-label,
#relationship-review-view .register-table .change-title strong {
  display: inline; margin-bottom: 0; font-size: var(--font-size-12);
}

/* The Owner's set-cell rule, 2026-10-10 (ADR-0075): the Change Group column holds a bounded
   set in ONE cell, as its members in the declared canonical order, comma-separated. The
   `.tag-list` block this column used to hold — the nested block the register standard names
   as a fault — is gone with it. The members are the cell's own content, so the set flows onto
   a second line where the four need it rather than widening the register past its 1118px
   frame; the 176px cap is the one the chips it replaced carried, so the row height stays
   predictable and the register still fits. */
.register-table td.change-groups-cell { color: var(--color-muted); font-size: var(--font-size-11); }
.change-register-table tbody td.change-groups-cell { white-space: normal; max-width: 176px; }
.tag, .status-chip, .criticality-chip { display: inline-flex; padding: 1px var(--space-2); border-radius: var(--radius-pill); font-size: var(--font-size-11); font-weight: 600; white-space: nowrap; }
.tag { background: var(--color-soft); color: var(--color-navy-soft); }
.status-chip { background: #e7f1f7; color: #205c82; }
.status-chip::before { content: "● "; }
.status-chip[data-status="Validated"] { background: #e3f3e8; color: var(--color-green); }
.status-chip[data-status="Draft"] { background: #eceff0; color: #4e5e64; }
.status-chip[data-status="Revalidation Required"] { background: #fff0d9; color: #805000; }
.status-chip[data-status="Withdrawn"], .status-chip[data-status="Superseded"] { background: #f2e9e9; color: #734343; }
.criticality-chip { border: 1px solid currentColor; background: var(--color-surface); }
.criticality-chip[data-criticality="Critical"] { color: var(--color-red); }
.criticality-chip[data-criticality="High"] { color: #b04f25; }
.criticality-chip[data-criticality="Medium"] { color: #8a6815; }
.criticality-chip[data-criticality="Low"] { color: #3a6c5b; }

/* ------------------------------------------------------------ row actions */

.row-actions-cell { position: relative; width: 46px; text-align: right; }
.row-menu-button { width: 28px; height: 28px; padding: 0; border: 1px solid var(--color-line); border-radius: var(--radius-control); background: var(--color-surface); color: var(--color-navy); font-size: var(--font-size-14); line-height: 1; }
.row-menu-button[aria-expanded="true"] { background: var(--color-soft); border-color: var(--color-blue); }
/* Placed against the viewport by `syncRowMenuCoverage()` (`src/app.js`), not
 * inside the register: `.register-card` is `overflow: hidden` and `.table-wrap`
 * is `overflow: auto`, and a menu opened on the last row has no row beneath it
 * to open over — absolutely positioned it opened past the container's bottom
 * edge and was drawn nowhere at all (design system §10/§11). `left`/`top` and
 * `data-placement` are set on open and re-derived on a register scroll and on a
 * viewport change. Its elevation is above the sticky utility bar (25) and the
 * sticky table head (2), which it can now be placed over, and below the modal
 * surfaces it must never outrank (the off-canvas backdrop 40, panel 45, drawer
 * 50) because any activation outside it dismisses it first. */
.row-menu { position: fixed; top: 0; left: 0; z-index: 30; min-width: 132px; padding: var(--space-1); border: var(--border-card); border-radius: var(--radius-card); background: var(--color-surface); box-shadow: var(--shadow-raised); }
.row-menu button { display: block; width: 100%; min-height: 28px; padding: var(--space-1) var(--space-2); border: 0; border-radius: 4px; background: transparent; color: var(--color-navy); font-size: var(--font-size-12); text-align: left; }
.row-menu button:hover, .row-menu button:focus-visible { background: var(--color-soft); }

/* Change Register states (design system §5): the empty, filtered-empty, loading
 * and error states each render their own copy. The error state is also given a
 * non-colour cue (weight) and every state states its meaning in words. */
.register-state { padding: var(--space-4); color: var(--color-muted); font-size: var(--font-size-12); text-align: center; }
.register-state[data-register-state="error"] { color: var(--color-red); font-weight: 600; }
.register-state[data-register-state="loading"] { font-style: italic; }
/* Slice 2 — the Change Network's own forms. Exactly one form band is open at a
   time (a band is never stacked on a band), and each is drawn as a panel inside
   the card that owns the list it writes to rather than as a second card. The
   state cell states its value in text, never by colour, and an absent value is
   the register's one honest-absence token. */
.network-form { margin: var(--space-2) var(--space-3) var(--space-3); padding: var(--space-2) var(--space-3); border: 1px solid var(--color-line); border-radius: var(--radius-control); background: var(--color-soft); }
.network-form[hidden] { display: none; }
.network-form h4 { margin: 0 0 var(--space-1); color: var(--color-navy); font-size: var(--font-size-12); font-weight: 600; }
.network-form .form-intro { margin: 0 0 var(--space-1); color: var(--color-muted); font-size: var(--font-size-12); }
/* The next step states itself, and its own rule in the rulebook's words, so the person taking
   the step does not have to open the help to know what it means (ADR-0029). */

/* The Change Network is a form screen, so its text is the same size as every other form's:
   the Owner's 2026-09-23 instruction is that form text is one step down, and the registers'
   own tables are 11px. Measured 2026-09-25: the screen's fields were inheriting 12px, which no
   other form does. The Context Help panel is excluded, exactly as the four dialogs exclude it:
   it carries its own type and no surface may set it (ADR-0025). */
#change-network-view :is(input, select, textarea, .field-label, .form-intro, label, small, strong, p, li, dt, dd):not(.context-help, .context-help *) {
  font-size: var(--font-size-12);
}

.step-value { margin: 0; font-size: var(--font-size-12); font-weight: 600; color: var(--color-navy); }
.step-rule { margin: 2px 0 0; font-size: var(--font-size-12); line-height: 1.45; color: var(--color-muted); }

.network-form-context { margin: 0 0 var(--space-1); color: var(--color-ink); font-size: var(--font-size-12); font-weight: 600; }
.network-form-actions { display: flex; justify-content: flex-end; gap: var(--space-2); margin-top: var(--space-2); }
.network-actions-cell { width: 46px; text-align: right; }
/* The row actions control keeps the register's own look and its 24x24 pointer
   target (§10); the menu it opens is the shared `.row-menu`, so placement,
   coverage and focus hand-back have one implementation for both lists. */
.network-menu-button { display: grid; place-items: center; width: 24px; height: 24px; padding: 0; border: 1px solid var(--color-line); border-radius: var(--radius-control); background: var(--color-surface); color: var(--color-navy); font-size: var(--font-size-14); line-height: 1; }
.network-menu-button:hover { border-color: var(--color-blue); }
.network-menu-button[aria-expanded="true"] { background: var(--color-soft); border-color: var(--color-blue); }
.register-cell-state { color: var(--color-ink); font-weight: 600; white-space: nowrap; }

/* §5.8 — the Communications & Engagement register's own form. Its text is the same
   size as every other form's (the Owner's 2026-09-23 instruction). */
#communications-view :is(input, select, textarea, .field-label, .form-intro, label, small, strong, p, li, dt, dd):not(.context-help, .context-help *) {
  font-size: var(--font-size-12);
}

/* Owner instruction 2026-10-03 (kept): the identity facts sit on one row. Owner ruling
   2026-10-05: each communication relates to a single stage, so the stage is an ordinary
   single-selection drop-down and the checkbox-grid picker it replaced is gone. Kind and
   the stage both open on a "Select" prompt, so an unanswered field cannot pass. */
.campaign-row { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--space-2) var(--space-3); }
/* Owner's finding, 2026-10-05 — "why are they different?": the controls on a one-row identity strip
   sat outside the field styling, so they rendered as bare browser inputs with a different height,
   padding and border from every other field on the same form. They now carry the same field
   surface, so a field is the same component wherever it appears. */
.campaign-row :is(input, select, textarea) {
  display: block;
  min-height: 30px;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-control);
  background: var(--color-surface);
  color: var(--color-ink);
}

/* Owner's standard, 2026-10-10: one fact per column, nothing stacked. The Kind and the
   Change the line belongs to are columns of their own now, so the stacked reference block
   that used to ride under the action's words is gone. */

/* Owner instruction 2026-10-03: a campaign line can be repositioned by click and drag,
   and the Owner's standing rule is that a row carries only the button's three dots
   (9b01e5b). So the line itself is the drag surface — there is no second dot mark and no
   extra column to squeeze the others — and the line being moved is marked by a tinted row
   plus a non-colour cue, never by colour alone. */
#communications-rows tr.is-dragging { background: var(--color-soft); }
#communications-rows tr.is-dragging td:first-child, #communications-rows tr.is-dragging th { font-weight: 600; }
#communications-view.is-reordering { user-select: none; }

/* ------------------------------------------------- compact AI presentation */

.ai-panel { margin-top: var(--space-3); padding: var(--space-3); border: 1px solid var(--color-line); border-radius: var(--radius-card); background: var(--color-surface); }
.ai-heading { display: flex; align-items: center; gap: var(--space-2); }
.ai-icon { display: grid; place-items: center; width: 24px; height: 24px; border-radius: 6px; background: var(--color-teal-pale); color: var(--color-teal-dark); font-size: var(--font-size-12); }
.review-chip { margin-left: auto; padding: 1px var(--space-2); border: 1px solid var(--color-line); border-radius: 4px; color: var(--color-muted); font-size: var(--font-size-10); font-weight: 600; }
.ai-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-2); margin-top: var(--space-2); }
.ai-grid article { padding: var(--space-2) var(--space-3); border-left: 3px solid var(--color-blue); border-radius: 4px; background: var(--color-soft); }
.ai-grid article strong { font-size: var(--font-size-12); }
.ai-grid article p { margin: var(--space-1) 0 0; color: var(--color-muted); font-size: var(--font-size-11); line-height: 1.45; }
.ai-guidance { border-color: var(--color-teal) !important; }
.ai-warning { border-color: var(--color-amber) !important; }
.ai-proposal { border-color: #7954a2 !important; }
.ai-proposal div { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-2); }
.ai-proposal button { padding: 1px var(--space-2); border: 1px solid var(--color-line); border-radius: 4px; font-size: var(--font-size-11); }
.ai-proposal span { color: var(--color-muted); font-size: var(--font-size-10); }

/* ------------------------------------------------------- stage help overlay */

/* Owner UAT correction 4 — Stage Help is an overlay over the current page, not
   an inline panel that reflows it (design system §7B). It is a native modal
   dialog: it is drawn above the page in the top layer, so opening and closing it
   changes no page layout and moves neither the practitioner's stage position nor
   the page scroll; the engine keeps focus inside it while it is open and returns
   focus to the control that opened it; and it carries its own visible close
   control, named for the action it performs. Escape closes it through the same
   path as that control. */
/* Stage Help (design system §7B) — Owner UAT correction package
   (2026-09-16T19:48:10Z, item 1). The overlay is a compact scanning surface
   rather than a document: a banner states where the stage sits, which stage it
   is and what it is for in one line, and four separated cards carry Purpose,
   what the practitioner should accomplish, the expected outputs and what
   completion means. Prose is not boxed: each card is separated by a rule, so
   the surface carries no nested chrome and no dead space between blocks. */
#stage-help-panel { width: min(880px, 100% - 32px); max-height: min(88vh, 700px); padding: 0; overflow-y: auto; border: var(--border-card); border-radius: var(--radius-card); background: var(--color-surface); color: var(--color-ink); box-shadow: var(--shadow-raised); }
#stage-help-panel::backdrop { background: rgb(17 40 79 / 42%); }
/* The overlay's banner. It is a two-column grid — the stage identity and the
   close control — with the stage summary on a full-width row of its own beneath
   them (Owner UAT correction package, item 2), so the summary sentence reads on
   one row in the supported desktop layout. */
.stage-help-heading { position: sticky; top: 0; z-index: 1; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; gap: var(--space-1) var(--space-4); padding: var(--space-4) var(--space-4) var(--space-3); border-bottom: 1px solid var(--color-line); background: var(--color-soft); }
/* The close control is a fixed 24x24 target: it must never be compressed by the
   summary it sits beside (§10 pointer-target floor). */
.stage-help-heading .icon-button { flex: 0 0 auto; }
.stage-help-identity { min-width: 0; }
.stage-help-position { margin: 0 0 var(--space-1); color: var(--color-teal-dark); font-size: var(--font-size-12); font-weight: 400; letter-spacing: .1em; text-transform: uppercase; }
.stage-help-heading h2 { margin: 0; font-size: var(--font-size-20); line-height: 1.2; }
/* The banner line spans the overlay's whole content width and is deliberately
   not width-capped: the cap that used to sit here is what wrapped the sentence
   inside the column beside the close control. */
.stage-help-summary { grid-column: 1 / -1; margin: var(--space-1) 0 0; color: var(--color-ink); font-size: var(--font-size-12); font-weight: 400; line-height: 1.45; }
/* The overlay's composition: the two statements (what the stage is for, what
   completion means) run full width, and the two scan lists sit side by side
   between them. Reading order is the document order, and neither column is left
   with dead space under a short card. */
.stage-help-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--space-4); padding: var(--space-2) var(--space-4) var(--space-4); }
.stage-help-card { min-width: 0; padding: var(--space-3) 0 var(--space-1); border-top: 1px solid var(--color-line-soft); }
.stage-help-purpose, .stage-help-completion { grid-column: 1 / -1; }
.stage-help-outputs { padding-left: var(--space-4); border-left: 1px solid var(--color-line-soft); }
.stage-help-card h3 { margin: 0 0 var(--space-2); color: var(--color-navy); font-size: var(--font-size-12); font-weight: 400; line-height: 1.3; letter-spacing: .06em; text-transform: uppercase; }
.stage-help p, .stage-help li { color: var(--color-muted); font-size: var(--font-size-12); font-weight: 400; line-height: 1.45; }
.stage-help p { margin: 0; }
.stage-help ul { margin: 0; padding-left: 1.1rem; }
.stage-help li + li { margin-top: 2px; }
.stage-help-purpose p, .stage-help-completion p { color: var(--color-ink); }

/* ----------------------------------------------------------- context help */

/* Context Help is a compact glyph inside a >=24x24 pointer target (design
   system §10): the button is the target, the span is the visible ring. */
.help-icon { display: inline-grid; place-items: center; width: 24px; height: 24px; margin-left: var(--space-1); padding: 0; border: 0; background: none; color: var(--color-navy); font-size: var(--font-size-10); font-weight: 600; line-height: 1; vertical-align: middle; }
.help-icon > span { display: grid; place-items: center; width: 16px; height: 16px; border: 1px solid var(--color-line); border-radius: 50%; background: var(--color-surface); }
.help-icon[aria-expanded="true"] > span { background: var(--color-soft); border-color: var(--color-blue); }

/* Owner UAT correction 5 — Context Help is a hover/focus popover, not an inline
   panel that reflows the page (design system §7C). The scope wraps the help
   control and its help together, so a pointer that moves from the `?` onto the
   help keeps it open, and the popover itself is drawn against the viewport by
   `placeContextHelp()` in `src/app.js` — the same placement pattern the row
   actions menu uses — because a popover drawn inside the form drawer would be
   clipped by that container's own scroll. It appears on pointer hover and on
   keyboard focus, and disappears when hover or focus leaves. */
.help-scope { position: relative; display: inline-flex; align-items: center; }
/* Owner ruling (2026-10-09): every help surface is ONE size and carries NO BOLD. The popover
   states its own weight so it never inherits the 600 of the heading it opens on, and every group
   is separated by space and a hairline rule rather than by weight. */
.context-help { font-size: var(--font-size-12); font-weight: 400; line-height: 1.45; position: fixed; top: 0; left: 0; z-index: 38; width: max-content; max-width: min(300px, 72vw); padding: var(--space-2) var(--space-3); border: var(--border-card); border-left: 3px solid var(--color-blue); border-radius: 4px; background: var(--color-surface); box-shadow: var(--shadow-raised); }
.context-help strong { display: block; color: var(--color-navy); font-size: var(--font-size-12); font-weight: 400; line-height: 1.45; }
.context-help-body { display: block; margin-top: 2px; color: var(--color-muted); font-size: var(--font-size-12); font-weight: 400; line-height: 1.45; white-space: pre-line; }
.context-help-group { display: block; }
.context-help-group ~ .context-help-group { margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--color-line-soft); }

/* ---------------------------------------------------------- help drawer */

/* Owner UAT correction — Help & Guidance as a popup (Issue #13 comment
   2026-09-17T03:32:01Z). The application-level help surface is a centred modal
   popup rather than a right-side drawer: it is drawn above the current workspace
   in the top layer, so it opens and closes without reflowing the page or moving
   the practitioner's Project or stage. `display` is never declared on the bare
   selector (an author display would outrank `dialog:not([open]) { display: none }`
   and leave a closed popup painted over the shell); the dialogue box is the
   engine's own, and the two columns below are the only layout this adds. */
.help-popup { width: min(var(--craft-dialog-width), 100% - 48px); max-height: min(88vh, 720px); padding: 0; overflow-y: auto; border: var(--border-card); border-radius: var(--radius-card); background: var(--color-surface); color: var(--color-ink); box-shadow: var(--shadow-raised); }
.help-popup::backdrop { background: rgb(17 40 79 / 42%); }
.help-popup-heading { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding: var(--space-4) var(--space-4) var(--space-3); border-bottom: 1px solid var(--color-line); background: var(--color-soft); }
.help-popup-heading h2 { font-size: var(--font-size-20); }
.help-popup-heading .icon-button { flex: 0 0 auto; }
.help-lead { margin: 0; padding: var(--space-3) var(--space-4) 0; color: var(--color-muted); font-size: var(--font-size-12); font-weight: 400; line-height: 1.45; }
/* The guidance itself: two columns at the supported desktop and tablet widths so
   the popup uses its width rather than growing downwards, one column in the
   off-canvas layout where the popup is a full-width sheet. */
.help-popup-body { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-2) var(--space-4); padding: var(--space-2) var(--space-4) var(--space-4); }
/* Owner ruling (2026-10-09): a help group is separated by space and a hairline rule, never by a
   weightier heading. The heading inside help is plain 400 at the one help size. */
.help-popup section { margin-top: var(--space-3); padding-top: var(--space-2); border-top: 1px solid var(--color-line-soft); }
.help-popup-body section:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.help-popup-body h3 { color: var(--color-navy); font-size: var(--font-size-12); font-weight: 400; line-height: 1.4; letter-spacing: .04em; text-transform: uppercase; }
.help-popup section p { margin: var(--space-1) 0 0; color: var(--color-muted); font-size: var(--font-size-12); font-weight: 400; line-height: 1.5; }

/* ------------------------------------------- unimplemented destination */

.planned-view { max-width: 720px; padding: var(--space-4); border: var(--border-card); border-left: 3px solid var(--color-line); border-radius: var(--radius-card); background: var(--color-surface); }
.planned-heading { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.planned-heading h2 { font-size: var(--font-size-20); }
.planned-badge { padding: 1px var(--space-2); border: 1px solid var(--color-line); border-radius: var(--radius-pill); background: var(--color-soft); color: var(--color-muted); font-size: var(--font-size-11); font-weight: 600; }
.planned-view p { color: var(--color-muted); font-size: var(--font-size-12); line-height: 1.5; }
.planned-scope { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--color-line-soft); }
.planned-scope h3 { font-size: var(--font-size-12); }
.planned-scope ul { margin: var(--space-2) 0 0; padding-left: 1.1rem; }
.planned-scope li { color: var(--color-muted); font-size: var(--font-size-12); line-height: 1.5; }
.planned-note { margin: var(--space-3) 0; padding: var(--space-2) var(--space-3); border-left: 3px solid var(--color-line); background: var(--color-soft); }

/* ----------------------------------------------------------- evaluate view */

.preview-badge { padding: 1px var(--space-2); border-radius: 4px; background: #fff0d9; color: #805000; font-size: var(--font-size-11); font-weight: 600; }
.preview-notice { margin-bottom: var(--space-3); padding: var(--space-2) var(--space-3); border-left: 3px solid var(--color-amber); background: #fff8e9; color: #654a15; font-size: var(--font-size-12); }
/* Owner UAT correction package (Issue #13 comment 2026-09-16T20:47:51Z, item 3):
   the continuity statement. A stage that is not available yet says, in the
   interface, that the Change it will work on is the one registered in DEFINE —
   the same record, with no separate identity — so the placeholder cannot be read
   as standing for a stage-local Change model. */
.stage-continuity { margin-bottom: var(--space-3); padding: var(--space-2) var(--space-3); border: var(--border-card); border-left: 3px solid var(--color-teal); border-radius: 4px; background: var(--color-surface); }
.stage-continuity strong { display: block; color: var(--color-navy); font-size: var(--font-size-12); }
.stage-continuity p { margin: var(--space-1) 0 0; color: var(--color-muted); font-size: var(--font-size-12); line-height: 1.5; }
.evaluate-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--space-3); margin-bottom: var(--space-3); }
.evaluate-grid article { padding: var(--space-4); }
.evaluate-grid article > p:not(.card-number), .evaluate-grid li { color: var(--color-muted); font-size: var(--font-size-12); line-height: 1.5; }
.evaluate-grid ul { margin: var(--space-2) 0; padding-left: 1.1rem; }
.card-number { margin: 0 0 var(--space-2); color: var(--color-teal); font-size: var(--font-size-10); font-weight: 600; letter-spacing: .1em; }
.evaluate-grid button { padding: var(--space-1) var(--space-2); border: 1px solid var(--color-line); border-radius: 4px; font-size: var(--font-size-11); }

/* ------------------------------------------------ change form popup (§6) */

/* Owner UAT correction package (2026-09-16T19:48:10Z, item 3). The Add/Edit
   Change form is a compact centred popup, sized to the form it holds: at the
   supported desktop viewport every field, including the 35-character Title
   limit note and the group legend, is reachable without the form scrolling
   inside itself. The dialog is sized by the application, not by the viewport,
   so it no longer stretches to full height. A genuinely small viewport may
   scroll the dialog naturally, which is the documented fallback. */
#change-dialog {
  width: min(1080px, 100% - 48px);
  max-width: 100%;
  max-height: min(94vh, 900px);
  margin: auto;
  padding: 0;
  border: var(--border-card);
  border-radius: var(--radius-card);
  color: var(--color-ink);
  box-shadow: var(--shadow-raised);
  overflow: hidden;
}
/* `display` is declared on `[open]` only: an author `display` on the bare
   selector outranks the engine's `dialog:not([open]) { display: none }`, which
   would leave a closed form rendered and focusable in the page behind the shell. */
#change-dialog[open] { display: flex; flex-direction: column; }
#change-dialog::backdrop { background: rgb(17 40 79 / 42%); }
#change-form { display: flex; flex: 1 1 auto; flex-direction: column; min-height: 0; max-height: 100%; padding: 0 var(--space-4) var(--space-2); overflow-y: auto; }
/* The heading and the actions stay put while the form scrolls on a short
   viewport, so the close control and Save/Cancel are always reachable. */
.dialog-heading { position: sticky; top: 0; z-index: 2; display: flex; align-items: flex-start; justify-content: space-between; padding: var(--space-1) 0 var(--space-2); border-bottom: 1px solid var(--color-line); background: var(--color-surface); }
/* Owner, 2026-09-23: space between the form's help line and the first section. */
.form-intro { margin: var(--space-1) 0 var(--space-4); color: var(--color-muted); font-size: var(--font-size-11); }
.form-legend { color: var(--color-navy); font-weight: 600; }
.form-message { margin: var(--space-2) 0; padding: var(--space-2); border-left: 3px solid var(--color-red); background: #fff0f0; color: #7f2828; font-size: var(--font-size-12); font-weight: 600; }
/* The five progressive groups are separated by a hairline rule rather than by
   five nested boxes: less chrome, no dead space, and the whole form — including
   the audit-metadata band added by the follow-on correction package (item 4) —
   fits the supported desktop viewport without an inner scrollbar. The section
   gap is one spacing step (4px) rather than two: the rule and the section's own
   top padding already separate the bands, so the removed 4px per section is the
   dead space the added band would otherwise cost. */
.form-section { margin: 0 0 var(--space-1); padding: var(--space-1) 0 0; border: 0; border-top: 1px solid var(--color-line-soft); border-radius: 0; }
.form-section > legend { padding: 0; margin-bottom: 2px; }
/* A Context Help control in a section heading is a 24x24 target (§10), but it must not
   make the heading taller than its own text: six legends carrying one cost the Change
   form 22px it does not have (measured 2026-09-25: 865px of a 844px box). The scope
   keeps a text-height box while the control keeps its full 24x24 hit area, so the
   target rule is untouched and the form's own geometry does not change. */
/* The same on every surface: a heading and a field label are text, so carrying a 24x24
   control must not make either of them taller than its own words (measured 2026-09-25:
   six legends carrying one cost the Change form 22px it did not have, and a label's line
   grew the same way). The control keeps its full 24x24 hit area (§10). */
.help-icon { margin-block: -4px; }
/* Six columns, so each section is one horizontal band: identity, classification,
   ownership, evidence and relationship each read left to right instead of
   stacking into a long vertical form. */
.form-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--space-1) var(--space-3); }
.field-2 { grid-column: span 2; }
.field-1 { grid-column: span 1; }
.field-3 { grid-column: span 3; }
.field-4 { grid-column: span 4; }
.field-6 { grid-column: span 6; }
.field-label { display: block; margin-bottom: 1px; color: var(--color-navy); font-size: var(--font-size-12); font-weight: 600; }
.field-label small { margin-left: var(--space-1); color: var(--color-muted); font-size: var(--font-size-10); font-weight: 400; }
/* Owner's instruction 2026-10-05: "Change the field height to 30". At 34px an 11px value floated
   in 23px of its own space; at 30px the text sits in the box. Every field moves together, so a
   component looks the same wherever it appears. */
.form-grid input, .form-grid select, .form-grid textarea { display: block; width: 100%; min-height: 30px; padding: var(--space-1) var(--space-2); border: 1px solid var(--color-line); border-radius: var(--radius-control); background: var(--color-surface); color: var(--color-ink); font-size: var(--font-size-13); }
.form-grid input[readonly], .form-grid textarea[readonly] { background: var(--color-soft); color: var(--color-muted); }
.form-grid textarea { resize: vertical; }
.form-grid input:disabled, .form-grid select:disabled, .form-grid textarea:disabled { background: var(--color-soft); color: var(--color-muted); }
fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }
legend { margin-bottom: var(--space-1); color: var(--color-navy); font-size: var(--font-size-12); font-weight: 600; }
legend small { margin-left: var(--space-1); color: var(--color-muted); font-size: var(--font-size-10); font-weight: 400; }
/* Owner UAT correction 9 — the four Change Group controls sit on one row at the
   supported desktop form width. Only a genuinely narrow viewport may wrap them,
   and the labels stay legible and the targets stay usable. */
/* Owner instruction 2026-09-23: every control in the form was as wide as its column,
   well past the longest text it can ever hold ("Select a Change Criticality", "Not
   recorded"), and the Change Group chips were just as wide. Each is capped near the
   width of its own longest content, so the form reads tighter without losing a field,
   a label or an option. */
.form-grid select { max-width: 260px; }

/* Owner's character limits (2026-10-05): a field is only as wide as the fact it holds. Measured
   at this form's own 11px type, 20 characters need 140px and 30 characters 210px, so a mobile
   number no longer sits in a 357px box with 251px of empty space beside it. A 20-character fact
   in the identity section is the same width wherever it appears, which is what keeps one fact
   one width there. Organisation, Location and Manager name left this group on the Owner's ruling
   of 2026-10-14: they stand on one row of their own below Business unit / Department / Team, and
   each takes an equal share of it - see the row block below. */
#stakeholder-form :is(input[name="firstName"], input[name="surname"], input[name="mobile"]) { width: 140px; max-width: 100%; }
#stakeholder-form input[name="jobTitle"] { width: 210px; max-width: 100%; }
/* The email's own limit is 40 characters (Owner's ruling, 2026-10-14, down from the 50 he raised it
   to on 2026-10-05), and a field is as wide as the fact it holds: 40 characters measure about
   280px at this form's 11px type. */
#stakeholder-form input[name="email"] { width: 280px; max-width: 100%; }
/* The Owner's layout is three fields to a row, each as wide as the fact it holds. An equal-share
   grid cannot do that: a third of this dialog is 234px, which caps the email below the 280 its 40
   characters need. A flex row lets every control take its own width - 280 for the email, 140 for a
   mobile - and the three still hold one row inside the dialog's own width. */
#stakeholder-form .form-grid { display: flex; flex-wrap: wrap; gap: var(--space-2); }
#stakeholder-form .form-grid > .field { flex: 0 0 auto; }
/* A drop-down is as wide as the words it has to show: the Owner's rule that text inside a field
   is completely visible applies to the prompt and the options, not only to what is typed. */
#stakeholder-form select[name="classification"] { width: 190px; max-width: 100%; }
/* ADR-0071 — the Category's TWO controls (External type / Role in the change) share this one cell,
   one shown at a time, and each keeps the 170px the Category column has always taken, so the
   column alignment (190 / 170 / 210) is unchanged. */
#stakeholder-form :is(select[name="externalType"], select[name="roleInChange"]) { width: 170px; max-width: 100%; }
/* The words the screen says when a switch clears a value (ADR-0071): one plain line, and no space
   at all while it is hidden, so the form's own height does not move. */
#stakeholder-category-move { margin: 2px 0 0; color: var(--color-muted); font-size: var(--font-size-10); font-weight: 600; }
#stakeholder-category-move[hidden] { display: none !important; }
/* Owner's ruling, 2026-10-14 (answer 3 on the bulk import): Organisation, Location and Manager
   name stand on ONE row beneath Business unit / Department / Team. Each group of fields is its own
   flex line, so the new row cannot be broken by the dialog's own width however long the labels
   beside it get, and the three fields share the row equally - which is the design's own row of
   three equal columns. The three organisation facts keep the widths the Owner gave them on
   2026-10-09 and still hold the longest name the taxonomy carries. ADR-0066: Business unit,
   Department and Team are chosen from the organisation taxonomy, so they are drop-downs. */
#stakeholder-form .form-grid.form-grid-rows { display: block; }
#stakeholder-form .form-row { display: flex; flex-wrap: wrap; gap: var(--space-2); }
#stakeholder-form .form-row + .form-row { margin-top: var(--space-2); }
#stakeholder-form .form-row > .field { flex: 0 0 auto; }
#stakeholder-form .form-row > .field-equal { flex: 1 1 0; min-width: 0; }
#stakeholder-form .field-equal :is(input, select) { width: 100%; max-width: 100%; }
#stakeholder-form select[name="businessUnit"] { width: 170px; max-width: 100%; }
#stakeholder-form select[name="department"] { width: 210px; max-width: 100%; }
#stakeholder-form select[name="team"] { width: 190px; max-width: 100%; }
/* The live character counter the Owner asked for (2026-10-14): what the field holds against its own
   maximum, read from the field's `maxlength` so the two can never disagree. It sits inside the
   label line, in the label's own muted type, so showing it moves nothing - the fault he reported
   when a counter was last tried (ADR-0043). The count turns amber at the limit. */
#stakeholder-form .field-count { font-variant-numeric: tabular-nums; }
#stakeholder-form .field-count.at-limit { color: var(--ds-amber); font-weight: 600; }
/* The channel list's group headings are the separation the Owner asked to keep. A native
   optgroup label is drawn bold by the browser, which is outside this design system's weight
   contract, so the label is set to the contract's own bold weight (Owner's list, 2026-10-05). */
#communication-channel optgroup { font-weight: 600; }
.form-grid input[name="owner"], .form-grid input[name="timing"] { max-width: 260px; }
.checkbox-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-1) 6px; }
.checkbox-grid label { display: flex; align-items: center; gap: var(--space-1); min-height: 30px; max-width: 156px; padding: var(--space-1); border: 1px solid var(--color-line); border-radius: var(--radius-control); font-size: var(--font-size-11); white-space: nowrap; }
.checkbox-grid input { width: auto; margin: 0; }
.relationship-fields { border-color: #d7cfe0; background: #faf8fc; }
/* §5.7 — the Change's own populations. The linked records are drawn as chips on
   the field itself: the answer, not a count of it. The chips appear only once
   something is linked, because the entry row above them already states what the
   field is for, and a field that says "None linked yet" in its own height costs
   the form room it needs for a real field. */
.link-entry { display: flex; align-items: center; flex-wrap: nowrap; gap: var(--space-1); overflow-x: auto; overflow-y: hidden; }
.link-entry input { flex: 1 1 auto; min-width: 0; min-height: 28px; }
.link-entry select { flex: 0 0 auto; width: auto; max-width: 132px; }
.link-add { flex: 0 0 auto; min-height: 28px; padding: 0 var(--space-2); border: 1px solid var(--color-line); border-radius: var(--radius-control); background: var(--color-surface); color: var(--color-navy); font-size: var(--font-size-12); font-weight: 600; }
.link-add:hover { border-color: var(--color-blue); }
/* `display: contents` puts the linked names directly in the entry row, so the
   field is one line however many populations are linked and the form's own height
   never depends on how many there are. The list keeps its name and its semantics. */
.link-list { display: contents; list-style: none; }
.link-list:empty { display: none; }
.link-extra { display: flex; align-items: center; gap: var(--space-1); margin-top: var(--space-1); }
.link-extra[hidden] { display: none; }
.link-chip { display: flex; flex: 0 0 auto; align-items: center; gap: 0; max-width: 100%; min-height: 24px; padding: 0 0 0 var(--space-2); border: 1px solid var(--color-line); border-radius: var(--radius-pill); background: var(--color-soft); color: var(--color-ink); font-size: var(--font-size-11); }
.link-chip > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.link-empty { color: var(--color-muted); font-size: var(--font-size-11); white-space: nowrap; }

/* ---------------------------------------------------------------------------
   ADR-0068 (Build D) — the derived Impacted Groups report and the Change's group selector.

   The report is READ-ONLY: its rows are derived from each Change's selections, so it carries no
   write control and says so in words (`.register-derived-note`), not only by the absence of
   buttons. The selector lists the organisation's own groups exactly as the hierarchy is — the
   business unit, its departments, each department's teams — grouped and searchable.
   --------------------------------------------------------------------------- */
.register-derived-note { margin: var(--space-2) 0 0; color: var(--color-muted); font-size: var(--font-size-12); }
.group-selector-body { display: flex; flex: 1 1 auto; flex-direction: column; gap: var(--space-2); min-height: 0; padding: 0 var(--space-4) var(--space-2); }
.group-selector-count { margin: 0; color: var(--color-muted); font-size: var(--font-size-12); }
.group-selector-list { flex: 1 1 auto; min-height: 220px; max-height: min(56vh, 460px); overflow-y: auto; border: var(--border-card); border-radius: var(--radius-card); padding: var(--space-2); }
.group-selector-unit-block { margin-bottom: var(--space-2); }
.group-selector-department-block { margin-top: var(--space-1); }
.group-selector-departments { margin-left: var(--space-4); }
.group-selector-teams { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); margin-left: var(--space-4); }
.group-selector-option { display: flex; align-items: center; gap: var(--space-1); padding: var(--space-1) var(--space-2); border-radius: var(--radius-card); font-size: var(--font-size-12); cursor: pointer; }
.group-selector-option:hover { background: var(--color-soft); }
.group-selector-option.group-selector-unit { font-weight: 600; }
.group-selector-option.group-selector-department { font-weight: 500; }
.group-selector-option input { flex: 0 0 auto; }
.group-selector-empty { margin: 0; padding: var(--space-4); color: var(--color-muted); font-size: var(--font-size-12); text-align: center; }
.link-remove { flex: 0 0 auto; display: grid; place-items: center; width: 24px; height: 24px; padding: 0; border: 0; border-radius: var(--radius-pill); background: transparent; color: var(--color-muted); font-size: var(--font-size-12); line-height: 1; }
.link-remove:hover { background: var(--color-line-soft); color: var(--color-navy); }
.field-error { display: block; min-height: 1em; margin-top: 2px; color: var(--color-red); font-size: var(--font-size-10); font-weight: 600; }
.field-error:not(:empty)::before { content: "! "; }
/* The Owner removed the "!" from the Stakeholder form's field messages (2026-10-16).
   Scoped to that one form: every other form keeps the mark. */
#stakeholder-form .field-error:not(:empty)::before { content: ""; }
/* Owner UAT correction — complete change audit history (Issue #13 comment
   2026-09-17T03:19:31Z, item 7): the Change's own history, presented as record
   rather than as input. It is text, so it carries no field surface at all - no
   border, no fill, no control box to mistake for something to fill in - and it is
   set as record lines: a muted kind label, the value in the record's own ink, and
   one line per edit event. A record's history grows without bound, so the lines
   are set one step smaller and tighter than a form control: the popup keeps
   fitting the supported desktop viewport for a history of the length the
   demonstration register carries, instead of spending that height on chrome.
   `white-space: pre-line` renders the events on separate lines while letting the
   kind and the first event share a line. */
/* The Owner's layout (2026-09-25): `Created:` and `Edited:` each sit on their own
   line with their entries beneath them, and one blank line separates the two
   groups. The lines keep the band's own type and the band stays flat and
   borderless (ADR-0012) - it is a record, not a control. */
.change-history { display: grid; gap: 0; }
.change-history-line { margin: 0; color: var(--color-ink); font-size: var(--font-size-12); line-height: 1.2; white-space: pre-line; }
.change-history-kind { display: block; margin: 0; color: var(--color-muted); font-size: var(--font-size-12); font-weight: 600; line-height: 1.25; }
/* The blank line the Owner's layout draws between the Created group and the Edited
   group: one spacing step, which reads as a blank line at this type size. */
#change-history-edited-kind { margin-top: var(--space-3); }
/* The history field sits directly against its own label: the two extra lines the
   Owner's layout adds are paid for here, inside the band that grew, rather than by
   taking spacing from the bands the Owner has already reviewed. */
#label-change-history { margin-bottom: 0; }

[aria-invalid="true"] { border-color: var(--color-red) !important; }
.unsaved-confirm { margin-top: var(--space-3); padding: var(--space-2) var(--space-3); border-left: 3px solid var(--color-amber); border-radius: 4px; background: #fff8e9; }
.unsaved-confirm p:first-child { margin: 0; color: #654a15; font-size: var(--font-size-13); font-weight: 600; }
.unsaved-confirm p { margin: var(--space-1) 0 0; color: #654a15; font-size: var(--font-size-11); }
.unsaved-actions { display: flex; gap: var(--space-2); margin-top: var(--space-2); }
.dialog-actions { position: sticky; bottom: 0; z-index: 2; display: flex; justify-content: flex-end; gap: var(--space-2); margin-top: auto; padding: var(--space-1) 0 0; border-top: 1px solid var(--color-line); background: var(--color-surface); }

.toast { position: fixed; right: var(--space-4); bottom: var(--space-4); z-index: 70; padding: var(--space-2) var(--space-3); border-radius: var(--radius-control); background: var(--color-navy); color: var(--ds-on-primary); font-size: var(--font-size-12); box-shadow: var(--shadow-raised); }

/* ------------------------------------------------- build provenance (UAT-21) */

.build-footer { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); max-width: 1440px; margin: 0 auto; padding: 0 var(--gutter) var(--space-4); color: var(--color-muted); font-size: var(--font-size-11); }
.build-caption { padding: 1px var(--space-2); border: 1px solid var(--color-line); border-radius: 4px; background: var(--color-soft); color: var(--color-navy); font-size: var(--font-size-10); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }

/* --------------------------------------------------------- motion (§11) */

/* The stage Help overlay's entry and exit are authored, like the popup's. */
@media (prefers-reduced-motion: no-preference) {
  .app-sidebar { transition: width 160ms ease-out; }
  #change-dialog[open] { animation: decide-dialog-in 160ms ease-out; }
  #project-dialog[open] { animation: decide-dialog-in 160ms ease-out; }
  #stage-help-panel[open] { animation: decide-dialog-in 160ms ease-out; }
  #help-popup[open] { animation: decide-dialog-in 160ms ease-out; }
}
@keyframes decide-dialog-in {
  from { transform: translateY(8px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

/* ------------------------------------------------------- responsive (§9) */

/* Tablet: collapsed icon rail by default (the runtime sets the collapsed state
   at 768–1199px), expandable by the user from the utility bar. */
@media (max-width: 1199px) {
  .utility-bar { gap: var(--space-2); }
}

/* Mobile: the global navigation becomes an off-canvas menu opened from the
   visible menu control; there is never an empty desktop rail. */
@media (max-width: 767px) {
  .app-frame,
  .app-frame[data-sidebar="collapsed"] { grid-template-columns: minmax(0, 1fr); }
  .app-sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 45;
    width: min(300px, 88vw);
    overflow-y: auto;
    border-right: 1px solid var(--color-line);
    box-shadow: var(--shadow-raised);
    transform: translateX(-102%);
  }
  /* The off-canvas panel is a single scrolling surface: pinning the navigation
     to the viewport is a desktop/tablet affordance only. */
  .sidebar-inner { position: static; height: auto; overflow: visible; }
  @media (prefers-reduced-motion: no-preference) {
    .app-sidebar { transition: transform 160ms ease-out; }
  }
  .app-frame[data-sidebar="open"] .app-sidebar { transform: translateX(0); }
  .sidebar-close { display: grid; }
  .sidebar-backdrop { position: fixed; inset: 0; z-index: 40; background: rgb(17 40 79 / 45%); }
  .app-frame[data-sidebar="collapsed"] .app-nav-text,
  .app-frame[data-sidebar="collapsed"] .app-nav-current,
  .app-frame[data-sidebar="collapsed"] .app-nav-state,
  .app-frame[data-sidebar="collapsed"] .app-nav-heading,
  .app-frame[data-sidebar="collapsed"] .app-nav-disclosure,
  .app-frame[data-sidebar="collapsed"] .brand-lockup,
  .app-frame[data-sidebar="collapsed"] .user-text,
  .app-frame[data-sidebar="collapsed"] .build-identifier {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip: auto;
    white-space: normal;
  }
  .app-frame[data-sidebar="collapsed"] .app-nav-sublist { display: block; }
  .app-frame[data-sidebar="collapsed"] .app-nav-list button,
  .app-frame[data-sidebar="collapsed"] .user-chip { justify-content: flex-start; padding: var(--space-2); }

  .utility-bar { min-height: 52px; }
  /* The environment statement is no longer hidden at this width: it lives in the
     sidebar footer's technical area, which is where the practitioner looks for
     build and environment information on any device (correction 2). */
  /* The header states its Project facts in one compact block: the identity line
     wraps rather than truncating a Project name the practitioner needs to read,
     the description sits on the line directly beneath the title, and the
     Owner/Target pair keeps its place beneath that (Owner instruction,
     docs/specs/NEXT-WORK.md item 1). One column, in the order the markup
     carries.
     The even rhythm stops here: the intervals need width to sit in, so at the
     off-canvas width the two facts stay grouped on one row at the smaller step,
     and the identifier keeps its tighter gap to the name, so the header is two
     compact lines rather than a three-line block with a two-line Project name.
     Both sides of each rule keep the same smaller step, so the spacing stays
     even at this width too. */
  .header-project { grid-template-columns: minmax(0, 1fr); grid-template-areas: "identity" "description" "facts"; }
  .header-identity { flex-wrap: wrap; align-items: flex-start; gap: var(--space-2); }
  .header-identity #project-title { overflow: visible; text-overflow: clip; white-space: normal; }
  .header-facts { gap: 0 var(--space-3); padding-left: var(--space-3); }
  .header-facts > div + div { padding-left: var(--space-3); }
  /* One Project row per line: the facts wrap under the identity rather than
     being squeezed beside it (issue #18, item 8). */
  /* Owner correction 22: at the narrow width the two least critical columns are
     dropped rather than squeezed, so the table never overflows sideways and the
     identity, owner, target and status stay readable. */
  .project-list th.col-created,
  .project-list td.project-cell-created { display: none; }
  .project-list th.col-project { width: 46%; }
  .project-list th.col-owner { width: 26%; }
  .project-list th.col-target { width: 20%; }
  .project-list th.col-changes { width: 12%; }
  .project-list th.col-actions { width: 8%; }
  /* Six stages, two rows of three: the bar never scrolls sideways, so every stage is
     always on screen (Owner, 2026-09-23). */
  .stage-nav ol { grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: var(--space-2); }
  .summary-grid { grid-template-columns: minmax(0, 1fr); }
  .page-heading, .register-toolbar { align-items: stretch; flex-direction: column; }
  .register-tools { flex-direction: column; }
  /* The popup is a full-bleed sheet at this width: the engine's own modal
     max-width would otherwise leave it a floating box with side margins, which
     is the wrong treatment for the off-canvas layout. */
  .help-popup { width: 100%; max-width: 100%; max-height: 100%; margin: 0; border: 0; border-radius: 0; }
  .help-popup-body { grid-template-columns: minmax(0, 1fr); }
  #change-dialog { width: 100%; max-height: 92vh; border-radius: 0; }
  #project-dialog { width: 100%; max-height: 92vh; border-radius: 0; }
  #impacted-group-dialog { width: 100%; max-height: 92vh; border-radius: 0; }
  #group-selector-dialog { width: 100%; max-height: 92vh; border-radius: 0; }
  #stakeholder-dialog { width: 100%; max-height: 92vh; border-radius: 0; }
  /* The Stage Help overlay stacks its four cards into one column at the
     off-canvas width, and the column rule stops drawing a divider that no
     longer separates anything. */
  #stage-help-panel { width: 100%; max-height: 92vh; }
  .stage-help-grid { grid-template-columns: minmax(0, 1fr); }
  .stage-help-outputs { padding-left: 0; border-left: 0; }
  .form-grid { grid-template-columns: minmax(0, 1fr); }
  .field-2, .field-3, .field-4, .field-6 { grid-column: auto; }
  /* The four Change Groups only wrap here, where the form is a single column
     narrower than four legible controls. */
  .checkbox-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ai-heading { align-items: flex-start; flex-wrap: wrap; }
  .review-chip { margin-left: 0; }
}

/* ---------------------------------------------------------------------------
   One list pattern (Owner, 2026-09-23). The four list tables — Projects, the
   Change Register, Impacted Groups and Stakeholders — share one table treatment
   and one panel-heading treatment. Measured with tools/diff-chrome.mjs: before
   this block 10 of 13 chrome properties differed across the four lists; the
   values below are the Change Register's, which is the list the Owner reviews
   against.
   --------------------------------------------------------------------------- */
.register-card table thead th,
.register-table thead th {
  padding: 8px var(--space-3);
  background: var(--color-soft);
  color: var(--color-muted);
  font-size: var(--font-size-10);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  text-align: left;
  white-space: nowrap;
}
.register-card table tbody td,
.register-card table tbody th,
.register-table tbody td,
.register-table tbody th {
  padding: 8px var(--space-3);
  border: 0;
  color: var(--color-ink);
  font-size: var(--font-size-12);
  vertical-align: middle;
}
.register-card table tbody tr,
.register-table tbody tr { border: 0; }
.project-cell { padding: 8px var(--space-3); color: var(--color-ink); }
/* The Projects list's own description read as a teal micro-label; on every other
   list it is the muted one-line description. It is the same thing on all four. */
#projects-view .page-heading p { margin: 4px 0 0; color: var(--color-muted); font-size: var(--font-size-11); }

/* The register's scrolling box is right for a long register and wrong for a short list:
   a two-row Projects list was clipped inside it, and the clipped row's action button showed
   as a stray ⋯ under the row above (Owner report 2026-09-23). A list that fits carries
   `.table-wrap-fit` and sizes to its own rows.
   .table-wrap-fit { max-height: none; overflow: visible; }

/* Owner instruction 2026-09-23: one icon per area, taken from the navigation item itself. */
.header-area-row { display: flex; align-items: center; gap: var(--space-2); margin: 0; color: var(--color-navy); font-size: var(--font-size-13); font-weight: 600; }
.header-area-icon { display: inline-flex; flex: 0 0 auto; width: 16px; height: 16px; color: var(--color-teal); }
.header-area-icon svg { width: 16px; height: 16px; }

/* Owner report 2026-09-23: 'the 3 dots show twice on each project', still there after a hard
   refresh. Measured on the served build: one row-action button per Project row. The second
   dot mark is the text-truncation ellipsis at the end of the truncated Project name and
   description — content, not a control. They read as the same mark because the Projects row
   action carried no chrome while every other list's row action is a bordered button. It
   carries the register's treatment now, so the control reads as a control and the truncated
   text reads as text. */
.project-row-menu {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-control);
  background: var(--color-surface);
  color: var(--color-navy);
  cursor: pointer;
}
.project-row-menu[aria-expanded="true"] { background: var(--color-soft); border-color: var(--color-blue); }

/* Owner: 'you've now added both icons in there, and it doesn't look good.' The band carries
   ONE identity icon — the area's own, taken from the navigation. The round control beside it
   keeps its place (five behaviours depend on it being operable in every state, including the
   tablet rail and the off-canvas panel), but it carries a collapse control's glyph rather
   than a panel-shaped one, so it reads as a control and not as a second area icon. */

/* ---------------------------------------------------------------------------
   Form surface type floor — researched resolution, 2026-09-23.

   The Owner reported the forms reading small. Measured in both dialogs, the smallest
   text ran 9px (dialog eyebrow, field hints), 10px (form intro, group chips) and 11px
   (section legends, field labels), while the fields themselves sat at 12px.

   What the guidance says:
   - the browser default body size is 16px (MDN, font-size) — the platform norm, and the
     size the 16px-body-text convention is anchored to;
   - 16px body text is the working standard and 12px is the practical floor — nothing in a
     user interface should be set below 12px (WCAG font-size guidance, typography audits);
   - form controls below 16px trigger automatic zoom-on-focus on mobile; 16px is the size
     that stops it (same source);
   - WebAIM lists small font sizes among the anti-patterns to avoid for readability.

   So on form surfaces only — the two dialogs — nothing is set below 12px, and the fields
   themselves are 16px. Everywhere else keeps the reduced scale the Owner asked for.
   --------------------------------------------------------------------------- */
#project-dialog .eyebrow, #change-dialog .eyebrow,
#project-dialog .field-label, #change-dialog .field-label,
#project-dialog legend, #change-dialog legend,
#project-dialog .form-legend, #change-dialog .form-legend,
#project-dialog .form-intro, #change-dialog .form-intro,
#project-dialog small, #change-dialog small,
#project-dialog .checkbox-grid label, #change-dialog .checkbox-grid label,
#project-dialog .project-audit, #change-dialog .change-audit {
  font-size: var(--font-size-12);
}
#project-dialog input:not([type="checkbox"]):not([type="radio"]),
#project-dialog select, #project-dialog textarea,
#change-dialog input:not([type="checkbox"]):not([type="radio"]),
#change-dialog select, #change-dialog textarea {
  font-size: var(--font-size-12);
}

/* Owner instruction 2026-09-23: 'place a pale colour to separate the rows in the registers.'
   A pale rule between rows, on all four lists (Projects, the Change Register, Impacted Groups
   and Stakeholders), so the rows read apart without the heavier dividers the earlier one-list
   pass removed. `--color-line-soft` is the pale line token the base table already uses. */
.register-card table tbody tr,
.register-table tbody tr,
.project-list tbody tr {
  border-top: 1px solid var(--color-line-soft, #e3e9f4);
}
.register-card table tbody tr:hover,
.register-table tbody tr:hover,
.project-list tbody tr:hover {
  background: var(--color-soft);
}

/* Owner instruction 2026-09-23, two things, one cause each.

   1. 'the project name in the project register is larger than the regular default or template
      that we agreed on … they should be all the same.' Measured: the Projects register set
      its name at var(--font-size-14) (13px) while the Change Register sets its name at
      var(--font-size-13) (12px) and both the Impacted Group and Stakeholder registers set
      theirs at var(--font-size-13) (12px). The Projects name is the odd one out and comes
      down one step to match.

   2. 'tell me why you cannot remove the three dots and leave the button three dots there.'
      Because a row carries THREE three-dot marks, not two: the row-action button's glyph,
      and the ellipsis that ends the truncated Project name AND the truncated description.
      The button's dots are a control; the other two are text, drawn by text-overflow. No
      amount of work on the button can remove them, because they are not the button. They go
      by not truncating: the name and the description wrap instead. */
.project-row-name { font-size: var(--font-size-13); }
.project-cell-project {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

/* Owner instruction 2026-09-23: 'remove the bold everything in the body of the table.' Every
   list body cell — and everything drawn inside it, the row names, the ID labels, the tags and
   the status and criticality chips — carries the regular weight. The column headings keep
   their emphasis: they are the header of the table, not its body. */
.register-card table tbody,
.register-card table tbody tr, .register-card table tbody td, .register-card table tbody th,
.register-card table tbody * ,
.register-table tbody tr, .register-table tbody td, .register-table tbody th,
.register-table tbody * ,
.project-list tbody tr, .project-list tbody td, .project-list tbody th,
.project-list tbody * {
  font-weight: 400;
}

/* Owner instruction 2026-09-23: 'make the table headers bold' — 'Changes in this Project',
   'Recorded Change', 'Change Group (TYPE)', 'Owner / timing', 'Status', 'Criticality'.

   Measured first: every column heading and the panel title already render at font-weight 600.
   600 is the boldest weight the design system allows — §4.1 admits 400, 500 and 600 only, and
   the gate fails the build on anything else, which is the same rule that flagged the two
   cells this afternoon. So the weight cannot go up without changing that rule.

   What did change, and is what makes them read as the header against a body that is now all
   regular: they carry the ink colour rather than the muted one, at the same 600, and the
   panel title with them. */
.register-card table thead th,
.register-table thead th,
.project-list thead th,
.register-card .card-title h3 {
  color: var(--color-navy);
  font-weight: 600;
}

/* Owner instruction 2026-09-23: 'Panel title — 13px to 11 and centre align with search and
   filter. Search field and filter select — 11px to 10.' */
.register-card .card-title h3,
.register-card > .card-title h3 {
  font-size: var(--font-size-12);   /* 11px */
}
/* Owner report 2026-09-28: "in the change network screen, the change network needed is too close
   to the borders." Measured on the running screen: the field sat **1px** from the card's edge
   while the card's own title sat 13px in, because the header carries the inset (12px padding plus
   the 1px border) and the body carried none. A card's body is inset like its own header, on every
   card, so the rule is stated once here rather than per screen. Tables are untouched: a register's
   rows and its header band are meant to reach the card's edges, and they do. */
.workspace-card > .form-grid,
.workspace-card > .register-state,
.workspace-card > .form-intro,
.workspace-card > .value-list-note,
.workspace-card > .field-hint,
.workspace-card > .backup-state,
.workspace-card > .backup-actions { padding-inline: var(--craft-panel-padding); }

/* Owner report 2026-10-10 (ADR-0062): on Administration -> Backup the body text of every
   card ran to the card's own bottom edge - the note, the hint and the state line carried no
   inset while the card's header carried one. The card's last line keeps the craft layer's
   panel padding above the card's bottom edge, on that screen's cards only: a register card's
   table is meant to reach its edges and still does. */
.backup-view .workspace-card { padding-bottom: var(--craft-panel-padding); }

/* A Save with nothing to save (Owner, 2026-09-28): the same greyed treatment a disabled button
   gets, on a control that keeps its place in the tab order and simply does nothing when pressed. */
/* Greyed, unmistakably: a fill and a text colour that read as switched off, not just a faded
   teal. Measured on a crop, opacity alone still read as an active button (Owner, 2026-09-28). */
.primary-button.is-inactive,
.primary-button[aria-disabled="true"] {
  background: var(--color-line-soft);
  border-color: var(--color-line);
  color: var(--color-muted);
  box-shadow: none;
  cursor: not-allowed;
}
.primary-button.is-inactive:hover,
.primary-button.is-inactive:active,
.primary-button[aria-disabled="true"]:hover,
.primary-button[aria-disabled="true"]:active {
  background: var(--color-line-soft);
  transform: none;
}

.register-toolbar { align-items: center; }
.register-tools input,
.register-tools select,
.register-tools select option {
  font-size: var(--font-size-11);   /* 10px */
}

/* Owner instruction 2026-09-23: 'align the header text with icon', naming the band's own
   text — 'PRJ-001 Customer Experience Transformation / Project owner Ather Malik / Target
   Q1 2027'. The icon moves out of the area line and into the band itself, so it is present
   whether the band names an area or an open Project, and it is centred on the text block it
   belongs to, with the text starting a fixed gap after it. */
.header-area-icon { align-self: center; margin-right: var(--space-2); }
.header-context { display: flex; flex-direction: column; justify-content: center; gap: 2px; }

/* The icon and the text block are one row now: the icon is centred on the block it belongs to
   and the text starts a fixed gap after it, whether the band names an area or an open Project. */
.header-context { display: flex; flex-direction: row; align-items: center; gap: var(--space-2); }
.header-text { display: flex; flex-direction: column; justify-content: center; gap: 2px; min-width: 0; }
.header-area-icon { align-self: center; margin-right: 0; }

/* Owner instruction 2026-09-23: 'now left align it next to the icon.' The band's context block
   was still carrying justify-content: center from the column layout it used to have, so the
   icon and the text sat centred in the space rather than at the left, 210px right of the
   column the rest of the page starts on. The row is left-aligned now. */
.header-context { justify-content: flex-start; }

/* Owner instruction 2026-09-23: 'change Customer Experience Transformation to 11px.' The
   Project name in the header band was var(--font-size-20) (16px); it is var(--font-size-12)
   (11px) now. The ID chip beside it keeps its own size. */
.header-identity { font-size: var(--font-size-12); }

/* Owner instruction 2026-09-23: 'change row-action glyph to 13px in the Projects register.'
   The Projects row action carried a 14px glyph against the Change Register's 13px. */
.project-row-menu { font-size: var(--font-size-14); }

/* Owner instruction 2026-09-23: 'Page actions (Add Change, Add Project, Stage Help, Cancel,
   Save) — 34px high, 11px text.' The text buttons were 36px high at 12px; the dialog's Save
   and Cancel carry the same classes, so they move with them and every register matches. */
.primary-button,
.secondary-button {
  min-height: 34px;
  height: 34px;
  font-size: var(--font-size-12);
}

/* Owner instruction 2026-09-23: every text element in the edit forms is 11px — the dialog
   eyebrow, its title, the intro line, the section legends, the field labels, the maximum-N
   hints, the fields themselves (readonly included) and the audit/history lines. This replaces
   the 12px floor and 13px fields set earlier today. */
#project-dialog :is(h1, h2, h3, p, span, legend, label, small, strong, em, input, select, textarea, li, dt, dd, option):not(.context-help, .context-help *),
#change-dialog :is(h1, h2, h3, p, span, legend, label, small, strong, em, input, select, textarea, li, dt, dd, option):not(.context-help, .context-help *) {
  font-size: var(--font-size-12);
}

/* Owner instruction 2026-09-23: 'change row action to 11px.' The row-action glyph on every
   register — the Change Register's and the Projects register's — is 11px. */
.row-menu-button,
.project-row-menu { font-size: var(--font-size-12); }

/* Owner question 2026-09-23, on the history block: 'Change history / recorded automatically /
   Created: … / Edited: … 11/09/2026 14:35 - Sarah Jayne'. The edit events are joined with a
   newline in one line, and the newline collapsed, so two edits ran together on one line. Each
   recorded edit is its own line now. */
.change-history-line { white-space: pre-line; }

/* Owner instruction 2026-09-24: 'the fields are too big — compact them so the five sections
   fit.' The Change form's controls come down to a 24px row (the minimum pointer target), the
   textareas to two lines, and the gaps between fields and sections tighten up. Nothing about
   the words changes — this is the same form with the air taken out of it.

   The restyle of 2026-09-24 comes down one step on the space above and below each section
   (six sections, 48px) — not because the fit needs it, but because it buys room for the one
   thing §6B says grows without bound: the history. Measured at 1440x900, the restyled form
   fits at `763px in a 763px box` with the popup's cap at 846px; with the earlier section rhythm
   it fits too, at `811px in an 811px box`, leaving 35px rather than 83px for recorded events.
   The field rhythm is untouched: the label still sits 2px off its control and the legend 4px
   off its fields, so the form the Owner reviewed keeps the spacing he reviewed. */
#change-dialog .form-grid { gap: var(--space-2) var(--space-4); }
#change-dialog .form-section { margin-bottom: 0; padding-top: var(--space-1); }
#change-dialog .form-section > legend { margin-bottom: var(--space-1); }
#change-dialog .field { gap: 2px; }
#change-dialog input:not([type="checkbox"]):not([type="radio"]),
#change-dialog select { min-height: 24px; height: 24px; padding: 0 var(--space-2); }
#change-dialog textarea { min-height: 32px; }
#change-dialog .checkbox-grid { gap: var(--space-1) var(--space-2); }
#change-dialog .dialog-heading { padding-bottom: var(--space-2); }
#change-dialog .form-intro { margin-bottom: var(--space-2); }
#change-dialog .dialog-actions { padding-top: var(--space-2); }

/* Only the selected section's fields stay on screen: the form's own display rule was winning
   over the hidden attribute, so every section showed at once — that is what looked like
   duplicated fields. */
#change-dialog fieldset.form-section[hidden] { display: none !important; }

/* ---------------------------------------------------------------------------
   Slice 2 §2 — the two register forms (Impacted Groups, Stakeholders).

   A register writes its own records from its own screen, so each register's form
   is the Project popup's design language applied to a register record: a compact
   centred modal sized to the fields it holds, the same heading block, the same
   field rhythm, the same Save / Cancel / close controls, and the same form type
   rule (every text element on a form surface is var(--font-size-12), 11px). No
   new size, weight or colour is introduced for them.
   --------------------------------------------------------------------------- */
#group-selector-dialog,
#impacted-group-dialog,
#stakeholder-dialog {
  width: min(var(--craft-dialog-width), 100% - 48px);
  max-width: 100%;
  max-height: min(94vh, 820px);
  margin: auto;
  padding: 0;
  border: var(--border-card);
  border-radius: var(--radius-card);
  color: var(--color-ink);
  box-shadow: var(--shadow-raised);
  overflow: hidden;
}
/* As with the other two popups: `display` is declared on `[open]` only, because an
   author `display` on the bare selector would outrank the engine's own
   `dialog:not([open]) { display: none }` and leave a closed form rendered behind
   the shell. */
#group-selector-dialog[open],
#impacted-group-dialog[open],
#stakeholder-dialog[open] { display: flex; flex-direction: column; }
#group-selector-dialog::backdrop,
#impacted-group-dialog::backdrop,
#stakeholder-dialog::backdrop { background: rgb(17 40 79 / 42%); }
#impacted-group-form,
#stakeholder-form { display: flex; flex: 1 1 auto; flex-direction: column; min-height: 0; max-height: 100%; padding: 0 var(--space-4) var(--space-2); overflow-y: auto; }
#impacted-group-dialog :is(h1, h2, h3, p, span, legend, label, small, strong, em, input, select, textarea, li, dt, dd, option):not(.context-help, .context-help *),
#stakeholder-dialog :is(h1, h2, h3, p, span, legend, label, small, strong, em, input, select, textarea, li, dt, dd, option):not(.context-help, .context-help *) {
  font-size: var(--font-size-12);
}
/* Two fields appear only when the rule that makes them meaningful applies: the
   date a population estimate was taken, and the representation of an External
   Stakeholder. A section's own `display` beat the hidden attribute in this
   codebase once already, so the hidden state wins here explicitly. */
#impacted-group-dialog .field[hidden],
#stakeholder-dialog .field[hidden] { display: none !important; }

/* ---------------------------------------------------------------------------
   Add Change — the six-section restyle (Owner-approved mockup, 2026-09-24).

   The form states SIX sections in the Owner's order, with the Change's own audit
   history LAST as the form's sixth band.

   Three of the project's own rules govern everything below, and none is relaxed:

   - the form still fits the supported desktop viewport without scrolling inside
     itself (§6/§9). The sixth band's chrome is therefore paid for inside the
     compaction block above, not by borrowing viewport height;
   - the six-column band grid is untouched, so Title / Change ID / Change status
     keep reading side by side, left to right. This block changes no grid
     geometry;
   - §6B of the design system governs the history surface itself and is kept
     exactly: see the note below the block. A bordered record surface was already
     falsified by the fit check, and that surface was never in the served build —
     only in the mockup file.

   What the mockup draws that is NOT adopted, and why:

   - an audit block with a border and a fill. §6B forbids a field surface, border
     or fill on that surface so nothing in it can be mistaken for something to
     type into, and the design system's coverage note records that a bordered
     version made the form scroll inside itself. The band is marked by its own
     heading and hairline rule instead;
   - a two-column field grid, 64px textareas and the hints on their own line
     beneath each field. The layout suite pins the six-column bands, the 32px
     textarea and the label-line hint, and §6 states the 35-character limit is
     shown *beside* the field. Those keep the form they already had.

   The three-section form behind a left-hand list — an earlier mockup, described
   by the `.form-split` / `.form-rail` rules that used to sit here — is NOT the
   agreed design and no markup carries its classes: its rules are removed rather
   than left in the stylesheet to describe a form that does not exist.
   --------------------------------------------------------------------------- */

/* Section 6: the audit band. The surface itself is deliberately NOT restyled:
   §6B of the design system states that the history is "styled as record, not as
   input: no field surface, border, fill or control box at all", and records that
   giving it a bordered surface was falsified — the form scrolled inside itself.
   So the band gets its own heading and its own hairline rule like every other
   section, and the record inside it keeps the treatment the design system
   requires: a muted `Created:` / `Edited:` kind label with the value in the
   record's own ink. `git log -S'.change-history' -- src/styles.css` shows this
   surface has never carried a box, and it still does not. */

/* A read-only value reads read-only before it is read: the same sunken fill it
   already had, a dashed edge, and no typing cursor. Change ID, Change status and
   a Related Change with no classification to select from are all DECIDE's, not
   the practitioner's. */
#change-dialog .form-grid input[readonly],
#change-dialog .form-grid textarea[readonly],
#change-dialog .form-grid input:disabled,
#change-dialog .form-grid select:disabled {
  border-style: dashed;
  cursor: default;
}

/* Equal Change Group tiles at the form's desktop width: the four controls share
   their row evenly, instead of each stopping at a fixed 156px and leaving the
   rest of the band empty.

   Deliberately scoped to the desktop width: the off-canvas form wraps these into
   two columns per row at 767px and below, and an unscoped rule here would sit
   after that breakpoint in the cascade and outrank it. */
@media (min-width: 768px) {
  #change-dialog .checkbox-grid label { max-width: none; }
}

/* ---------------------------------------------------------------------------
   ADR-0020 — the Change's own Stakeholders screen, and the compact panel that
   records its six Change-specific engagement values.

   The screen is a per-record screen behind the Change Register row's own `...`
   menu, so it reuses the register's list anatomy and its table markup: heading
   and action, summary, panel, table. Nothing new is invented for it, and no
   colour carries a state on its own — an unassessed value says "Not recorded" in
   words (H1), so the column reads the same in light and dark.

   The panel is the app's standard pop box — `width: min(var(--craft-dialog-width), 100% - 48px)`,
   the craft layer's own width (ADR-0062) — sized to the six
   selects it holds rather than stretched to the viewport, with `display` declared
   on `[open]` only, exactly as the Change and Project forms are: an author
   `display` on the bare selector would outrank the engine's
   `dialog:not([open]) { display: none }` and leave a closed panel rendered behind
   the shell. */
#change-stakeholders-view { display: block; }
#change-stakeholders-view[hidden] { display: none; }
#change-stakeholders-heading:focus-visible { outline: 2px solid var(--color-blue); outline-offset: 2px; }
#change-stakeholders-source { margin: 0; color: var(--color-muted); font-size: var(--font-size-11); }
.assessment-actions-cell { width: 1%; white-space: nowrap; }

#assessment-dialog {
  width: min(var(--craft-dialog-width), 100% - 48px);
  max-width: 100%;
  max-height: min(94vh, 900px);
  margin: auto;
  padding: 0;
  border: var(--border-card);
  border-radius: var(--radius-card);
  color: var(--color-ink);
  box-shadow: var(--shadow-raised);
  overflow: hidden;
}
#assessment-dialog[open] { display: flex; flex-direction: column; }
#assessment-dialog::backdrop { background: rgb(17 40 79 / 42%); }
#assessment-form {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
  max-height: 100%;
  padding: 0 var(--space-4) var(--space-2);
  overflow-y: auto;
}
/* Three bands of two values each: the six are read in the model's own order
   (`03_DOMAIN_MODEL.md` §10.4), and the panel stays a statement rather than a
   long vertical form. */
#assessment-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
#assessment-dialog .field-error { min-height: 0; }

/* ---------------------------------------------------------------------------
   The mass Stakeholder upload (Owner's agreement, 2026-10-05).

   The approved layout's own order and blocks, dressed in the register forms'
   chrome: the paste box first, the count bar, the preview grid whose second
   column is the situation, the groups line, then Cancel and the count-stated
   confirm. It is the same design language as the two register popups, only
   wider, because it holds a grid. No colour carries a state on its own: every
   situation is written in words, and the row tint only reinforces them.
   --------------------------------------------------------------------------- */
#stakeholder-import-dialog {
  width: min(1180px, 100% - 48px);
  max-width: 100%;
  max-height: min(94vh, 880px);
  margin: auto;
  padding: 0;
  border: var(--border-card);
  border-radius: var(--radius-card);
  color: var(--color-ink);
  box-shadow: var(--shadow-raised);
  overflow: hidden;
}
#stakeholder-import-dialog[open] { display: flex; flex-direction: column; }
#stakeholder-import-dialog::backdrop { background: rgb(17 40 79 / 42%); }
#stakeholder-import-form {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
  max-height: 100%;
  padding: 0 var(--space-4) var(--space-2);
  overflow: hidden;
}
#stakeholder-import-dialog :is(h1, h2, h3, p, span, label, small, strong, em, input, select, textarea, li, dt, dd, option):not(.context-help, .context-help *, .craft-micro-label, .craft-pill, .craft-status) {
  font-size: var(--font-size-12);
}
#stakeholder-import-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding-top: var(--space-2); }
#stakeholder-import-dialog .form-intro { margin-bottom: var(--space-2); }
.mass-file { display: inline-flex; align-items: center; gap: var(--space-2); }
.mass-file input { font-size: var(--font-size-11); max-width: 190px; }
.mass-defaults { margin-top: var(--space-2); color: var(--color-muted); font-size: var(--font-size-11); }
.mass-defaults strong { color: var(--color-navy); }
.mass-read {
  display: flex;
  flex-wrap: wrap;
  gap: 4px var(--space-4);
  margin-top: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-line-soft);
  border-radius: var(--radius-control);
  background: var(--color-soft);
  font-size: var(--font-size-12);
}
.mass-read b { color: var(--color-navy); }
.mass-read .ok { color: var(--color-green); font-weight: 600; }
.mass-read .warn { color: var(--color-amber); font-weight: 600; }
.mass-read .bad { color: var(--color-red); font-weight: 600; }
.mass-preview { margin-top: var(--space-2); border: 1px solid var(--color-line); border-radius: var(--radius-control); overflow: hidden; }
/* ---------------------------------------------- the two-step upload's own layout (Owner,
   approved 2026-10-08): the three-part progress indicator, the template panel, the drop zone,
   the file panel, the filter pills, the groups card and the frozen grid. The upload is .csv
   only (Owner ruling, 2026-10-09): the paste box, the segmented tabs and the two shown sample
   lines are gone, leaving the drop zone and the file input as the one route. */
.mass-progress { display: flex; flex-wrap: wrap; align-items: center; gap: 0; margin: 0 0 var(--space-3); padding: 0; list-style: none; }
.mass-progress-step { position: relative; display: inline-flex; align-items: center; gap: var(--space-2); color: var(--color-muted); font-size: var(--font-size-11); }
/* The connector between two numbered circles, drawn in the gap so the three read as one path. */
.mass-progress-step:not(:last-child) { margin-right: 34px; }
.mass-progress-step:not(:last-child)::after { content: ''; position: absolute; left: 100%; top: 50%; width: 34px; height: 2px; background: var(--color-line); transform: translateY(-50%); }
.mass-progress-marker { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border: 2px solid var(--color-line); border-radius: 999px; background: var(--color-surface); color: var(--color-muted); font-size: var(--font-size-11); font-weight: 600; }
/* A step's state is carried by its own words, its border weight and a tick in its marker,
   never by colour alone. */
.mass-progress-step.is-complete { color: var(--color-green); }
.mass-progress-step.is-complete .mass-progress-marker { border-color: var(--color-green); background: var(--color-green); color: var(--color-surface); }
.mass-progress-step.is-current { color: var(--color-navy); font-weight: 600; }
.mass-progress-step.is-current .mass-progress-marker { border-color: var(--color-navy); background: var(--color-navy); color: var(--color-surface); }
.mass-progress-note { font-weight: 400; }
.mass-step { display: block; }
.mass-template-panel { margin: 0 0 var(--space-3); padding: var(--space-4) var(--space-5); border: 1px solid var(--color-line); border-radius: var(--radius-card); background: var(--color-soft); }
.mass-template-panel h3 { margin: 0 0 var(--space-2); font-weight: 600; color: var(--color-navy); }
.mass-template-note { margin: 0 0 var(--space-3); color: var(--color-muted); font-weight: 400; }
.mass-template-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); }
.mass-sample-download { display: inline-flex; align-items: center; gap: var(--space-2); }
/* REQUIRED and NOTE: the micro-label, then the pill tags that carry the column names. The words
   of the list are unchanged (name, separator, name), so nothing the rest of the application reads
   from this line moves; only the way a name is drawn changed. The `[?]` beside them opens the app's
   own context help with all twelve columns, their limits, the accepted values and the duplicate
   rule (Owner ruling, 2026-10-09). */
.mass-required, .mass-defaults { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 6px; margin: 0; color: var(--color-ink); }
.mass-defaults { margin-top: var(--space-3); color: var(--color-muted); font-weight: 400; }
/* Owner ruling (2026-10-09): no help surface carries bold, so the value it names is plain too. */
.mass-defaults strong { color: var(--color-navy); font-weight: 400; }
.mass-rows-panel h3 { margin: 0 0 var(--space-2); font-weight: 600; color: var(--color-navy); }
.mass-file-note { margin: var(--space-2) 0 0; color: var(--color-muted); font-weight: 400; }
.mass-file-note strong { font-weight: 400; }
.mass-choose-file { display: inline-flex; align-items: center; gap: var(--space-2); min-height: 32px; height: 32px; padding: 0 var(--space-4); cursor: pointer; }
.mass-file-panel { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2); margin-bottom: var(--space-2); padding: var(--space-2) var(--space-3); border: 1px solid var(--color-line); border-radius: var(--radius-control); background: var(--color-soft); }
.mass-file-panel[hidden] { display: none; }
.mass-file-panel-text { display: flex; flex-direction: column; }
.mass-file-panel-text strong { color: var(--color-navy); }
.mass-file-meta { color: var(--color-muted); font-size: var(--font-size-11); }
.mass-file-panel-actions { display: flex; gap: var(--space-3); }
.mass-filters { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-bottom: var(--space-2); }
.mass-filter { padding: 4px var(--space-2); border: 1px solid var(--color-line); border-radius: 999px; background: var(--color-surface); color: var(--color-muted); font-size: var(--font-size-11); cursor: pointer; }
/* The pill on show is marked by a border and a weight as well as by colour. */
.mass-filter.is-selected { border-color: var(--color-navy); border-width: 2px; background: var(--color-navy); color: var(--color-surface); font-weight: 600; }
.mass-download-refused { margin-left: auto; }
.mass-groups-card { margin-bottom: var(--space-2); padding: var(--space-2) var(--space-3); border: 1px solid var(--color-line); border-radius: var(--radius-control); }
.mass-groups-card h3 { margin: 0; color: var(--color-navy); font-weight: 600; }
.mass-groups-note { margin: 2px 0 var(--space-1); color: var(--color-muted); font-size: var(--font-size-11); }
.mass-group-chips { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-2); margin: 0; padding: 0; list-style: none; }
.mass-group-chip { display: inline-flex; align-items: center; gap: 6px; padding: 2px var(--space-2); border: 1px solid var(--color-line); border-radius: 999px; background: var(--color-soft); font-size: var(--font-size-11); }
.mass-group-chip-name { color: var(--color-ink); }
.mass-group-chip-state { padding: 0 6px; border-radius: 999px; background: var(--color-surface); color: var(--color-navy); font-size: var(--font-size-10); font-weight: 600; }
.mass-group-chip-count { color: var(--color-muted); font-size: var(--font-size-10); }
.mass-group-chip-empty { color: var(--color-muted); }
.mass-footer-note { margin: var(--space-1) 0 0; color: var(--color-muted); font-size: var(--font-size-12); font-weight: 400; }
.mass-empty td { padding: var(--space-2); color: var(--color-muted); font-size: var(--font-size-11); }
/* The grid keeps the row's own verdict and classification in view while it scrolls sideways:
   Row, Situation, Internal or External, Category and Organisation are pinned, and every column is
   as wide as the fact it holds. The widths come from measurement (app.js measures each column's own
   character budget and the longest value it carries, and writes the result as a custom property),
   so a value is always readable whole rather than wrapped into fragments or cut off at the column's
   edge. The pinned columns keep fixed widths for the same reason: a column that grew with its
   content would slide the frozen panes out of line with the cells beneath them. */
.mass-frozen-table { width: var(--mass-total, 1980px); min-width: var(--mass-total, 1980px); table-layout: fixed; border-collapse: separate; border-spacing: 0; }
.mass-frozen-table thead th { z-index: 2; white-space: nowrap; }
.mass-frozen-table col { width: auto; }
/* The frozen header cells must paint above the header cells that scroll under them, and the
   frozen body cells above the body cells, or a scrolled heading covers the frozen one. The four
   pinned columns are Row, Situation, Internal or External and Organisation (the Category left the
   upload's column set, Owner ruling 2026-10-09); their left offsets are written by app.js from the
   measured widths, so they cannot drift. */
.mass-frozen-table thead th:nth-child(-n+4) { position: sticky; z-index: 5; }
.mass-frozen-table tbody tr > :nth-child(-n+4) { position: sticky; z-index: 3; }
.mass-frozen-table thead th:nth-child(1), .mass-frozen-table tbody tr > :nth-child(1) { left: 0; }
.mass-frozen-table thead th:nth-child(2), .mass-frozen-table tbody tr > :nth-child(2) { left: var(--mass-left-2, 92px); }
.mass-frozen-table thead th:nth-child(3), .mass-frozen-table tbody tr > :nth-child(3) { left: var(--mass-left-3, 264px); }
.mass-frozen-table thead th:nth-child(4), .mass-frozen-table tbody tr > :nth-child(4) { left: var(--mass-left-4, 414px); }
.mass-frozen-table thead th:nth-child(1),
.mass-frozen-table thead th:nth-child(2),
.mass-frozen-table thead th:nth-child(3),
.mass-frozen-table thead th:nth-child(4) { background: var(--color-soft); }
.mass-frozen-table tbody tr { background: var(--color-surface); }
.mass-frozen-table tbody tr.refused { background: #fdf3f3; }
.mass-frozen-table tbody tr.duplicate { background: #fff9ec; }
.mass-frozen-table tbody tr > :nth-child(-n+4) { background: inherit; }
/* One fact per cell, read whole: a value never wraps and is never cut off. */
.mass-frozen-table tbody [data-import-value] { display: inline-block; white-space: nowrap; }
/* The Tick that begins every row, and the Tick at the head of the Row column that takes every
   row at once. The label carries the click, so the target is the whole 24px tile. */
.mass-tick { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; min-height: 24px; cursor: pointer; }
.mass-tick input { width: 16px; height: 16px; margin: 0; accent-color: var(--color-teal-dark); }
.mass-row-head { display: flex; align-items: center; gap: 4px; }
.mass-row-select { display: flex; align-items: center; gap: 6px; }
.mass-row-number-text { font-weight: 600; }
/* The selection line: what is ticked, said in words, and the three actions that act on it. Each
   button carries the number it affects; a button with nothing to act on is disabled and says why. */
.mass-selection { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: var(--space-2) 0 0; padding: var(--space-2) var(--space-3); border: 1px solid var(--color-line); border-radius: var(--radius-control); background: var(--color-soft); }
.mass-selection-count { font-weight: 600; color: var(--color-navy); }
.mass-selection-reason { color: var(--color-muted); font-size: var(--font-size-11); }
.mass-selection-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-left: auto; }
.mass-selection .secondary-button { min-height: 30px; height: 30px; padding: 0 var(--space-3); font-size: var(--font-size-11); }
.mass-selection .secondary-button:disabled { color: var(--color-muted); background: var(--color-surface); border: 1px dashed var(--color-line); cursor: not-allowed; }
/* The situation cell: a status pill whose words are the status, then the row's own notes. */
.mass-situation { vertical-align: top; }
.mass-situation-note { display: block; margin-top: 3px; color: var(--color-muted); font-size: var(--font-size-10); font-weight: 400; white-space: normal; }
/* The grid scrolls in its own window rather than the popup: the paste box and the
   confirm stay where they are while a long paste is read. The window is tall enough
   that a handful of rows, their situations included, are all visible at once. */
.mass-preview .table-wrap { max-height: min(45vh, 400px); scrollbar-width: thin; }
/* The grid scrolls sideways over the honest total width, so the sideways scrollbar is always drawn
   rather than hidden until a scroll happens: the footer note says the grid scrolls, and the
   control that scrolls it has to be visible for that to be true. */
.mass-preview .table-wrap::-webkit-scrollbar { height: 12px; width: 12px; }
.mass-preview .table-wrap::-webkit-scrollbar-track { background: var(--color-soft); border-radius: var(--radius-pill); }
.mass-preview .table-wrap::-webkit-scrollbar-thumb { background: var(--color-line); border: 3px solid var(--color-surface); border-radius: var(--radius-pill); }
.mass-preview table.register-table { font-size: var(--font-size-11); }
.mass-preview .register-table thead th,
.mass-preview .register-table tbody td,
.mass-preview .register-table tbody th {
  padding: 4px var(--space-2);
  border-bottom: 1px solid var(--color-line-soft);
  font-size: var(--font-size-11);
  vertical-align: top;
  overflow-wrap: anywhere;
}
.mass-preview .register-table thead th { background: var(--color-soft); font-size: var(--font-size-10); letter-spacing: .04em; }
.mass-preview .register-table tbody tr { border: 0; }
.mass-preview .register-table tbody tr.refused { background: #fdf3f3; }
.mass-preview .register-table tbody tr.duplicate { background: #fff9ec; }
.mass-preview .register-table tbody tr:hover { background: var(--color-soft); }
.mass-situation.ok { color: var(--color-green); }
.mass-situation.dup { color: var(--color-amber); }
.mass-situation.bad { color: var(--color-red); }
.mass-situation .mass-fix { display: block; color: var(--color-muted); font-size: var(--font-size-10); font-weight: 400; }
.mass-cell-fix { display: inline-flex; align-items: center; max-width: 100%; vertical-align: middle; }
.mass-cell-fix input,
.mass-cell-fix select {
  width: auto;
  max-width: 100%;
  min-height: 26px;
  height: 26px;
  padding: 0 var(--space-1);
  border: 1px solid var(--color-red);
  border-radius: var(--radius-control);
  font-size: var(--font-size-11);
}
/* The row's own number, its Tick and its Remove control, in the first cell where the
   sideways-scrolling grid leaves them in sight. */
.mass-row-number { white-space: nowrap; }
/* The single second step the Stakeholder form offers for a shared mailbox (Owner's ruling,
   2026-10-07): shown only by the duplicate-email refusal. */
.form-handoff { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-top: var(--space-2); padding: var(--space-2) var(--space-3); border: 1px solid var(--color-amber); border-radius: var(--radius-control); background: #fff9ec; }
.form-handoff[hidden] { display: none; }
.form-handoff p { flex: 1 1 320px; margin: 0; color: var(--color-ink); font-size: var(--font-size-11); }
/* The gap the register states in words: how many of its records have no role or type recorded yet,
   so it reads as a to-do rather than a default. Neutral ink, not a warning colour.
   R3 (Owner, 2026-10-16): the count lives INSIDE the toolbar, beside the selection count. It was
   a full-width band of its own, and "a band that carries a count is the same waste" as R2's band.
   It sits on the toolbar's own line and wraps where the screen is narrow (390), never overflowing. */
.register-category-gap {
  display: inline-flex;
  align-items: center;
  margin: 0;
  padding: 0 var(--space-2);
  border: 1px dashed var(--color-line);
  border-radius: var(--radius-control);
  background: var(--color-surface);
  color: var(--color-navy);
  font-size: var(--font-size-12);
  min-height: var(--ds-control-height);
  white-space: normal;
}
/* The register's own selection line, BESIDE the search field (Owner's correction, 2026-10-09): the
   selection and the Delete control that acts on it sit in one place, on the toolbar's own line. The
   selection is stated in words and the Delete control names how many records it would act on. */
.register-selection {
  display: inline-flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: var(--space-2);
  white-space: nowrap;
  font-size: var(--font-size-12);
}
.register-selection-count { font-weight: 600; color: var(--color-navy); }
.register-selection .secondary-button { min-height: 30px; height: 30px; padding: 0 var(--space-3); font-size: var(--font-size-11); }
.register-selection .secondary-button:disabled {
  color: var(--color-muted);
  background: var(--color-surface);
  border: 1px dashed var(--color-line);
  cursor: not-allowed;
}
/* Why the Delete control cannot be used, on screen and in words, never a tooltip alone. */
.register-selection-reason {
  margin: 0;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--color-line);
  background: var(--color-soft);
  color: var(--color-muted);
  font-size: var(--font-size-11);
}
/* One row per record, one fact per column, nothing stacked and NO cell wrapping (Owner's
   correction, 2026-10-09): every cell holds its one fact on its one line, and the grid scrolls
   sideways over the honest total width rather than breaking a value into fragments. */
#stakeholder-list thead th,
#stakeholder-list tbody td,
#stakeholder-list tbody th { white-space: nowrap; }
/* R4 (Owner, 2026-10-16): a long value is CUT and shown IN FULL on hover, on keyboard focus and on
   tap. His figures: Name 30 characters, Email 35; every row keeps ONE line and the typed limits do
   not change. The full text is carried by the element's own `title` (hover, and assistive tech),
   and the element is focusable — so a keyboard user reaches it with Tab and a tap focuses it — and
   on focus the clamp is lifted, so the whole value is readable there too. */
.cell-clamp {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}
.cell-clamp[data-clamp="30"] { max-width: 30ch; }
.cell-clamp[data-clamp="35"] { max-width: 35ch; }
.cell-clamp:focus {
  position: relative;
  z-index: 2;
  max-width: none;
  overflow: visible;
  background: var(--color-surface);
  outline: 2px solid var(--color-navy);
  outline-offset: 1px;
}
/* The register now carries a column per fact — Team among them since Build B (ADR-0066) — so its
   cells take the same tighter inset the Change Register took (ADR-0064 §3): the honest total width
   fits the card's 1118px frame at the supported desktop width and a row's own actions stay in view
   without a sideways scroll (Owner's correction, 2026-10-09; ADR-0066). */
#stakeholder-list th,
#stakeholder-list td { padding-inline: var(--space-1); }
/* The Actions column's own heading is aligned as its cells are, so the header sits over its column
   by MEASUREMENT and not by width alone (Owner's correction, 2026-10-09). */
#stakeholder-list thead th.col-actions { text-align: right; }
/* The register's own Tick column: one per row, plus the select-all at its head. */
.register-table th.col-select,
.register-table td.col-select { width: 1px; white-space: nowrap; }
/* The Duplicate email mark: an icon BESIDE the words, so nothing is carried by shape or colour
   alone (Owner's ruling, 2026-10-09). */
.duplicate-email-mark {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-left: var(--space-2);
  padding: 1px var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-soft);
  color: var(--color-navy-soft);
  font-size: var(--font-size-10);
  font-weight: 600;
  white-space: nowrap;
}
.duplicate-email-mark .craft-icon { width: 12px; height: 12px; }
.link-button {
  border: 0;
  padding: 0;
  background: none;
  color: var(--color-teal-dark);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
}
.link-button:hover { color: var(--color-navy); }

/* ---------------------------------------------------------------------------
   The shared craft layer (ADR-0048)

   The small building blocks every surface is entitled to draw the same way:
   the inline icon set, the micro-label, the pill tag, the segmented control,
   the dashed drop zone, the status pill and the disclosure. The look lives
   here; the little behaviour a block needs lives in `src/craft.js`. Nothing
   below knows about Stakeholders or the upload: the upload popup is simply the
   first surface to be drawn with them, and the other screens keep their own
   markup until the Owner agrees to the same treatment.

   Every block meets WCAG 2.2 AA against this application's own palette, and
   nothing is carried by colour alone: a status, a pill, a badge and a
   selection all state their meaning in words, and the tint only helps the eye.
   --------------------------------------------------------------------------- */

/* The icon: drawn inline as SVG on a 16 unit grid, inheriting currentColor so it takes the
   colour of the words beside it, and sized to the type scale it sits in. */
.craft-icon { display: inline-block; flex: 0 0 auto; width: 1em; height: 1em; vertical-align: -0.15em; }
.craft-status .craft-icon,
.craft-pill .craft-icon { width: 1em; height: 1em; }

/* The micro-label: small, letter-spaced, uppercase. The words are written in their own case and
   shouted by the style, so the text a screen reader reads is the text as written. */
.craft-micro-label {
  display: inline-block;
  font-size: var(--font-size-10);
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--color-muted);
}
.craft-micro-label[data-tone="strong"] { color: var(--color-navy); }

/* The pill tag: a small rounded chip for a column name or a group chip. */
.craft-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 8px;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  color: var(--color-ink);
  font-size: var(--font-size-11);
  line-height: 1.6;
  white-space: nowrap;
}
.craft-pill[data-tone="soft"] { background: var(--color-soft); }
.craft-pill[data-tone="strong"] { background: var(--color-navy); border-color: var(--color-navy); color: var(--color-surface); }

/* The status pill: an icon and its words, tinted. The words are the status; the tint and the
   icon are decoration, so nothing here is carried by colour alone. */
.craft-status {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  max-width: 100%;
  padding: 1px 9px;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-pill);
  background: var(--color-soft);
  color: var(--color-ink);
  font-size: var(--font-size-11);
  font-weight: 600;
  white-space: nowrap;
}
.craft-status[data-tone="ok"] { border-color: var(--color-green); background: #eaf5ee; color: var(--color-green); }
.craft-status[data-tone="warn"] { border-color: var(--color-amber); background: #fff6e6; color: var(--color-amber); }
.craft-status[data-tone="bad"] { border-color: var(--color-red); background: #fdeeee; color: var(--color-red); }

/* The segmented control: one track, one active pill with a border and a shadow, the inactive
   segment plain. The buttons are real tabs (role="tab", aria-selected, one tab stop), and
   `enhanceSegmentedControl` in craft.js walks them with the arrow keys. */
.craft-segmented {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: var(--space-3);
  padding: 3px;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-pill);
  background: var(--color-soft);
}
.craft-segmented > [role="tab"] {
  min-height: 30px;
  padding: 0 var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--color-muted);
  font: inherit;
  font-size: var(--font-size-11);
  font-weight: 600;
  cursor: pointer;
}
.craft-segmented > [role="tab"][aria-selected="true"] {
  border-color: var(--color-line);
  background: var(--color-surface);
  color: var(--color-navy);
  box-shadow: var(--shadow-card);
}

/* The dashed drop zone: dashed border, generous padding, a centred circular icon badge, the
   heading, "or", and the caller's own control. */
.craft-dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: var(--space-4);
  border: 2px dashed var(--color-line);
  border-radius: var(--radius-card);
  background: var(--color-surface);
  text-align: center;
}
.craft-dropzone.is-over { border-color: var(--color-navy); background: var(--color-soft); }
.craft-dropzone-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-pill);
  background: var(--color-teal-pale);
  color: var(--color-teal-dark);
}
.craft-dropzone-badge .craft-icon { width: 24px; height: 24px; }
.craft-dropzone-title { margin: 0; color: var(--color-ink); font-weight: 600; }
.craft-dropzone-or { margin: 0; color: var(--color-muted); }
.craft-dropzone-note { margin: 0; color: var(--color-muted); }

/* The disclosure: the triangle and its label, a native details/summary so the toggle, the
   keyboard and the expanded state in the accessibility tree come from the browser. The triangle
   turns when the disclosure is open, which is a second cue beside the change of words. */
.craft-disclosure { margin-top: var(--space-3); }
.craft-disclosure-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 24px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-navy);
  font-family: inherit;
  font-size: var(--font-size-11);
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.craft-disclosure-toggle::-webkit-details-marker { display: none; }
.craft-disclosure-triangle { width: 0.9em; height: 0.9em; transition: transform 120ms ease; }
.craft-disclosure.is-open .craft-disclosure-triangle { transform: rotate(90deg); }
.craft-disclosure-panel { margin-top: var(--space-2); }

/* The measuring rule: a hidden span the width of one piece of text, used to size a grid column
   for the fact it holds rather than for a sample value. It is placed inside the popup so it
   inherits the type the grid draws, and it is never on screen and never read out. */
.craft-measure {
  position: absolute;
  left: -10000px;
  top: 0;
  white-space: pre;
  visibility: hidden;
  pointer-events: none;
}
.mass-measure-host {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  overflow: hidden;
  visibility: hidden;
  pointer-events: none;
}

/* ---------------------------------------------------------------------------
   The craft layer's panel and pop-box metrics (ADR-0062).

   The Owner reported the Backup screen's text sitting against the panel edges, and
   the restore popup bigger than the app's regular pop box. Both are now read from ONE
   declared set of numbers, stated here and mirrored exactly by the constants in
   `src/craft.js` (`CRAFT_PANEL_PADDING`, `CRAFT_DIALOG_PADDING`, `CRAFT_DIALOG_WIDTH`,
   `CRAFT_DIALOG_WIDTH_EXCEPTIONS`), so a browser criterion can measure the rendered
   inset and the rendered width against the same values instead of trusting an eye.

   - `--craft-panel-padding`  a card body's inset, so a card's body sits inside like its
                              own header (the rule stated once on 2026-09-28).
   - `--craft-dialog-padding` a dialog body's inset; each popup's own form already carried
                              it, and the popups without a form wrapper carry it now too.
   - `--craft-dialog-width`   the app's ONE regular pop box. Every dialog is this width
                              except the three named for a reason in
                              `CRAFT_DIALOG_WIDTH_EXCEPTIONS`.
   --------------------------------------------------------------------------- */
:root {
  --craft-panel-padding: var(--space-3);
  --craft-dialog-padding: var(--space-4);
  --craft-dialog-width: 760px;
}

/* One regular pop box. A dialog named below takes the standard width, the standard body
   inset and the shared popup chrome. The three popups that hold a grid or two columns of
   help cards keep their own deliberately wider rules (#change-dialog,
   #stakeholder-import-dialog, #stage-help-panel), and each states why in its own rule. */
:is(#unit-department-dialog, #category-dialog, #account-dialog, #account-role-dialog,
    #account-reset-dialog, #forgot-dialog, #user-dialog,
    #stakeholder-delete-warning-dialog, #backup-restore-dialog) {
  width: min(var(--craft-dialog-width), 100% - 48px);
  max-width: 100%;
  max-height: min(94vh, 880px);
  margin: auto;
  padding: var(--craft-dialog-padding) 0 var(--space-2);
  border: var(--border-card);
  border-radius: var(--radius-card);
  color: var(--color-ink);
  box-shadow: var(--shadow-raised);
}
/* The body of that pop box is inset by the craft layer's dialog padding, on every direct
   child, so no popup's text sits against its own edge - the same inset every other
   dialog's form already carries. */
:is(#unit-department-dialog, #category-dialog, #account-dialog, #account-role-dialog,
    #account-reset-dialog, #forgot-dialog, #user-dialog,
    #stakeholder-delete-warning-dialog, #backup-restore-dialog) > * {
  padding-inline: var(--craft-dialog-padding);
}
:is(#unit-department-dialog, #category-dialog, #account-dialog, #account-role-dialog,
    #account-reset-dialog, #forgot-dialog, #user-dialog,
    #stakeholder-delete-warning-dialog, #backup-restore-dialog) > .dialog-heading {
  padding-top: 0;
}
/* At the off-canvas width every popup takes the whole width, the standard pop box
   included, so it behaves exactly as the four forms above already do (ADR-0062). Stated
   here, after the standard rule, so the standard rule cannot outrank it. */
@media (max-width: 767px) {
  #assessment-dialog,
  :is(#unit-department-dialog, #category-dialog, #account-dialog, #account-role-dialog,
      #account-reset-dialog, #forgot-dialog, #user-dialog,
      #stakeholder-delete-warning-dialog, #backup-restore-dialog) {
    width: 100%;
    max-height: 92vh;
    border-radius: 0;
  }
}

/* ---------------------------------------------------------------------------
   Administration → Value Lists (Owner's ruling, 2026-10-09, ADR-0052).

   The register's own lists: the units and departments, and the categories. Each entry states its
   facts, what is in use, and whether it is still active, in words first. The per-entry actions use
   the one shared row-actions menu (the same `.row-menu` the registers use) so dismissal, placement
   and focus hand-back stay one implementation.
   --------------------------------------------------------------------------- */
.value-lists-view { display: block; padding: var(--space-4); }
.value-lists-view[hidden] { display: none; }
.value-lists-access {
  margin: 0 0 var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--color-line);
  background: var(--color-soft);
  color: var(--color-ink);
  font-size: var(--font-size-12);
}
.value-list-card { margin-bottom: var(--space-4); }
.value-list-note { margin: 0 0 var(--space-2); color: var(--color-muted); font-size: var(--font-size-12); }
.value-list-table { width: 100%; }
.value-list-usage, .value-list-state { white-space: nowrap; }
.value-list-inactive td { color: var(--color-muted); }
.value-list-actions-cell { position: relative; width: 46px; text-align: right; }
.value-list-menu-button {
  width: 24px;
  height: 24px;
  padding: 0;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-control);
  background: var(--color-surface);
  color: var(--color-navy);
  font-size: var(--font-size-14);
  line-height: 1;
}
.value-list-menu-button[aria-expanded="true"] { background: var(--color-soft); border-color: var(--color-blue); }
.value-list-empty { display: block; }
.value-list-empty[hidden] { display: none; }

/* The Roles cell's count and its popup (Owner's set-cell rule, 2026-10-10, ADR-0075). The
   Roles fact does not qualify for a set cell — a person's Project dimension is unbounded — so
   the cell states a count that says what it counts, and the full list lives in this popup,
   opened from the count control by mouse or keyboard. The popup sits OUTSIDE the register
   table, beside the card, so no cell carries a nested block. */
.account-roles-cell { white-space: nowrap; }
.account-roles-count {
  padding: 1px var(--space-2);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-control);
  background: var(--color-surface);
  color: var(--color-navy);
  font-size: var(--font-size-12);
  font-weight: 600;
}
.account-roles-count[aria-expanded="true"] { background: var(--color-soft); border-color: var(--color-blue); }
.roles-popup {
  margin-top: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: var(--border-card);
  border-radius: var(--radius-control);
  background: var(--color-surface);
  box-shadow: var(--shadow-card);
}
.roles-popup[hidden] { display: none; }
.roles-popup h4 { margin: 0 0 var(--space-1); color: var(--color-navy); font-size: var(--font-size-12); }
.roles-popup ul { margin: 0 0 var(--space-2); padding-left: var(--space-4); color: var(--color-ink); font-size: var(--font-size-12); }
.roles-popup li + li { margin-top: 2px; }

/* The organisation's three levels (Owner's ruling, 2026-10-10, ADR-0065): a business unit, the
   departments in it, and the teams in each department, drawn as a hierarchy with the counted
   totals stated in words above it. Read from the store's own list, so an edited list reads its
   own totals. */
.org-totals {
  margin: 0 0 var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--color-blue);
  background: var(--color-soft);
  color: var(--color-ink);
  font-size: var(--font-size-13);
  font-weight: 600;
}
/* ----------------------------------------------------------------------------------------------
   THE ORGANISATION DIRECTORY (Owner's instruction 2026-10-10: "the org structure design is
   terrible. It should look more like this. Redesign to make it look like this." — ADR-0069).

   The reference's structure and density, drawn in DECIDE's own tokens, type contract and link
   colour: a summary strip of five stat cards, a toolbar (search, a three-way filter, Expand all /
   Collapse all) and a hierarchical table whose rows carry the taxonomy's three levels plus each
   department's "Not in a team" row. No state is carried by colour alone — the attention colour is
   a second signal, and the "Not in a team" row says so in words.
   ------------------------------------------------------------------------------------------------ */
.org-stat-strip {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--space-2);
  margin: 0 0 var(--space-3);
  padding: 0;
  list-style: none;
}
.org-stat-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2) var(--space-3);
  border: var(--border-card);
  border-radius: var(--radius-card);
  background: var(--color-surface);
  box-shadow: var(--shadow-card);
}
.org-stat-label {
  margin: 0;
  color: var(--color-muted);
  font-size: var(--font-size-10);
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.org-stat-row { display: flex; align-items: baseline; gap: var(--space-2); }
.org-stat-value {
  color: var(--color-navy);
  font-size: var(--font-size-20);
  font-weight: 600;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
/* The fifth card is the one that needs attention: a warm edge and a warm number beside the words
   "Not in a team", which already say the state (WCAG 2.2 AA — the colour is a second signal). */
.org-stat-card-attention { border-color: var(--color-amber); }
.org-stat-card-attention .org-stat-value { color: var(--color-amber); }
.org-stat-link { font-size: var(--font-size-12); }

.org-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-2);
}
.org-search-field { position: relative; display: inline-flex; align-items: center; flex: 1 1 260px; min-width: 200px; }
.org-search-icon {
  position: absolute;
  left: var(--space-2);
  color: var(--color-muted);
  font-size: var(--font-size-14);
  pointer-events: none;
}
.org-search-field input {
  width: 100%;
  min-height: var(--ds-control-height);
  padding: var(--space-1) var(--space-2) var(--space-1) 28px;
  border: 1px solid var(--color-line);
  border-radius: var(--radius-control);
  background: var(--color-surface);
  color: var(--color-ink);
  font-size: var(--font-size-12);
}
.org-filter { display: inline-flex; border: 1px solid var(--color-line); border-radius: var(--radius-control); overflow: hidden; }
.org-filter-segment {
  min-height: 30px;
  padding: 0 var(--space-3);
  border: 0;
  border-left: 1px solid var(--color-line);
  background: var(--color-surface);
  color: var(--color-ink);
  font: inherit;
  font-size: var(--font-size-12);
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
}
.org-filter-segment:first-child { border-left: 0; }
.org-filter-segment[aria-pressed="true"] { background: var(--color-navy); color: var(--ds-on-primary); font-weight: 600; }
.org-toolbar-links { display: inline-flex; gap: var(--space-3); margin-left: auto; }
.org-link-button {
  border: 0;
  padding: 0;
  background: transparent;
  color: var(--color-blue);
  font: inherit;
  font-size: var(--font-size-12);
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
}
.org-link-button:hover { color: var(--color-navy); }

.org-table { width: 100%; }
.org-col-people { width: 72px; }
.org-col-actions-narrow { width: 44px; }
.org-table thead th.org-col-name,
.org-table thead th.org-col-contains { width: auto; }
/* Children are indented by the name cell's own inset, so the level a row sits at is visible. */
.org-table tbody th.org-name-cell { padding-left: var(--space-3); white-space: nowrap; }
.org-table tbody th.org-depth-1 { padding-left: 34px; }
.org-table tbody th.org-depth-2 { padding-left: 60px; }
.org-node-label.org-node-unit { color: var(--color-navy); font-size: var(--font-size-13); font-weight: 600; }
.org-node-label.org-node-department { color: var(--color-ink); font-size: var(--font-size-12); font-weight: 600; }
.org-node-label.org-node-team { color: var(--color-muted); font-size: var(--font-size-12); font-weight: 400; }
.org-node-label.org-node-unassigned { color: var(--color-amber); font-size: var(--font-size-12); font-weight: 600; }
/* Top-level rows are faintly tinted so the three levels read at a glance. */
.org-table tbody tr.org-row-top > th,
.org-table tbody tr.org-row-top > td { background: var(--color-soft); }
.org-chevron {
  width: 18px;
  min-height: 18px;
  margin-right: var(--space-1);
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--color-navy);
  font-size: var(--font-size-12);
  line-height: 1;
  cursor: pointer;
}
.org-chevron:hover { background: var(--color-line-soft); }
.org-leaf-dot { display: inline-block; width: 18px; margin-right: var(--space-1); color: var(--color-line); text-align: center; }
.org-contains-cell { color: var(--color-muted); white-space: nowrap; }
.org-people-cell { font-variant-numeric: tabular-nums; white-space: nowrap; }
.org-people-value { color: var(--color-navy); font-weight: 600; }
.org-people-dash { color: var(--color-muted); }
.org-actions-cell { width: 44px; text-align: right; white-space: nowrap; }
.org-assign-link {
  border: 0;
  padding: 0;
  background: transparent;
  color: var(--color-blue);
  font: inherit;
  font-size: var(--font-size-11);
  font-weight: 600;
  text-decoration: underline;
  white-space: nowrap;
  cursor: pointer;
}
.org-assign-link:hover { color: var(--color-navy); }
.org-footnote {
  margin: var(--space-2) 0 0;
  color: var(--color-muted);
  font-size: var(--font-size-11);
}
/* The register's "filtered to one node" line (ADR-0069 §6): words plus a Clear control. */
.register-org-filter {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-2);
  color: var(--color-navy);
  font-size: var(--font-size-11);
  font-weight: 600;
}
@media (max-width: 1100px) {
  .org-stat-strip { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
}
/* The roll-up: the three level totals in words, then each business unit's own line (ADR-0067). */
.org-rollup-summary { margin-top: var(--space-2); }
.org-rollup-list {
  margin: 0 0 var(--space-2);
  padding-left: 0;
  list-style: none;
  color: var(--color-ink);
  font-size: var(--font-size-12);
}
.org-rollup-unit + .org-rollup-unit { margin-top: var(--space-1); }

/* The two list-backed cells of the upload grid (ADR-0052): an always-editable control that
   offers the register's own list, with the row's own verdict in words beside it. */
.mass-frozen-table tbody [data-import-value].mass-list-cell { display: block; white-space: normal; }
.mass-frozen-table tbody [data-import-value].mass-list-cell .mass-match-input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  min-height: 26px;
  height: 26px;
  padding: 0 var(--space-1);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-control);
  background: var(--color-surface);
  font-size: var(--font-size-11);
}
.mass-match-note {
  display: block;
  margin-top: 2px;
  color: var(--color-muted);
  font-size: var(--font-size-10);
  white-space: normal;
}

/* ------------------------------------------- Sign-in gate and account screen (ADR-0059)
   The Owner's ruling of 2026-10-09. The first-run setup, the sign-in screen and the
   administration account screen. Everything reuses the application's own tokens and the
   register/value-list card language, so no other screen is restyled. */

.auth-gate { display: flex; align-items: flex-start; justify-content: center; min-height: 100vh; padding: var(--space-6) var(--space-4); background: var(--color-soft); }
.auth-gate[hidden] { display: none; }
.auth-card { width: 100%; max-width: 460px; padding: var(--space-5); border: var(--border-card); border-radius: var(--radius-card); background: var(--color-surface); box-shadow: var(--shadow-raised); }
.auth-card[hidden] { display: none; }
.auth-card h1 { margin: var(--space-1) 0 var(--space-2); font-size: var(--font-size-20); font-weight: 600; color: var(--color-navy); }
.auth-card .eyebrow { margin: 0; color: var(--color-muted); font-size: var(--font-size-10); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
.auth-lead { margin: 0 0 var(--space-3); color: var(--color-muted); font-size: var(--font-size-12); }
.auth-card .dialog-actions { margin-top: var(--space-4); }
.auth-forgot { margin: var(--space-3) 0 0; color: var(--color-muted); font-size: var(--font-size-12); }
.auth-recovery { margin-top: var(--space-3); padding-top: var(--space-3); border-top: var(--border-card); }
.auth-recovery h2 { margin: 0 0 var(--space-1); font-size: var(--font-size-14); font-weight: 600; color: var(--color-navy); }
.auth-recovery p { margin: 0 0 var(--space-2); color: var(--color-muted); font-size: var(--font-size-12); }
.recovery-code { padding: var(--space-2) var(--space-3); border: 1px dashed var(--color-blue); border-radius: var(--radius-control); background: var(--color-soft); color: var(--color-navy); font-size: var(--font-size-16); font-weight: 600; letter-spacing: 0.06em; text-align: center; }
.link-button { border: 0; padding: 0; background: transparent; color: var(--color-blue); font: inherit; font-weight: 600; text-decoration: underline; cursor: pointer; }
.link-button:hover { color: var(--color-navy); }

.accounts-view { display: block; padding: var(--space-4); }
.accounts-view[hidden] { display: none; }
.role-assignment-list { list-style: none; margin: var(--space-2) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.role-assignment-list:empty { display: none; }
.role-assignment-list li { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding: var(--space-1) var(--space-2); border: var(--border-card); border-radius: var(--radius-control); background: var(--color-soft); font-size: var(--font-size-12); }
.role-assignment-list .role-fact { color: var(--color-navy); font-weight: 500; }
.role-assignment-list button { min-height: 28px; }
.role-assignment-list .role-flag {
  display: block;
  justify-content: flex-start;
  color: var(--color-navy);
  background: var(--color-soft);
  border-left: 3px solid var(--color-amber);
  font-weight: 500;
}
.field-hint { margin: var(--space-1) 0 0; color: var(--color-muted); font-size: var(--font-size-11); }
.field-hint[hidden] { display: none; }
.account-facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--space-1) var(--space-3); margin: var(--space-2) 0 var(--space-3); }
.account-facts dt { color: var(--color-muted); font-size: var(--font-size-11); }
.account-facts dd { margin: 0; color: var(--color-navy); font-size: var(--font-size-12); font-weight: 500; overflow-wrap: anywhere; }

/* ---------------------------------------------------------------------------
   Administration → Backup (Owner's ruling, 2026-10-10, ADR-0061). The screen
   reads with the other Administration screens, so it borrows their card and note
   anatomy and adds three small pieces: the single-Product-Owner notice, the
   server copy's state line, and the restore's own summary.
   --------------------------------------------------------------------------- */
.accounts-owner-notice {
  margin: 0 0 var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--color-teal-dark);
  background: var(--color-soft);
  color: var(--color-ink);
  font-size: var(--font-size-12);
}
.accounts-owner-notice[hidden] { display: none; }
.backup-actions { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-2); }
.backup-actions .field-hint { margin: 0; }
.backup-state {
  margin: var(--space-3) 0 0;
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--color-line);
  background: var(--color-soft);
  color: var(--color-ink);
  font-size: var(--font-size-12);
}
.backup-restore-summary { margin: 0 0 var(--space-3); color: var(--color-ink); font-size: var(--font-size-13); }

/* ADR-0072 - the read-only per-Project role matrix.
   Every state in a cell is carried by WORDS; the tint below is the second signal only,
   never the only one (WCAG 2.2 AA, no state by colour alone). */
.roles-matrix-view .roles-matrix-scope { margin: var(--space-2) 0 0; padding: var(--space-2) var(--space-3); border-radius: var(--radius-control); background: var(--color-soft); color: var(--color-muted); font-size: var(--font-size-12); }
.roles-matrix-view .roles-matrix-org-wide { margin: var(--space-2) 0 0; color: var(--color-ink); font-size: var(--font-size-12); }
.roles-matrix-view .roles-matrix-flags { margin: var(--space-2) 0 0; color: var(--color-ink); font-size: var(--font-size-12); }
.roles-matrix-view .roles-matrix-flags[hidden] { display: none; }
.roles-matrix-table th, .roles-matrix-table td { white-space: nowrap; }
.roles-matrix-person { font-weight: 600; }
.roles-matrix-cell { font-weight: 500; }
.roles-matrix-cell-held { color: var(--color-teal-dark); }
.roles-matrix-cell-not-held, .roles-matrix-cell-org-wide { color: var(--color-muted); font-weight: 400; }
