  /* ══ v14 (W8): THE WEBFONTS, EMBEDDED — the app makes NO outbound call ════════════
     Fetched from Google Fonts ONCE, at build time, and inlined as data: URIs. His ruling
     (2026-08-04): the app's founding constraint is offline with no server calls, and the
     stylesheet import this replaced reached the Google CDN on every open — while also making
     the typeface unreliable, because a network that blocks that CDN silently fell back to
     something else.
     ⚠ The words 'at-import' and the CDN hostnames are spelled around deliberately here: the
     embed script asserts that no fetchable reference survives, and it aborted on its own
     documentation twice before this comment stopped quoting them literally.
     ⚠ INLINE, NOT A SIDECAR FILE OR A fonts/ SUBFOLDER (2026-08-05). A font referenced by a
     relative URL is FETCHED, and on a bare file:// open Chrome refuses that as cross-origin —
     measured by W8's probe, whose error names the allowed schemes: chrome, data, http, https.
     `data:` is on that list; a sibling file is not. A subfolder would therefore have broken the
     fonts in exactly the read-only viewer ◆3 adds.
     ⚠ SUBSET: latin only. Every glyph outside it (⚠, ✓, the RAG emoji) already falls back to a
     system font today, so this changes nothing a user sees.
     ⚠ DM SANS IS ONE VARIABLE FILE covering 300-600. Asking for the three weights separately
     returns the SAME download three times (proven by hash), so it is embedded ONCE with a
     weight range — embedding per weight would have added ~98 KB of identical base64.
     ⚠ The six `font-weight: 700` rules keep being synthesised from 600, exactly as they are
     today: loading a real 700 would be a visual change nobody asked for.
     ⚠ Both families are SIL Open Font License — embedding and redistribution are permitted.
     TO REGENERATE: qa/history/w8_fetch_fonts.py then w8_embed_fonts.py. Never hand-edit the
     base64. */
  @font-face { font-family: 'DM Sans'; font-style: normal; font-weight: 300 600; font-display: swap;
    /* latin subset, 36932 bytes, one variable file for weights 300/400/500/600 */
    src: url(/fonts/dm-sans-300-600.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  @font-face { font-family: 'DM Mono'; font-style: normal; font-weight: 400; font-display: swap;
    /* latin subset, 14820 bytes */
    src: url(/fonts/dm-mono-400.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  @font-face { font-family: 'DM Mono'; font-style: normal; font-weight: 500; font-display: swap;
    /* latin subset, 14988 bytes */
    src: url(/fonts/dm-mono-500.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
  :root {
    --bg: #f5f4f0; --surface: #ffffff; --surface2: #f0efe9; --border: #dddbd3;
    /* ⚠ v13.1 (A32): --border-strong was USED four times and DEFINED nowhere. One use
       carries its own fallback; the other three (.chip-add-input's dashed border, the
       attendee reorder hover, the KPI dot focus outline) resolved to nothing and simply
       painted no border at all — an invisible control edge, silently, in both themes.
       Defined here as a deliberate one step darker than --border, which is what every
       use site assumed it was. */
    --border-strong: #bbb8ae;
    --text: #1a1916; --text2: #6b6a64; --text3: #9b9a94;
    /* v2.98: warm dark charcoal used as the "primary dark fill" for active pills,
       Save file button, and light-mode toast bg. Softer than --text (#1a1916)
       which was previously used and felt too harsh. Body text stays on --text. */
    --accent-dark: #3a3833;
    --high: #c0392b; --high-bg: #fdf0ef; --high-border: #e8a09a;
    --medium: #c87d1a; --medium-bg: #fdf6ec; --medium-border: #e8c27a;
    --low: #2d7a3a; --low-bg: #f0f8f1; --low-border: #9fd4a8;
    /* v4.0: Kanban column dots + flag + label (label/flag match the app's existing chips) */
    --col-open: #5f6b7a; --col-prog: #c87d1a; --col-hold: #9b9a94; --col-done: #2d7a3a; --col-cancel: #c0392b;
    --kb-flag: #0d9488; --kb-label: #7c3aed; --kb-label-bg: #ede9fe; --kb-label-border: #d6c9fb;
    --font: 'DM Sans', system-ui, sans-serif; --mono: 'DM Mono', monospace;
    --focus-ring: rgba(26,25,22,.42); /* v5.2: theme-safe focus ring (replaces undefined --accent) */
    }
  .dark {
    --bg: #1a1815; --surface: #242220; --surface2: #2e2c28; --border: #3a3733;
    --border-strong: #565149;   /* v13.1 (A32): one step LIGHTER than --border in dark */
    --text: #e8e6e0; --text2: #9a978f; --text3: #6b6862;
    --high: #ff7a6e; --high-bg: #3a1f1c; --high-border: #6e3530;
    --medium: #f4a942; --medium-bg: #3a2c18; --medium-border: #6e5224;
    --low: #6fcd7e; --low-bg: #1c3022; --low-border: #355d3d;
    --col-open: #9aa6b4; --col-prog: #f4a942; --col-hold: #8a8880; --col-done: #6fcd7e; --col-cancel: #ff7a6e;
    --kb-flag: #2dd4bf; --kb-label: #b794f4; --kb-label-bg: #2d2640; --kb-label-border: #4d4072;
    --focus-ring: rgba(232,230,224,.5);
  }
  /* Hardcoded-color overrides for dark mode */
  .dark .save-btn { background: var(--surface2); color: var(--text); border: 1px solid var(--border); }
  .dark .save-btn:hover { background: var(--border); opacity: 1; }
  .dark .save-btn.saved { background: #2d7a3a; color: #fff; border-color: #2d7a3a; }
  .dark .search-input:focus { border-color: #888; }
  .dark .action-card.expanded { border-color: #4a4742; box-shadow: 0 2px 12px rgba(0,0,0,0.5); }
  .dark .action-card.has-update { background: #2a2718; }
  .dark .badge-status-completed { background: #1c3022; color: #6fcd7e; }
  .dark .badge-status-in-progress { background: #1c2a3e; color: #7aa8f0; }
  .dark .badge-status-not-started { background: #2e2c28; color: #9a978f; }
  /* v2.19: dark-mode on-hold (amber) and cancelled (grey, line-through) */
  .dark .badge-status-on-hold { background: #3a2c18; color: #f4a942; }
  .dark .badge-status-cancelled { background: #2a2826; color: #807e78; text-decoration: line-through; }
  /* v2.19 item 9: dark-mode fix for update entries — use theme variables instead of hardcoded #fffdf5/#f0d080 */
  .dark .update-entry { background: var(--surface2); border-color: var(--border); }
  /* The edit textarea border #aaa is fine in light but harsh in dark */
  .dark .update-entry-text-edit { border-color: var(--border); }
  .dark .update-pill { background: #2a2516; color: #e8b54f; border-color: #5a4720; }
  .dark .changed-dot { background: #e8b54f; }
  .dark .new-action-tag { background: #1c2a3e; color: #7aa8f0; border-color: #2e4566; }
  .dark .live-tag { background: #2a2516; color: #e8b54f; border-color: #5a4720; }
  .dark .update-textarea:focus { border-color: #888; }
  .dark .session-card.current { border-color: #4a6896; box-shadow: 0 0 0 3px rgba(122,168,240,0.12); }
  .dark .session-date-input:focus { border-color: #888; }
  .dark .session-current-tag { background: #1c2a3e; color: #7aa8f0; }
  .dark .minutes-textarea:focus { border-color: #888; }
  .dark .diff-to { color: #7aa8f0; }
  /* Theme toggle button */
  .theme-toggle {
    background: none; border: 1px solid var(--border); cursor: pointer;
    padding: 7px 9px; border-radius: 6px; color: var(--text2);
    display: inline-flex; align-items: center; justify-content: center;
    transition: all 0.15s; margin-right: 10px;
  }
  .theme-toggle:hover { color: var(--text); border-color: var(--text3); background: var(--surface2); }
  .theme-toggle svg { width: 14px; height: 14px; display: block; }
  .theme-toggle .icon-sun { display: none; }
  .dark .theme-toggle .icon-moon { display: none; }
  .dark .theme-toggle .icon-sun { display: block; }
  /* Smooth theme transitions */
  /* v13.1 (U07): .stat-card removed from this list — the class has not been emitted
     since the KPI strip replaced the old stat cards; only its data KEYS survive, and
     those are a different thing (see the legacy-mapping comment in the script). */
  body, .action-card, .session-card, .header-meta, header, input, textarea, select, button {
    transition: background-color 0.2s, color 0.2s, border-color 0.2s;
  }
  /* v2.95: stabilize the vertical scrollbar gutter so the page doesn't shift
     horizontally when content height crosses the viewport boundary
     (e.g. expanding/collapsing a card). */
  html { scrollbar-gutter: stable; }
  body { font-family: var(--font); background: var(--bg); color: var(--text); min-height: 100vh; }

  /* ── HEADER ── */
  .sticky-zone { position: sticky; top: 0; z-index: 100; background: var(--bg); box-shadow: 0 4px 12px rgba(0,0,0,0.05); }
  .sticky-zone::after { content: ''; display: block; height: 1px; background: var(--border); }
  header { background: var(--surface); border-bottom: 1px solid var(--border); padding: 18px 32px 0; }
  .header-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding-bottom: 14px; }
  .brand { display: flex; align-items: center; gap: 10px; }
  .brand-logo { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
  .brand-logo svg { width: 100%; height: 100%; display: block; }
  /* v10.5 (W1) — the title-and-trail rule. Every level shows its OWN name as the title;
     the crumb trail above says where that sits. Before v10.5 the CURRENT entity was the
     quietest text in the header (.brand-name 12px/muted sitting UNDER .brand-title
     17px/solid), so the deeper you went the quieter it got. The two treatments are
     SWAPPED, not re-invented, and the DOM order is unchanged: the project name takes the
     title treatment, the product name is demoted to the muted line. */
  .brand-name { font-size: 17px; font-weight: 600; color: var(--text); letter-spacing: -0.01em; }
  .brand-title { font-size: 12px; font-weight: 500; color: var(--text2); letter-spacing: 0.02em; }
  /* ── v4.0: live "MEETING LIVE" indicator badge (child selectors scoped under
     .live-badge so the generic dot/time/sep/pp names can't collide). ── */
  .live-wrap { display:inline-flex; }
  .live-wrap.hidden { display:none; }
  .live-badge { display:inline-flex; align-items:center; gap:8px; font-family:var(--mono); font-size:11px; font-weight:500; text-transform:uppercase; letter-spacing:.7px; padding:6px 12px; border-radius:999px; white-space:nowrap; cursor:pointer; background:var(--high-bg); border:1px solid color-mix(in srgb, var(--high) 40%, var(--surface)); color:var(--high); transition:filter .15s, transform .08s; }
  .live-badge:hover { filter:brightness(0.97); }
  .live-badge:active { transform:scale(0.97); }
  .live-badge .dot { width:8px; height:8px; border-radius:50%; background:var(--high); flex-shrink:0; }
  .live-badge.running .dot { animation:liveDotPulse 1.5s ease-in-out infinite; }
  .live-badge.paused .dot { opacity:.45; }
  @keyframes liveDotPulse { 0%,100%{box-shadow:0 0 0 0 color-mix(in srgb, var(--high) 55%, transparent);} 70%{box-shadow:0 0 0 6px transparent;} }
  .live-badge .time { font-variant-numeric:tabular-nums; }
  .live-badge.paused .time { opacity:.6; }
  .live-badge .sep { opacity:.5; }
  .live-badge .pp { display:inline-flex; opacity:.7; margin-left:1px; }
  .live-badge .pp svg { width:11px; height:11px; }
  .live-wrap.enter { animation:liveEnter .5s cubic-bezier(.34,1.56,.64,1); }
  @keyframes liveEnter { 0%{transform:scale(.4) translateY(-8px);opacity:0;} 100%{transform:scale(1) translateY(0);opacity:1;} }
  .live-wrap.leaving { animation:liveLeave .42s ease forwards; }
  @keyframes liveLeave { 0%{transform:scale(1);opacity:1;} 100%{transform:scale(.6) translateY(-6px);opacity:0;} }
  /* ── v4.0: Kanban board (Actions tab, List <-> Board) ── */
  .view-toggle { display:inline-flex; background:var(--surface2); border:1px solid var(--border); border-radius:8px; padding:2px; gap:2px; vertical-align:middle; }
  .vt-btn { font-family:var(--font); font-size:12.5px; font-weight:500; color:var(--text2); background:transparent; border:none; padding:5px 12px; border-radius:6px; cursor:pointer; display:inline-flex; align-items:center; gap:6px; transition:background .15s, color .15s; }
  .vt-btn svg { width:14px; height:14px; }
  .vt-btn.active { background:var(--surface); color:var(--text); box-shadow:0 1px 2px rgba(0,0,0,0.06); }
  .dark .vt-btn.active { background:var(--border); color:var(--text); }
  #actionBoard { display:none; }
  body.actions-board #actionsList { display:none; }
  body.actions-board #emptyState { display:none !important; }
  #groupSelect { display:none; }                              /* v14.2 (d): board only */
  body.actions-board #groupSelect { display:inline-block; }
  body.actions-board #statusFilters { display:none; }
  body.actions-board #hideCompletedBtn { display:none; }
  .kb-board { display:flex; gap:14px; align-items:flex-start; overflow-x:auto; padding-bottom:10px; }
  .kb-col { flex:0 0 250px; background:var(--surface2); border:1px solid var(--border); border-radius:12px; padding:10px 10px 12px; transition:background .15s, box-shadow .15s, border-color .15s; min-height:120px; }
  .kb-col.terminal { background:transparent; border-style:dashed; }
  .kb-col.drop-target { border-color:var(--kb-flag); box-shadow:0 0 0 2px color-mix(in srgb, var(--kb-flag) 35%, transparent); background:color-mix(in srgb, var(--kb-flag) 7%, var(--surface2)); }
  .kb-col-head { display:flex; align-items:center; gap:8px; padding:3px 4px 11px; }
  .kb-col-dot { width:9px; height:9px; border-radius:50%; flex-shrink:0; }
  .kb-col-name { font-family:var(--mono); font-size:10.5px; text-transform:uppercase; letter-spacing:.6px; color:var(--text2); font-weight:500; }
  .kb-col-count { font-family:var(--mono); font-size:10.5px; color:var(--text3); background:var(--surface); border:1px solid var(--border); border-radius:9px; padding:0 7px; line-height:17px; }
  .kb-col-spacer { flex:1; }
  .kb-collapse { background:none; border:none; color:var(--text3); cursor:pointer; padding:2px; display:inline-flex; border-radius:4px; }
  .kb-collapse:hover { color:var(--text2); }
  .kb-collapse svg { width:13px; height:13px; transition:transform .2s; }
  .kb-col.collapsed .kb-collapse svg { transform:rotate(-90deg); }
  .kb-cards { display:flex; flex-direction:column; gap:8px; min-height:8px; }
  .kb-col.collapsed .kb-cards { display:none; }
  .kb-empty { font-size:11.5px; color:var(--text3); text-align:center; padding:14px 0 8px; font-style:italic; }
  .kb-card { background:var(--surface); border:1px solid var(--border); border-radius:9px; padding:10px 11px 9px; position:relative; cursor:grab; touch-action:none; box-shadow:0 1px 2px rgba(0,0,0,0.04); transition:box-shadow .15s, border-color .15s, transform .12s; animation:kbIn .26s ease both; }
  .kb-card:hover { border-color:var(--text3); box-shadow:0 2px 8px rgba(0,0,0,0.07); }
  .kb-card:active { cursor:grabbing; }
  .kb-card.ghost { opacity:0.32; }
  .kb-card.just-moved { animation:kbPulse .6s ease; }
  .kb-card.terminal-card { opacity:0.78; }
  @keyframes kbIn { from { opacity:0; transform:translateY(6px) scale(0.985); } to { opacity:1; transform:none; } }
  @keyframes kbPulse { 0% { box-shadow:0 0 0 0 color-mix(in srgb, var(--kb-flag) 55%, transparent); } 100% { box-shadow:0 0 0 9px transparent; } }
  .kb-card-top { display:flex; align-items:center; gap:6px; margin-bottom:7px; }
  .kb-pri { font-family:var(--mono); font-size:9px; text-transform:uppercase; letter-spacing:.5px; padding:1px 7px; border-radius:8px; border:1px solid; font-weight:500; }
  .kb-pri.high { color:var(--high); background:var(--high-bg); border-color:var(--high-border); }
  .kb-pri.medium { color:var(--medium); background:var(--medium-bg); border-color:var(--medium-border); }
  .kb-pri.low { color:var(--low); background:var(--low-bg); border-color:var(--low-border); }
  .kb-top-spacer { flex:1; }
  .kb-flag { color:var(--kb-flag); display:inline-flex; }
  .kb-flag svg { width:13px; height:13px; }
  .kb-id { font-family:var(--mono); font-size:10px; color:var(--text3); }
  .kb-title { font-size:13px; font-weight:500; line-height:1.35; color:var(--text); margin-bottom:9px; word-break:break-word; }
  .kb-card.terminal-card .kb-title { color:var(--text2); }
  .kb-labels { display:flex; flex-wrap:wrap; gap:4px; margin-bottom:9px; }
  .kb-label { font-family:var(--mono); font-size:9.5px; color:var(--kb-label); background:var(--kb-label-bg); border:1px solid var(--kb-label-border); border-radius:7px; padding:1px 7px; }
  .kb-blocked { font-family:var(--mono); font-size:9.5px; color:var(--high); background:var(--high-bg); border:1px solid var(--high-border); border-radius:7px; padding:1px 7px; }
  .kb-progress { height:4px; background:var(--surface2); border-radius:3px; overflow:hidden; margin-bottom:9px; }
  .dark .kb-progress { background:#3a3733; }
  .kb-progress-bar { height:100%; background:var(--low); border-radius:3px; transition:width .4s ease; }
  .kb-meta { display:flex; align-items:center; gap:8px; }
  .kb-owner { display:inline-flex; align-items:center; gap:6px; min-width:0; }
  .kb-avatar { width:20px; height:20px; border-radius:50%; background:var(--surface2); border:1px solid var(--border); color:var(--text2); font-family:var(--mono); font-size:9px; font-weight:500; display:inline-flex; align-items:center; justify-content:center; flex-shrink:0; }
  .kb-owner-name { font-size:11px; color:var(--text2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .kb-meta-spacer { flex:1; }
  .kb-due { font-family:var(--mono); font-size:10.5px; color:var(--text3); white-space:nowrap; }
  .kb-due.overdue { color:var(--high); }
  .kb-subs { margin-top:8px; border-top:1px solid var(--border); padding-top:7px; }
  .kb-subs-toggle { font-family:var(--mono); font-size:10px; color:var(--text2); background:none; border:none; cursor:pointer; display:inline-flex; align-items:center; gap:5px; padding:0; }
  .kb-subs-toggle:hover { color:var(--text); }
  .kb-subs-toggle svg { width:11px; height:11px; transition:transform .2s; }
  .kb-subs.open .kb-subs-toggle svg { transform:rotate(90deg); }
  .kb-sublist { display:none; margin-top:7px; flex-direction:column; gap:5px; }
  .kb-subs.open .kb-sublist { display:flex; }
  .kb-subitem { display:flex; align-items:center; gap:7px; font-size:11px; color:var(--text2); }
  .kb-subdot { width:6px; height:6px; border-radius:50%; background:var(--medium); flex-shrink:0; }
  .kb-subitem.done .kb-subdot { background:var(--low); }
  .kb-subitem.done { color:var(--text3); text-decoration:line-through; }
  .kb-card-floating { position:fixed; z-index:9999; pointer-events:none; width:250px; box-shadow:0 14px 34px rgba(0,0,0,0.22); transform:rotate(2.2deg) scale(1.02); cursor:grabbing; animation:none; opacity:0.97; }
  .dark .kb-card-floating { box-shadow:0 14px 34px rgba(0,0,0,0.5); }
  .header-right { display: flex; align-items: center; gap: 10px; }
  .header-meta { font-size: 11px; color: var(--text3); font-family: var(--mono); text-align: right; line-height: 1.6; }
  .save-btn { font-family: var(--font); font-size: 13px; font-weight: 600; padding: 8px 16px; border-radius: 8px; cursor: pointer; background: var(--accent-dark); color: #fff; border: none; display: flex; align-items: center; gap: 6px; transition: opacity 0.15s, background 0.2s; white-space: nowrap; }
  .save-btn:hover { opacity: 0.85; }
  .save-btn svg { width: 13px; height: 13px; }
  .save-btn.saved { background: #2d7a3a; }
  /* v10.4.2 (W3): the in-between state. Before this the button knew only dirty/saved/idle,
     so from the click until the write resolved it showed NOTHING — which reads as
     unresponsive. v10.3 deliberately stopped flashing green before the write (the old
     instant green was applied to an un-awaited write, so a failure still looked like a
     save); this gives the feedback back WITHOUT claiming success. */
  .save-btn.saving { background: var(--text2); cursor: progress; }
  .save-btn.saving svg { animation: saveSpin 0.9s linear infinite; transform-origin: 50% 50%; }
  @keyframes saveSpin { to { transform: rotate(360deg); } }
  /* v2.40: dirty indicator on save button — small amber dot when there are unsaved changes */
  .save-btn.dirty::before {
    content: '';
    display: inline-block;
    width: 7px; height: 7px;
    background: var(--medium);
    border-radius: 50%;
    margin-right: 2px;
    animation: dirtyPulse 1.8s ease-in-out infinite;
  }
  @keyframes dirtyPulse {
    0%, 100% { opacity: 0.95; }
    50% { opacity: 0.5; }
  }
  /* v2.40: disabled Reset tracker button styling */
  .reset-tracker-btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
  }

  /* v2.40: PURPLE label chips — multi-value labels replacing single-value category.
     Distinct from teal flag (v2.22), amber blocker (v2.21), neutral related (v2.21). */
  .label-chip {
    display: inline-flex; align-items: center; gap: 6px;
    background: #ede9fe; color: #7c3aed;
    font-size: 12px; padding: 3px 10px; border-radius: 12px;
    font-weight: 500;
    border: 1px solid transparent;
  }
  .label-chip-meta {
    /* Smaller variant for inline display in collapsed card meta row */
    font-size: 11px; padding: 1px 8px; border-radius: 10px;
    background: #ede9fe; color: #7c3aed;
    font-weight: 500;
  }
  .label-chip .chip-x {
    display: inline-flex; align-items: center; justify-content: center;
    width: 14px; height: 14px;
    cursor: pointer; opacity: 0.6;
    margin-left: 1px; margin-right: -3px;
    color: #7c3aed; border-radius: 50%;
  }
  .label-chip .chip-x:hover { opacity: 1; background: rgba(124,58,237,0.15); }
  .label-chip .chip-x svg { width: 8px; height: 8px; }
  .label-add-input {
    font-family: var(--font); font-size: 12px;
    padding: 3px 10px; border-radius: 12px;
    border: 1px dashed var(--border-strong, var(--border));
    background: transparent; color: var(--text2);
    width: 200px;
  }
  .label-add-input:focus { outline: none; border-color: #7c3aed; }
  .label-add-input::placeholder { color: var(--text3); }
  .dark .label-chip, .dark .label-chip-meta { background: #2d2640; color: #b794f4; }
  .dark .label-chip .chip-x:hover { background: rgba(183, 148, 244, 0.15); }

  /* ── TABS ── */
  .tabs { display: flex; gap: 0; border-top: 1px solid var(--border); margin: 0 -32px; padding: 0 32px; }
  .tab-btn { font-family: var(--font); font-size: 13px; font-weight: 500; padding: 10px 18px; border: none; background: transparent; color: var(--text3); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; transition: color 0.15s, border-color 0.15s; display: flex; align-items: center; gap: 6px; }
  .tab-btn:hover { color: var(--text2); }
  .tab-btn.active { color: var(--text); border-bottom-color: var(--text); }
  .tab-btn svg { width: 13px; height: 13px; }

  /* ── ACTIONS TAB CONTROLS ── */
  .controls { display: flex; gap: 8px; padding: 16px 32px 14px; flex-wrap: wrap; align-items: center; }
  .filter-group { display: flex; gap: 4px; background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; padding: 3px; }
  .filter-btn { font-family: var(--font); font-size: 12px; font-weight: 500; padding: 5px 11px; border: none; border-radius: 5px; cursor: pointer; background: transparent; color: var(--text2); transition: all 0.15s; white-space: nowrap; }
  .filter-btn.active { background: var(--surface); color: var(--text); box-shadow: 0 1px 3px rgba(0,0,0,0.08); }
  /* v2.7: hide-completed button always has a visible background (in both toggle states) — label change conveys the state, not color.
     min-width keeps the button stable when label switches between "Hide completed" and "Show all" so neighbours don't jump. */
  .hide-completed-btn,
  .hide-completed-btn.active { background: var(--surface); color: var(--text); box-shadow: 0 1px 3px rgba(0,0,0,0.08); min-width: 110px; text-align: center; }
  /* v2.9: expand/collapse-all buttons — stable width so neighbours don't shift when label switches */
  .expand-toggle-btn { min-width: 100px; text-align: center; }
  .filter-btn:hover:not(.active) { color: var(--text); }
  .count-badge { font-family: var(--mono); font-size: 10px; background: var(--surface2); border: 1px solid var(--border); border-radius: 3px; padding: 0 4px; color: var(--text2); margin-left: 4px; }
  .search-wrap { flex: 1; min-width: 160px; max-width: 220px; position: relative; }
  .search-wrap svg { position: absolute; left: 9px; top: 50%; transform: translateY(-50%); width: 13px; height: 13px; color: var(--text3); pointer-events: none; }
  .search-input { font-family: var(--font); font-size: 13px; width: 100%; padding: 7px 10px 7px 28px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); color: var(--text); outline: none; }
  .search-input:focus { border-color: #aaa; }
  .search-wrap.has-text .search-input { padding-right: 28px; }
  .search-clear { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); width: 20px; height: 20px; border: none; background: transparent; color: var(--text3); cursor: pointer; display: none; align-items: center; justify-content: center; padding: 0; border-radius: 4px; }
  .search-clear:hover { color: var(--text); background: var(--surface2); }
  .search-clear svg { width: 10px; height: 10px; pointer-events: none; }
  .search-wrap.has-text .search-clear { display: flex; }
  .sort-select { font-family: var(--font); font-size: 12px; font-weight: 500; padding: 6px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); color: var(--text2); cursor: pointer; outline: none; }
  /* v13.1 (A57): see .risk-tb-select:focus-visible — `outline: none` with no replacement */
  .sort-select:focus-visible { border-color: var(--accent-dark); box-shadow: 0 0 0 2px var(--accent-dark); }
  .add-action-btn { font-family: var(--font); font-size: 12px; font-weight: 500; padding: 6px 13px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); color: var(--text2); cursor: pointer; display: flex; align-items: center; gap: 5px; transition: all 0.15s; }
  .add-action-btn:hover { background: var(--surface2); color: var(--text); }
  .add-action-btn svg { width: 12px; height: 12px; }

  /* ── MAIN PANELS ── */
  main { padding: 20px 32px 48px; }
  .panel { display: none; }
  .panel.active { display: block; }

  /* ── PILL STRIP (v2.90 — replaces the 5-tile stats row) ──
     Total pill on the left + vertical separator + colored shortcut pills.
     Each pill is a button; active state is dark fill in light mode, cream fill in dark mode.
     Per-pill colored counts use muted color variants.
     Pills with count=0 are hidden. */
  .pill-strip { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 16px; }
  .pill {
    display: inline-flex; align-items: center; gap: 7px;
    background: var(--surface); border: 1px solid var(--border); border-radius: 18px;
    padding: 5px 13px 5px 11px;
    font-family: var(--font); font-size: 12px; font-weight: 500; color: var(--text2);
    cursor: pointer; transition: background 0.15s, color 0.15s, border-color 0.15s;
    user-select: none;
  }
  .pill:hover { background: var(--surface2); color: var(--text); border-color: var(--text3); }
  .pill.active { background: var(--accent-dark); color: #fff; border-color: var(--accent-dark); }
  .pill.active .pill-count { background: rgba(255,255,255,0.18); color: #fff; }
  .pill-icon { display: inline-flex; align-items: center; justify-content: center; }
  .pill-icon svg { width: 13px; height: 13px; display: block; }
  .pill-count {
    font-family: var(--mono); font-size: 11px; font-weight: 600;
    background: var(--surface2); padding: 1px 7px; border-radius: 8px;
    color: var(--text);
  }
  /* TOTAL pill — neutral, default-active */
  .pill-total { color: var(--text); font-weight: 600; }
  .pill-total .pill-count { background: var(--surface2); color: var(--text); }
  /* Per-pill colored variants (inactive state) */
  .pill-overdue { color: var(--high); }
  .pill-overdue .pill-count { background: var(--high-bg); color: var(--high); }
  .pill-blocked { color: #92400e; }
  .pill-blocked .pill-count { background: #fef3c7; color: #92400e; }
  .pill-agenda { color: #0d9488; }
  .pill-agenda .pill-count { background: #ccfbf1; color: #0d9488; }
  .pill-high { color: var(--high); }
  .pill-high .pill-count { background: var(--high-bg); color: var(--high); }
  /* Vertical separator between TOTAL and shortcut pills */
  .pill-sep { width: 1px; height: 22px; background: var(--border); margin: 0 4px; }
  /* Dark mode coverage */
  .dark .pill { background: var(--surface2); border-color: var(--border); color: var(--text2); }
  .dark .pill:hover { background: #34343a; color: var(--text); border-color: var(--text3); }
  .dark .pill.active { background: var(--surface); color: var(--text); border-color: var(--surface); }
  .dark .pill.active .pill-count { background: rgba(245,244,240,0.16); color: var(--text); }
  .dark .pill-count { background: #1e1e22; color: var(--text); }
  .dark .pill-total { color: var(--text); }
  .dark .pill-overdue { color: #f5a097; }
  .dark .pill-overdue .pill-count { background: #3b1c19; color: #f5a097; }
  .dark .pill-blocked { color: #f4d480; }
  .dark .pill-blocked .pill-count { background: #3a2c18; color: #f4d480; }
  .dark .pill-agenda { color: #5eead4; }
  .dark .pill-agenda .pill-count { background: #134e4a; color: #5eead4; }
  .dark .pill-high { color: #f5a097; }
  .dark .pill-high .pill-count { background: #3b1c19; color: #f5a097; }
  .dark .pill-sep { background: var(--border); }

  /* ── ACTION CARDS ── */
  .actions-list { display: flex; flex-direction: column; gap: 7px; }
  .action-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 14px 18px; border-left: 3px solid transparent; transition: box-shadow 0.15s, border-color 0.15s; position: relative; /* v2.90: required for agenda flag + focus marker absolute positioning */ }
  .action-card:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
  .action-card.priority-high { border-left-color: var(--high); }
  .action-card.priority-medium { border-left-color: var(--medium); }
  .action-card.priority-low { border-left-color: var(--low); }
  /* v2.90 ── SUB-ACTIONS (single-level nesting; sub-action = full action card visually nested under parent) ── */
  .subs-container {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px dashed var(--border);
  }
  .subs-list {
    display: flex; flex-direction: column; gap: 6px;
    padding-left: 18px;
    margin-left: 10px;
    border-left: 2px solid #ede9fe;  /* purple-tinted spine */
  }
  /* Sub-action card visual tweaks: slightly smaller padding, no bottom margin (gap handled by container) */
  .action-card.is-subaction {
    padding: 10px 14px;
    border-radius: 8px;
    margin-bottom: 0;
  }
  .action-card.is-subaction .action-desc { font-size: 13px; }
  .action-card.is-subaction .action-id { font-size: 10px; min-width: 36px; }
  /* "+ Add sub-action" button at bottom of sub-list (or in parent's empty state) */
  .add-sub-row { margin-top: 8px; padding-left: 28px; }
  .add-sub-btn {
    font-family: var(--font); font-size: 11px; font-weight: 500;
    padding: 5px 11px; border-radius: 7px;
    border: 1px dashed var(--border); background: transparent;
    color: var(--text3); cursor: pointer;
    display: inline-flex; align-items: center; gap: 5px;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
  }
  .add-sub-btn:hover { background: #ede9fe; color: #7c3aed; border-color: #7c3aed; border-style: solid; }
  .add-sub-btn svg { width: 11px; height: 11px; }
  /* Parent action chip-picker — appears in expanded view of any action (lets user re-parent it) */
  .parent-picker-row {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    margin-top: 4px;
  }
  .parent-chip {
    display: inline-flex; align-items: center; gap: 6px;
    background: #ede9fe; color: #7c3aed;
    font-size: 11px; padding: 2px 8px 2px 10px; border-radius: 11px;
    font-weight: 500;
  }
  .parent-chip .parent-chip-x {
    cursor: pointer; opacity: 0.6; padding: 1px 3px; line-height: 1;
    border-radius: 50%; transition: opacity 0.15s, background 0.15s;
    /* v2.91: explicit display + flex-center so the SVG renders at the intended size */
    display: inline-flex; align-items: center; justify-content: center;
  }
  .parent-chip .parent-chip-x:hover { opacity: 1; background: rgba(124, 58, 237, 0.15); }
  /* v2.91: explicit SVG sizing — matches the working .chip-x pattern */
  .parent-chip .parent-chip-x svg { width: 8px; height: 8px; display: block; }
  .parent-chip-input {
    font-family: var(--font); font-size: 12px;
    padding: 4px 8px; border: 1px dashed var(--border); border-radius: 6px;
    background: var(--surface2); color: var(--text);
    width: 70px;
    outline: none;
    transition: border-color 0.15s;
  }
  .parent-chip-input:focus { border-style: solid; border-color: #7c3aed; }
  /* Purple banner shown on the new-action modal when creating a sub-action */
  .sub-action-banner {
    background: #ede9fe; color: #7c3aed;
    font-size: 12px; font-weight: 500;
    padding: 8px 14px; border-radius: 7px;
    margin-bottom: 14px;
    display: flex; align-items: center; gap: 8px;
  }
  .sub-action-banner svg { width: 14px; height: 14px; flex-shrink: 0; }
  /* Dark mode — purple stays purple but counters use darker variants */
  .dark .subs-list { border-left-color: #2d2640; }
  .dark .add-sub-btn { color: var(--text2); border-color: var(--border); }
  .dark .add-sub-btn:hover { background: #2d2640; color: #b794f4; border-color: #b794f4; }
  .dark .parent-chip { background: #2d2640; color: #b794f4; }
  .dark .parent-chip-input { background: var(--surface2); border-color: var(--border); color: var(--text); }
  .dark .parent-chip-input:focus { border-color: #b794f4; }
  .dark .sub-action-banner { background: #2d2640; color: #b794f4; }
  /* /sub-actions */
  .action-card.expanded { border-color: #c5c3bc; box-shadow: 0 2px 12px rgba(0,0,0,0.08); }
  .action-card.has-update { background: #fffdf7; }
  .action-header { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; user-select: none; }
  .action-id { font-family: var(--mono); font-size: 11px; color: var(--text3); min-width: 26px; padding-top: 3px; flex-shrink: 0; }
  .action-main { flex: 1; min-width: 0; }
  .action-desc { font-size: 14px; font-weight: 500; color: var(--text); line-height: 1.45; margin-bottom: 6px; }
  .action-meta { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
  .badge { display: inline-flex; align-items: center; font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: 4px; white-space: nowrap; }
  .badge-status-completed { background: #e6f4ea; color: #2d6a35; }
  .badge-status-in-progress { background: #dbeafe; color: #1d4ed8; }
  .badge-status-not-started { background: #f3f4f6; color: #6b7280; }
  /* v2.19: on-hold (amber/muted) and cancelled (grey/muted) statuses */
  .badge-status-on-hold { background: #fef3c7; color: #92400e; }
  .badge-status-cancelled { background: #e5e7eb; color: #4b5563; text-decoration: line-through; }
  /* v2.19 item 5: overdue marker — red date text + small OVERDUE tag */
  .meta-text.meta-overdue { color: var(--high); }
  .overdue-tag { display: inline-block; font-size: 9px; font-weight: 600; padding: 1px 5px; margin-left: 4px; border-radius: 3px; background: var(--high-bg); color: var(--high); border: 1px solid var(--high-border); vertical-align: 1px; letter-spacing: 0.3px; }
  /* v2.19 item 8: focus marker (crosshair) — far-right card header.
     v2.94: uniform 28x28 size with 18x18 SVG (matches bookmark, chevron, ×). */
  .focus-marker {
    flex-shrink: 0;
    width: 28px; height: 28px;
    background: transparent;
    border: none;
    cursor: pointer;
    border-radius: 6px;
    color: var(--text3);
    margin-top: -2px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.15s, color 0.15s, background 0.15s;
  }
  .action-header:hover .focus-marker { opacity: 0.55; }
  .focus-marker:hover { opacity: 1; color: var(--medium); background: rgba(0,0,0,0.04); }
  .focus-marker.focused { opacity: 1; color: var(--medium); }
  .focus-marker svg { width: 18px; height: 18px; display: block; }
  /* Focused card gets a subtle amber left border accent */
  .action-card.is-focused { box-shadow: inset 3px 0 0 var(--medium); }

  /* v2.21: dependency and related-link chips */
  .chips-section { margin-top: 12px; }
  .chips-label { font-size: 11px; font-weight: 500; color: var(--text3); margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.5px; }
  .chips-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
  .chip { display: inline-flex; align-items: center; gap: 6px; padding: 3px 9px; border-radius: 14px; font-size: 12px; line-height: 1.3; border: 1px solid var(--border); background: var(--surface2); color: var(--text2); cursor: pointer; transition: background 0.12s, border-color 0.12s; max-width: 320px; }
  .chip:hover { background: var(--surface); border-color: var(--text3); }
  .chip-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 280px; }
  .chip-arrow { font-size: 11px; opacity: 0.6; flex-shrink: 0; }
  .chip-x { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; margin-left: 1px; margin-right: -3px; color: var(--text3); border-radius: 50%; cursor: pointer; flex-shrink: 0; opacity: 0.6; }
  .chip-x:hover { opacity: 1; background: rgba(0,0,0,0.06); color: var(--high); }
  .chip-x svg { width: 8px; height: 8px; }

  /* Blocking dependency: amber-ish chip */
  .chip-blocked { background: #fef3c7; border-color: #f0d080; color: #92400e; }
  .chip-blocked:hover { background: #fde68a; }
  /* Reverse (Blocks): neutral grey, derived/read-only */
  .chip-blocks { background: var(--surface2); border-color: var(--border); color: var(--text2); }
  /* Related: also neutral grey */
  .chip-related { background: var(--surface2); border-color: var(--border); color: var(--text2); }

  /* Dark mode adjustments */
  .dark .chip-blocked { background: #3a2c18; border-color: #6b4d20; color: #f4a942; }
  .dark .chip-blocked:hover { background: #4a3a22; }

  /* Chip-add inline input */
  .chip-add-input { font-size: 12px; padding: 3px 9px; border-radius: 14px; border: 1px dashed var(--border-strong); background: transparent; color: var(--text2); width: 220px; max-width: 100%; }
  .chip-add-input:focus { outline: none; border-color: var(--medium); }
  .chip-add-input::placeholder { color: var(--text3); }

  /* Open blocker visual marker on collapsed card */
  .blocker-tag { display: inline-block; font-size: 10px; font-weight: 600; padding: 1px 6px; margin-left: 4px; border-radius: 3px; background: #fef3c7; color: #92400e; border: 1px solid #f0d080; vertical-align: 1px; letter-spacing: 0.3px; }
  .dark .blocker-tag { background: #3a2c18; color: #f4a942; border-color: #6b4d20; }

  /* v2.21: chip-flash — brief amber border pulse on a card after chip click navigation */
  @keyframes chipFlash {
    0%   { box-shadow: 0 0 0 2px var(--medium); }
    50%  { box-shadow: 0 0 0 4px var(--medium); }
    100% { box-shadow: 0 0 0 0 transparent; }
  }
  .action-card.chip-flash { animation: chipFlash 700ms ease-out; }

  /* v2.22: agenda-flag icon.
     v2.92: converted from absolute to flex flow.
     v2.93: moved to LEFT column (own slot before #ID), bookmark icon, always
     visible (no hover-reveal). Outlined when off, filled teal when on.
     28×28 hit target with 18×18 icon — generous click area to fix the
     "too small / accidentally hit focus" complaint. */
  .agenda-flag {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    background: transparent;
    border: none;
    border-radius: 6px;
    color: var(--text3);
    cursor: pointer;
    opacity: 1;
    transition: color 0.15s, background 0.15s;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-top: -2px;  /* nudge up to align with title baseline */
    padding: 0;
  }
  .agenda-flag:hover { background: rgba(0,0,0,0.04); color: #0d9488; }
  .agenda-flag svg {
    width: 18px;
    height: 18px;
    display: block;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
    stroke-linejoin: round;
  }
  .agenda-flag.flagged { color: #0d9488; }
  .agenda-flag.flagged svg { fill: currentColor; stroke: currentColor; }
  .dark .agenda-flag.flagged { color: #2dd4bf; }
  .dark .agenda-flag:hover { background: rgba(255,255,255,0.06); color: #2dd4bf; }

  /* v2.96: .agenda-count-pill removed — see render() comment. */
  /* v2.22: progress chip in meta + chips in expanded view */
  .progress-pill {
    display: inline-block;
    font-size: 11px;
    padding: 1px 7px;
    border-radius: 10px;
    background: var(--surface2);
    color: var(--text2);
    border: 1px solid var(--border);
    font-weight: 500;
  }
  .progress-chip {
    display: inline-block;
    font-size: 11px;
    padding: 2px 8px;
    border-radius: 12px;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text2);
    cursor: pointer;
    margin-right: 4px;
  }
  .progress-chip:hover { background: var(--surface2); }
  /* v2.90: .progress-bar-mini removed — only the % pill in the meta row displays progress */
  .progress-input { width: 70px; }

  /* v2.22: toast undo styling — extends the existing toast with action button */
  .toast-undo {
    background: var(--accent-dark);
    color: var(--surface);
    display: inline-flex;
    align-items: center;
    gap: 14px;
  }
  .toast-undo-btn {
    background: transparent;
    border: none;
    color: #fbbf24;
    font-weight: 600;
    font-size: 12px;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 3px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
  }
  .toast-undo-btn:hover { background: rgba(251, 191, 36, 0.15); }

  /* v2.22: position the undo toast bottom-LEFT (Material snackbar pattern) */
  #toastHostBottomLeft {
    position: fixed; left: 24px; bottom: 24px;
    display: flex; flex-direction: column; gap: 8px;
    z-index: 9999; pointer-events: none;
  }
  #toastHostBottomLeft .toast { pointer-events: auto; }

  /* v2.21: toast subsystem */
  #toastHost { position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); display: flex; flex-direction: column; gap: 8px; z-index: 9999; pointer-events: none; }
  /* ⚠ v14.4: THE THIRD AND OLDEST INSTANCE, and the one with the widest blast radius — EVERY
     toast in the app rendered #242220 text on #3a3833 in dark mode, i.e. unreadable, including
     the undo toasts that carry a six-second deadline. Found while measuring the pane switch
     (above); a census of the pairing turned up exactly three rules and this was the third.
     Fixed here rather than deferred BECAUSE IT IS THE SAME ONE-WORD DEFECT: shipping two of
     three would leave the identical bug in the release that fixed its siblings. */
  .toast { background: var(--accent-dark); color: #fff; padding: 10px 18px; border-radius: 6px; font-size: 13px; line-height: 1.4; max-width: 480px; opacity: 0; transform: translateY(8px); transition: opacity 0.2s, transform 0.2s; pointer-events: auto; box-shadow: 0 4px 12px rgba(0,0,0,0.15); }
  .toast.toast-visible { opacity: 1; transform: translateY(0); }
  .toast.toast-warn { background: var(--high); color: white; }
  /* v2.98: dark-mode toast now uses #4a4843 — lighter than card surface so the
     toast "floats forward" instead of blending in (the previous var(--surface)
     bg was the same color as cards). Light text retained. */
  .dark .toast { background: #4a4843; color: var(--text); }
  .dark .toast-undo { background: #4a4843; color: var(--text); }
  .badge-priority-high { background: var(--high-bg); color: var(--high); border: 1px solid var(--high-border); }
  .badge-priority-medium { background: var(--medium-bg); color: var(--medium); border: 1px solid var(--medium-border); }
  .badge-priority-low { background: var(--low-bg); color: var(--low); border: 1px solid var(--low-border); }
  .meta-text { font-size: 12px; color: var(--text3); }
  .meta-sep { color: var(--border); font-size: 12px; }
  .update-pill { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 500; padding: 2px 7px; border-radius: 4px; background: #fef9e7; color: #b7860c; border: 1px solid #f0d080; }
  .update-pill svg { width: 10px; height: 10px; flex-shrink: 0; }
  .changed-dot { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: #b7860c; margin-left: 5px; vertical-align: middle; }
  .new-action-tag { font-size: 9px; background: #e8f4ff; color: #1d4ed8; border: 1px solid #bfdbfe; padding: 1px 5px; border-radius: 3px; margin-left: 4px; vertical-align: middle; }
  /* v2.94: chevron uniform with other icons — 28x28 bare icon, no border/bg.
     Rotation when expanded is preserved. */
  .action-chevron {
    flex-shrink: 0;
    width: 28px; height: 28px;
    background: transparent;
    border: none;
    border-radius: 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text3);
    margin-top: -2px;
    cursor: pointer;
    transition: color 0.15s, background 0.15s;
  }
  .action-chevron:hover { background: rgba(0,0,0,0.04); }
  .action-chevron svg { width: 18px; height: 18px; transition: transform 0.2s; }
  .action-card.expanded > .action-header .action-chevron svg { transform: rotate(180deg); }
  /* v2.94: delete × uniform with other icons — 28x28. Red destructive hover preserved. */
  .card-del-btn {
    flex-shrink: 0;
    width: 28px; height: 28px;
    background: transparent;
    border: none;
    cursor: pointer;
    border-radius: 6px;
    color: var(--text3);
    margin-top: -2px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 0.15s, background 0.15s;
  }
  .card-del-btn:hover { color: var(--high); background: var(--high-bg); }
  .card-del-btn svg { width: 18px; height: 18px; display: block; }
  .action-details { display: none; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); }
  .action-card.expanded > .action-details { display: block; }
  .detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 14px; }
  .detail-label { font-size: 10px; font-weight: 600; letter-spacing: 0.07em; text-transform: uppercase; color: var(--text3); margin-bottom: 4px; }
  .edit-select, .edit-date { font-family: var(--font); font-size: 13px; color: var(--text); border: 1px solid var(--border); border-radius: 6px; background: var(--surface2); padding: 5px 8px; cursor: pointer; outline: none; width: 100%; }
  .edit-select:focus, .edit-date:focus { border-color: #aaa; background: var(--surface); }
  .edit-date { font-family: var(--mono); font-size: 12px; }
  .edit-textarea { font-family: var(--font); font-size: 13px; color: var(--text); border: 1px solid var(--border); border-radius: 6px; background: var(--surface2); padding: 7px 10px; outline: none; width: 100%; line-height: 1.5; min-height: 56px; resize: vertical; }
  .edit-textarea:focus { border-color: #aaa; background: var(--surface); }
  .edit-textarea::placeholder { color: var(--text3); }
  .edit-textarea.desc-field { font-weight: 500; }

  .update-section { }
  .update-label { font-size: 10px; font-weight: 600; letter-spacing: 0.07em; text-transform: uppercase; color: var(--text3); margin-bottom: 8px; display: flex; align-items: center; gap: 6px; }
  .live-tag { font-size: 9px; background: #fef9e7; color: #b7860c; border: 1px solid #f0d080; padding: 1px 5px; border-radius: 3px; }
  .update-log { margin-bottom: 8px; display: flex; flex-direction: column; gap: 6px; }
  .update-entry { background: #fffdf5; border: 1px solid #f0d080; border-radius: 7px; padding: 8px 12px; font-size: 13px; color: var(--text2); line-height: 1.5; display: flex; gap: 10px; align-items: flex-start; min-width: 0; }
  .update-entry-time { font-family: var(--mono); font-size: 10px; color: var(--text3); white-space: nowrap; padding-top: 2px; flex-shrink: 0; }
  /* v2.18.1: pre-wrap preserves newlines from data, overflow-wrap handles long unbroken strings, min-width:0 lets the flex item shrink so it stops overlapping the delete button */
  .update-entry-text { flex: 1; min-width: 0; white-space: pre-wrap; overflow-wrap: break-word; word-break: break-word; cursor: text; }
  .update-entry-text:hover { background: rgba(0, 0, 0, 0.03); border-radius: 4px; }
  /* v2.18.1: inline textarea used for edit-in-place. Same font + sizing as the static text so the swap is invisible. */
  .update-entry-text-edit { flex: 1; min-width: 0; font-family: inherit; font-size: inherit; line-height: inherit; color: var(--text); background: var(--surface); border: 1px solid #aaa; border-radius: 4px; padding: 2px 6px; resize: vertical; outline: none; }
  .update-entry-del { flex-shrink: 0; background: none; border: none; cursor: pointer; padding: 2px 4px; color: var(--text3); border-radius: 4px; line-height: 1; transition: color 0.15s, background 0.15s; }
  .update-entry-del:hover { color: var(--high); background: var(--high-bg); }
  .update-textarea { font-family: var(--font); font-size: 13px; color: var(--text); width: 100%; min-height: 60px; resize: vertical; border: 1px solid var(--border); border-radius: 7px; background: var(--surface); padding: 9px 12px; line-height: 1.5; outline: none; transition: border-color 0.15s; }
  .update-textarea:focus { border-color: #aaa; }
  .update-textarea::placeholder { color: var(--text3); }
  .update-actions { display: flex; gap: 8px; margin-top: 6px; align-items: center; }
  .add-update-btn { font-family: var(--font); font-size: 12px; font-weight: 500; padding: 5px 12px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); color: var(--text2); cursor: pointer; transition: all 0.15s; }
  .add-update-btn:hover { background: var(--surface2); color: var(--text); }
  .hint-text { font-size: 11px; color: var(--text3); }
  .empty-state { text-align: center; padding: 48px 24px; color: var(--text3); font-size: 14px; }
  /* v2.90: polished empty state — icon, title, subtitle, active filter pills, clear button */
  .empty-state .empty-icon { color: var(--text3); margin-bottom: 14px; }
  .empty-state .empty-icon svg { width: 48px; height: 48px; opacity: 0.5; display: inline-block; }
  .empty-state .empty-title { font-size: 16px; font-weight: 500; color: var(--text2); margin-bottom: 6px; }
  .empty-state .empty-msg { font-size: 12px; color: var(--text3); max-width: 340px; margin: 0 auto 14px; line-height: 1.5; }
  .empty-state .empty-active-filters { display: inline-flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-bottom: 14px; min-height: 22px; }
  .empty-state .empty-active-filters:empty { display: none; }
  .empty-state .empty-filter-pill { display: inline-flex; align-items: center; gap: 5px; background: var(--surface2); border: 1px solid var(--border); border-radius: 12px; padding: 3px 10px; font-size: 11px; color: var(--text2); }
  .empty-state .empty-clear-btn { font-family: var(--font); font-size: 12px; font-weight: 500; padding: 7px 16px; border-radius: 7px; border: 1px solid var(--text2); background: transparent; color: var(--text); cursor: pointer; transition: background 0.15s; }
  .empty-state .empty-clear-btn:hover { background: var(--surface2); }
  .dark .empty-state .empty-filter-pill { background: var(--surface2); border-color: var(--border); color: var(--text2); }
  .dark .empty-state .empty-clear-btn { color: var(--text); border-color: var(--text2); }

  /* ── MEETING NOTES TAB ── */
  .notes-panel-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; flex-wrap: wrap; gap: 12px; }
  .new-session-btn { font-family: var(--font); font-size: 12px; font-weight: 500; padding: 7px 14px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); color: var(--text2); cursor: pointer; display: flex; align-items: center; gap: 5px; transition: all 0.15s; }
  .new-session-btn:hover { background: var(--surface2); color: var(--text); }
  .new-session-btn svg { width: 12px; height: 12px; }
  .notes-panel-controls { display: flex; align-items: center; gap: 8px; }
  .session-sort-btn { font-family: var(--font); font-size: 12px; font-weight: 500; padding: 7px 12px; border: 1px solid var(--border); border-radius: 8px; background: transparent; color: var(--text2); cursor: pointer; display: flex; align-items: center; gap: 6px; transition: all 0.15s; }
  .session-sort-btn:hover { background: var(--surface); color: var(--text); }
  .session-sort-btn svg { width: 12px; height: 12px; flex-shrink: 0; }
  /* ⚠ v15.3 (d): RESERVE THE LABEL'S WIDTH, so the button stops resizing on every toggle and
     the controls to its right stop sliding — his report: "new action etc. to the right … gently
     move to the right and left when toggling, so the UI doesnt seem stable".
     Every label PAIR differs in width ("High priority first" 95.34px vs "Low priority first"
     92.64px; "Earliest closed first" 107.83 vs "Latest closed first" 101.55; "Active first"
     61.03 vs "Done first" 54.86), so the button was content-sized to whichever was showing.
     ⚠ 113px is MEASURED, not counted: every one of the sixteen labels this button can show was
     rendered and measured in situ, and the widest — "Least complete first" — came to 112.94px.
     A character count would have picked the longest STRING ("Earliest closed first", 21 chars),
     which is 5px NARROWER than the winner. §v15's law: state the test, not the verdict.
     ⚠ SCOPED BY ID, not on .session-sort-btn: the meetings sort button shares that class and
     has its own, shorter label set, so widening the class would pad a button nobody complained
     about. A label that ever exceeds this simply grows the button as it does today. */
  #sortDirLabel { display: inline-block; min-width: 113px; }

  .session-list { display: flex; flex-direction: column; gap: 12px; }

  .session-card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; }
  .session-card.current { border-color: #b0c4e8; box-shadow: 0 0 0 3px rgba(59,130,246,0.08); }

  .session-header { display: flex; align-items: center; gap: 12px; padding: 14px 18px; cursor: pointer; user-select: none; }
  /* v2.97: session-dot removed — "Latest" pill is the canonical indicator. */
  .session-date-wrap { flex: 1; min-width: 0; }
  .session-date-input { font-family: var(--mono); font-size: 13px; font-weight: 400; color: var(--text); border: 1px solid var(--border); border-radius: 5px; background: var(--surface2); padding: 3px 7px; outline: none; }
  .session-date-input:focus { border-color: #aaa; }
  .session-attendee-preview { font-size: 12px; color: var(--text3); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .session-current-tag { font-size: 10px; font-weight: 600; background: #dbeafe; color: #1d4ed8; padding: 2px 7px; border-radius: 4px; white-space: nowrap; }
  /* v2.98: session-chevron aligned with v2.94 .action-chevron — 28x28 bare icon. */
  .session-chevron {
    flex-shrink: 0;
    width: 28px; height: 28px;
    background: transparent;
    border: none;
    border-radius: 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text3);
    cursor: pointer;
    transition: color 0.15s, background 0.15s;
  }
  .session-chevron:hover { background: rgba(0,0,0,0.04); }
  .session-chevron svg { width: 18px; height: 18px; transition: transform 0.2s; }
  .session-card.expanded .session-chevron svg { transform: rotate(180deg); }
  /* v2.98: session-del-btn aligned with v2.94 .card-del-btn — 28x28 uniform. */
  .session-del-btn {
    flex-shrink: 0;
    width: 28px; height: 28px;
    background: transparent;
    border: none;
    cursor: pointer;
    border-radius: 6px;
    color: var(--text3);
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 0.15s, background 0.15s;
  }
  .session-del-btn:hover { color: var(--high); background: var(--high-bg); }
  .session-del-btn svg { width: 18px; height: 18px; display: block; }

  .session-body { display: none; padding: 0 18px 18px; border-top: 1px solid var(--border); }
  .session-card.expanded .session-body { display: block; padding-top: 16px; }

  .session-field { margin-bottom: 16px; }
  .session-field-label { font-size: 10px; font-weight: 600; letter-spacing: 0.07em; text-transform: uppercase; color: var(--text3); margin-bottom: 6px; display: flex; align-items: center; gap: 6px; }

  .minutes-textarea { font-family: var(--font); font-size: 13px; color: var(--text); width: 100%; min-height: 220px; resize: vertical; border: 1px solid var(--border); border-radius: 7px; background: var(--surface); padding: 12px 14px; line-height: 1.65; outline: none; transition: border-color 0.15s; }
  .minutes-textarea:focus { border-color: #aaa; }
  .minutes-textarea::placeholder { color: var(--text3); }

  .char-hint { font-size: 11px; color: var(--text3); text-align: right; margin-top: 4px; }

  /* ── MODAL ── */
  .modal-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.35); z-index: 200; align-items: center; justify-content: center; }
  .modal-overlay.open { display: flex; }
  .modal { background: var(--surface); border: 1px solid var(--border); border-radius: 14px; padding: 24px 28px; width: 100%; max-width: 520px; margin: 16px; box-shadow: 0 8px 32px rgba(0,0,0,0.14); }
  .modal-title { font-size: 15px; font-weight: 600; color: var(--text); margin-bottom: 20px; }
  .modal-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px; }
  .modal-field { display: flex; flex-direction: column; gap: 5px; }
  .modal-field.full { grid-column: 1 / -1; }
  .modal-label { font-size: 10px; font-weight: 600; letter-spacing: 0.07em; text-transform: uppercase; color: var(--text3); }
  .modal-input, .modal-select, .modal-textarea { font-family: var(--font); font-size: 13px; color: var(--text); border: 1px solid var(--border); border-radius: 7px; background: var(--surface2); padding: 7px 10px; outline: none; width: 100%; }
  .modal-input:focus, .modal-select:focus, .modal-textarea:focus { border-color: #aaa; background: var(--surface); }
  .modal-textarea { min-height: 64px; resize: vertical; line-height: 1.5; }
  .modal-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 20px; }
  .modal-cancel { font-family: var(--font); font-size: 13px; padding: 8px 16px; border-radius: 7px; border: 1px solid var(--border); background: var(--surface); color: var(--text2); cursor: pointer; }
  .modal-cancel:hover { background: var(--surface2); }
  .modal-submit { font-family: var(--font); font-size: 13px; font-weight: 600; padding: 8px 18px; border-radius: 7px; border: none; background: var(--accent-dark); color: #fff; cursor: pointer; transition: opacity 0.15s; }
  .modal-submit:hover { opacity: 0.85; }
  .modal-danger { background: var(--high); }
  .modal-danger:hover { opacity: 0.9; }
  .modal-small { max-width: 420px !important; }
  /* P2: suggestions stay in the action modal's own scroll flow. */
  #modalOverlay .modal { max-height: calc(100dvh - 32px); overflow-y: auto; }
  #modalOverlay .modal-field { min-width: 0; }
  .action-label-options { max-height: 180px; overflow-y: auto; border: 1px solid var(--border); border-radius: 7px; background: var(--surface); }
  .action-label-options button { display: block; width: 100%; border: 0; padding: 8px 10px; text-align: left; font: inherit; font-size: 13px; color: var(--text); background: transparent; cursor: pointer; overflow-wrap: anywhere; }
  .action-label-options button:hover, .action-label-options button[aria-selected="true"] { background: var(--surface2); box-shadow: inset 3px 0 var(--text2); }
  .action-label-hint { font-size: 11px; color: var(--text2); }
  .confirm-msg { font-size: 13px; color: var(--text2); line-height: 1.6; margin-bottom: 20px; }
  .confirm-msg em { font-style: italic; color: var(--text); }
  .confirm-msg strong { font-weight: 600; color: var(--text); }


  .session-title-input { font-family: var(--font); font-size: 14px; font-weight: 600; color: var(--text); border: 1px solid var(--border); border-radius: 6px; background: var(--surface2); padding: 5px 10px; outline: none; width: 100%; margin-top: 4px; }
  .session-title-input:focus { border-color: #aaa; background: var(--surface); }
  .session-title-input::placeholder { color: var(--text3); font-weight: 500; }

  .field-row { display: flex; gap: 10px; flex-wrap: wrap; }
  .field-row > .session-field { flex: 1; min-width: 140px; margin-bottom: 0; }
  .time-input { font-family: var(--mono); font-size: 13px; color: var(--text); border: 1px solid var(--border); border-radius: 6px; background: var(--surface2); padding: 5px 8px; outline: none; width: 100%; }
  .time-input:focus { border-color: #aaa; background: var(--surface); }
  .attendee-group { display: flex; gap: 8px; align-items: flex-start; margin-bottom: 8px; max-width: 640px; }
.attendee-present { align-self: center; flex: none; width: 16px; height: 16px; cursor: pointer; }
  /* ── v16 (b): the "optional" lozenge ────────────────────────────────────────────────
     Marks an attendee as OPTIONAL. Deliberately a lozenge with the word spelled out and
     NOT a second checkbox: two bare ticks side by side cannot be told apart, which is why
     design A was rejected — on ambiguity, not on space. The word fits: measured in the
     shell's own DM Sans the pill is 62.7px against 37.7px for "opt", leaving the Name field
     ~240px where the longest real attendee name needs 141.5px.
     ⚠ COLOUR, AND THE FIRST DRAFT FAILED THIS. The natural choice — amber --medium text on
     the --medium-bg ground, both tokens correctly redefined under .dark — measures 3.06:1 in
     LIGHT against 6.82:1 in DARK. That is under the 4.5:1 bar qa_regression.py enforces and
     lopsided between themes: the --accent-dark fault's FAMILY, reached with a token that
     flips perfectly well, so "use tokens that flip" is necessary and not sufficient. Amber
     cannot be the text colour at this size in light mode at all (3.28:1 even on plain
     --surface). So the LABEL is --text and the amber signal is carried by the GROUND and the
     BORDER. Measured after the change: light off 5.43, light on 16.38, dark off 5.43,
     dark on 10.83 — all four pass. --accent-dark is not used here and must not be. */
  .att-opt { align-self: center; flex: none; height: 22px; padding: 0 9px; border-radius: 999px;
       font-family: var(--font); font-size: 10px; font-weight: 600; line-height: 1;
       letter-spacing: .04em; cursor: pointer; white-space: nowrap;
       background: var(--surface); color: var(--text2); border: 1px solid var(--border);
       transition: background .12s, color .12s, border-color .12s; }
  .att-opt:hover:not(:disabled) { border-color: var(--border-strong); color: var(--text); }
  .att-opt[aria-pressed="true"] { background: var(--medium-bg); color: var(--text);
       border-color: var(--medium-border); }
  /* ⚠ v16 (b), option C: on a row with no NAME the pill recedes — it does not disappear.
     Hiding it was his first instinct and was rejected deliberately: the row is a flex layout
     capped at 640px, so a control that appears once the name becomes non-empty shifts
     Organisation and Name by ~70px ON THE FIRST KEYSTROKE — the class §v15.3 (d) had just
     fixed, and worse here because it fires while the user is looking at the field they are
     typing into. It also hid state: mark somebody optional, clear their name, and the flag
     stayed stored on a row with no visible control.
     `opacity` and `disabled` were chosen precisely because NEITHER AFFECTS LAYOUT, so the
     footprint is identical whether the row is named or not — which is the whole point, and is
     asserted by attendee_optional_pill_recedes_without_moving_the_row. A LIT pill whose name
     is later cleared stays visibly lit, merely dimmed, so nothing is ever concealed. */
  .att-opt:disabled { opacity: .45; cursor: default; }
  .attendee-group:last-of-type { margin-bottom: 0; }
  .attendee-organisation {
    font-family: var(--font); font-size: 12px; font-weight: 600; color: var(--text);
    border: 1px solid var(--border); border-radius: 6px; background: var(--surface2);
    padding: 7px 10px; outline: none; width: 200px; flex-shrink: 0;
  }
  .attendee-organisation:focus { border-color: #aaa; background: var(--surface); }
  .attendee-organisation::placeholder { color: var(--text3); font-weight: 500; }
  .attendee-name {
    font-family: var(--font); font-size: 13px; color: var(--text);
    border: 1px solid var(--border); border-radius: 6px; background: var(--surface2);
    padding: 7px 10px; outline: none; flex: 1; min-width: 0;
  }
  .attendee-name:focus { border-color: #aaa; background: var(--surface); }
  .attendee-name::placeholder { color: var(--text3); }
  .attendee-group-del {
    flex-shrink: 0; background: none; border: 1px solid transparent; cursor: pointer;
    padding: 6px 7px; border-radius: 6px; color: var(--text3); transition: all 0.15s; align-self: center;
  }
  .attendee-group-del:hover { color: var(--high); border-color: var(--high-border); background: var(--high-bg); }
  .attendee-group-del svg { width: 11px; height: 11px; display: block; }
  /* v2.16: attendee reorder up/down buttons */
  .attendee-group-move {
    flex-shrink: 0; background: none; border: 1px solid transparent; cursor: pointer;
    padding: 6px 5px; border-radius: 6px; color: var(--text3); transition: all 0.15s; align-self: center;
  }
  .attendee-group-move:hover:not(:disabled) { color: var(--text); border-color: var(--border-strong); background: var(--surface2); }
  .attendee-group-move:disabled { opacity: 0.25; cursor: default; }
  .attendee-group-move svg { width: 11px; height: 11px; display: block; }
  .add-organisation-btn {
    font-family: var(--font); font-size: 12px; font-weight: 500; color: var(--text2);
    border: 1px dashed var(--border); border-radius: 6px; background: transparent;
    padding: 6px 12px; cursor: pointer; display: inline-flex; align-items: center; gap: 5px;
    transition: all 0.15s; margin-top: 8px;
  }
  .add-organisation-btn:hover { border-color: #aaa; color: var(--text); background: var(--surface2); }
  .add-organisation-btn svg { width: 11px; height: 11px; }
  .editable-inline { border-bottom: 1px dashed transparent; padding: 0 2px; cursor: text; outline: none; transition: border-color 0.15s, background 0.15s; border-radius: 2px; }
  .editable-inline:hover { border-bottom-color: var(--text3); }
  .editable-inline:focus { border-bottom-color: var(--text); background: rgba(0,0,0,0.04); }


  .session-title-display { font-size: 14px; font-weight: 600; color: var(--text); margin-bottom: 2px; }
  .session-title-sub { font-family: var(--mono); font-size: 11px; color: var(--text3); margin-bottom: 2px; }
  .diff-entry { background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 7px; padding: 8px 12px; font-size: 13px; color: var(--text2); line-height: 1.5; display: flex; gap: 10px; align-items: flex-start; }
  .diff-entry-id { font-family: var(--mono); font-size: 11px; color: #1d4ed8; font-weight: 600; white-space: nowrap; padding-top: 1px; flex-shrink: 0; min-width: 34px; }
  .diff-entry-body { flex: 1; min-width: 0; }
  .diff-entry-desc { font-size: 12px; color: var(--text); font-weight: 500; margin-bottom: 3px; }
  .diff-entry-change { font-size: 12px; color: var(--text2); }
  .diff-entry-del {
    flex-shrink: 0; background: none; border: 1px solid transparent; cursor: pointer;
    padding: 4px 5px; border-radius: 5px; color: #93a3c4; transition: all 0.15s;
    align-self: flex-start; margin-top: -1px;
  }
  .diff-entry-del:hover { color: var(--high); border-color: var(--high-border); background: var(--high-bg); }
  /* v2.5: action summary block (replaces tracker UI) */
  .action-summary-controls { display: flex; gap: 8px; margin-bottom: 8px; flex-wrap: wrap; }
  .summary-btn { font-family: var(--font); font-size: 12px; padding: 5px 11px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); color: var(--text); cursor: pointer; transition: background 0.15s; }
  .summary-btn:hover:not(:disabled) { background: var(--surface2); }
  .summary-btn:disabled { opacity: 0.4; cursor: not-allowed; }
  .summary-btn-secondary { color: var(--text2); }
  .action-summary-output { font-family: var(--mono); font-size: 12px; line-height: 1.55; color: var(--text); width: 100%; min-height: 110px; resize: vertical; border: 1px solid var(--border); border-radius: 7px; background: var(--surface2); padding: 10px 12px; outline: none; transition: border-color 0.15s; }
  .action-summary-output:focus { border-color: #aaa; }
  .dark .action-summary-output:focus { border-color: #888; }
  .diff-entry-del svg { width: 10px; height: 10px; display: block; }
  .diff-from { color: var(--text3); text-decoration: line-through; }
  .diff-to { color: #1d4ed8; font-weight: 500; }
  .diff-none { font-size: 12px; color: var(--text3); font-style: italic; padding: 8px 2px; }

  /* ─────────────────────────────────────────────────────────────────────
     v3.0 — Stakeholders tab styling
     New tabs in v3.0: Dashboard (empty scaffold), Stakeholders (full),
     Risks (empty scaffold). Dashboard + Risks intentionally have no
     content yet — they exist as panel divs but render nothing.
     ───────────────────────────────────────────────────────────────────── */

  /* Stakeholders tab controls header */
  /* v12 (W1): the allocation chip — the visible resource marker on a register row */
  .stk-alloc-chip { display: inline-block; font-size: 10.5px; font-weight: 600; padding: 1px 7px; margin-left: 6px; border-radius: 999px; border: 1px solid #bcd8bf; background: #eef4ee; color: #2e7d43; vertical-align: 1px; }
  .dark .stk-alloc-chip { border-color: #3c5a41; background: #1d2b20; color: #7fc38f; }
  /* v12 (W2): the Add-from-portfolio picker rows (the frame reuses the ws-modal classes) */
  .pp-row { display: flex; gap: 9px; padding: 8px 6px; border-bottom: 1px solid var(--border); align-items: flex-start; font-size: 13px; cursor: pointer; }
  .pp-row:last-child { border-bottom: none; }
  .pp-row input { margin-top: 3px; }
  .pp-row .pp-nm { font-weight: 600; }
  .pp-row .pp-org { color: var(--text2); font-size: 12px; }
  .pp-row .pp-in { color: var(--text3); font-size: 11px; }
  .pp-row.pp-grey { opacity: .45; cursor: default; }
  .pp-none { padding: 18px 10px; text-align: center; color: var(--text3); font-size: 12.5px; }
  .stk-add-btn { font-family: var(--font); font-size: 13px; font-weight: 500; padding: 7px 14px; border-radius: 7px; border: 1px solid var(--border); background: var(--surface); color: var(--text); cursor: pointer; transition: background 0.15s; display: inline-flex; align-items: center; gap: 6px; }
  .stk-add-btn:hover { background: var(--surface2); }
  .stk-add-btn svg { width: 12px; height: 12px; stroke: currentColor; fill: none; stroke-width: 1.8; }

  /* Stakeholder card grid */
  .stk-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 30px; }
  @media (max-width: 760px) { .stk-grid { grid-template-columns: 1fr; } }
  .stk-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; position: relative; }
  .stk-card-del { position: absolute; top: 8px; right: 8px; width: 22px; height: 22px; border: none; background: transparent; color: var(--text3); cursor: pointer; opacity: 0; transition: opacity 0.15s, color 0.15s; border-radius: 4px; display: inline-flex; align-items: center; justify-content: center; padding: 0; }
  .stk-card:hover .stk-card-del { opacity: 1; }
  .stk-card-del:hover { color: var(--high); background: var(--high-bg); }
  .stk-card-del svg { width: 12px; height: 12px; stroke: currentColor; fill: none; stroke-width: 1.8; }

  .stk-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding-right: 24px; }
  .stk-name { font-size: 14.5px; font-weight: 600; letter-spacing: -0.1px; outline: none; border-radius: 4px; padding: 1px 3px; margin: -1px -3px; min-width: 30px; line-height: 1.4; }
  .stk-name:focus { background: var(--surface2); box-shadow: 0 0 0 2px var(--accent-dark); }
  .stk-name:empty::before { content: 'Name…'; color: var(--text3); font-style: italic; font-weight: 400; }
  /* v3.0: right-side meta column — Role above Company, both right-aligned */
  .stk-meta-right { display: flex; flex-direction: column; align-items: flex-end; max-width: 55%; gap: 1px; line-height: 1.35; padding-top: 1px; }
  .stk-role { font-size: 12px; color: var(--text2); font-style: italic; outline: none; border-radius: 4px; padding: 1px 3px; margin: -1px -3px; min-width: 30px; }
  .stk-role:focus { background: var(--surface2); font-style: normal; box-shadow: 0 0 0 2px var(--accent-dark); }
  .stk-role:empty::before { content: 'Role…'; color: var(--text3); }
  /* v4.0: .stk-organisation is now an <input> (was contenteditable) — reset the native
     input chrome so it sits flush + italic like the Role sibling above it. */
  .stk-organisation { font-size: 11.5px; color: var(--text3); font-style: italic; outline: none; border: none; background: transparent; font-family: inherit; text-align: right; border-radius: 4px; padding: 1px 3px; margin: -1px -3px; min-width: 30px; width: 100%; box-sizing: border-box; }
  .stk-organisation:focus { background: var(--surface2); font-style: normal; color: var(--text); box-shadow: 0 0 0 2px var(--accent-dark); }
  .stk-organisation::placeholder { color: var(--text3); opacity: 0.7; font-style: italic; }
  /* v14.1 (c): the third stacked line on a card. Deliberately identical to its sibling
     above - one more quiet italic line, not a new visual idiom. */
  .stk-location { font-size: 11.5px; color: var(--text3); font-style: italic; outline: none; border: none; background: transparent; font-family: inherit; text-align: right; border-radius: 4px; padding: 1px 3px; margin: -1px -3px; min-width: 30px; width: 100%; box-sizing: border-box; }
  .stk-location:focus { background: var(--surface2); font-style: normal; color: var(--text); box-shadow: 0 0 0 2px var(--accent-dark); }
  .stk-location::placeholder { color: var(--text3); opacity: 0.7; font-style: italic; }

  .stk-pills { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

  /* Pill chip — neutral background, colored dot for level */

  /* Engagement chip — split into Current/Target click zones */
  .stk-eng { display: inline-flex; align-items: center; gap: 2px; padding: 2px 4px; border-radius: 12px; background: var(--surface2); border: 1px solid var(--border); font-size: 11.5px; user-select: none; }
  .stk-eng-label { color: var(--text2); font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.5px; font-family: var(--mono); padding: 1px 4px 1px 5px; }
  .stk-eng-current, .stk-eng-target { padding: 2px 6px; border-radius: 8px; cursor: pointer; transition: background 0.15s; }
  .stk-eng-current { color: var(--text); font-weight: 500; }
  .stk-eng-target { color: var(--accent-dark); font-weight: 600; }
  .stk-eng-current:hover, .stk-eng-target:hover { background: var(--border); }
  .stk-eng-arrow { color: var(--text3); font-size: 10px; padding: 0 1px; pointer-events: none; }
  .stk-eng-same .stk-eng-target { color: var(--text3); font-weight: 400; }
  .stk-eng-same .stk-eng-arrow { color: var(--text3); opacity: 0.6; }

  /* Engagement popover (5-state picker) */
  .stk-eng-popover { position: absolute; z-index: 150; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 6px 24px rgba(0,0,0,0.12); padding: 4px; display: flex; flex-direction: column; min-width: 130px; }
  .stk-eng-option { font-family: var(--font); font-size: 12.5px; padding: 6px 12px; border: none; background: transparent; color: var(--text); text-align: left; cursor: pointer; border-radius: 5px; transition: background 0.1s; }
  .stk-eng-option:hover { background: var(--surface2); }
  .stk-eng-option.is-selected { background: var(--accent-dark); color: #fff; font-weight: 500; }
  .stk-eng-option.is-selected:hover { background: var(--accent-dark); }

  /* Notes textarea — inline, always visible */
  .stk-notes { width: 100%; min-height: 64px; padding: 8px 10px; border: 1px solid var(--border); border-radius: 7px; font-family: var(--font); font-size: 12.5px; color: var(--text); background: var(--bg); resize: vertical; line-height: 1.45; outline: none; transition: border-color 0.15s, background 0.15s; }
  .stk-notes:focus { border-color: var(--accent-dark); background: var(--surface); }
  .stk-notes::placeholder { color: var(--text3); font-style: italic; }

  /* ── v5.1 §8: stakeholder role/type (PMI) — NEUTRAL chips (attitude lives on the engagement chip) ── */
  .stk-roles { display:flex; flex-wrap:wrap; gap:6px; align-items:center; }
  .stk-roles-label { color:var(--text2); font-size:10.5px; text-transform:uppercase; letter-spacing:.5px; font-family:var(--mono); }
  .stk-role-chip { font-size:11.5px; padding:3px 9px; border-radius:8px; border:1px solid var(--border); background:var(--surface2); color:var(--text); white-space:nowrap; }
  .stk-role-none { font-size:11.5px; color:var(--text3); font-style:italic; }
  .stk-role-add { font-size:11.5px; padding:3px 9px; border-radius:8px; border:1px dashed var(--border); background:transparent; color:var(--text3); cursor:pointer; font-family:var(--font); }
  .stk-role-add:hover { color:var(--text); border-color:var(--text3); }
  .stk-roletype-popover { position:absolute; z-index:200; background:var(--surface); border:1px solid var(--border); border-radius:8px; box-shadow:0 6px 24px rgba(0,0,0,0.14); padding:8px; min-width:230px; max-width:280px; }
  .srt-group { margin-bottom:8px; } .srt-group:last-child { margin-bottom:0; }
  .srt-group-label { font-family:var(--mono); font-size:9.5px; text-transform:uppercase; letter-spacing:.5px; color:var(--text3); margin:2px 2px 5px; }
  .srt-opts { display:flex; flex-wrap:wrap; gap:5px; }
  .srt-opt { font-size:11.5px; padding:4px 9px; border-radius:7px; border:1px solid var(--border); background:var(--surface2); color:var(--text2); cursor:pointer; user-select:none; font-family:var(--font); }
  .srt-opt[aria-pressed="true"] { background:var(--accent-dark); color:#fff; border-color:var(--accent-dark); }
  .srt-opt[aria-pressed="true"]::before { content:"✓ "; }
  .dark .srt-opt[aria-pressed="true"] { background:var(--text); color:var(--bg); border-color:var(--text); }
  .stk-roletype-filter-wrap { display:inline-flex; align-items:center; gap:6px; }

  /* Stakeholders empty state */
  .stk-empty { text-align: center; padding: 50px 20px; color: var(--text2); font-size: 13px; }
  .stk-empty-title { font-size: 14px; font-weight: 500; color: var(--text); margin-bottom: 4px; }

  /* ── Power/Interest auto-plot grid (Mendelow) ─────────────────────── */
  .pi-section { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 20px 22px 22px; margin-bottom: 24px; }
  .pi-head { margin-bottom: 16px; }
  .pi-title { font-size: 14.5px; font-weight: 600; margin-bottom: 3px; }

  /* 2x2 grid layout */
  .pi-wrap { display: grid; grid-template-columns: 32px 1fr 1fr; grid-template-rows: 1fr 1fr 32px; gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; height: 380px; }
  .pi-yaxis { background: var(--surface); display: flex; align-items: center; justify-content: center; grid-row: 1 / span 2; grid-column: 1; }
  .pi-yaxis-label { transform: rotate(-90deg); font-size: 10.5px; color: var(--text2); font-family: var(--mono); text-transform: uppercase; letter-spacing: 1px; white-space: nowrap; }
  .pi-xaxis { background: var(--surface); display: flex; align-items: center; justify-content: center; font-size: 10.5px; color: var(--text2); font-family: var(--mono); text-transform: uppercase; letter-spacing: 1px; grid-column: 2 / span 2; }
  .pi-corner { background: var(--surface); }

  /* Quadrants — colors mirror the H/M/L palette of the app */
  .pi-quad { position: relative; padding: 10px 12px; overflow: visible; }
  /* v5.2.1 FIX: the #piDots overlay (below) explicitly spans rows 1–2 / cols 2–3, and
     .pi-yaxis holds col 1 — leaving no auto cells, so the four quadrants (previously
     auto-placed) were evicted into implicit rows and collapsed. Pin every cell explicitly
     so the dots overlay sits ON TOP of the quads instead of displacing them. */
  .pi-quad-keep-satisfied { grid-row: 1; grid-column: 2; }  /* TL: high power, low interest */
  .pi-quad-manage         { grid-row: 1; grid-column: 3; }  /* TR: high power, high interest */
  .pi-quad-monitor        { grid-row: 2; grid-column: 2; }  /* BL: low power, low interest */
  .pi-quad-keep-informed  { grid-row: 2; grid-column: 3; }  /* BR: low power, high interest */
  .pi-corner              { grid-row: 3; grid-column: 1; }
  .pi-xaxis               { grid-row: 3; }                   /* already grid-column: 2 / span 2 */
  /* v5.2: continuous dots overlay (spans the 2×2 quad area), replaces per-quad placement */
  .pi-dots { grid-row: 1 / span 2; grid-column: 2 / span 2; position: relative; pointer-events: none; z-index: 4; }
  .pi-pt { position: absolute; transform: translate(-50%, 50%); }
  .pi-pt.focused { z-index: 6; }
  .pi-cdot { width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
       font-size: 11px; font-weight: 600; color: #fff; border: 2px solid var(--surface); box-shadow: 0 2px 6px rgba(20,20,40,.22);
       cursor: pointer; pointer-events: auto; transition: opacity .12s, transform .12s; user-select: none; }
  .pi-cname { position: absolute; left: 50%; top: -6px; transform: translate(-50%, -100%); white-space: nowrap;
       background: var(--surface); border: 1px solid var(--border); color: var(--text); font-size: 11px; font-weight: 600;
       padding: 3px 8px; border-radius: 7px; box-shadow: 0 2px 8px rgba(20,20,40,.16); opacity: 0; transition: opacity .12s; pointer-events: none; }
  /* v13.1 (A35): high in the grid the label would be cut off by .pi-wrap's overflow:hidden,
     so it hangs BELOW its dot instead. Same 6px gap, mirrored. */
  .pi-pt.pi-below .pi-cname { top: auto; bottom: -6px; transform: translate(-50%, 100%); }
  /* ── v16.1 (b): the CROWDED-CORNER badge ───────────────────────────────────────────
     When the spiral cannot find a free slot within its rings, v16 left that dot sitting on
     top of another one — safely, but SILENTLY, which is the defect. Those dots are now
     withheld and rolled up into one of these per cluster, so a full corner says so.
     ⚠ Colours are .pi-cname's trio (--surface / --border / --text): all three are redefined
     in the dark block, so they flip together. Never pair --accent-dark with a flipping
     token here — that fault has shipped four times (v14.4, v15, v15.2, v15.3).
     ⚠ pointer-events must be re-enabled: .pi-dots sets none, so without this the badge's
     title tooltip — the only way to see WHO was withheld — would never appear. */
  .pi-more { position: absolute; transform: translate(-50%, 50%); z-index: 5;
       background: var(--surface); border: 1px solid var(--border); color: var(--text);
       font-size: 11px; font-weight: 600; padding: 3px 8px; border-radius: 999px;
       box-shadow: 0 2px 8px rgba(20,20,40,.16); white-space: nowrap; pointer-events: auto;
       cursor: default; user-select: none; }
  .pi-dots.focusing .pi-cdot { opacity: .3; }
  .pi-dots.focusing .pi-pt.focused .pi-cdot { opacity: 1; transform: scale(1.07); box-shadow: 0 0 0 3px var(--focus-ring), 0 2px 6px rgba(20,20,40,.22); }
  .pi-pt.focused .pi-cname { opacity: 1; }
  .pi-quad-manage         { background: #fdf0ef; }
  .pi-quad-keep-satisfied { background: #fdf6ec; }
  .pi-quad-keep-informed  { background: #f0f8f1; }
  .pi-quad-monitor        { background: #f5f5f5; }
  .pi-quad-title { font-size: 10px; font-weight: 600; color: var(--text2); text-transform: uppercase; letter-spacing: 0.8px; font-family: var(--mono); }
  .pi-quad-action { font-size: 10.5px; color: var(--text3); margin-top: 2px; font-style: italic; }

  /* Stakeholder dots on the grid */

  /* Empty Mendelow grid state */

  /* Empty scaffold tabs (Dashboard, Risks) */
  #panel-dashboard, #panel-risks { min-height: 200px; }

  /* v3.0: Dashboard "Project notes" — single textarea scaffold.
     Bound to appMeta.dashboard.notes. v3.1+ will add more sections
     around this without restructuring. */
  .dash-section { margin-bottom: 30px; }
  .dash-section-head { margin-bottom: 10px; }
  .dash-section-title { font-size: 14.5px; font-weight: 600; margin-bottom: 3px; }
  .dash-section-sub { font-size: 12px; color: var(--text2); }
  /* v8.6.2: dashboard sections are native <details> collapsibles — same light look,
     the head becomes a clickable <summary> with a small caret (mirrors .raid-summary's). */
  summary.dash-section-head { cursor: pointer; list-style: none; user-select: none; position: relative; padding-left: 16px; }
  summary.dash-section-head::-webkit-details-marker { display: none; }
  summary.dash-section-head::before { content: '▸'; position: absolute; left: 0; top: 3px; font-size: 11px; color: var(--text3); transition: transform .12s; }
  details.dash-section[open] > summary.dash-section-head::before { transform: rotate(90deg); }
  /* v8.6.2: inside the register collapsible the pi-section keeps its own box + title —
     it is the register's "Matrix" view, labelled as such alongside Cards/Table. */
  #stkRegisterSection .pi-section { margin-bottom: 0; }
  /* v3.4: narrative harmonised — wrapped in a card matching cadence/products
     so the label sits inside the box; the textarea is borderless/transparent
     and the focus border lives on the card via :focus-within. */
  .notes-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; transition: border-color 0.15s; }
  .notes-card:focus-within { border-color: var(--accent-dark); }
  .dash-notes { width: 100%; min-height: 240px; padding: 0; border: none; background: transparent; font-family: var(--font); font-size: 13px; color: var(--text); resize: vertical; line-height: 1.55; outline: none; }
  .dash-notes::placeholder { color: var(--text3); font-style: italic; }
  /* v17.5 project-charter guide */
  .charter-guide { margin: 0 0 10px; border: 1px solid var(--border); border-radius: 9px; background: var(--surface2); }
  .charter-guide[hidden], .charter-empty[hidden] { display: none; }
  .charter-guide > summary { cursor: pointer; list-style: none; padding: 9px 12px; color: var(--text2); font-size: 12.5px; font-weight: 600; }
  .charter-guide > summary::-webkit-details-marker { display: none; }
  .charter-guide > summary::before { content: '▸'; display: inline-block; width: 14px; color: var(--text3); transition: transform .12s; }
  .charter-guide[open] > summary::before { transform: rotate(90deg); }
  .charter-guide-content { padding: 0 12px 11px 26px; color: var(--text2); font-size: 12px; line-height: 1.48; }
  .charter-guide-content p { margin: 0 0 8px; }
  .charter-guide-content p:last-of-type { margin-bottom: 9px; }
  .charter-guide-content strong { color: var(--text); }
  .charter-guide-foot { color: var(--text3); font-style: italic; }
  .charter-empty { display: flex; align-items: center; flex-wrap: wrap; gap: 5px 10px; margin: 0 0 10px; color: var(--text2); font-size: 12.5px; }
  .charter-link { appearance: none; border: 0; background: transparent; color: var(--accent-dark); cursor: pointer; font: inherit; font-size: 12.5px; font-weight: 600; padding: 3px 2px; text-decoration: underline; text-underline-offset: 2px; }
  .charter-link:hover { color: var(--text); }
  .charter-link:focus-visible, .charter-guide > summary:focus-visible { outline: 2px solid var(--accent-dark); outline-offset: 2px; border-radius: 4px; }
  .charter-nav { display: flex; flex-wrap: wrap; gap: 4px 16px; margin-top: 9px; }
  .dark .notes-card { background: var(--surface2); }
  .dark .notes-card:focus-within { background: var(--surface); border-color: var(--text2); }
  .dark .charter-guide { background: var(--surface2); }
  .dark .charter-link { color: var(--text2); }
  @media (max-width: 520px) {
    .charter-empty { align-items: flex-start; flex-direction: column; }
    .charter-nav { align-items: flex-start; flex-direction: column; gap: 2px; }
  }

  /* ── Dark-mode overrides for v3.0 ─────────────────────────────────── */
  .dark .stk-card-del:hover { color: #ff7a6e; background: rgba(255,122,110,0.12); }
  .dark .stk-eng-option.is-selected { background: var(--surface); color: var(--text); }
  .dark .stk-eng-option.is-selected:hover { background: var(--surface2); }
  .dark .stk-notes { background: var(--surface2); }
  .dark .stk-notes:focus { background: var(--surface); border-color: var(--text2); }
  .dark .pi-quad-manage         { background: #3a1f1c; }
  .dark .pi-quad-keep-satisfied { background: #3a2c18; }
  .dark .pi-quad-keep-informed  { background: #1c3022; }
  .dark .pi-quad-monitor        { background: #2a2826; }

  /* ─────────────────────────────────────────────────────────────────────
     v3.0.2 — search-result match highlighting + spacing fix
     ───────────────────────────────────────────────────────────────────── */

  /* Search highlight (Variant 2 — soft warm yellow). Used wherever the
     active Actions or Minutes search query matches free-form text inside
     a visible card. Tiny horizontal padding + 3px radius — reads as a
     marker brush behind the text, not a chip. */
  .search-highlight {
    background: #fef3c7;
    color: var(--text);
    border-radius: 3px;
    padding: 0 2px;
  }
  .dark .search-highlight {
    background: #5c4520;
    color: #fde68a;
  }

  /* v3.0.2 spacing fix: the chips block (Depends on / Related to / etc.)
     sits directly above the "Meeting updates LIVE" section. The transition
     was too tight — add breathing room consistent with the card's other
     vertical rhythm. */
  .update-section { margin-top: 16px; }

  /* ─────────────────────────────────────────────────────────────────────
     v3.1 — Stakeholders tab: search, sort, drag-and-drop on Mendelow grid
     ───────────────────────────────────────────────────────────────────── */

  /* Search + sort toolbar above the cards */
  .stk-toolbar { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
  .stk-search-wrap { position: relative; display: inline-flex; align-items: center; flex: 1; min-width: 240px; max-width: 380px; }
  .stk-search-icon { position: absolute; left: 10px; width: 14px; height: 14px; pointer-events: none; color: var(--text2); }
  .stk-search-input { font-family: var(--font); font-size: 13px; padding: 7px 32px 7px 32px; border-radius: 7px; border: 1px solid var(--border); background: var(--surface); color: var(--text); width: 100%; outline: none; }
  .stk-search-input:focus { border-color: var(--accent-dark); }
  .stk-search-clear { position: absolute; right: 8px; width: 18px; height: 18px; border-radius: 50%; border: none; background: var(--surface2); color: var(--text2); cursor: pointer; font-size: 12px; line-height: 1; display: none; align-items: center; justify-content: center; padding: 0; }
  .stk-search-wrap.has-text .stk-search-clear { display: inline-flex; }
  .stk-search-clear:hover { background: var(--border); }

  /* Sort dropdown + dir button (mirrors actions/minutes pattern) */
  .stk-sort-wrap { display: inline-flex; align-items: center; gap: 6px; }
  .stk-sort-label { font-family: var(--mono); font-size: 10.5px; color: var(--text2); text-transform: uppercase; letter-spacing: 0.5px; }
  .stk-sort-select { font-family: var(--font); font-size: 13px; padding: 6px 28px 6px 10px; border-radius: 7px; border: 1px solid var(--border); background: var(--surface); color: var(--text); cursor: pointer; outline: none; appearance: none; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10' fill='none' stroke='%236b6a64' stroke-width='1.6'><path d='M2 3.5l3 3 3-3'/></svg>"); background-repeat: no-repeat; background-position: right 8px center; }
  .stk-sort-select:focus { border-color: var(--accent-dark); }
  .stk-sort-dir { width: 30px; height: 30px; border: 1px solid var(--border); background: var(--surface); border-radius: 6px; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; color: var(--text); padding: 0; }
  .stk-sort-dir:hover { background: var(--surface2); }
  .stk-sort-dir svg { width: 13px; height: 13px; }
  .stk-sort-dir.desc svg { transform: rotate(180deg); }

  /* Empty-state when filtered to nothing (different message from "no stakeholders yet") */
  .stk-empty-filtered { text-align: center; padding: 50px 20px; color: var(--text2); font-size: 13px; }

  /* v13.1 (U04 / D04): the v3.0-era .pi-dot / .pi-dot-label / .pi-focused / .pi-focusing
     rules were removed here. The dots have been .pi-cdot inside .pi-pt since v5.2, and the
     hover dimming runs on .pi-dots.focusing / .pi-pt.focused — different classes entirely,
     defined above. ⚠ The register described this as "retired drag CSS"; the census found no
     drag class in the file at all (it left with v5.1.1). What actually survived was this
     block plus two comments claiming it had already gone. */

  /* ── v3.4: stakeholder category pill (inline <select> on each card) ──────── */
  .stk-cat-select { font-family:var(--mono); font-size:10px; text-transform:uppercase; letter-spacing:.5px; padding:2px 9px; border-radius:11px; border:1px solid var(--border); background:var(--surface2); color:var(--text2); cursor:pointer; outline:none; white-space:nowrap; -webkit-appearance:none; appearance:none; }
  .stk-cat-select:focus { box-shadow:0 0 0 2px var(--accent-dark); }
  .stk-cat-select.cat-customer { color:var(--cat-customer); background:var(--cat-customer-bg); border-color:var(--cat-customer-bd); }
  .stk-cat-select.cat-internal { color:var(--cat-internal); background:var(--cat-internal-bg); border-color:var(--cat-internal-bd); }
  .stk-cat-select.cat-partner  { color:var(--cat-partner);  background:var(--cat-partner-bg);  border-color:var(--cat-partner-bd); }
  .stk-cat-select.cat-other    { color:var(--cat-other);    background:var(--cat-other-bg);    border-color:var(--cat-other-bd); }

  /* ── v3.4: grid filter chips + colour-by-category toggle ─────────────────── */
  /* v4.0: tab-wide category filter bar at the top of the Stakeholders tab. */
  .stk-cat-filter-bar { display:flex; align-items:center; gap:8px; margin:0 0 14px; flex-wrap:wrap; }
  .gfb-label { font-size:11px; color:var(--text3); font-family:var(--mono); text-transform:uppercase; letter-spacing:.5px; margin-right:2px; }
  .filter-chip { font-family:var(--mono); font-size:10px; text-transform:uppercase; letter-spacing:.5px; padding:3px 10px; border-radius:12px; border:1px solid; cursor:pointer; display:inline-flex; align-items:center; gap:6px; user-select:none; transition:opacity .15s; }
  .filter-chip .fc-dot { width:8px; height:8px; border-radius:50%; }
  .filter-chip.off { opacity:0.4; text-decoration:line-through; }
  .filter-chip.fc-customer { color:var(--cat-customer); border-color:var(--cat-customer-bd); background:var(--cat-customer-bg); }
  .filter-chip.fc-customer .fc-dot { background:var(--cat-customer); }
  .filter-chip.fc-internal { color:var(--cat-internal); border-color:var(--cat-internal-bd); background:var(--cat-internal-bg); }
  .filter-chip.fc-internal .fc-dot { background:var(--cat-internal); }
  .filter-chip.fc-partner  { color:var(--cat-partner);  border-color:var(--cat-partner-bd);  background:var(--cat-partner-bg); }
  .filter-chip.fc-partner .fc-dot { background:var(--cat-partner); }
  .filter-chip.fc-other    { color:var(--cat-other);    border-color:var(--cat-other-bd);    background:var(--cat-other-bg); }
  .filter-chip.fc-other .fc-dot { background:var(--cat-other); }

  /* ── v3.4: category-coloured grid dots (gated by .grid-color-by-cat) + filter hide ─ */
  /* v4.0: the hide-cat-* grid CSS was removed — per-category visibility is now
     handled by data-filtering in getFilteredStakeholders (cards + grid together). */

  /* Help line below the grid explaining drag + reset */
  .pi-help { font-size: 11.5px; color: var(--text3); margin-top: 12px; line-height: 1.5; }

  /* ── v5.2: stat strip ── */
  .stk-stats { display: flex; flex-wrap: wrap; gap: 9px; margin: 2px 0 16px; }
  .stk-stat { display: flex; align-items: baseline; gap: 7px; padding: 7px 13px; border: 1px solid var(--border); border-radius: 9px; background: var(--surface); }
  .stk-stat .n { font-family: var(--mono); font-weight: 600; font-size: 16px; color: var(--text); line-height: 1; }
  .stk-stat .l { font-size: 11.5px; color: var(--text2); white-space: nowrap; }
  .stk-stat--total { background: var(--surface2); }
  .stk-stat[data-k="mc"] { border-color: var(--high-border);   background: var(--high-bg); }
  .stk-stat[data-k="ks"] { border-color: var(--medium-border); background: var(--medium-bg); }
  .stk-stat[data-k="ki"] { border-color: var(--low-border);    background: var(--low-bg); }
  .stk-stat[data-k="mc"] .n { color: var(--high); }
  .stk-stat[data-k="ks"] .n { color: var(--medium); }
  .stk-stat[data-k="ki"] .n { color: var(--low); }
  .stk-stat[data-k="mo"] .n { color: var(--text2); }

  /* ── v5.2: segmented toggles (view + colour-by) ── */
  .stk-tb-toggles { display: flex; gap: 12px; align-items: center; margin-left: auto; flex-wrap: wrap; }
  .stk-seg { display: inline-flex; align-items: center; gap: 2px; background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; padding: 2px; }
  .stk-seg-label { font-size: 10px; color: var(--text3); font-family: var(--mono); text-transform: uppercase; letter-spacing: .5px; padding: 0 5px 0 6px; }
  .stk-seg button { border: 0; background: transparent; color: var(--text2); font: inherit; font-size: 12.5px; padding: 5px 12px; border-radius: 6px; cursor: pointer; transition: background .12s, color .12s; }
  .stk-seg button:hover { color: var(--text); }
  .stk-seg button.active { background: var(--surface); color: var(--text); box-shadow: 0 1px 2px rgba(20,20,40,.08); font-weight: 500; }
  .dark .stk-seg button.active { background: var(--accent-dark); color: var(--text); }

  /* ── v5.2: dense Table view ── */
  .stk-table { border: 1px solid var(--border); border-radius: 10px; overflow: hidden; margin-bottom: 24px; background: var(--surface); }
  /* ⚠ v14.1 (c): the column IS widened, and the scope's claim that the template would not
     need touching was wrong. .stk-trole is ellipsised, so a third segment overflowed it:
     measured, with a location the cell clipped below ~1600px of window, and today's two
     segments clip at no width from 1280 up. Because the location sits LAST it was the first
     thing dropped - the new field would have been invisible on the surface people scan.
     1.2fr -> 1.6fr with a 130px floor, paid for by the two slider columns at 1.1 -> 1.0:
     that clears every clip at 1366px AND 1280px while the bars only go 173px -> 146px, far
     above their 36px floor and still legible as proportional bars. */
  .stk-tgrid { grid-template-columns: 34px minmax(140px,1.4fr) minmax(130px,1.6fr) 92px 1.0fr 1.0fr 122px 30px; gap: 12px; }
  .stk-thead { display: grid; align-items: center; padding: 8px 14px; background: var(--surface2); font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .6px; color: var(--text3); }
  .stk-trow { display: grid; align-items: center; padding: 9px 14px; border-top: 1px solid var(--border); cursor: pointer; transition: background .1s; }
  .stk-trow:hover { background: var(--surface2); }
  .stk-tavatar { width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 600; color: #fff; }
  .stk-tname { font-weight: 500; color: var(--text); font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .stk-trole { font-size: 12px; color: var(--text2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .stk-tbar-wrap { display: flex; align-items: center; gap: 8px; }
  .stk-tbar { flex: 1; height: 6px; border-radius: 3px; background: var(--surface2); overflow: hidden; min-width: 36px; }
  .stk-tbar > i { display: block; height: 100%; border-radius: 3px; }
  .stk-tbar-lvl { font-family: var(--mono); font-size: 10.5px; color: var(--text2); width: 28px; text-align: right; }
  .stk-tcat, .stk-tstrat { font-size: 10.5px; padding: 3px 9px; border-radius: 10px; border: 1px solid var(--border); white-space: nowrap; justify-self: start; }
  .stk-tstrat { font-weight: 500; }
  .stk-trm { width: 22px; height: 22px; border: 0; background: transparent; color: var(--text3); border-radius: 5px; cursor: pointer; font-size: 16px; line-height: 1; justify-self: center; }
  .stk-trm:hover { background: var(--high-bg); color: var(--high); }
  .stk-tempty { padding: 28px 16px; text-align: center; color: var(--text3); font-size: 13px; }
  @media (max-width: 860px) {
    .stk-thead { display: none; }
    .stk-tgrid { grid-template-columns: 30px 1fr 96px 30px; }
    .stk-trow > .stk-trole, .stk-trow > .stk-tcat, .stk-trow > .stk-tbar-i { display: none; }
  }

  /* ── v5.2: inline Influence/Interest sliders (the bars double as the control) ── */
  .stk-sliders { display: flex; flex-direction: column; gap: 8px; margin: 11px 0 4px; }
  .stk-slider-row { display: flex; align-items: center; gap: 9px; }
  .stk-slider-label { font-size: 10.5px; font-family: var(--mono); text-transform: uppercase; letter-spacing: .4px; color: var(--text3); width: 60px; flex: none; }
  .stk-slider-lvl { font-family: var(--mono); font-size: 11px; color: var(--text2); width: 30px; text-align: right; flex: none; }
  .stk-slider { -webkit-appearance: none; appearance: none; height: 6px; border-radius: 3px; background: var(--surface2); outline: none; cursor: pointer; flex: 1; min-width: 60px; }
  .stk-slider::-webkit-slider-runnable-track { height: 6px; border-radius: 3px; background: transparent; }
  .stk-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 14px; height: 14px; border-radius: 50%; background: var(--surface); border: 2px solid var(--text2); box-shadow: 0 1px 3px rgba(20,20,40,.25); cursor: pointer; margin-top: -4px; }
  .stk-slider::-moz-range-track { height: 6px; border-radius: 3px; background: transparent; }
  .stk-slider::-moz-range-thumb { width: 14px; height: 14px; border-radius: 50%; background: var(--surface); border: 2px solid var(--text2); box-shadow: 0 1px 3px rgba(20,20,40,.25); cursor: pointer; }
  .stk-slider:focus-visible { box-shadow: 0 0 0 3px var(--focus-ring); }
  /* v13.1 (A34): the RAG pills and category chips are reachable by keyboard now, so
     they need to SHOW where the keyboard is — same ring as the slider above. */
  .rag-pill:focus-visible, .filter-chip:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
  .stk-slider-presets { display: inline-flex; gap: 2px; flex: none; }
  .stk-slider-presets button { width: 20px; height: 20px; border: 1px solid var(--border); background: var(--surface); color: var(--text2); border-radius: 5px; font-size: 10px; font-family: var(--mono); cursor: pointer; padding: 0; line-height: 1; }
  .stk-slider-presets button:hover { background: var(--surface2); color: var(--text); }
  .stk-strat-chip { font-size: 10px; font-family: var(--mono); text-transform: uppercase; letter-spacing: .4px; padding: 3px 9px; border-radius: 11px; border: 1px solid var(--border); white-space: nowrap; align-self: center; }

  /* ── v5.2: slide-in editor drawer (matrix-dot + table-row clicks; "+ Add" = blank) ── */
  .stk-drawer-overlay { position: fixed; inset: 0; background: rgba(20,20,30,.38); display: flex; justify-content: flex-end; opacity: 0; pointer-events: none; transition: opacity .2s; z-index: 1000; }
  .stk-drawer-overlay.open { opacity: 1; pointer-events: auto; }
  .stk-drawer { width: 440px; max-width: 92vw; height: 100%; background: var(--surface); box-shadow: -8px 0 30px rgba(20,20,40,.18); display: flex; flex-direction: column; transform: translateX(100%); transition: transform .22s cubic-bezier(.4,0,.2,1); }
  .stk-drawer.open { transform: translateX(0); }
  .stk-drawer-head { display: flex; align-items: center; justify-content: space-between; padding: 17px 20px; border-bottom: 1px solid var(--border); flex: none; }
  .stk-drawer-title { font-size: 16px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .stk-drawer-close { width: 30px; height: 30px; border: 0; background: transparent; color: var(--text2); font-size: 22px; line-height: 1; border-radius: 6px; cursor: pointer; flex: none; }
  .stk-drawer-close:hover { background: var(--surface2); color: var(--text); }
  .stk-drawer-body { flex: 1; overflow-y: auto; padding: 18px 20px; display: flex; flex-direction: column; gap: 14px; }
  .stk-dfield { display: flex; flex-direction: column; gap: 5px; }
  .stk-dlabel { font-size: 11px; font-family: var(--mono); text-transform: uppercase; letter-spacing: .5px; color: var(--text3); }
  .stk-dinput { font: inherit; font-size: 13.5px; color: var(--text); background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; padding: 9px 11px; outline: none; width: 100%; box-sizing: border-box; }
  .stk-dinput:focus { border-color: var(--text3); box-shadow: 0 0 0 3px var(--focus-ring); }
  .stk-dnotes { min-height: 84px; resize: vertical; }
  .stk-drawer .stk-roles, .stk-drawer .stk-slider-row { margin: 0; }
  .stk-drawer-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 14px 20px; border-top: 1px solid var(--border); flex: none; }
  .stk-dbtn { font: inherit; font-size: 13px; padding: 8px 16px; border-radius: 8px; cursor: pointer; border: 1px solid var(--border); background: var(--surface); color: var(--text); }
  .stk-dbtn--primary { background: var(--accent-dark); color: #fff; border-color: var(--accent-dark); }
  .stk-dbtn--danger { color: var(--high); border-color: var(--high-border); background: var(--high-bg); }
  .stk-dbtn:hover { filter: brightness(.97); }
  .pi-help kbd { font-family: var(--mono); font-size: 10.5px; padding: 1px 5px; border: 1px solid var(--border); border-radius: 3px; background: var(--surface2); color: var(--text2); }

  /* ── Dark-mode overrides for v3.1 additions ──────────────────────── */
  .dark .stk-sort-select { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10' fill='none' stroke='%23a8a6a0' stroke-width='1.6'><path d='M2 3.5l3 3 3-3'/></svg>"); }

  /* ── End v3.1 stakeholders block ──────────────────────────────────── */

  /* ═══════════════════════════════════════════════════════════════════════
     v3.2 — DASHBOARD substance: RAG, products, cadence, milestones,
     key risks, success projects. Reuses .dash-section / .dash-section-head
     / .dash-section-title / .dash-section-sub from the v3.0 block above.
     ═══════════════════════════════════════════════════════════════════════ */

  /* v10.2: three definition-only leftovers of the pre-v8.8 Overview removed
     (the tentative-section tag, the mini heading and the two-column row grid). */

  /* ── Project Status: RAG pill (click-to-cycle) + rationale ───────── */
  .rag-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; display: flex; align-items: center; gap: 14px; }
  .rag-pill { display: inline-flex; align-items: center; justify-content: center; min-width: 92px; padding: 6px 16px; border-radius: 14px; font-family: var(--font); font-size: 13px; font-weight: 500; border: 1px solid var(--border); cursor: pointer; user-select: none; flex-shrink: 0; transition: background 0.12s, border-color 0.12s, color 0.12s; }
  .rag-pill.rag-red   { background: var(--high-bg);   color: var(--high);   border-color: var(--high-border); }
  .rag-pill.rag-amber { background: var(--medium-bg); color: var(--medium); border-color: var(--medium-border); }
  .rag-pill.rag-green { background: var(--low-bg);    color: var(--low);    border-color: var(--low-border); }
  .rag-pill.rag-none  { background: var(--surface2);  color: var(--text2);  border-color: var(--border); }
  .rag-rationale { flex: 1; font-size: 13px; color: var(--text); outline: none; padding: 5px 8px; margin: -5px -8px; border-radius: 6px; }
  .rag-rationale:focus { background: var(--surface2); box-shadow: 0 0 0 2px var(--accent-dark); }
  .rag-rationale:empty::before { content: 'Add a one-line rationale…'; color: var(--text3); font-style: italic; }

  /* v17.5 P7: one reported project percentage, with details on demand. */
  .project-progress-row { display:grid; grid-template-columns:minmax(150px,1fr) minmax(90px,180px) auto;
    align-items:center; gap:12px 16px; margin-top:9px; padding:11px 13px; border:1px solid var(--border);
    border-radius:9px; background:var(--surface2); }
  .project-progress-row:empty { display:none; }
  .project-progress-heading { display:flex; align-items:center; gap:7px; min-width:0; flex-wrap:wrap;
    color:var(--text); font-size:12px; font-weight:650; }
  .project-progress-source { color:var(--text2); font-size:10.5px; font-weight:400; }
  .project-progress-track { display:block; height:5px; min-width:72px; overflow:hidden;
    border-radius:999px; background:var(--border); }
  .project-progress-fill { display:block; height:100%; border-radius:inherit; background:var(--text2); }
  .project-progress-value-wrap { display:flex; align-items:center; justify-content:flex-end; gap:6px;
    min-width:0; white-space:nowrap; }
  .project-progress-value { display:inline-flex; align-items:center; justify-content:center; min-width:48px;
    padding:5px 8px; border:1px solid var(--border); border-radius:7px; background:var(--surface);
    color:var(--text); font-family:var(--mono); font-size:12px; font-weight:650; line-height:1; }
  button.project-progress-value { cursor:pointer; }
  button.project-progress-value:hover { border-color:var(--text3); background:var(--bg); }
  button.project-progress-value:focus-visible { outline:2px solid var(--accent-dark); outline-offset:2px; }
  .progress-assessed { display:inline-flex; align-items:center; padding:2px 7px; border:1px solid var(--border);
    border-radius:999px; background:var(--surface); color:var(--text2); font-size:9.5px;
    font-weight:600; line-height:1.35; white-space:nowrap; }
  button.ov-info-i.progress-help-trigger { appearance:none; display:inline-grid; place-items:center; flex:none;
    width:24px; height:24px; margin:0; padding:0; border:1px solid var(--border); border-radius:50%;
    background:var(--surface); color:var(--text2); font:italic 10px/1 var(--mono); cursor:help; vertical-align:middle; }
  button.ov-info-i.progress-help-trigger:hover { border-color:var(--text3); color:var(--text); }
  button.ov-info-i.progress-help-trigger:focus-visible { outline:2px solid var(--accent-dark); outline-offset:2px; }
  .progress-help-tooltip { position:fixed; z-index:520; width:min(320px,calc(100vw - 24px));
    max-height:min(420px,calc(100vh - 24px)); overflow:auto; padding:11px 12px; border:1px solid var(--border);
    border-radius:9px; background:var(--surface); color:var(--text); box-shadow:0 8px 28px rgba(20,20,35,.20);
    font-size:11.5px; line-height:1.46; }
  .progress-help-tooltip[hidden] { display:none; }
  .progress-help-line { margin:0 0 7px; }
  .progress-help-line:last-child { margin-bottom:0; }
  .progress-help-note { margin-top:2px; white-space:pre-wrap; overflow-wrap:anywhere; }

  .pm-progress { min-width:128px; }
  .pm-progress-main { display:flex; align-items:center; justify-content:center; gap:7px; }
  .pm-progress .pm-pct { display:inline; margin:0; flex:none; }
  .pm-progress .pm-bar { width:58px; margin:0; flex:none; }
  .pm-progress-meta { display:flex; justify-content:center; align-items:center; gap:4px; margin-top:4px; min-height:24px; }
  .pm-progress .progress-assessed { font-size:9px; }
  .pf-project-progress { display:flex; align-items:center; gap:5px; flex-wrap:wrap; margin-top:4px;
    color:var(--text2); font-size:11px; }
  .pf-project-progress strong { color:var(--text); font-family:var(--mono); font-size:10.5px; }

  .progress-dialog { width:min(440px,calc(100vw - 32px)); max-width:440px;
    max-height:calc(100vh - 32px); overflow-y:auto; margin:auto; padding:0; border:1px solid var(--border);
    border-radius:13px; background:var(--surface); color:var(--text); box-shadow:0 18px 58px rgba(0,0,0,.30); }
  .progress-dialog::backdrop { background:rgba(0,0,0,.38); }
  .progress-dialog-form { padding:21px 22px 19px; }
  .progress-dialog-title { margin:0; font-size:17px; font-weight:650; }
  .progress-dialog-project { margin:3px 0 16px; color:var(--text2); font-size:12px; overflow-wrap:anywhere; }
  .progress-source-fieldset { margin:0; padding:0; border:0; }
  .progress-source-legend { margin-bottom:7px; color:var(--text2); font-family:var(--mono); font-size:10px;
    font-weight:600; text-transform:uppercase; letter-spacing:.06em; }
  .progress-source-choice { display:grid; grid-template-columns:auto 1fr; gap:2px 9px; align-items:start;
    margin-top:8px; padding:9px 10px; border:1px solid var(--border); border-radius:8px; cursor:pointer; }
  .progress-source-choice:has(input:checked) { background:var(--surface2); border-color:var(--text3); }
  .progress-source-choice input { grid-row:1 / 3; margin:3px 0 0; accent-color:var(--accent-dark); }
  .progress-source-choice strong { font-size:12.5px; font-weight:650; }
  .progress-source-choice span { color:var(--text2); font-size:11.5px; line-height:1.4; }
  .progress-assessment-fields { margin:12px 0 0 29px; }
  .progress-assessment-fields[hidden], .progress-auto-copy[hidden], .progress-field-error[hidden],
  .progress-dialog-error[hidden] { display:none; }
  .progress-auto-copy { margin:11px 0 0 29px; color:var(--text2); font-size:11.5px; }
  .progress-field { display:block; margin-top:10px; color:var(--text); font-size:11.5px; font-weight:600; }
  .progress-field input, .progress-field textarea { display:block; width:100%; margin-top:5px;
    border:1px solid var(--border); border-radius:7px; background:var(--surface2); color:var(--text);
    padding:8px 9px; outline:none; font:13px/1.4 var(--font); }
  .progress-field input { max-width:120px; }
  .progress-field textarea { min-height:82px; resize:vertical; }
  .progress-field input:focus, .progress-field textarea:focus { border-color:var(--text3); background:var(--surface); }
  .progress-field input[aria-invalid="true"], .progress-field textarea[aria-invalid="true"] { border-color:var(--high); }
  .progress-field-error, .progress-dialog-error { margin-top:5px; color:var(--high); font-size:11px; line-height:1.4; }
  .progress-dialog-error { padding:8px 9px; border:1px solid var(--high-border); border-radius:7px;
    background:var(--high-bg); color:var(--text); }
  .progress-assessment-helper { margin:7px 0 0; color:var(--text2); font-size:11px; line-height:1.4; }
  .progress-dialog-actions { display:flex; justify-content:flex-end; gap:8px; margin-top:19px; }

  @media (max-width:520px) {
    .project-progress-row { grid-template-columns:1fr auto; gap:9px 12px; }
    .project-progress-track { grid-column:1 / -1; grid-row:2; }
    .progress-dialog-form { padding:18px 17px 16px; }
  }
  @media (max-width:390px) {
    .project-progress-row { grid-template-columns:1fr; }
    .project-progress-track { grid-column:1; grid-row:auto; }
    .project-progress-value-wrap { justify-content:flex-start; }
    .progress-assessment-fields, .progress-auto-copy { margin-left:0; }
  }

  /* v10.2: the Meeting cadence and Key products/CRM CSS families removed —
     their UI left in v8 Phase 2 (products/CRM) and v8.8 (cadence); the last
     JS users went with the v10.2 dormant strip. */

  /* ── List card (shared by milestones + key risks) ────────────────── */
  .dash-list-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 6px 8px; }
  .dlc-row { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 7px; }
  .dlc-row + .dlc-row { border-top: 1px solid var(--border); }
  .dlc-row:hover { background: var(--surface2); }
  /* v17.0 W1: only rows which actually navigate advertise that behaviour.  Keeping the
     shared row paint preserves the dashboard's visual weight; the cursor and keyboard
     ring are the restrained interaction cues. */
  .dash-jump-row { cursor: pointer; }
  .dash-jump-row:focus-visible { outline: 2px solid var(--accent-dark); outline-offset: 1px; }
  .dash-jump-row:hover .mil-title,
  .dash-jump-row:hover .kr-statement { text-decoration: underline; text-decoration-thickness: 1px; }
  .dlc-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; background: var(--accent-dark); }
  .dash-list-empty { padding: 28px 14px; text-align: center; color: var(--text3); font-size: 12.5px; }
  /* Milestone row specifics */
  .mil-row.overdue .dlc-dot { background: var(--high); }
  .mil-date { font-family: var(--mono); font-size: 12px; color: var(--text2); min-width: 104px; flex-shrink: 0; }
  .mil-row.overdue .mil-date { color: var(--high); }
  .mil-id { font-family: var(--mono); font-size: 11px; color: var(--text3); min-width: 36px; flex-shrink: 0; }
  .mil-title { font-size: 13px; color: var(--text); flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .mil-rel { font-family: var(--mono); font-size: 11px; color: var(--text3); flex-shrink: 0; text-align: right; white-space: nowrap; }
  .mil-row.overdue .mil-rel { color: var(--high); font-weight: 500; }
  /* Key-risk row specifics */
  .kr-dot.lvl-high { background: var(--high); } .kr-dot.lvl-medium { background: var(--medium); } .kr-dot.lvl-low { background: var(--low); }
  .kr-id { font-family: var(--mono); font-size: 11px; color: var(--text3); min-width: 36px; flex-shrink: 0; }
  .kr-statement { font-size: 13px; color: var(--text); flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .kr-score { font-size: 11px; font-weight: 600; padding: 2px 10px; border-radius: 10px; font-family: var(--mono); flex-shrink: 0; }
  .kr-score.lvl-high { background: var(--high-bg); color: var(--high); border: 1px solid var(--high-border); }
  .kr-score.lvl-medium { background: var(--medium-bg); color: var(--medium); border: 1px solid var(--medium-border); }
  .kr-score.lvl-low { background: var(--low-bg); color: var(--low); border: 1px solid var(--low-border); }

  /* ── Success Projects (expandable cards) ─────────────────────────── */
  .ws-list { display: flex; flex-direction: column; gap: 10px; }
  .ws-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
  .ws-header { display: flex; align-items: center; flex-wrap:wrap; gap: 9px 12px; padding: 12px 14px; cursor: pointer; user-select: none; }
  .ws-header:hover { background: var(--surface2); }
  .ws-card.expanded { /* expanded state */ }
  /* v3.3: SP chevron now matches the .action-chevron / .session-chevron pattern
     pixel-identical (size, hover, transition, rotation). The v3.2 version was a
     small right-pointing 14×14 SVG that read as a dash on mobile. Stays on the
     LEFT of the SP card header (the progress bar occupies the right). */
  .ws-chevron {
    flex-shrink: 0;
    width: 28px; height: 28px;
    background: transparent;
    border: none;
    border-radius: 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text3);
    margin-top: -2px;
    cursor: pointer;
    transition: color 0.15s, background 0.15s;
  }
  .ws-chevron:hover { background: rgba(0,0,0,0.04); }
  .ws-chevron svg { width: 18px; height: 18px; transition: transform 0.2s; }
  .ws-card.expanded .ws-chevron svg { transform: rotate(180deg); }
  .ws-title { font-size: 14px; font-weight: 500; flex: 1 1 170px; min-width:90px; color: var(--text); outline: none; padding: 2px 4px; margin: -2px -4px; border-radius: 4px; }
  .ws-title:focus { background: var(--surface2); box-shadow: 0 0 0 2px var(--accent-dark); }
  .ws-title:empty::before { content: 'Untitled project'; color: var(--text3); font-style: italic; }
  .ws-count { font-family: var(--mono); font-size: 11px; color: var(--text2); white-space: nowrap; flex-shrink: 0; }
  .ws-progress-wrap { flex:0 1 auto; display: flex; align-items: center; gap: 7px; min-width:0; }
  .ws-progress-label { color:var(--text2); font-size:10.5px; white-space:nowrap; }
  .ws-progress-bar { display: block; width: 78px; height: 6px; background: var(--surface2); border-radius: 3px; overflow: hidden; border: 1px solid var(--border); }
  .ws-progress-fill { display: block; height: 100%; background: var(--accent-dark); transition: width 0.2s; }
  .ws-progress-pct { font-family: var(--mono); font-size: 12px; font-weight: 600; color: var(--text); min-width: 34px; text-align: right; }
  .ws-progress-wrap .progress-help-trigger { width:24px; height:24px; }
  .ws-lifecycle { appearance:auto; max-width:128px; margin-left:0; padding:3px 5px; font-family:var(--font); cursor:pointer; }
  .ws-lifecycle:focus-visible { outline:2px solid var(--accent-dark); outline-offset:2px; }
  .ws-lifecycle:disabled { cursor:default; opacity:.78; }
  .ws-calculated { margin:12px 0 2px; color:var(--text2); font-size:11.5px; }
  .ws-body { display: none; padding: 4px 16px 16px; border-top: 1px solid var(--border); }
  .ws-card.expanded .ws-body { display: block; }
  .ws-sub-label { font-family: var(--mono); font-size: 10.5px; color: var(--text3); text-transform: uppercase; letter-spacing: 0.5px; margin: 14px 0 8px; display: flex; align-items: center; justify-content: space-between; }
  .ws-scope { font-size: 13px; color: var(--text); line-height: 1.55; padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); outline: none; min-height: 56px; }
  .ws-scope:focus { border-color: var(--accent-dark); }
  .ws-scope:empty::before { content: "What's in scope for this project? Boundaries, deliverables, and what success looks like…"; color: var(--text3); font-style: italic; }
  .dark .ws-scope { background: var(--surface2); }
  .ws-assign-btn { font-family: var(--font); font-size: 11.5px; padding: 4px 10px; border: 1px solid var(--border); border-radius: 7px; background: var(--surface); color: var(--text); cursor: pointer; }
  .ws-assign-btn:hover { background: var(--surface2); }
  .ws-action-row { display: flex; align-items: center; gap: 10px; padding: 8px 4px; border-bottom: 1px solid var(--border); }
  .ws-action-row:last-child { border-bottom: none; }
  .ws-ar-id { font-family: var(--mono); font-size: 11px; color: var(--text3); min-width: 36px; flex-shrink: 0; }
  .ws-ar-title { font-size: 13px; color: var(--text); flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .ws-ar-status { font-size: 11px; color: var(--text2); flex-shrink: 0; }
  .ws-ar-prog { font-family: var(--mono); font-size: 11px; color: var(--text2); min-width: 40px; text-align: right; flex-shrink: 0; }
  .ws-ar-remove { background: none; border: none; color: var(--text3); cursor: pointer; padding: 2px 6px; border-radius: 4px; font-size: 14px; line-height: 1; flex-shrink: 0; }

  /* v8.7: WBS tree — indentation by level, derived-code chip, work-package badge,
     per-card tree controls, and the coverage strip (the 100% rule). */
  .ws-card.wbs-lvl2 { margin-left: 34px; }
  .ws-card.wbs-lvl3 { margin-left: 68px; }
  .wbs-code { font-family: var(--mono); font-size: 10px; font-weight: 600; color: var(--text3); background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; padding: 2px 7px; white-space: nowrap; min-width: 30px; text-align: center; flex-shrink: 0; }
  .ws-card.wbs-lvl1 > .ws-header .wbs-code { color: var(--text); border-color: var(--text3); }
  .wbs-wp { font-family: var(--mono); font-size: 8.5px; letter-spacing: .4px; text-transform: uppercase; color: var(--text2); background: var(--surface2); border: 1px solid var(--border); border-radius: 7px; padding: 1px 6px; white-space: nowrap; flex-shrink: 0; }
  .wbs-ctl { font-family: var(--font); font-size: 11px; padding: 3px 8px; border: 1px solid var(--border); border-radius: 7px; background: var(--surface); color: var(--text2); cursor: pointer; }
  .wbs-ctl:hover { color: var(--text); border-color: var(--text3); }
  .wbs-ctls { display: inline-flex; gap: 6px; align-items: center; }
  .wbs-toolbar { display:flex; justify-content:flex-end; align-items:center; min-height:0; margin:0 0 10px; }
  .wbs-toolbar:empty { display:none; }
  .wbs-order-move-slot { width:53px; min-width:53px; display:inline-flex; align-items:center;
                         justify-content:flex-end; flex:0 0 53px; margin-left:auto; }
  .wbs-order-move-slot:empty { display:none; }
  .wbs-order-moves { display:inline-flex; align-items:center; gap:3px; }
  .wbs-order-move { width:25px; height:25px; padding:0; border:1px solid var(--border);
                    border-radius:5px; background:var(--surface); color:var(--text2);
                    font:600 13px/1 var(--font); cursor:pointer; }
  .wbs-order-move:hover[aria-disabled="false"] { background:var(--surface2); color:var(--text); }
  .wbs-order-move[aria-disabled="true"] { opacity:.38; cursor:default; }
  .wbs-order-move:focus-visible, .wbs-reorder-toggle:focus-visible { outline:2px solid var(--accent-dark); outline-offset:2px; }
  /* v8.7.1: element delete is now the app-standard subtle × (was a text "Remove"
     button) — consistent with every other card delete and the assigned-action unlink. */
  .wbs-del { font-size: 15px; padding: 2px 7px; }
  .wbs-del:hover { color: var(--text); background: var(--surface2); }
  .wbs-cov { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; background: var(--surface2); border: 1px solid var(--border); border-radius: 9px; padding: 8px 12px; margin-bottom: 12px; font-size: 12px; color: var(--text2); }
  .wbs-cov-num { font-family: var(--mono); font-weight: 700; color: var(--text); }
  .wbs-cov-bar { flex: 1; min-width: 110px; height: 6px; border-radius: 3px; background: var(--border); overflow: hidden; }
  .wbs-cov-bar i { display: block; height: 100%; background: var(--accent-dark); }
  .wbs-cov-warn { color: var(--text); font-weight: 600; }
  .wbs-cov-ok { color: var(--text3); }
  .wbs-cov-chip { font-family: var(--mono); font-size: 10px; color: var(--text2); background: var(--surface); border: 1px dashed var(--border); border-radius: 8px; padding: 2px 7px; cursor: pointer; }
  .wbs-cov-chip:hover { color: var(--text); border-color: var(--text3); }
  .ws-ar-remove:hover { color: var(--high); background: var(--high-bg); }
  .ws-no-actions { font-size: 12.5px; color: var(--text3); font-style: italic; padding: 10px 4px; }
  .add-btn { margin-top: 10px; font-family: var(--font); font-size: 13px; padding: 7px 14px; border-radius: 7px; border: 1px solid var(--border); background: var(--surface); color: var(--text); cursor: pointer; }
  .add-btn:hover { background: var(--surface2); }
  .ws-empty { text-align: center; padding: 28px 16px; color: var(--text3); font-size: 13px; }
  @media (max-width:520px) {
    .ws-card.wbs-lvl2 { margin-left:18px; }
    .ws-card.wbs-lvl3 { margin-left:36px; }
    .ws-progress-wrap { flex:1 1 230px; }
    .ws-progress-bar { flex:1 1 54px; width:auto; min-width:42px; }
    .ws-lifecycle { max-width:118px; }
  }

  /* ── Action picker modal (Success Projects assignment) ───────────── */
  .ws-modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.4); display: none; align-items: center; justify-content: center; z-index: 200; }
  .ws-modal-overlay.open { display: flex; }
  .ws-modal { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 12px 40px rgba(0,0,0,0.25); width: 92%; max-width: 480px; max-height: 80vh; display: flex; flex-direction: column; }
  .ws-modal-head { padding: 16px 18px 12px; border-bottom: 1px solid var(--border); }
  .ws-modal-title { font-size: 14.5px; font-weight: 600; color: var(--text); }
  .ws-modal-sub { font-size: 11.5px; color: var(--text2); margin-top: 2px; }
  .ws-modal-search { margin: 12px 18px 0; }
  .ws-modal-search input { width: 100%; font-family: var(--font); font-size: 13px; padding: 7px 12px; border: 1px solid var(--border); border-radius: 7px; background: var(--surface); color: var(--text); outline: none; }
  /* v3.3 patch: open-only filter row below the search */
  .ws-modal-filter { margin: 8px 18px 0; }
  .ws-modal-filter-label { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--text2); cursor: pointer; user-select: none; }
  .ws-modal-filter-label input[type="checkbox"] { margin: 0; cursor: pointer; }
  .ws-modal-filter-label:hover { color: var(--text); }
  .ws-modal-filter-hint { color: var(--text3); font-size: 11.5px; }
  .ws-modal-search input:focus { border-color: var(--accent-dark); }
  .ws-modal-list { overflow-y: auto; padding: 8px 10px; flex: 1; }
  .ws-pick-row { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 7px; cursor: pointer; }
  .ws-pick-row:hover { background: var(--surface2); }
  .ws-pick-row.disabled { cursor: not-allowed; opacity: 0.55; }
  .ws-pick-row.disabled:hover { background: transparent; }
  .ws-pick-check { width: 16px; height: 16px; border: 1.5px solid var(--text3); border-radius: 4px; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; }
  .ws-pick-row.checked .ws-pick-check { background: var(--accent-dark); border-color: var(--accent-dark); }
  .ws-pick-check svg { width: 10px; height: 10px; stroke: #fff; stroke-width: 2.5; fill: none; display: none; }
  .dark .ws-pick-row.checked .ws-pick-check { background: var(--text); border-color: var(--text); }
  .dark .ws-pick-check svg { stroke: var(--bg); }
  .ws-pick-row.checked .ws-pick-check svg { display: block; }
  .ws-pick-id { font-family: var(--mono); font-size: 11px; color: var(--text3); min-width: 36px; flex-shrink: 0; }
  .ws-pick-title { font-size: 13px; color: var(--text); flex: 1; }
  .ws-pick-elsewhere { font-family: var(--mono); font-size: 10px; color: var(--text3); font-style: italic; flex-shrink: 0; }
  .ws-modal-foot { padding: 12px 18px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; }
  .ws-modal-done { font-family: var(--font); font-size: 13px; padding: 7px 18px; border-radius: 7px; border: none; background: var(--accent-dark); color: #fff; cursor: pointer; }
  .dark .ws-modal-done { background: var(--text); color: var(--bg); }
  .ws-modal-empty { padding: 24px 12px; text-align: center; color: var(--text3); font-size: 12.5px; }

  /* ── End v3.2 dashboard block ─────────────────────────────────────── */

  /* ═══════════════════════════════════════════════════════════════════════
     v3.3 — RISK REGISTER. Mirrors the Stakeholders pattern: cards on top,
     P×I matrix heatmap below. Each risk has a TYPE (threat | opportunity)
     and the matrix has a toggle to view either set with its own coloring.
     ═══════════════════════════════════════════════════════════════════════ */

  /* Opportunity teal palette (companion to --high/medium/low for threats).
     Used for opportunity score badges, type chips, and the matrix's
     "positive ramp" coloring (high P × high I = good = saturated teal). */
  :root {
    --opp:#0f7a8a; --opp-bg:#e6f4f6; --opp-border:#9ccfd6;
    /* v3.4: stakeholder category palette — a separate colour family from the
       red/amber/green severity scale, so a category never reads as a "status".
       Customer teal · Internal cool slate · Partner purple · Other warm stone. */
    --cat-customer:#0f7a8a; --cat-customer-bg:#e4f3f5; --cat-customer-bd:#a3d2d9;
    --cat-internal:#5f6b7a; --cat-internal-bg:#eceff2; --cat-internal-bd:#ccd3db;
    --cat-partner:#7a55b0;  --cat-partner-bg:#efe8f7;  --cat-partner-bd:#cbb9e8;
    --cat-other:#8a7d6b;    --cat-other-bg:#efece6;    --cat-other-bd:#d6cdbf;
  }
  .dark {
    --opp:#3fb6c4; --opp-bg:#16323a; --opp-border:#2b5a64;
    --cat-customer:#45b3c2; --cat-customer-bg:#15323a; --cat-customer-bd:#2c5b66;
    --cat-internal:#9aa6b4; --cat-internal-bg:#2a2f36; --cat-internal-bd:#454e59;
    --cat-partner:#b095e0;  --cat-partner-bg:#2c2543;  --cat-partner-bd:#4d4072;
    --cat-other:#bdae98;    --cat-other-bg:#332f2a;    --cat-other-bd:#564e42;
  }

  .risk-toolbar { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:16px; }
  .risk-search { flex:1; min-width:180px; position:relative; }
  .risk-search input { width:100%; font-family:var(--font); font-size:13px; padding:7px 12px 7px 30px; border:1px solid var(--border); border-radius:8px; background:var(--surface); color:var(--text); outline:none; }
  .risk-search input:focus { border-color:var(--accent-dark); }
  .risk-search svg { position:absolute; left:9px; top:50%; transform:translateY(-50%); width:14px; height:14px; stroke:var(--text3); fill:none; stroke-width:2; }
  .risk-tb-select { font-family:var(--font); font-size:12.5px; padding:7px 10px; border:1px solid var(--border); border-radius:8px; background:var(--surface); color:var(--text); cursor:pointer; outline:none; }
  /* v13.1 (A57): the second of the two dropdowns that killed the focus ring and put nothing
     back — a keyboard user tabbing through the RAID toolbar had no way to see where they
     were. .stk-sort-select already had this; these two were the outliers. :focus-visible so
     the ring appears for keyboard focus and not on a mouse click. */
  .risk-tb-select:focus-visible { border-color: var(--accent-dark); box-shadow: 0 0 0 2px var(--accent-dark); }
  /* ⚠ v15.3 (e): THIS BUTTON USED TO INVERT WITH THE THEME. It was
     `background:var(--accent-dark); color:#fff` with a `.dark` override to
     `background:var(--text); color:var(--bg)` — so light mode painted a near-black #3a3833
     slab and dark mode a near-white #e8e6e0 one, which is what he reported ("dark color on
     bright mode, and bright color on dark mode"). `--accent-dark` is the token defined once
     and deliberately never flipped, its fourth outing as a defect after v14.4, v15 and v15.2.
     ⚠ NOT A LEGIBILITY FAULT — both states measure far above threshold, which is exactly why
     `nothing_is_unreadable_in_either_theme` passes them and always would; the fault is design
     consistency, so a contrast sweep was never going to find it.
     ⚠ ALIGNED WITH THE TREATMENT HE CHOSE IN §v15 for `+ New project` / `+ New programme`
     (*"so its all aligned in design"*): surface ground, body ink, a `--text2` border. Both
     tokens flip, so the button now reads the same in both themes with no `.dark` rule at all
     — one definition, which is the point. Three buttons share this class (+ Add communication,
     + Add risk, + Add assumption). */
  .risk-tb-add { font-family:var(--font); font-size:13px; padding:7px 16px; border:1px solid var(--text2); border-radius:8px; background:var(--surface); color:var(--text); cursor:pointer; }
  .risk-tb-add:hover { background:var(--surface2); }

  .risk-list { display:flex; flex-direction:column; gap:10px; margin-bottom:34px; }
  .risk-card { background:var(--surface); border:1px solid var(--border); border-left-width:3px; border-radius:10px; padding:13px 15px; transition: border-color 0.15s; }
  .risk-card.type-threat { border-left-color:var(--high); }
  .risk-card.type-opportunity { border-left-color:var(--opp); }
  .rc-top { display:flex; align-items:center; gap:8px; margin-bottom:8px; flex-wrap:wrap; }
  .rc-type { font-family:var(--mono); font-size:10px; text-transform:uppercase; letter-spacing:.5px; padding:2px 8px; border-radius:10px; border:1px solid; cursor:pointer; user-select:none; }
  .type-threat .rc-type { color:var(--high); background:var(--high-bg); border-color:var(--high-border); }
  .type-opportunity .rc-type { color:var(--opp); background:var(--opp-bg); border-color:var(--opp-border); }
  .rc-cat { font-size:11.5px; color:var(--text2); background:var(--surface2); border:1px solid var(--border); border-radius:10px; padding:2px 9px; outline:none; cursor:pointer; }
  .rc-cat:focus { background:var(--surface); box-shadow:0 0 0 2px var(--accent-dark); }
  .rc-spacer { flex:1; }
  .rc-score { font-family:var(--mono); font-size:11px; font-weight:600; padding:2px 10px; border-radius:10px; border:1px solid; white-space:nowrap; }
  .rc-score.sev-high { color:var(--high); background:var(--high-bg); border-color:var(--high-border); }
  .rc-score.sev-med  { color:var(--medium); background:var(--medium-bg); border-color:var(--medium-border); }
  .rc-score.sev-low  { color:var(--low); background:var(--low-bg); border-color:var(--low-border); }
  .rc-score.opp-pos  { color:var(--opp); background:var(--opp-bg); border-color:var(--opp-border); }
  .rc-status { font-size:11px; color:var(--text2); border:1px solid var(--border); border-radius:10px; padding:2px 9px; white-space:nowrap; background:var(--surface); cursor:pointer; outline:none; }
  .rc-status:focus { box-shadow:0 0 0 2px var(--accent-dark); }
  .rc-status.st-occurred { color:var(--medium); border-color:var(--medium-border); background:var(--medium-bg); }
  .rc-status.st-closed { color:var(--text3); }
  .rc-card-actions { display:flex; align-items:center; gap:4px; }
  .rc-delete { background:none; border:none; color:var(--text3); cursor:pointer; padding:3px 6px; border-radius:4px; font-size:13px; line-height:1; }
  .rc-delete:hover { color:var(--high); background:var(--high-bg); }
  .rc-statement { font-size:13.5px; color:var(--text); line-height:1.45; margin-bottom:9px; padding:3px 5px; margin-left:-5px; margin-right:-5px; border-radius:5px; outline:none; }
  .rc-statement:focus { background:var(--surface2); box-shadow:0 0 0 2px var(--accent-dark); }
  .rc-statement:empty::before { content:'(no statement)'; color:var(--text3); font-style:italic; }
  .rc-meta { display:flex; flex-wrap:wrap; gap:14px; font-size:11.5px; color:var(--text2); font-family:var(--mono); align-items:center; }
  .rc-meta b { color:var(--text); font-weight:500; }
  .rc-meta-field { display:inline-flex; align-items:center; gap:4px; }
  .rc-meta-field select, .rc-meta-field input { font-family:var(--font); font-size:11.5px; padding:1px 4px; border:1px solid transparent; border-radius:4px; background:transparent; color:var(--text); outline:none; cursor:pointer; }
  .rc-meta-field input { font-family:var(--mono); font-size:11.5px; min-width:80px; }
  .rc-meta-field select:focus, .rc-meta-field input:focus { background:var(--surface2); border-color:var(--accent-dark); }
  .dark .rc-meta-field select { background-color: var(--surface); }
  .dark .rc-meta-field select:focus { background-color: var(--surface2); }
  .rc-notes { font-size:12px; color:var(--text2); margin-top:8px; padding:8px 5px 3px; border-top:1px dashed var(--border); line-height:1.45; outline:none; }
  .rc-notes:focus { background:var(--surface2); box-shadow:0 0 0 2px var(--accent-dark); border-radius:5px; }
  .rc-notes:empty::before { content:'Notes (optional)…'; color:var(--text3); font-style:italic; }

  /* ── v8.4: RAID sections (collapsible) ── */
  .raid-section { border:1px solid var(--border); border-radius:12px; background:var(--surface); margin-bottom:16px; overflow:hidden; }
  .raid-summary { cursor:pointer; list-style:none; padding:12px 16px; font-size:13px; font-weight:600; color:var(--text); display:flex; align-items:center; gap:10px; background:var(--surface2); user-select:none; }
  .raid-summary::-webkit-details-marker { display:none; }
  .raid-summary::before { content:'▸'; font-size:11px; color:var(--text3); transition:transform .12s; }
  details[open] > .raid-summary::before { transform:rotate(90deg); }
  .raid-count { font-family:var(--mono); font-size:11px; font-weight:500; color:var(--text3); }
  .raid-body { padding:14px 16px 16px; }
  /* ⚠ v15.3 (e): "+ Log issue" is DELIBERATELY LEFT AS IT RENDERS. Its amber fill is semantic
     — a problem that has already happened, in the app's own `--medium` language — and unlike
     `--accent-dark` that token DOES flip (#c87d1a light, #f4a942 dark), so it was never part
     of the defect. It only needs the two properties its sibling used to supply: the white ink
     (which came from `.risk-tb-add`'s old `color:#fff`) and a border matching its own fill, so
     the 1px border added above is invisible on it. Stated ONCE for both themes, so the `.dark`
     rule that used to restate the same two values is gone rather than left as a second
     definition to drift. */
  .risk-tb-issue { background:var(--medium); color:#fff; border-color:var(--medium); }

  /* register id pill on risk/issue cards */
  .rc-regid { font-family:var(--mono); font-size:10px; font-weight:600; color:var(--text3); background:var(--surface2); border:1px solid var(--border); border-radius:8px; padding:2px 7px; white-space:nowrap; }
  .rc-type-fixed { cursor:default; }

  /* issue-phase card accent + fields */
  .risk-card.is-issue { border-left-color:var(--high); }
  .risk-card.is-issue .rc-type { color:#fff; background:var(--high); border-color:var(--high); }
  .rc-history { font-size:11.5px; color:var(--text2); background:var(--surface2); border:1px solid var(--border); border-radius:8px; padding:6px 10px; margin-bottom:9px; line-height:1.5; }
  .rc-history-tag { font-family:var(--mono); font-size:9.5px; text-transform:uppercase; letter-spacing:.5px; color:var(--text3); border:1px solid var(--border); border-radius:6px; padding:1px 6px; margin-right:6px; }
  .rc-history strong { color:var(--text); font-weight:600; }
  .rc-sublabel { font-size:10.5px; text-transform:uppercase; letter-spacing:.4px; color:var(--text3); margin:9px 0 3px; }
  .rc-resolution { font-size:12.5px; color:var(--text); line-height:1.45; padding:6px 8px; border:1px solid var(--border); border-radius:6px; background:var(--surface2); outline:none; min-height:20px; }
  .rc-resolution:focus { background:var(--surface); box-shadow:0 0 0 2px var(--accent-dark); }

  /* contenteditable placeholders (assumptions + resolution) */
  [data-placeholder]:empty::before { content:attr(data-placeholder); color:var(--text3); font-style:italic; }

  /* ── v8.4: Assumptions cards ── */
  .assumption-card { background:var(--surface); border:1px solid var(--border); border-left-width:3px; border-left-color:var(--medium); border-radius:10px; padding:12px 14px; margin-bottom:10px; }
  .assumption-card.val-validated { border-left-color:var(--opp); }
  .assumption-card.val-invalidated { border-left-color:var(--high); }
  .as-top { display:flex; align-items:center; gap:10px; margin-bottom:8px; flex-wrap:wrap; }
  .as-regid { font-family:var(--mono); font-size:10px; font-weight:600; color:var(--text3); background:var(--surface2); border:1px solid var(--border); border-radius:8px; padding:2px 7px; }
  .as-spacer { flex:1; }
  .as-field { font-size:11px; color:var(--text2); display:inline-flex; align-items:center; gap:5px; }
  .as-field select { font-family:var(--font); font-size:11.5px; padding:2px 6px; border:1px solid var(--border); border-radius:8px; background:var(--surface); color:var(--text); outline:none; cursor:pointer; }
  .as-field select:focus { box-shadow:0 0 0 2px var(--accent-dark); }

  /* v8.6: Communications plan cards (People · third section). The card frame reuses the
     assumption-card / as-* / rc-* styles wholesale — only the audience chip row is new. */
  .comm-card { border-left-color:var(--border); }
  .comm-aud-row { display:flex; align-items:center; gap:6px; flex-wrap:wrap; margin-bottom:9px; font-size:11px; color:var(--text2); }
  .comm-aud-lbl { font-family:var(--mono); color:var(--text2); }
  .comm-aud { display:inline-flex; align-items:center; gap:5px; font-size:11px; color:var(--text2); background:var(--surface2); border:1px solid var(--border); border-radius:999px; padding:2px 4px 2px 9px; white-space:nowrap; }
  .comm-aud button { background:none; border:none; color:var(--text3); cursor:pointer; padding:0 3px; font-size:12px; line-height:1; border-radius:50%; }
  .comm-aud button:hover { color:var(--text); }
  .comm-aud-add { font-family:var(--font); font-size:11px; padding:2px 6px; border:1px dashed var(--border); border-radius:999px; background:transparent; color:var(--text3); outline:none; cursor:pointer; max-width:160px; }
  .comm-aud-add:focus { background:var(--surface2); border-color:var(--accent-dark); color:var(--text); }
  .dark .comm-aud-add { background-color:transparent; }
  .dark .comm-aud-add:focus { background-color:var(--surface2); }

  /* v8.6: overview (landing page) meta — the date + version, far right of ov-head. (v14 W6: the
     label reads "Last saved <date>"; it was "As of" until then, and the semantics did not change.)
     Reuses .header-meta typography; this only stops it shrinking in the flex row. */
  .ov-meta { flex:0 0 auto; }

  /* ── v8.8: KPIs — Governance definition cards + the Overview dot echo ──
     The pill reuses .rag-pill classes (kpi-pill only resizes it). Definition slots
     are contenteditable free text with the app-standard :empty placeholders. */
  .kpi-card { background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:12px 14px; margin-bottom:10px; }
  .kpi-head { display:flex; align-items:center; gap:10px; margin-bottom:8px; }
  .kpi-label { font-size:13px; font-weight:700; color:var(--text); min-width:76px; }
  .kpi-pill { min-width:72px; padding:3px 12px; font-size:11.5px; }
  .kpi-def { display:grid; grid-template-columns:auto 1fr; gap:4px 12px; margin-bottom:8px; align-items:baseline; }
  .kpi-k { font-family:var(--mono); font-size:9.5px; color:var(--text3); text-transform:uppercase; letter-spacing:0.5px; white-space:nowrap; padding-top:1px; }
  .kpi-v { font-size:12.5px; color:var(--text); }
  .kpi-field { outline:none; padding:1px 5px; margin:-1px -5px; border-radius:4px; display:inline-block; min-width:36px; }
  .kpi-field:focus { background:var(--surface2); box-shadow:0 0 0 2px var(--accent-dark); }
  .kpi-field:empty::before { content:attr(data-ph); color:var(--text3); font-style:italic; }
  .kpi-bt-arrow { color:var(--text3); margin:0 6px; }
  .kpi-now { color:var(--text3); margin-left:6px; }
  .kpi-rationale { font-size:12.5px; color:var(--text2); outline:none; padding:2px 5px; margin:-2px -5px; border-radius:4px; }
  .kpi-rationale:focus { background:var(--surface2); box-shadow:0 0 0 2px var(--accent-dark); }
  .kpi-rationale:empty::before { content:'Add a one-line rationale…'; color:var(--text3); font-style:italic; }
  .kpi-hint { font-size:10.5px; color:var(--text3); font-style:italic; margin-top:6px; }
  /* Overview echo: five read-only dots — display-only by hard design constraint
     (the single writable home is Governance ▸ KPIs); the row is a click-through. */
  .kpi-dot-row { display:flex; align-items:center; gap:16px; flex-wrap:wrap; padding:10px 4px 0 4px; }
  .kpi-dot-item { display:inline-flex; align-items:center; gap:6px; cursor:pointer; }
  /* v10.0: + display:inline-block — a bare dot in a table cell (the heatmap) is a plain
     inline span whose width/height are IGNORED (it painted 0×0; caught by eyeballing the
     screenshot while the class-based check was green — the v8.9 lesson's sibling). Flex
     children (the v8.8 dot rows) blockify anyway, so they are unaffected. */
  .kpi-dot { display:inline-block; width:10px; height:10px; border-radius:50%; flex-shrink:0; background:var(--text3); }
  .kpi-dot.kd-green { background:var(--low); }
  .kpi-dot.kd-amber { background:var(--medium); }
  .kpi-dot.kd-red { background:var(--high); }
  .kpi-dot-word { font-size:11px; color:var(--text2); }
  .kpi-dot-item:hover .kpi-dot-word { color:var(--text); }
  .kpi-dot-link { margin-left:auto; font-size:11px; font-family:var(--font); color:var(--text2); background:none; border:none; border-bottom:1px dotted var(--text3); cursor:pointer; padding:0; }
  .kpi-dot-link:hover { color:var(--text); border-bottom-color:var(--text); }

  /* ── v8.4: Dependencies (surfaced, read-only) ── */
  .dependency-item { background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:10px 14px; margin-bottom:8px; }
  .dep-head { font-size:12.5px; color:var(--text); font-weight:600; margin-bottom:4px; }
  .dep-sub { font-size:12px; color:var(--text2); display:flex; flex-wrap:wrap; gap:6px; align-items:center; }
  .dep-arrow { font-size:11px; color:var(--text3); }
  .dep-chip { font-family:var(--mono); font-size:11px; color:var(--text); background:var(--surface2); border:1px solid var(--border); border-radius:8px; padding:2px 8px; }

  /* ── v8.4: RACI matrix ── */
  /* v13.1 (U07): .raci-intro-title / .raci-intro-sub removed — never emitted. */
  .raci-matrix-wrap { overflow-x:auto; border:1px solid var(--border); border-radius:12px; }
  .raci-table { border-collapse:collapse; width:100%; font-size:12.5px; }
  .raci-table th, .raci-table td { border:1px solid var(--border); }
  .raci-corner { background:var(--surface2); color:var(--text3); font-size:11px; font-weight:500; text-align:left; padding:8px 12px; white-space:nowrap; }
  .raci-corner-slash { color:var(--border); margin:0 3px; }
  .raci-colh { background:var(--surface2); padding:8px 10px; text-align:center; font-weight:600; color:var(--text); vertical-align:bottom; }
  .raci-colh-name { display:inline-block; white-space:nowrap; }
  .raci-rowh { background:var(--surface); padding:8px 12px; text-align:left; font-weight:500; color:var(--text); white-space:nowrap; position:sticky; left:0; }
  .raci-rowh-noa { color:var(--high); }
  .raci-rowh-noa::after { content:' ⚠'; font-size:11px; }
  .raci-cell { text-align:center; padding:8px 10px; cursor:pointer; font-family:var(--mono); font-weight:700; color:var(--text); min-width:38px; user-select:none; transition:background .1s; }
  .raci-cell:hover { background:var(--surface2); }
  .raci-cell.raci-R { background:var(--opp-bg); color:var(--opp); }
  .raci-cell.raci-A { background:var(--high-bg); color:var(--high); }
  .raci-cell.raci-C { background:var(--medium-bg); color:var(--medium); }
  .raci-cell.raci-I { background:var(--low-bg); color:var(--low); }

  .risk-empty { padding:36px 18px; text-align:center; color:var(--text3); font-size:13.5px; background:var(--surface); border:1px dashed var(--border); border-radius:10px; margin-bottom:34px; }
  .risk-empty-filtered { padding:24px 18px; text-align:center; color:var(--text3); font-size:13px; font-style:italic; }

  /* ── Matrix ────────────────────────────────────────────────────────── */
  .risk-matrix-title { font-size:15px; font-weight:600; margin-bottom:3px; color:var(--text); }
  .risk-matrix-sub { font-size:12px; color:var(--text2); margin-bottom:14px; }
  .risk-matrix-toggle { display:inline-flex; border:1px solid var(--border); border-radius:8px; overflow:hidden; margin-bottom:16px; }
  .risk-matrix-toggle button { font-family:var(--font); font-size:12.5px; padding:6px 16px; border:none; background:var(--surface); color:var(--text2); cursor:pointer; }
  .risk-matrix-toggle button.active { background:var(--accent-dark); color:#fff; }
  .dark .risk-matrix-toggle button.active { background:var(--text); color:var(--bg); }
  .risk-matrix-card { background:var(--surface); border:1px solid var(--border); border-radius:12px; padding:20px 22px; }
  .risk-matrix-layout { display:grid; grid-template-columns:22px 34px 1fr 1fr 1fr; grid-template-rows:1fr 1fr 1fr 22px; gap:6px; height: 380px; }
  .rm-ytitle { grid-row:1 / 4; grid-column:1; writing-mode:vertical-rl; transform:rotate(180deg); text-align:center; font-family:var(--mono); font-size:10px; text-transform:uppercase; letter-spacing:1px; color:var(--text3); align-self:center; }
  .rm-ylabel { grid-column:2; font-family:var(--mono); font-size:10px; color:var(--text3); display:flex; align-items:center; justify-content:flex-end; padding-right:2px; }
  .rm-cell { border-radius:8px; min-height:62px; padding:6px; display:flex; flex-wrap:wrap; gap:4px; align-content:flex-start; border:1px solid transparent; position:relative; }
  .rm-cell .rm-cellscore { position:absolute; right:5px; bottom:3px; font-family:var(--mono); font-size:9px; color:rgba(0,0,0,.32); }
  .dark .rm-cell .rm-cellscore { color:rgba(255,255,255,.3); }
  /* threat severity palette */
  .rm-cell.sev-high { background:var(--high-bg); border-color:var(--high-border); }
  .rm-cell.sev-med  { background:var(--medium-bg); border-color:var(--medium-border); }
  .rm-cell.sev-low  { background:var(--low-bg); border-color:var(--low-border); }
  /* opportunity positive palette (intensity = potential) */
  .rm-cell.opp-high { background:var(--opp); border-color:var(--opp); }
  .rm-cell.opp-med  { background:var(--opp-bg); border-color:var(--opp-border); }
  .rm-cell.opp-low  { background:var(--surface2); border-color:var(--border); }
  .rm-xlabel { font-family:var(--mono); font-size:10px; color:var(--text3); text-align:center; display:flex; align-items:flex-start; justify-content:center; padding-top:2px; }
  .rm-xtitle { grid-column:3 / 6; text-align:center; font-family:var(--mono); font-size:10px; text-transform:uppercase; letter-spacing:1px; color:var(--text3); padding-top:4px; }
  /* ⚠⚠ v16.7 W4 (P4-F1): 22x22 WITH `white-space:normal` COULD NOT HOLD ITS OWN LABEL.
     Found by looking at a screenshot with 273 checks green. `R-001` needs ~30px at this face, so
     it wrapped to two lines and the second SPILLED OUTSIDE THE CIRCLE onto the cell (measured:
     scrollHeight 24 against clientHeight 22). Every standard id is five characters, so this was
     not an edge case — it rendered that way EVERY time, in both themes. Nothing measures a label
     against its container, which is why no check saw it; §v16.1's `+N more` badge was the same
     class and was also caught by eye.
     The fix keeps the id readable rather than truncating it: a PILL that grows to its text, with
     a min-width so a short label still reads as a dot, and nowrap so it can never wrap again. */
  .rm-dot { min-width:22px; height:22px; padding:0 5px; border-radius:11px; white-space:nowrap; display:inline-flex; align-items:center; justify-content:center; font-family:var(--mono); font-size:10px; font-weight:600; color:#fff; cursor:default; }
  .rm-dot.threat { background:var(--high); }
  .rm-dot.opportunity { background:var(--opp); }
  .rm-cell.opp-high .rm-dot.opportunity { background:#fff; color:var(--opp); }

  .risk-matrix-legend { display:flex; gap:16px; flex-wrap:wrap; margin-top:16px; font-size:11px; color:var(--text2); }
  .rml-item { display:flex; align-items:center; gap:6px; }
  .rml-sw { width:12px; height:12px; border-radius:3px; border:1px solid var(--border); }

  /* ── Add-risk modal — reuses .modal-overlay/.modal pattern from add-action ── */
  .risk-modal-grid { display:grid; grid-template-columns: 1fr 1fr; gap:14px 12px; }
  .risk-modal-grid .full { grid-column: 1 / -1; }

  /* ── Dashboard "Key risks" — v3.3 opportunity-aware coloring ───────── */
  /* Add a new row class for opportunities; reuses .kr-* layout from v3.2.
     The v3.2 .kr-dot.lvl-* and .kr-score.lvl-* still apply to threats.
     For opportunities we use the .opp variant via .kr-dot.opp / .kr-score.opp. */
  .kr-dot.opp-on-dashboard { background:var(--opp); }
  .kr-score.opp-on-dashboard { background:var(--opp-bg); color:var(--opp); border:1px solid var(--opp-border); }
  /* Type chip in front of the dashboard key-risks rows */
  .kr-type-chip { font-family:var(--mono); font-size:9.5px; text-transform:uppercase; letter-spacing:.5px; padding:1px 6px; border-radius:8px; border:1px solid; flex-shrink:0; }
  .kr-type-chip.threat { color:var(--high); background:var(--high-bg); border-color:var(--high-border); }
  .kr-type-chip.opportunity { color:var(--opp); background:var(--opp-bg); border-color:var(--opp-border); }

  /* ── End v3.3 risk register block ──────────────────────────────────── */

  @media (max-width: 600px) { header, main { padding-left: 14px; padding-right: 14px; } .controls { padding-left: 14px; padding-right: 14px; } }
  /* ── v5.0: Programme Management Plan overview + breadcrumb navigation ──────── */
  #overviewView { display: none; }
  body.view-overview #overviewView { display: block; }
  body.view-overview #projectView { display: none; }
  /* v6: Focus — third top-level view, peer to overview */
  #focusView { display: none; }
  body.view-focus #focusView { display: block; }
  body.view-focus #projectView { display: none; }
  body.view-focus #overviewView { display: none; }
  body.view-overview #focusView { display: none; }
  /* ── v10.5 (W2): the PORTFOLIO — a fourth top-level view, one level ABOVE the
     programme. Same idiom as Focus: a peer div toggled by a body class. The landing
     bar stays (logo + theme toggle) but its Projects|Focus switch and Save are hidden,
     because both are scoped to a programme and there is no open programme up here. */
  #portfolioView { display: none; }
  body.view-portfolio #portfolioView { display: block; }
  body.view-portfolio #projectView { display: none; }
  body.view-portfolio #overviewView { display: none; }
  body.view-portfolio #focusView { display: none; }
  body.view-portfolio #landingBar { display: block; }
  /* v12.1 (W3): Save is VISIBLE on the portfolio. The v10.5 rule that hid it ("Save is
     programme-scoped, and no programme is open up here") died with v11's one-file model,
     and W1 makes it untenable — archiving or deleting a programme dirties the file from
     this very view. The Projects|Focus switch stays hidden: those ARE programme-scoped. */
  body.view-portfolio #landingBar .ls-seg { display: none; }
  /* v17.0 W1: one location rail serves programme and project.  Portfolio and Focus are
     peer destinations rather than locations inside that trail, so they hide the rail. */
  body.view-focus .crumbbar { display: none; }
  body.view-portfolio #crumbProgrammeSlot, body.view-portfolio #crumbProgrammeSep,
  body.view-portfolio #crumbProjectSlot, body.view-portfolio #crumbProjectSep { visibility: hidden; }

  /* ── v11.1 (W2): the routing strip ─────────────────────────────────────
     Shown on programme / project / Focus — the levels that do NOT own the data file —
     and never on the portfolio. Gated by a CLASS, deliberately NOT the hidden
     attribute: an author `display` beats the UA's [hidden] rule (the v8.9 lesson), so
     a hidden-based strip would paint permanently. Colours match the existing
     .ov-reconnect / .ov-mismatch banners so the family reads as one. */
  #fileAlertStrip { display: none; }
  #fileAlertStrip.has-alert { display: block; max-width: 1120px; margin: 0 auto; padding: 16px 24px 0; }
  body.view-portfolio #fileAlertStrip { display: none; }
  .fa-strip { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 0 0 12px; padding: 10px 15px; border: 1px solid; border-radius: 10px; font-size: 12.5px; }
  .fa-strip .fa-msg { flex: 1 1 240px; }
  .fa-strip .fa-go { flex: none; }
  .fa-strip.fa-red { border-color: var(--high-border, #e3a0a0); background: var(--high-bg, #fbeaea); }
  .fa-strip.fa-amber { border-color: #f0c36d; background: #fff7e6; }
  .dark .fa-strip.fa-amber { border-color: #7a5b1e; background: #2a2310; }
  /* v11.1 (W3 / ◆1): the blocked Save state — the fifth, after idle/dirty/saving/saved.
     Visible on EVERY level by construction, the button being in the header everywhere.
     It must not look clickable-and-fine; it must still BE clickable, because a blocked
     Save explains itself rather than doing nothing. */
  .save-btn.blocked { opacity: 0.5; box-shadow: inset 0 0 0 1.5px var(--high, #b3261e); }

  /* v14 (W8): Import refusing a teammate's part — amber, because it is a "not this file" answer
     rather than a failure. See the guard in onImportFileChosen for why it is a correctness issue. */
  .import-refused { background: var(--medium-bg); border: 1px solid var(--medium-border);
                    border-radius: 7px; padding: 9px 11px; font-size: 12px; line-height: 1.55;
                    color: var(--text); margin-top: 10px; }
  .import-refused code { font-size: 11px; }

  .pf-wrap { max-width: 1120px; margin: 0 auto; padding: 34px 24px 64px; }
  /* v14.4 (b): the header is TWO rows — row 1 title + meta (the two things that never change
     with the pane), row 2 the pane switch LEFT-ANCHORED at the container edge with the action
     buttons right-aligned after it. The switch's anchor cannot move when its neighbours appear
     and disappear, which is what stopped it jumping between panes; before this it sat inside a
     single right-aligned toolbar, so its position depended on how many buttons rendered beside
     it — four on Programmes, none on Activity. */
  .pf-head { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 10px; }
  .pf-head .ov-meta { margin-left: auto; }
  .pf-bar { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; flex-wrap: wrap; }
  .pf-actions { margin-left: auto; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
  /* v17.5 P4: display order is a compact personal preference. The status sentence stays quiet;
     it explains persistence without competing with the portfolio's data-source state. */
  .list-order { display: inline-flex; align-items: center; gap: 7px; flex-wrap: wrap;
                color: var(--text2); font-size: 11.5px; }
  .list-order label { display: inline-flex; align-items: center; gap: 5px; font-weight: 600; }
  .list-order-select { font: inherit; font-size: 12px; color: var(--text); background: var(--surface);
                       border: 1px solid var(--border); border-radius: 6px; padding: 5px 24px 5px 7px; }
  .list-order-select:focus-visible, .list-order-toggle:focus-visible, .list-order-move:focus-visible {
    outline: 2px solid var(--accent, var(--text3)); outline-offset: 2px;
  }
  .list-order-toggle { white-space: nowrap; }
  .list-order-search-hint { color: var(--text2); font-weight: 500; }
  .list-order-move-slot { width: 53px; min-width: 53px; display: inline-flex;
                          align-items: center; justify-content: flex-end; flex: 0 0 53px; }
  .list-order-moves { display: inline-flex; align-items: center; gap: 3px; flex: 0 0 auto; }
  .list-order-move { width: 25px; height: 25px; padding: 0; border: 1px solid var(--border);
                     border-radius: 5px; background: var(--surface); color: var(--text2);
                     font: 600 13px/1 var(--font); cursor: pointer; }
  .list-order-move:hover[aria-disabled="false"] { background: var(--surface2); color: var(--text); }
  .list-order-move[aria-disabled="true"] { opacity: .38; cursor: default; }
  /* v14.4 (b): slimmer buttons, SCOPED to this bar — .ov-btn is a shared class on other
     surfaces and stays untouched there. white-space keeps any label on ONE line ("Change
     folder" wrapped onto two in his screenshot); when the window is narrow the ROW wraps
     as a whole instead of squeezing anything. */
  .pf-bar .ov-btn { font-size: 12px; padding: 6px 11px; white-space: nowrap; }
  /* ⚠ v15: THIS RULE SHIPPED BROKEN IN v14.4 AND THIS IS THE FIX. Lightening the button for
     light mode, it set `color: var(--accent-dark)` — the ONE token that does not flip — against
     `var(--surface)`, which does. Measured: 11.71:1 in light, **1.35:1 in dark**, where v14.3's
     filled slab had been 11.71:1 in both. So the release that fixed three instances of this
     pairing introduced a fourth, in the very rule it added, and the check written to catch the
     class only measured three NAMED selectors. Both tokens here flip, so both themes hold:
     light = near-black on white, dark = near-white on near-black; the weight and the border
     carry the emphasis instead of a fill. */
  /* ⚠ v15: ONE rule, TWO hosts — his instruction was *“make that new project button also with
     bright background in bright mode so its all aligned in design”*, and writing a second
     `.ov-toolbar .ov-btn-primary` block would be the second-definition class this repo keeps
     paying for. A comma selector is one definition serving both.
     ⚠ SCOPED ON PURPOSE, and the census is why: of the eight `.ov-btn-primary` sites, SIX are
     banner recovery actions (“Save in the right place”, “Reconnect data file”, “Reload now”…)
     that sit inside amber and red banners where a filled slab is the right emphasis. Only the
     two “+ New …” toolbar buttons are being aligned. */
  .pf-bar .ov-btn-primary,
  .ov-toolbar .ov-btn-primary { background: var(--surface); color: var(--text);
                                border-color: var(--text2); font-weight: 600; }
  .pf-bar .ov-btn-primary:hover,
  .ov-toolbar .ov-btn-primary:hover { background: var(--surface2); filter: none; }
  .pf-list { border: 1px solid var(--border); border-radius: 10px; overflow: hidden; background: var(--surface); }
  .pf-row { display: flex; align-items: center; gap: 13px; width: 100%; padding: 13px 16px; border: 0; border-bottom: 1px solid var(--border); background: none; font: inherit; text-align: left; cursor: pointer; }
  .pf-row:last-child { border-bottom: 0; }
  .pf-row:hover { background: var(--surface2); }
  .pf-programme-group + .pf-programme-group { border-top:1px solid var(--border); }
  .pf-programme-group > .pf-row { border-bottom:0; }
  .pf-disclosure, .pf-disclosure-slot { width:24px; height:28px; flex:0 0 24px; }
  .pf-disclosure { display:inline-flex; align-items:center; justify-content:center; border:1px solid transparent; border-radius:5px; background:transparent; color:var(--text2); font:inherit; font-size:22px; padding:0; cursor:pointer; }
  .pf-disclosure:hover { background:var(--surface); border-color:var(--border); }
  .pf-disclosure:focus-visible { outline:2px solid var(--accent); outline-offset:1px; }
  .pf-children .pf-project-hit { padding-left:78px; }
  /* v17.2 W1: portfolio search results stay inside the existing programme list instead of
     introducing a second search surface. A project hit is visibly subordinate to its parent;
     archived/unavailable hits dim only their content so their menu remains independently
     composited for W2's archived-menu correction. */
  .pf-search-group + .pf-search-group { border-top: 1px solid var(--border); }
  .pf-search-group > .pf-row { border-bottom: 0; }
  .pf-project-hit { display: flex; align-items: center; gap: 10px; width: 100%; box-sizing: border-box;
    padding: 9px 16px 9px 50px; border: 0; border-top: 1px solid var(--border); background: var(--surface2);
    color: var(--text); font: inherit; text-align: left; }
  .pf-project-hit[role="button"] { cursor: pointer; }
  .pf-project-hit[role="button"]:hover { background: var(--bg); }
  .pf-project-hit[role="button"]:focus-visible { outline: 2px solid var(--accent, var(--text3)); outline-offset: -2px; }
  .pf-project-hit-mark { color: var(--text3); font-size: 14px; flex: 0 0 auto; }
  .pf-project-hit-main { min-width: 0; flex: 1 1 auto; }
  .pf-project-hit-name { font-size: 13.5px; font-weight: 600; overflow-wrap: anywhere; }
  .pf-project-hit-meta { color: var(--text3); font-size: 11.5px; margin-top: 2px; }
  .pf-project-hit-arch .pf-project-hit-main,
  .pf-project-hit-arch .pf-project-hit-mark { opacity: 0.58; }
  .pf-search-archive-note { display: flex; align-items: center; padding: 3px 2px 10px; }
  .pf-search-archive-toggle { border: 0; background: none; color: var(--text2); font: inherit;
    font-size: 12px; padding: 2px 0; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
  .pf-search-archive-toggle:hover { color: var(--text); }
  .pf-dot { width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto; background: var(--surface2); border: 1px solid var(--border); }
  .pf-dot.rag-red   { background: var(--high);   border-color: var(--high-border); }
  .pf-dot.rag-amber { background: var(--medium); border-color: var(--medium-border); }
  .pf-dot.rag-green { background: var(--low);    border-color: var(--low-border); }
  .pf-main { min-width: 0; }
  .pf-name { font-size: 14.5px; font-weight: 600; color: var(--text); }
  .pf-name.pf-unnamed { font-weight: 500; font-style: italic; color: var(--text2); }
  .pf-file { font-size: 11.5px; color: var(--text3); margin-top: 2px; word-break: break-all; }
  .pf-meta { margin-left: auto; display: flex; align-items: center; gap: 16px; font-size: 12.5px; color: var(--text2); white-space: nowrap; flex: 0 0 auto; }
  /* Keep the same right-side controls on narrow screens, with the programme count on
     its own line so it cannot squeeze or overprint the name during Reorder. */
  @media (max-width: 600px) {
    .pf-row { display: grid; grid-template-columns: 11px minmax(0, 1fr) 24px; gap: 4px 10px; }
    .pf-row:has(.list-order-move-slot) { grid-template-columns: 11px minmax(0, 1fr) 53px 24px; }
    .pf-row > .pf-dot { grid-column: 1; grid-row: 1; }
    .pf-row > .pf-main { grid-column: 2; grid-row: 1; overflow-wrap: anywhere; }
    .pf-row > .pf-meta { display: contents; white-space: normal; }
    .pf-row > .pf-meta > span:first-child { grid-column: 2 / -1; grid-row: 2; }
    .pf-row > .pf-meta > .list-order-move-slot { grid-column: 3; grid-row: 1; }
    .pf-row > .pf-meta > .pm-menu-wrap { grid-column: -2 / -1; grid-row: 1; }
    .pf-row.pf-with-disclosure { grid-template-columns:24px 11px minmax(0,1fr) 24px; }
    .pf-row.pf-with-disclosure:has(.list-order-move-slot) { grid-template-columns:24px 11px minmax(0,1fr) 53px 24px; }
    .pf-with-disclosure > .pf-disclosure, .pf-with-disclosure > .pf-disclosure-slot { grid-column:1; grid-row:1; }
    .pf-row.pf-with-disclosure > .pf-dot { grid-column:2; }
    .pf-row.pf-with-disclosure > .pf-main { grid-column:3; }
    .pf-row.pf-with-disclosure > .pf-meta > span:first-child { grid-column:3 / -1; }
    .pf-row.pf-with-disclosure > .pf-meta > .list-order-move-slot { grid-column:4; }
    .pf-children .pf-project-hit { padding-left:66px; }
  }
  /* v16.5 (d): the quotable id. Tabular figures so a column of them aligns, and a MUTED tone —
     it is a reference, not the thing you read first; the name still leads. */
  .disp-id { font-variant-numeric: tabular-nums; font-size: 11.5px; font-weight: 600; color: var(--text3);
             letter-spacing: 0.02em; margin-right: 8px; }
  /* v16.5 (f): the lifecycle badge. ⚠ Deliberately NOT the RAG palette - RAG is health and this
     is where-in-its-life, and colouring them alike is exactly how two orthogonal things collapse
     into one in a reader's head. Neutral by default; only the two that stop work are tinted. */
  .lc-badge { font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
              border: 1px solid var(--border); background: var(--surface2); color: var(--text2);
              border-radius: 9px; padding: 1px 7px; margin-left: 8px; white-space: nowrap; }
  /* v17.0 W2: only the PROGRAMME lifecycle's In progress state is purple. These are
     deliberate theme pairs rather than a shared accent token: #5b21b6 on #ede9fe is
     7.57:1; #d8c7ff on #2d2640 is 9.25:1. Project/action status badges are separate
     classes and retain their existing blue/amber paint. */
  .lc-badge.lc-in-progress { border-color: #c4b5fd; background: #ede9fe; color: #5b21b6; }
  .dark .lc-badge.lc-in-progress { border-color: #5b4b86; background: #2d2640; color: #d8c7ff; }
  .lc-badge.lc-on-hold   { border-color: var(--medium-border); background: var(--medium-bg); color: var(--medium); }
  .lc-badge.lc-cancelled { border-color: var(--high-border);   background: var(--high-bg);   color: var(--high); }
  .lc-badge.lc-completed { border-color: var(--low-border);    background: var(--low-bg);    color: var(--low); }
  /* v16.5 (f): the menu's section heading - a label, never a button, so it cannot be clicked. */
  /* v16.5 (c): the header search. ⚠ A FIXED WIDTH, deliberately: a field that grows with its
     content would move the theme toggle as you type, which is the exact thing he asked to avoid.
     flex:0 0 auto for the same reason. */
  .hdr-search { position: relative; flex: 0 0 auto; margin-right: 10px; }
  .hdr-search input { width: 190px; box-sizing: border-box; font: inherit; font-size: 12.5px;
    padding: 5px 26px 5px 10px; border: 1px solid var(--border); border-radius: 7px;
    background: var(--surface); color: var(--text); }
  .hdr-search input::placeholder { color: var(--text3); }
  .hdr-search input:focus { outline: none; border-color: var(--accent, var(--text3)); }
  .hdr-search input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
  .pf-search-note { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text2);
    padding: 4px 2px 8px; }
  .pf-search-clear { font: inherit; font-size: 12px; border: 1px solid var(--border); background: var(--surface2);
    color: var(--text2); border-radius: 6px; padding: 1px 8px; cursor: pointer; }
  .proj-menu-head { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
                    color: var(--text3); padding: 6px 10px 3px; }
  /* ── v16.2: THE "OPEN NOW" PILL IS GONE ────────────────────────────────────────────
     It marked whichever programme was currently open. He reported it as confusing and asked
     how to switch it off — which is the tell: it read as a CONTROL, not a status. The words
     came from the v11.1/v12.3 portfolio mockups, where "Open now ›" sat on EVERY row with a
     chevron as an AFFORDANCE ("open this one"); the shipped code kept the wording and
     repurposed it as a STATE badge on one row. Imperative words, descriptive meaning.
     ⚠ RULE WORTH KEEPING: a state badge must be worded as a state ("current", "you are
     here"), never as an instruction.
     ⚠ REMOVED, NOT HIDDEN. `display:none` would have left this rule, the node and the
     `here` computation as deliberate dead code — the thing residual_dead_code_is_gone
     exists to prevent. The rule, the span and the variable all went together.
     ⚠ THE RESUME IS UNTOUCHED, and that is the point: this pill only REPORTED
     `activeProgrammeId`. _saveLastProgramme / _loadLastProgramme /
     _restoreLastProgrammeAndView still remember the programme you saved from and take you
     back there on the next launch. Removing the label never touched the behaviour.
     ⚠ This comment names the old class deliberately, as an epitaph. Its checks are DOM-
     based for exactly that reason — a source grep cannot tell live code from a headstone
     (v13.1 A56 / v15.3 both learned this the hard way). */
  /* v12.1 (W1): archived programmes — dimmed rows under the Show-archived toggle, the
     project-table idiom one level up. An archived programme cannot be OPENED, so its row
     carries no select handler and no pointer cursor. */
  /* v17.2 W2: opacity belongs to the archived CONTENT, never the row. The fixed manage
     menu is a descendant of .pf-meta; putting opacity on .pf-row composites that popup too,
     so its already-solid --surface background becomes translucent. Keep the button subdued
     independently while the popup itself has an all-1 opacity chain. */
  .pf-row.pf-arch { cursor: default; }
  .pf-row.pf-arch > .pf-dot,
  .pf-row.pf-arch > .pf-main,
  .pf-row.pf-arch > .pf-meta > span,
  .pf-row.pf-arch > .pf-meta > .pm-menu-wrap > .pm-menu-btn { opacity: 0.55; }
  .pf-row.pf-arch:hover { background: none; }
  .pf-row.pf-arch .pf-name::after { content: " · archived"; font-weight: 400; color: var(--text3); font-size: 11px; }
  /* ══ v14.3 (a): the Activity view ══════════════════════════════════════════════════════ */
  /* v14.4 (b): flex-shrink:0 is the never-clipped guarantee — overflow:hidden exists for the
     rounded corners, and on the shipped v14.3 a squeezed row let flex compress the switch so
     that overflow amputated the second label mid-word ("Programmes | Activ…"). */
  .pf-switch { display:inline-flex; gap:0; border:1px solid var(--border); border-radius:8px;
               overflow:hidden; flex-shrink:0; }
  .pf-switch button { font:600 12px var(--font); padding:6px 13px; border:0; cursor:pointer;
               background:var(--surface); color:var(--text2); }
  .pf-switch button + button { border-left:1px solid var(--border); }
  /* ⚠ v14.4 (b): `color:#fff`, NOT `var(--surface)`. FOUND BY LOOKING AT THE DARK-MODE
     SCREENSHOT AND THEN MEASURING IT: `--accent-dark` (#3a3833) is defined ONCE and never
     flips with the theme — deliberately, it is the brand ink the Save button uses in both —
     while `--surface` DOES flip, to #242220. So the active pane read #242220 on #3a3833, a
     contrast of roughly 1.1:1: the label of the pane you are actually on was invisible in dark
     mode. `#fff` is the app's own established answer for text on this ink (.ov-btn-primary). */
  .pf-switch button[aria-pressed="true"] { background:var(--accent-dark); color:#fff; }
  .act-bar { display:flex; gap:8px; flex-wrap:wrap; align-items:flex-end; margin:0 0 14px; }
  .act-bar > *, .act-control .sort-select { max-width:100%; }
  .act-control { display:flex; flex-direction:column; gap:4px; min-width:0; }
  .act-control label { font-size:11px; font-weight:600; color:var(--text2); }
  .act-search { flex:1 1 240px; }
  .act-search-box { display:flex; border:1px solid var(--border); border-radius:6px; background:var(--surface); }
  .act-search-box input { width:100%; min-width:0; padding:7px 9px; border:0; border-radius:6px; background:transparent; color:var(--text); font:inherit; font-size:12px; }
  .act-search-box button { border:0; background:transparent; color:var(--text2); padding:0 10px; cursor:pointer; font-size:18px; }
  .act-count { color:var(--text3); font-size:12px; margin-bottom:8px; }
  .act-day { display:flex; align-items:baseline; gap:9px; padding:8px 14px; background:var(--surface2);
             border:1px solid var(--border); border-radius:8px; margin:14px 0 8px; }
  .act-day b { font-size:12.5px; } .act-day span { font-size:12px; color:var(--text3); }
  .act-save { background:var(--surface); border:1px solid var(--border); border-radius:9px;
              padding:11px 14px; margin:0 0 8px; }
  .act-head { display:flex; align-items:center; gap:11px; }
  .act-av { width:26px; height:26px; border-radius:50%; background:var(--surface2);
            border:1px solid var(--border); color:var(--text2); font:600 10.5px var(--font);
            display:flex; align-items:center; justify-content:center; flex:0 0 auto; }
  /* ⚠ v14.4: the same pairing, same fix — my own initials on my own saves were unreadable in
     dark mode. Two rules is a pattern, not a slip: see the note on .pf-switch above. */
  .act-av.me { background:var(--accent-dark); color:#fff; border-color:var(--accent-dark); }
  .act-who { flex:1; font-size:13.5px; }
  .act-who b { font-weight:600; }
  .act-when { font-size:11.5px; color:var(--text3); font-family:var(--mono); }
  .act-changes { margin:7px 0 0; padding:0 0 0 37px; }
  .act-row { display:flex; gap:9px; align-items:baseline; padding:3px 0; font-size:12.5px;
             flex-wrap:wrap; }
  .act-verb { font:600 9.5px var(--font); letter-spacing:.03em; text-transform:uppercase;
              padding:1px 7px; border-radius:99px; border:1px solid var(--border);
              background:var(--surface2); color:var(--text2); flex:0 0 auto; }
  .act-verb.added { background:var(--low-bg); border-color:var(--low-border); color:var(--low); }
  .act-verb.completed { background:var(--low-bg); border-color:var(--low-border); color:var(--low); }
  .act-verb.deleted { background:var(--high-bg); border-color:var(--high-border); color:var(--high); }
  .act-verb.cancelled { background:var(--high-bg); border-color:var(--high-border); color:var(--high); }
  .act-verb.changed { background:var(--medium-bg); border-color:var(--medium-border); color:var(--medium); }
  .act-ref { font-family:var(--mono); font-size:11.5px; color:var(--text3); flex:0 0 auto; }
  .act-title { color:var(--text); }
  .act-kind { color:var(--text3); font-size:11.5px; }
  .act-ctx { color:var(--text3); font-size:11.5px; }
  .act-fields { color:var(--text2); font-size:11.5px; width:100%; padding-left:0; }
  .act-from { color:var(--text3); text-decoration:line-through; }
  .act-more { display:block; width:100%; padding:10px; margin:12px 0 0; border:1px solid var(--border);
              border-radius:9px; background:var(--surface); color:var(--text2);
              font:500 12.5px var(--font); cursor:pointer; }
  .act-more:hover { background:var(--surface2); }
  .act-empty { padding:34px 14px; text-align:center; color:var(--text2); font-size:13px;
               border:1px dashed var(--border); border-radius:10px; }
  .act-empty b { display:block; color:var(--text); font-size:14px; margin-bottom:4px; }
  .act-broken { background:var(--medium-bg); border:1px solid var(--medium-border);
                border-radius:8px; padding:9px 13px; margin:0 0 10px; font-size:12.5px; }
  /* ══ v14.4 (a): Continuous improvement — the capture section and the portfolio pane ══════ */
  .ci-form { background:var(--surface2); border:1px solid var(--border); border-radius:9px;
             padding:13px 14px; margin:0 0 14px; }
  .ci-form-ttl { font:600 12px var(--font); color:var(--text2); margin:0 0 10px;
                 text-transform:uppercase; letter-spacing:.04em; }
  .ci-grid { display:grid; grid-template-columns:1fr 1fr; gap:10px 14px; }
  .ci-f { display:flex; flex-direction:column; gap:4px; }
  .ci-f.ci-wide { grid-column:1/-1; }
  .ci-f label { font:600 11px var(--font); color:var(--text3); text-transform:uppercase;
                letter-spacing:.04em; }
  .ci-f input, .ci-f textarea { font:13px var(--font); padding:7px 9px;
        border:1px solid var(--border); border-radius:7px; background:var(--surface);
        color:var(--text); }
  .ci-f textarea { resize:none; height:44px; }
  .ci-hint { font-size:11px; color:var(--text3); }
  .ci-pillrow { display:flex; gap:6px; }
  .ci-pill { font:600 11.5px var(--font); padding:5px 12px; border-radius:99px; cursor:pointer;
             border:1px solid var(--border); background:var(--surface); color:var(--text2); }
  .ci-pill.on-good { background:var(--low-bg); border-color:var(--low-border); color:var(--low); }
  .ci-pill.on-bad { background:var(--medium-bg); border-color:var(--medium-border); color:var(--medium); }
  .ci-form-foot { display:flex; gap:8px; justify-content:flex-end; margin-top:11px; }
  .ci-entry { border:1px solid var(--border); border-radius:9px; padding:11px 14px; margin:0 0 9px;
              background:var(--surface); }
  .ci-lhead { display:flex; align-items:center; gap:9px; flex-wrap:wrap; }
  .ci-ref { font-family:var(--mono); font-size:11.5px; color:var(--text3); flex:0 0 auto; }
  .ci-type { font:600 10px var(--font); letter-spacing:.03em; text-transform:uppercase;
             padding:2px 8px; border-radius:99px; border:1px solid; cursor:pointer; flex:0 0 auto; }
  .ci-type.good { color:var(--low); background:var(--low-bg); border-color:var(--low-border); }
  .ci-type.bad { color:var(--medium); background:var(--medium-bg); border-color:var(--medium-border); }
  .ci-cat-input { font:600 10.5px var(--font); padding:2px 8px; border-radius:99px; width:150px;
        border:1px solid var(--border); background:var(--surface2); color:var(--text2); }
  .ci-spacer { flex:1; }
  .ci-who-input { font:11.5px var(--font); color:var(--text3); padding:2px 6px; width:110px;
        border:1px solid var(--border); border-radius:6px; background:var(--surface); }
  .ci-date { font:11.5px var(--font); color:var(--text3); padding:1px 4px;
        border:1px solid var(--border); border-radius:6px; background:var(--surface); }
  .ci-what { margin:7px 0 0; font-size:13.5px; }
  .ci-what:empty::before { content:attr(data-ph); color:var(--text3); }
  .ci-next { margin:4px 0 0; font-size:12.5px; color:var(--text2); }
  .ci-next b { color:var(--text); font-weight:600; }
  .ci-next span:empty::before { content:attr(data-ph); color:var(--text3); }
  .ci-catbar { display:flex; align-items:baseline; gap:9px; padding:8px 14px;
               background:var(--surface2); border:1px solid var(--border); border-radius:8px;
               margin:14px 0 8px; }
  .ci-catbar b { font-size:12.5px; } .ci-catbar span { font-size:12px; color:var(--text3); }
  .ci-prow { display:flex; gap:11px; padding:10px 4px; border-bottom:1px solid var(--border); }
  .ci-prow:last-child { border-bottom:0; }
  .ci-pdot { width:8px; height:8px; border-radius:50%; margin-top:6px; flex:0 0 auto; }
  .ci-pdot.good { background:var(--low); } .ci-pdot.bad { background:var(--medium); }
  .ci-pbody { flex:1; min-width:0; }
  .ci-pline { font-size:13.5px; }
  .ci-pnext { font-size:12.5px; color:var(--text2); margin-top:2px; }
  .ci-pnext b { color:var(--text); font-weight:600; }
  .ci-pctx { font-size:11.5px; color:var(--text3); margin-top:3px; }
  .ci-pctx .ci-dot { margin:0 5px; }
  .pf-arch-head { font-size: 11px; letter-spacing: .6px; text-transform: uppercase; color: var(--text3); padding: 10px 16px 4px; }
  .pf-empty { padding: 34px 16px; text-align: center; color: var(--text2); font-size: 13.5px; }
  /* v13.1 (U06 / D05): twelve rules over eight classes — .pf-broken, .pf-conflict, .pf-note,
     .pf-act, .pf-hint, .pf-new, .pf-new-row, .pf-newhint — were removed here, together with
     the two design comments describing behaviour the code stopped having. They are left over
     from the pre-v11 model where a programme was a FILE and the portfolio listed the folder:
     broken files, sync-conflict copies and a create-a-programme row. One file holds the whole
     portfolio now, so none of it is emitted. ⚠ .pf-row, .pf-arch, .pf-empty, .pf-file and
     .pf-name are LIVE and stay — which is why this was a per-SELECTOR edit: .pf-row.pf-broken
     names a dead class while styling a live row, and a line-level sweep would have taken the
     row with it. .pf-file in particular was on the candidate list and is in use. */

  /* landing switch (Projects | Focus) — shared by overview + focus heads */
  .ls-seg { display: flex; background: var(--surface2); border: 1px solid var(--border); border-radius: 9px; padding: 3px; }
  .ls-seg button { font: inherit; font-size: 13px; font-weight: 500; border: 0; background: transparent; color: var(--text2); padding: 6px 16px; border-radius: 6px; cursor: pointer; }
  .ls-seg button.on { background: var(--surface); color: var(--text); box-shadow: 0 1px 2px rgba(0,0,0,0.06); font-weight: 600; }

  /* v6.1: shared landing bar — one persistent top bar for the two landing views
     (Accounts + Focus). Holds logo + the Accounts|Focus switch + dark-mode toggle.
     Hidden on the project view (which has its own crumbbar + theme toggle). Because
     the switch is the SAME node in both landing views, it never moves when toggling. */
  #landingBar { display: none; }
  body.view-overview #landingBar, body.view-focus #landingBar { display: block; }
  .lb-inner { max-width: 1120px; margin: 0 auto; padding: 18px 24px 0; display: flex; align-items: center; gap: 14px; }
  .lb-logo { width: 40px; height: 40px; }
  /* v14 (W6): the wordmark beside the mark on the landing views — his ask. Light 300, option A,
     "matches the brand PNG" (his verdict). Deliberately NOT .brand-name's semibold 600: the
     product name is quieter furniture than a project name, and 300 is what the brand uses. */
  .lb-wordmark { font-size: 18px; font-weight: 300; color: var(--text); letter-spacing: .01em;
                 white-space: nowrap; margin-left: -4px; }
  .lb-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }
  .lb-divider { width: 1px; height: 22px; background: var(--border); flex: 0 0 auto; }  /* v7: visual weight before global Save all */

  /* v17.5 MI-01 UI review: keep folder identity and Save controls reachable on narrow screens.
     The shared bar retains its desktop ordering; long folder names may wrap below the title. */
  @media (max-width: 680px) {
    .lb-inner { flex-wrap: wrap; }
    .lb-right { flex: 1 1 100%; flex-wrap: wrap; min-width: 0; }
    .lb-right .ls-seg { flex-basis: 100%; justify-content: center; }
    .lb-right .hdr-search { flex: 1 1 120px; min-width: 0; margin-right: 0; }
    .lb-right .hdr-search input { width: 100%; }
    body.view-portfolio .lb-right .hdr-search[hidden] + .theme-toggle { margin-left: auto; }
    .pf-head, .ov-head { flex-wrap: wrap; }
    .pf-head .ov-meta, .ov-head .ov-meta { max-width: 100%; min-width: 0; overflow-wrap: anywhere; }
  }

  /* Focus view */
  .fx-view { max-width: 980px; margin: 0 auto; padding: 26px 26px 70px; }
  .fx-head { display: flex; align-items: center; gap: 14px; margin-bottom: 18px; }
  .fx-title { font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
  .fx-sub { color: var(--text3); font-size: 12.5px; margin-top: 1px; }

  .fx-filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
  .fx-chip { background: var(--surface); border: 1px solid var(--border); border-radius: 999px; padding: 6px 13px; font-size: 12.5px; color: var(--text2); display: flex; align-items: center; gap: 6px; cursor: pointer; user-select: none; }
  .fx-chip:hover { border-color: var(--text3); }
  .fx-chip b { font-size: 14px; font-weight: 700; font-family: var(--mono, 'DM Mono', monospace); }
  .fx-chip.red b { color: var(--high); } .fx-chip.amber b { color: var(--medium); } .fx-chip.dim b { color: var(--text); }
  .fx-chip.on { background: var(--accent-dark); border-color: var(--accent-dark); color: #fff; }
  .fx-chip.on b { color: #fff; }

  .fx-ctl { display: flex; align-items: center; justify-content: flex-end; gap: 6px; margin-bottom: 10px; }
  .fx-ctl button { font: inherit; font-size: 12px; color: var(--text2); background: var(--surface); border: 1px solid var(--border); border-radius: 7px; padding: 5px 11px; cursor: pointer; }
  .fx-ctl button:hover { background: var(--surface2); }

  .fx-bucket { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; margin-bottom: 12px; overflow: hidden; }
  .fx-bk-head { display: flex; align-items: center; gap: 11px; padding: 13px 16px; cursor: pointer; user-select: none; }
  .fx-bk-head:hover { background: var(--surface2); }
  .fx-bk-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
  .fx-bk-title { font-weight: 600; font-size: 14.5px; }
  .fx-bk-count { font-family: var(--mono, 'DM Mono', monospace); font-size: 11px; font-weight: 600; padding: 2px 9px; border-radius: 999px; letter-spacing: 0.3px; }
  .fx-bk-sub { color: var(--text3); font-size: 12px; margin-left: 2px; }
  .fx-chev { margin-left: auto; color: var(--text3); transition: transform 0.18s; flex: none; }
  .fx-bucket.collapsed .fx-chev { transform: rotate(-90deg); }
  .fx-bucket.collapsed .fx-bk-list { display: none; }
  .fx-bk-list { border-top: 1px solid var(--border); }

  .fx-row { display: flex; align-items: center; gap: 12px; padding: 11px 16px; border-bottom: 1px solid var(--border); cursor: pointer; }
  .fx-row:last-child { border-bottom: 0; }
  .fx-row:hover { background: var(--surface2); }
  .fx-pri { width: 8px; height: 8px; border-radius: 50%; flex: none; }
  .fx-pri.h { background: var(--high); } .fx-pri.m { background: var(--medium); } .fx-pri.l { background: var(--low); } .fx-pri.q { background: var(--text3); }
  .fx-row-main { min-width: 0; flex: 1; }
  .fx-row-title { font-size: 13.5px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .fx-row-meta { display: flex; align-items: center; gap: 9px; font-size: 12px; color: var(--text3); margin-top: 2px; }
  .fx-proj { color: var(--text2); font-weight: 500; }
  .fx-proj::before { content: ""; display: inline-block; width: 5px; height: 5px; border-radius: 50%; background: var(--text3); margin-right: 6px; vertical-align: middle; }
  .fx-right { display: flex; align-items: center; gap: 10px; flex: none; }
  .fx-due { font-family: var(--mono, 'DM Mono', monospace); font-size: 12px; color: var(--text2); white-space: nowrap; }
  .fx-due.over { color: var(--high); font-weight: 600; }
  .fx-badge { font-size: 10.5px; font-family: var(--mono, 'DM Mono', monospace); letter-spacing: 0.3px; padding: 2px 8px; border-radius: 6px; white-space: nowrap; }
  .fx-b-block { color: var(--medium); background: var(--medium-bg); border: 1px solid var(--medium-border); }
  .fx-b-open { color: var(--text2); background: var(--surface2); border: 1px solid var(--border); }
  .fx-b-agenda { color: var(--low); background: var(--low-bg); border: 1px solid var(--low-border); }
  .fx-jump { color: var(--text3); flex: none; }
  .fx-row:hover .fx-jump { color: var(--text); }
  .fx-empty { padding: 40px 16px; text-align: center; color: var(--text3); font-size: 13.5px; }

  /* jumped-to action highlight */
  @keyframes fxFlash { 0% { background: var(--medium-bg); } 100% { background: transparent; } }
  .action-card.fx-flash { animation: fxFlash 1.6s ease-out; }
  .overview-view { max-width: 1120px; margin: 0 auto; padding: 34px 24px 64px; }
  .ov-head { display: flex; align-items: center; gap: 14px; margin-bottom: 26px; }
  .ov-title { font-size: 20px; font-weight: 600; color: var(--text); letter-spacing: -0.01em; }
  /* v10.5 (W1): title-and-trail on the landing view — trail above, the programme's own
     name as the title. The unnamed state is muted-italic because it is standing in the
     FILE name, not asserting a programme name that does not exist. */
  .ov-title-unnamed { color: var(--text2); font-weight: 500; font-style: italic; }
  .ov-title-hint { font-size: 12px; color: var(--text3); margin-top: 3px; }
  /* ◆2: the title is gated, not hidden — it keeps its box so nothing jumps when the
     boot handle-restore settles and the real programme name arrives. */
  .ov-title-pending { opacity: 0; }
  .ov-sub { font-size: 13px; color: var(--text2); margin-top: 2px; }
  .ov-empty { color: var(--text2); font-size: 14px; padding: 40px 0; text-align: center; }
  .ov-head-text { flex: 0 1 auto; }
  .ov-toolbar { margin-left: auto; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
  .ov-reconnect { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin: 0 0 18px; padding: 12px 16px; border: 1px solid #f0c36d; background: #fff7e6; border-radius: 10px; }
  .dark .ov-reconnect { border-color: #7a5b1e; background: #2a2310; }
  .ov-reconnect-msg { font-size: 13px; color: var(--text2); }
  /* v11 (W3): the folder sentry. Amber (the .ov-reconnect idiom) for a data-like sibling
     — someone's work; a quiet grey note for any other stray .js (◆B), so amber keeps its
     meaning and does not get trained away. */
  .ov-sentry { align-items: flex-start; }
  .ov-sentry-list { margin: 8px 0 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; }
  .ov-sentry-list li { font-size: 12.5px; line-height: 1.6; }
  .ov-sentry-list code { font-size: 12px; background: var(--surface); padding: 1px 5px; border-radius: 4px; word-break: break-all; }
  .ov-sentry-list .ov-btn { margin-left: 4px; }
  .ov-quiet-note { margin: 0 0 18px; padding: 9px 14px; border: 1px solid var(--border); background: var(--surface2); border-radius: 8px; font-size: 12.5px; color: var(--text3); line-height: 1.55; }
  .ov-quiet-note code { font-size: 12px; background: var(--surface); padding: 1px 5px; border-radius: 4px; }
  .launcher-note { display: flex; align-items: center; gap: 8px 16px; flex-wrap: wrap; color: var(--text2); }
  .launcher-note span { flex: 1 1 480px; }
  .launcher-note button { flex: none; white-space: nowrap; }
  .launcher-note button:focus-visible { outline: 2px solid var(--text2); outline-offset: 2px; }
  .launcher-announcement { position: absolute; width: 1px; height: 1px; padding: 0;
                           overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  /* v14 (W6): the ROSTER. Deliberately built on .ov-quiet-note rather than given its own panel:
     "who is in the folder" is reassurance, not an alert, and the one thing here that IS an alert
     (a colleague missing from the portfolio, ◆7) borrows the amber .ov-sentry styling instead. A
     roster that shouted would train the eye to ignore amber, which is the mistake ◆B avoided. */
  .ov-roster strong { color: var(--text2); }
  .ov-roster-list { margin: 8px 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 5px; }
  .ov-roster-list li { font-size: 12.5px; line-height: 1.6; display: flex; align-items: baseline; gap: 6px; }
  .ov-roster-list li strong { color: var(--text); font-weight: 600; }
  .ov-roster-me strong { color: var(--accent, var(--text)); }
  .ov-roster-you { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
                   border: 1px solid var(--border); border-radius: 999px; padding: 0 6px;
                   color: var(--text3); flex: 0 0 auto; }
  .ov-roster-line { margin-bottom: 0; }

  /* v8.9: data-source line (in the landing ov-meta) + ⓘ, and the Q-b stale-tab
     banner (mirrors the reconnect banner's amber). The line is display-only. */
  .ov-datasrc { font-size: 11px; color: var(--text3); }
  .ov-datasrc.ov-datasrc-warn { color: var(--medium); }
  .ov-info-i { display: inline-block; margin-left: 5px; width: 13px; height: 13px; line-height: 12px; text-align: center; font-size: 9px; font-family: var(--mono); font-style: italic; color: var(--text3); border: 1px solid var(--border); border-radius: 50%; cursor: help; vertical-align: 1px; }
  .ov-info-i:hover { color: var(--text); border-color: var(--text3); }
  .ov-stale { display: flex; align-items: center; gap: 16px; margin: 0 0 18px; padding: 12px 16px; border: 1px solid #f0c36d; background: #fff7e6; border-radius: 10px; }
  /* an author display beats the UA's [hidden]{display:none} — restate it, or the
     banner paints permanently (caught by pixel-diffing the v8.9 screenshots) */
  .ov-stale[hidden] { display: none; }
  .dark .ov-stale { border-color: #7a5b1e; background: #2a2310; }
  .ov-stale-msg { font-size: 13px; color: var(--text2); }

  /* ── v9.0: WBS planned dates (on the Work-breakdown cards — the one writable home) ── */
  .wbs-dates { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin: 12px 0 4px; }
  .wbs-dates-lbl { font-family: var(--mono); font-size: 10.5px; color: var(--text3); text-transform: uppercase; letter-spacing: 0.5px; }
  .wbs-dates .sched-row { padding: 0; }
  .wbs-dates .sched-label { width: auto; }
  .wbs-dates .sched-hint { flex-basis: 100%; margin: 0; }

  /* ── v9.0: Schedule — the read-only Gantt ── */
  .gantt { border: 1px solid var(--border); border-radius: 10px; background: var(--surface); overflow-x: auto; }
  .gantt-inner { min-width: 640px; }
  .gantt-axis-row, .gantt-row { display: grid; grid-template-columns: 250px 1fr; align-items: stretch; }
  .gantt-axis-row { background: var(--surface2); border-bottom: 1px solid var(--border); font-family: var(--mono); font-size: 9.5px; color: var(--text3); text-transform: uppercase; letter-spacing: 0.5px; }
  .gantt-axis-lbl { display: flex; align-items: center; padding: 0 12px; }
  .gantt-axis { position: relative; height: 26px; }
  .gantt-month { position: absolute; top: 0; height: 100%; display: flex; align-items: center; padding-left: 6px; border-left: 1px solid var(--border); white-space: nowrap; overflow: hidden; }
  .gantt-row { border-top: 1px solid var(--border); }
  .gantt-row:first-of-type { border-top: none; }
  .gantt-label { display: flex; align-items: center; gap: 8px; padding: 0 10px 0 12px; min-width: 0; height: 34px; }
  .gantt-lvl2 .gantt-label { padding-left: 26px; }
  .gantt-lvl3 .gantt-label { padding-left: 40px; }
  .gantt-title { font-size: 12.5px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .gantt-lvl1 .gantt-title { font-weight: 600; }
  .gantt-track { position: relative; height: 34px; }
  .gantt-grid { position: absolute; top: 0; bottom: 0; width: 0; border-left: 1px solid var(--border); opacity: 0.5; }
  .gantt-today { position: absolute; top: 0; bottom: 0; width: 0; border-left: 2px solid var(--medium); opacity: 0.75; }
  .gantt-bar { position: absolute; top: 8px; height: 18px; background: var(--surface2); border: 1px solid var(--border); border-radius: 5px; overflow: hidden; min-width: 6px; }
  .gantt-fill { position: absolute; left: 0; top: 0; bottom: 0; background: var(--accent-dark); opacity: 0.55; }
  /* ══ v15: --accent-dark USED AS A MARK, NOT AS A BACKGROUND-FOR-TEXT ═══════════════════════
     v14.4 swept the pairing where --accent-dark is a BACKGROUND behind flipping text. This is
     the other half of the same class, and it needed a sweep of its own: --accent-dark used as
     the INK of a graphic against a surface that flips. It never changes (#3a3833), so in dark
     mode each of these sat on a near-black ground:
       · .wbs-cov-bar i   fill vs its --border track  ≈ 1.01:1 — a 0% and a 100% coverage bar
                          were pixel-identical, which is worse than showing nothing
       · .ws-progress-fill vs --surface2 track        ≈ 1.19:1, and the same colour as the
                          track's own border, in a 6px bar
       · .gantt-fill      blended at .55 over --surface2 ≈ 1.09:1 — the progress shading vanished
       · .dlc-dot         milestone bullet on --surface  ≈ 1.35:1 — and because
                          .mil-row.overdue .dlc-dot DOES flip to --high, the list looked as
                          though only overdue rows had bullets
       · .stk-eng-target  #3a3833 on --surface2 ≈ 1.19:1 — the engagement TARGET was unreadable
                          exactly when it differed from current, which is the point of the chip
     ⚠ FIXED WITH .dark OVERRIDES, not by repointing the base rules: that is this shell's own
     idiom (.dark .toast, .dark .stk-eng-option.is-selected) and it leaves light mode
     byte-for-byte as it was. He asked for a QA round, not a redesign. */
  .dark .wbs-cov-bar i,
  .dark .ws-progress-fill,
  .dark .gantt-fill,
  /* v17.1 W2: .dlc-dot is shared by milestones and key risks. The old dark override
     painted every one grey after the semantic risk rules had already selected
     --high / --medium / --low / --opp. Keep the neutral milestone treatment, but let
     the key-risk classes resolve to their theme-aware semantic tokens. */
  .dark .dlc-dot:not(.kr-dot) { background: var(--text2); }
  .dark .gantt-fill { opacity: 0.75; }
  .dark .stk-eng-target { color: var(--text); }
  .gantt-bar.gantt-env { background: transparent; border: 1px dashed var(--text3); }
  .gantt-note { font-size: 11px; color: var(--text3); font-style: italic; line-height: 34px; padding: 0 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .gantt-empty { padding: 26px 14px; text-align: center; color: var(--text3); font-size: 12.5px; }

  /* ── v9.0: actions ↔ WBS traceability — the element pill + jump flash ── */
  .wbs-pill { display: inline-flex; align-items: center; gap: 4px; font-size: 10.5px; font-family: var(--mono); color: var(--text2); background: var(--surface2); border: 1px solid var(--border); border-radius: 999px; padding: 1px 8px; cursor: pointer; max-width: 220px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .wbs-pill:hover { color: var(--text); border-color: var(--text3); }
  .wbs-pill-none { border-style: dashed; background: transparent; color: var(--text3); font-style: italic; }
  /* v12.2 (W3): "not a WBS item" - quiet and dotted, deliberately NOT italic-dashed so it
     reads as a settled state rather than the unassigned nag. Still clickable: reversible. */
  .wbs-pill-na { border-style: dotted; background: transparent; color: var(--text3); }
  .ws-action-row { cursor: pointer; }
  .ws-action-row:hover .ws-ar-title { text-decoration: underline; }
  .wbs-jump-flash { animation: wbsJumpFlash 1.6s ease-out; }
  @keyframes wbsJumpFlash { 0% { box-shadow: 0 0 0 3px var(--medium); } 100% { box-shadow: 0 0 0 0 transparent; } }

  /* ── v10.0: the programme layer (landing page) ── */
  .ov-prag { margin: 0 0 16px; }
  .ov-heat { border: 1px solid var(--border); border-radius: 10px; background: var(--surface); overflow-x: auto; margin: 0 0 18px; }
  .pm-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
  .pm-th { font-family: var(--mono); font-size: 9.5px; color: var(--text2); text-transform: uppercase; letter-spacing: 0.5px; text-align: center; padding: 8px 8px; border-bottom: 1px solid var(--border); background: var(--surface2); }
  .pm-th.l { text-align: left; padding-left: 14px; }
  .pm-td { text-align: center; padding: 9px 8px; border-bottom: 1px solid var(--surface2); }
  .pm-td.l { text-align: left; padding-left: 14px; font-weight: 600; color: var(--text); }
  .pm-td.l small { display: block; font-weight: 400; color: var(--text3); font-family: var(--mono); font-size: 9.5px; }
  .pm-row { cursor: pointer; }
  .pm-row:hover td { background: var(--surface2); }
  .pm-table tr:last-child td { border-bottom: none; }
  /* v10.4 (W3): the consolidated project table's own cells. The table absorbed the
     cards, so it carries the status rationale, Gate, Progress and the ⋯ menu. */
  .pm-name { font-size: 13px; font-weight: 600; color: var(--text); }
  .pm-why { display: block; font-weight: 400; color: var(--text3); font-size: 11px; line-height: 1.35; margin-top: 2px; max-width: 46ch; }
  .pm-td-pm { font-weight: 400; color: var(--text2); font-size: 12px; white-space: nowrap; }
  .pm-none { color: var(--text3); }
  .pm-gate { display: inline-block; font-size: 10.5px; font-weight: 600; color: var(--text2); background: var(--surface2); border: 1px solid var(--border); border-radius: 999px; padding: 2px 9px; white-space: nowrap; }
  .pm-pct { display: block; font-family: var(--mono); font-size: 11px; color: var(--text2); margin-bottom: 3px; }
  .pm-bar { display: block; height: 3px; width: 54px; margin: 0 auto; background: var(--surface2); border-radius: 2px; overflow: hidden; }
  .pm-bar i { display: block; height: 100%; background: var(--text3); border-radius: 2px; }
  .pm-td-dot { cursor: pointer; }
  .pm-td-dot:hover .kpi-dot { outline: 2px solid var(--border-strong); outline-offset: 2px; }
  .pm-th-menu, .pm-td-menu { width: 34px; min-width: 34px; padding-left: 0; padding-right: 6px; }
  .pm-th-menu.pm-menu-manual, .pm-td-menu.pm-menu-manual { width: 112px; min-width: 112px;
    text-align: right; white-space: nowrap; }
  .pm-td-menu .list-order-move-slot { margin-right: 16px; vertical-align: middle; }
  .pm-menu-wrap { position: relative; display: inline-flex; vertical-align: middle; }
  /* archived projects: dimmed rows below the live ones (the toggle keeps its home).
     v17.2 W2 keeps opacity off the menu CELL for the same compositing reason as the
     portfolio row above; only its button is dim, while every non-menu cell stays dim. */
  .pm-row-arch td:not(.pm-td-menu) { opacity: 0.5; }
  .pm-row-arch .pm-td-menu > .pm-menu-wrap > .pm-menu-btn { opacity: 0.5; }
  .pm-row-arch .pm-td-menu > .list-order-move-slot { opacity: 0.5; }
  .pm-row-arch .pm-name::after { content: " · archived"; font-weight: 400; color: var(--text3); font-size: 11px; }
  /* v17.1 W3: project predecessors stay out of the already-dense programme table.
     A quiet chain/count sits beside the name; the relationship itself opens underneath
     the table as a horizontally scrollable native SVG programme map. */
  .pred-count { display: inline-flex; align-items: center; gap: 3px; margin-left: 7px;
                padding: 1px 6px; border: 1px solid var(--border); border-radius: 999px;
                background: transparent; color: var(--text2); font: 600 10.5px var(--mono);
                line-height: 1.35; vertical-align: 1px; cursor: pointer; }
  .pred-count:hover { color: var(--text); border-color: var(--text3); background: var(--surface2); }
  .pred-count svg { width: 11px; height: 11px; fill: none; stroke: currentColor;
                    stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
  .pred-count[hidden] { display: none; }
  .pred-count-crumb { flex: 0 0 auto; margin: 3px 1px 0 2px; }
  .pred-map-panel { margin: -4px 0 18px; border: 1px solid var(--border); border-radius: 10px;
                    background: var(--surface); overflow: hidden; }
  .pred-map-head { display: flex; align-items: baseline; gap: 9px; padding: 11px 14px;
                   border-bottom: 1px solid var(--border); background: var(--surface2); }
  .pred-map-title { color: var(--text); font-size: 13px; font-weight: 700; }
  .pred-map-note { color: var(--text3); font-size: 11.5px; }
  .pred-map-warning { margin: 10px 14px 0; padding: 8px 10px; border: 1px solid var(--medium-border);
                      border-radius: 7px; background: var(--medium-bg); color: var(--medium);
                      font-size: 11.5px; }
  .pred-map-scroll { overflow: auto; padding: 10px 12px 12px; }
  .pred-map-svg { display: block; min-width: 540px; color: var(--text3); }
  .pred-map-edge { fill: none; stroke: var(--text3); stroke-width: 1.45; opacity: .75; }
  .pred-map-arrow { fill: var(--text3); }
  .pred-map-node rect { fill: var(--surface); stroke: var(--border-strong); stroke-width: 1.2; }
  .pred-map-node[role="button"] { cursor: pointer; }
  .pred-map-node[role="button"]:hover rect,
  .pred-map-node[role="button"]:focus rect { stroke: var(--accent-dark); stroke-width: 1.8; }
  .pred-map-node:focus { outline: none; }
  .pred-map-node-id { fill: var(--text3); font: 9.5px var(--mono); letter-spacing: .3px; }
  .pred-map-node-name { fill: var(--text); font: 600 12px var(--font); }
  .pred-map-node-archived { opacity: .55; }
  .pred-map-node-unavailable rect { fill: var(--surface2); stroke-dasharray: 4 3; }
  .pred-map-node-unavailable .pred-map-node-name { fill: var(--text2); font-weight: 500; }
  .pred-map-empty { padding: 22px 14px; color: var(--text3); font-size: 12.5px; text-align: center; }
  .pred-list { display: flex; flex-direction: column; max-height: 330px; overflow-y: auto;
               margin: 12px 0 4px; border: 1px solid var(--border); border-radius: 9px; padding: 5px; }
  .pred-row { display: grid; grid-template-columns: 20px minmax(0,1fr); gap: 8px;
              align-items: start; padding: 8px 9px; border-radius: 7px; cursor: pointer; }
  .pred-row:hover { background: var(--surface2); }
  .pred-row input { margin: 2px 0 0; cursor: pointer; }
  .pred-row-main { min-width: 0; }
  .pred-row-name { display: block; color: var(--text); font-size: 13px; font-weight: 600; }
  .pred-row-meta { display: block; margin-top: 1px; color: var(--text3); font-size: 11px; }
  .pred-row-unavailable .pred-row-name { color: var(--text2); font-weight: 500; }
  .pred-error { min-height: 18px; margin-top: 7px; color: var(--high); font-size: 11.5px; }
  .ov-benefits { margin: 0 0 22px; }
  .ov-benefits-head { font-size: 14px; font-weight: 700; color: var(--text); margin-bottom: 10px; display: flex; align-items: center; gap: 8px; }
  .ov-benefits-empty { font-size: 12.5px; color: var(--text3); padding: 4px 0 8px; }
  .pb-card { border-left-color: var(--border); }
  .pb-name { font-size: 13px; font-weight: 600; color: var(--text); outline: none; padding: 2px 6px; margin: -2px 0 -2px -2px; border-radius: 5px; min-width: 140px; }
  .pb-name:focus { background: var(--surface2); box-shadow: 0 0 0 2px var(--accent-dark); }
  .pb-name:empty::before { content: attr(data-ph); color: var(--text3); font-style: italic; font-weight: 400; }
  .pb-def { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; font-size: 12.5px; color: var(--text); }
  .pb-def .kpi-k { padding-top: 0; }
  .ben-status { cursor: pointer; }
  /* the hints-to-ⓘ sweep: the ⓘ sits inside <summary> rows too — keep it from
     inheriting the summary's bold weight */
  .raid-summary .ov-info-i { font-weight: 400; }
  .ov-mismatch { margin: 0 0 18px; padding: 12px 16px; border: 1px solid var(--high-border, #e3a0a0); background: var(--high-bg, #fbeaea); border-radius: 10px; }
  .ov-mismatch-msg { font-size: 13px; color: var(--text); line-height: 1.5; }
  /* v14.0.1 (W3): the misplaced-part banner — .ov-reconnect's flex layout (it needs a button)
     with .ov-mismatch's red, and its own class so a check can tell it from the amber ones. */
  .ov-misplaced { border-color: var(--high-border, #e3a0a0); background: var(--high-bg, #fbeaea); }
  .ov-btn { font-family: var(--font); font-size: 13px; font-weight: 500; padding: 8px 14px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface); color: var(--text); cursor: pointer; transition: background .12s, border-color .12s, filter .12s; }
  .ov-btn:hover { background: var(--surface2); }
  .ov-btn-primary { background: var(--accent-dark); border-color: var(--accent-dark); color: #fff; font-weight: 600; }
  .ov-btn-primary:hover { filter: brightness(0.93); background: var(--accent-dark); }
  /* v5.2.2: import dialog */
  .import-file { display: block; width: 100%; box-sizing: border-box; font: inherit; font-size: 13px; margin: 4px 0 4px; color: var(--text); }
  .import-found { font-size: 12.5px; color: var(--text2); margin: 12px 0 6px; }
  .import-list { max-height: 190px; overflow: auto; border: 1px solid var(--border); border-radius: 8px; }
  .import-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 7px 12px; border-top: 1px solid var(--border); font-size: 13px; }
  .import-row:first-child { border-top: 0; }
  .import-row-name { color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .import-badge { font-size: 10px; font-family: var(--mono); text-transform: uppercase; letter-spacing: .4px; padding: 2px 8px; border-radius: 10px; white-space: nowrap; flex: none; }
  .import-badge-new { color: var(--low); background: var(--low-bg); border: 1px solid var(--low-border); }
  .import-badge-exists { color: var(--medium); background: var(--medium-bg); border: 1px solid var(--medium-border); }
  /* v11 (◆E): the binary triage badge on a collision. "differs" is the one that asks for
     attention, so it reads red; "same" is reassurance, so it stays quiet. */
  .import-badge-differs { color: var(--high); background: var(--high-bg); border: 1px solid var(--high-border); }
  .import-badge-same { color: var(--text3); background: var(--surface2); border: 1px solid var(--border); }
  .import-conflict { margin-top: 12px; padding: 11px 12px; background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; }
  .import-conflict-q { font-size: 12.5px; color: var(--text); margin-bottom: 6px; font-weight: 500; }
  .import-opt { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--text2); padding: 3px 0; cursor: pointer; }
  .import-error { color: var(--high); background: var(--high-bg); border: 1px solid var(--high-border); border-radius: 8px; padding: 10px 12px; font-size: 12.5px; margin-top: 8px; }
  .ov-new-input { font-family: var(--font); font-size: 13px; padding: 8px 12px; border-radius: 8px; border: 1px solid var(--accent-dark); background: var(--surface); color: var(--text); min-width: 220px; outline: none; }
  .ov-arch-toggle { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text2); cursor: pointer; user-select: none; }
  .ov-arch-toggle input { cursor: pointer; }
  .ov-card-menu-btn, .crumb-manage-btn { display: inline-flex; align-items: center; justify-content: center; background: none; border: none; border-radius: 6px; color: var(--text3); cursor: pointer; padding: 0; }
  .ov-card-menu-btn { width: 26px; height: 24px; }
  .ov-card-menu-btn:hover, .crumb-manage-btn:hover { background: var(--surface2); color: var(--text); }
  .ov-card-menu-btn svg, .crumb-manage-btn svg { fill: currentColor; }
  .crumb-manage { position: relative; display: inline-flex; }
  .crumb-manage-btn { width: 26px; height: 24px; }
  .ov-card-menu, .proj-menu { position: absolute; min-width: 152px; background: var(--surface); border: 1px solid var(--border); border-radius: 9px; box-shadow: 0 8px 26px rgba(0,0,0,0.16); z-index: 320; padding: 5px; }
  /* v10.4.1: the ROW menu must escape the table wrapper. `.ov-heat` is overflow-x:auto,
     and per the CSS overflow spec a `visible` axis beside a non-visible one computes to
     `auto` — so that wrapper is a scroll container on BOTH axes and an absolutely-
     positioned menu inside it is CLIPPED, not overlaid (v10.4 shipped it trapped in a
     one-line scrollbox). `fixed` is not clipped by a scrolling ancestor; the coordinates
     come from the button's viewport rect in _placeRowMenu. The crumbbar's .proj-menu
     shares the base rule above but is NOT inside a clipper, so it stays absolute. */
  .ov-card-menu { position: fixed; }
  .proj-menu { top: calc(100% + 5px); left: 0; }
  .ov-card-menu[hidden], .proj-menu[hidden] { display: none; }
  /* ══ v14.3 (b): move a project between programmes ═════════════════════════════════════ */
  .mv-list { display:flex; flex-direction:column; gap:6px; margin:4px 0 0; }
  .mv-row { display:flex; align-items:center; gap:10px; padding:10px 12px; border-radius:8px;
            border:1px solid var(--border); background:var(--surface); color:var(--text);
            font:500 13.5px var(--font); cursor:pointer; text-align:left; width:100%; }
  .mv-row:hover { background:var(--surface2); }
  .mv-row[disabled] { cursor:default; opacity:.62; }
  .mv-row[disabled]:hover { background:var(--surface); }
  .mv-name { flex:1; }
  .mv-cur { font:600 10px var(--font); letter-spacing:.03em; text-transform:uppercase;
            padding:1px 8px; border-radius:99px; border:1px solid var(--border);
            background:var(--surface2); color:var(--text2); }
  .mv-n { font-size:11.5px; color:var(--text3); }
  .proj-menu-item { display: block; width: 100%; text-align: left; background: none; border: none; color: var(--text); cursor: pointer; font-family: var(--font); font-size: 13px; padding: 8px 10px; border-radius: 7px; }
  .proj-menu-item:hover { background: var(--surface2); }
  .proj-menu-item.danger { color: var(--high); }
  .proj-menu-item.danger:hover { background: var(--high-bg); }
  .proj-menu-sep { height: 1px; background: var(--border); margin: 5px 4px; }
  .export-list { display: flex; flex-direction: column; gap: 2px; max-height: 320px; overflow-y: auto; margin: 10px 0 4px; border: 1px solid var(--border); border-radius: 9px; padding: 6px; }
  .export-row { display: flex; align-items: center; gap: 9px; padding: 8px 10px; border-radius: 7px; cursor: pointer; font-size: 13.5px; color: var(--text); }
.export-selectall { font-weight: 600; border-bottom: 1px solid var(--border); border-radius: 7px 7px 0 0; margin-top: 4px; }
  .export-row:hover { background: var(--surface2); }
  .export-row input { cursor: pointer; flex: 0 0 auto; }
  .export-arch { color: var(--text3); font-size: 12px; }
  /* v12.3 (W4): grouped-by-programme export list. The heading IS a row (so its checkbox
     lines up with the project ones) but reads as a band, and members indent under it. */
  .export-group { margin: 6px 0 2px; }
  .export-ghead { background: var(--surface2); font-weight: 600; font-size: 13px; }
  .export-ghead:hover { background: var(--surface2); }
  .export-gcount { margin-left: auto; font-weight: 400; font-size: 11.5px; color: var(--text2); }
  .export-group .export-row:not(.export-ghead) { padding-left: 30px; }
  .confirm-msg code { font-family: 'DM Mono', ui-monospace, monospace; font-size: 12px; background: var(--surface2); padding: 1px 5px; border-radius: 4px; }
  .ov-rename-input { font-family: var(--font); font-size: 14px; font-weight: 600; padding: 2px 6px; border: 1px solid var(--accent-dark); border-radius: 6px; background: var(--surface); color: var(--text); max-width: 100%; width: 88%; outline: none; }
  /* v17.0 W1: shared, stable breadcrumb rail.  The programme slot follows its actual name
     up to a readable 190px cap, so a short name does not leave a mockup-like blank before
     the project.  Hiding the project at programme level uses visibility, not display, so
     the rail itself stays in place. Names wrap at the cap — never an ellipsis, because the
     distinguishing end of a name must remain readable. */
  .crumbbar { display: grid; grid-template-columns: max-content 12px fit-content(190px) 12px minmax(180px, 1fr) max-content;
              align-items: start; column-gap: 6px; row-gap: 4px; min-height: 48px;
              padding: 8px 20px; border-bottom: 1px solid var(--border); background: var(--surface); font-size: 13px; }
  .crumb-slot { min-width: 0; display: flex; align-items: flex-start; }
  .crumb-programme-slot .crumb-back, .crumb-project-slot .crumb-proj-btn {
              min-width: 0; max-width: 100%; white-space: normal; overflow-wrap: anywhere;
              line-height: 1.35; text-align: left; }
  .crumb-project-slot { gap: 3px; }
  .crumb-project-slot .crumb-proj { min-width: 0; flex: 1; }
  .crumb-utility-slot { justify-self: end; align-self: start; min-width: 86px; min-height: 28px; }
  body.view-overview #crumbProjectSlot, body.view-overview #crumbProjectSep { visibility: hidden; }
  .crumb-back { display: inline-flex; align-items: center; gap: 5px; background: none; border: none; color: var(--text2); cursor: pointer; font-family: var(--font); font-size: 13px; padding: 3px 7px; border-radius: 6px; }
  .crumb-back:hover { color: var(--text); background: var(--surface2); }
  .crumb-back.is-current { color: var(--text); font-weight: 600; }
  /* v8.3.0: right-aligned "↩ Focus" return chip — shown only when the project was opened
     from the Focus view. Full border, so the pill radius is allowed. */
  .crumb-focusback { display: inline-flex; align-items: center; gap: 5px; background: none; border: 1px solid var(--border); color: var(--text2); cursor: pointer; font-family: var(--font); font-size: 12.5px; padding: 3px 10px; border-radius: 999px; }
  .crumb-focusback:hover { color: var(--text); background: var(--surface2); border-color: var(--text3); }
  .crumb-focusback[hidden] { display: none; }
  .crumb-focus-sep { display: none; }
  .crumb-focus-sep[hidden] { display: none; }
  .crumb-sep { color: var(--text3); }
  .crumb-unnamed { font-style: italic; }   /* v10.5 (W1): the crumb is standing in a file name */
  .crumb-proj { position: relative; }
  .crumb-proj-btn { display: inline-flex; align-items: center; gap: 5px; background: none; border: none; color: var(--text); font-weight: 600; cursor: pointer; font-family: var(--font); font-size: 13px; padding: 3px 7px; border-radius: 6px; }
  .crumb-proj-btn:hover { background: var(--surface2); }
  @media (max-width: 700px) {
    .crumbbar { grid-template-columns: max-content 12px minmax(0, 1fr) 86px;
                grid-template-rows: auto auto; padding-left: 14px; padding-right: 14px; }
    #crumbPortfolioSlot { grid-column: 1; grid-row: 1; }
    #crumbProgrammeSep { grid-column: 2; grid-row: 1; }
    #crumbProgrammeSlot { grid-column: 3; grid-row: 1; }
    #crumbUtilitySlot { grid-column: 4; grid-row: 1; }
    #crumbProjectSep { grid-column: 2; grid-row: 2; }
    #crumbProjectSlot { grid-column: 3 / 5; grid-row: 2; }
  }
  .proj-switcher { position: absolute; top: calc(100% + 5px); left: 0; min-width: 230px; max-height: 340px; overflow-y: auto; background: var(--surface); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 8px 28px rgba(0,0,0,0.14); z-index: 300; padding: 5px; }
  .proj-switcher[hidden] { display: none; }
  .proj-switch-item { display: block; width: 100%; text-align: left; background: none; border: none; color: var(--text); cursor: pointer; font-family: var(--font); font-size: 13px; padding: 8px 10px; border-radius: 7px; }
  .proj-switch-item:hover { background: var(--surface2); }
  .proj-switch-item.current { color: var(--low); font-weight: 600; }
/* v8 Phase 4.0 — PgMP dashboard sections */
.scope-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px 22px}
.scope-lbl{font-size:11px;font-weight:600;color:var(--text2);margin-bottom:5px}
.scope-list{list-style:none;margin:0 0 5px;padding:0}
.scope-item{display:flex;align-items:flex-start;gap:6px;font-size:12.5px;margin-bottom:3px}
.scope-item-txt{flex:1;outline:none;border-radius:4px;padding:1px 3px;color:var(--text)}
.scope-item-txt:focus{background:var(--surface2)}
.scope-del{border:none;background:none;color:var(--text3);cursor:pointer;font-size:15px;line-height:1;padding:0 2px}
.scope-del:hover{color:var(--high)}
.scope-add{width:100%;border:1px dashed var(--border);background:transparent;border-radius:6px;padding:4px 8px;font-size:12px;color:var(--text2);font-family:inherit}
.scope-add:focus{outline:none;border-color:var(--text3);background:var(--surface2)}
.gate-strip{display:flex;gap:6px;flex-wrap:wrap}
.gate{flex:1;min-width:108px;border:1px solid var(--border);border-radius:9px;padding:9px 11px;background:var(--surface2);cursor:pointer}
.gate-n{font-family:var(--mono);font-size:10px;color:var(--text3);letter-spacing:.5px}
.gate-name{font-size:12px;font-weight:600;color:var(--text);margin-top:2px;outline:none;border-radius:3px}
.gate-name:focus{background:var(--surface)}
.gate-s{font-size:10px;margin-top:6px;color:var(--text3)}
.gate.passed{background:var(--low-bg);border-color:var(--low-border)}
.gate.passed .gate-s{color:var(--low)}
.gate.current{background:var(--medium-bg);border-color:var(--medium-border)}
.gate.current .gate-s{color:var(--medium);font-weight:600}
.sched-row{display:flex;align-items:center;gap:10px;padding:3px 0;font-size:12.5px}
.sched-label{width:104px;flex-shrink:0;color:var(--text2);font-size:11px}
.sched-date{border:1px solid var(--border);border-radius:6px;padding:3px 7px;font-family:inherit;font-size:12px;color:var(--text);background:var(--surface)}
.sched-hint{margin:1px 0 2px 114px;font-size:11px;color:var(--medium);line-height:1.35}
.sched-hint[hidden]{display:none}
.sched-date:focus{outline:none;border-color:var(--text3)}
/* v10.2: the project-level Benefits table CSS removed (UI left in v8.8; JS went
   with the dormant strip). .ben-status/.b-* below STAY — the v10.0 programme
   benefits register uses them. */
.ben-status{font-size:10.5px;font-weight:600;padding:2px 8px;border-radius:12px;border:1px solid var(--border);background:var(--surface2);color:var(--text2);cursor:pointer;text-align:center}
.ben-status.b-green{background:var(--low-bg);color:var(--low);border-color:var(--low-border)}
.ben-status.b-amber{background:var(--medium-bg);color:var(--medium);border-color:var(--medium-border)}
.ben-status.b-red{background:var(--high-bg);color:var(--high);border-color:var(--high-border)}
.ben-status.b-blue{background:#e4ebf1;color:#3a5a7a;border-color:#c5d4e0}
/* v8 Phase 4.0 — change-request register */
.cr-wrap{margin-bottom:8px}
.cr-empty{color:var(--text3);font-size:12.5px;padding:8px 2px}
.cr-card{border:1px solid var(--border);border-radius:10px;padding:11px 13px;margin-bottom:9px;background:var(--surface)}
.cr-top{display:flex;align-items:center;gap:9px}
.cr-ref{font-family:var(--mono);font-size:11px;font-weight:600;color:var(--text2);letter-spacing:.5px}
.cr-date{border:1px solid var(--border);border-radius:6px;padding:2px 6px;font-family:inherit;font-size:11.5px;color:var(--text);background:var(--surface2)}
.cr-date:focus{outline:none;border-color:var(--text3)}
.cr-type{font-size:10.5px;font-weight:600;padding:2px 9px;border-radius:12px;border:1px solid var(--border);background:var(--surface2);color:var(--text2);cursor:pointer}
.cr-spacer{flex:1}
.cr-status{font-size:10.5px;font-weight:600;padding:2px 10px;border-radius:12px;border:1px solid var(--border);cursor:pointer}
.cr-status.cs-submitted{background:var(--surface2);color:var(--text2);border-color:var(--border)}
.cr-status.cs-review{background:var(--medium-bg);color:var(--medium);border-color:var(--medium-border)}
.cr-status.cs-approved{background:var(--low-bg);color:var(--low);border-color:var(--low-border)}
.cr-status.cs-rejected{background:var(--high-bg);color:var(--high);border-color:var(--high-border)}
.cr-status.cs-deferred{background:var(--surface2);color:var(--text3);border-color:var(--border)}
.cr-status.cs-implemented{background:#e4ebf1;color:#3a5a7a;border-color:#c5d4e0}
.cr-del{border:none;background:none;color:var(--text3);cursor:pointer;font-size:16px;line-height:1;padding:0 0 0 2px}
.cr-del:hover{color:var(--high)}
.cr-desc{margin:9px 0;font-size:13px;color:var(--text);line-height:1.5;outline:none;border-radius:5px;padding:3px 5px;min-height:20px}
.cr-desc:focus{background:var(--surface2)}
.cr-desc:empty::before{content:attr(data-ph);color:var(--text3)}
.cr-foot{display:flex;align-items:center;gap:8px;font-size:11.5px}
.cr-foot-lbl{color:var(--text3);font-size:10.5px}
.cr-req{color:var(--text);outline:none;border-radius:4px;padding:1px 4px;min-width:40px}
.cr-req:focus{background:var(--surface2)}
.cr-req:empty::before{content:attr(data-ph);color:var(--text3)}
.cr-impact{font-size:10.5px;font-weight:600;padding:2px 9px;border-radius:12px;border:1px solid var(--border);background:var(--surface2);color:var(--text2);cursor:pointer;margin-right:6px}
.cr-impact.ci-low{background:var(--low-bg);color:var(--low);border-color:var(--low-border)}
.cr-impact.ci-med{background:var(--medium-bg);color:var(--medium);border-color:var(--medium-border)}
.cr-impact.ci-high{background:var(--high-bg);color:var(--high);border-color:var(--high-border)}

  /* ══ v18: the server's chrome — account chip, menu, sign-in and admin dialogs, conflicts ════
     Built on the existing tokens so dark mode is correct by construction. Every [hidden] rule is
     load-bearing for the same reason as before: an authored display beats the UA's [hidden]. */
  .user-chip { display: inline-flex; align-items: center; gap: 7px; height: 30px; padding: 0 11px;
               border-radius: 999px; border: 1px solid var(--border); background: var(--surface);
               color: var(--text2); font-family: var(--font); font-size: 12px; font-weight: 500;
               cursor: pointer; white-space: nowrap; max-width: 180px; }
  .user-chip:hover { background: var(--surface2); color: var(--text); }
  .user-chip[hidden] { display: none; }
  .user-chip-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--low, #3b8b5a); flex: 0 0 auto; }
  .user-chip-name { overflow: hidden; text-overflow: ellipsis; }
  .user-menu { position: fixed; z-index: 260; min-width: 200px; background: var(--surface);
               border: 1px solid var(--border); border-radius: 10px; padding: 6px;
               box-shadow: 0 8px 28px rgba(0,0,0,0.16); display: flex; flex-direction: column; }
  .user-menu[hidden] { display: none; }
  .user-menu-who { font-size: 11px; color: var(--text3); padding: 6px 10px 8px; border-bottom: 1px solid var(--border); margin-bottom: 4px; }
  .user-menu button { text-align: left; font-family: var(--font); font-size: 13px; color: var(--text);
                      background: none; border: 0; border-radius: 6px; padding: 8px 10px; cursor: pointer; }
  .user-menu button:hover { background: var(--surface2); }
  .user-menu button[hidden] { display: none; }
  .fd-form-msg { min-height: 18px; margin-top: 10px; font-size: 12px; color: var(--high); }
  #usersMsg { color: var(--text2); }
  /* Sign-in sits above everything, and nothing behind it is reachable while it is open. */
  .modal-overlay.fd-login { z-index: 400; background: var(--bg, #f4f3ef); }
  .dark .modal-overlay.fd-login { background: var(--bg, #161614); }
  .fd-login-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; font-size: 17px; font-weight: 600; color: var(--text); }
  .fd-login-brand .brand-mark { width: 30px; height: 30px; }
  body.fd-login-open { overflow: hidden; }
  .ua-list { display: flex; flex-direction: column; max-height: 42vh; overflow-y: auto; margin-bottom: 14px; }
  .ua-row { display: grid; grid-template-columns: 1fr auto; gap: 4px 12px; align-items: center;
            padding: 9px 0; border-bottom: 1px solid var(--border); font-size: 13px; color: var(--text); }
  .ua-row.ua-disabled .ua-name { opacity: 0.55; }
  .ua-user { color: var(--text3); font-size: 12px; margin-left: 4px; }
  .ua-role { font-size: 11.5px; color: var(--text2); text-align: right; }
  .ua-acts { grid-column: 1 / -1; display: flex; gap: 6px; flex-wrap: wrap; }
  .ua-new { display: flex; flex-direction: column; gap: 8px; border-top: 1px solid var(--border); padding-top: 12px; }
  .ua-new-row { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
  .ua-new .modal-submit { align-self: flex-start; }
  .ua-admin { font-size: 12.5px; color: var(--text2); display: flex; align-items: center; gap: 6px; }
  .cf-list { margin: 4px 0 14px; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; font-size: 13px; color: var(--text); }
  .cf-kind { font-size: 10px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text3); }
  .cf-who { color: var(--text2); }
  @media (max-width: 560px) { .ua-new-row { grid-template-columns: 1fr; } }
