/* ============================================================================
   PERCIVAL — style.css
   Governance · Risk · Compliance  |  sinanaugustus.com
   ----------------------------------------------------------------------------
   Core CSS framework. All colour, spacing, and type decisions are defined
   once as :root custom properties and reused throughout. Retheme the entire
   application by editing Section 1 only.

   Colour rule: the seven brand/risk colours are fixed. Surface, border, and
   hover tones are NOT new colours — they are alpha-derived from the navy
   palette, plus neutral white. No additional hues are introduced.

   Section index:
     1. Custom properties (palette, risk, derived tones, type, spacing)
     2. Reset & base
     3. Typography
     4. Application layout (header / sidebar / main grid)
     5. Header & brand wordmark
     6. Sidebar navigation
     7. Main content & view panels
     8. Components — cards
     9. Components — buttons
    10. Components — tables
    11. Components — forms
    12. Components — badges (status & risk)
    13. Utilities
    14. Responsive (mobile)
    15. Accessibility (focus & reduced motion)
   ============================================================================ */


/* ----------------------------------------------------------------------------
   1. CUSTOM PROPERTIES
   ---------------------------------------------------------------------------- */
:root {

    /* --- Fixed brand palette (do not alter without instruction) --- */
    --colour-navy:   #1A2B4C;   /* Dominant base — authority, stability */
    --colour-steel:  #4A6984;   /* Secondary tone — approachable, trustworthy */
    --colour-gold:   #D4AF37;   /* Accent — premium quality, vigilance */
    --colour-ice:    #F4F7F9;   /* Background neutral — maximum readability */

    /* --- Fixed risk heat-map palette (do not alter without instruction) --- */
    --risk-high:     #8B1A1A;   /* High risk */
    --risk-medium:   #C17F24;   /* Medium risk */
    --risk-low:      #2D6A4F;   /* Low risk */

    /* --- CSMP Unit 1 five-band IRV palette --------------------------------
       Authorised extension (owner instruction, Session 3). Renders the five
       CSMP bands in their authentic colours rather than mapping onto three.
       Negligible / Moderate / High reuse the existing palette; Low (yellow)
       and Extreme (near-black) are the two new additions. These become the
       canonical heat-map colours for Module 7. */
    --band-negligible: #2D6A4F;   /* green   — reuses risk-low */
    --band-low:        #E0B62D;   /* yellow  — NEW */
    --band-moderate:   #C17F24;   /* amber   — reuses risk-medium */
    --band-high:       #8B1A1A;   /* crimson — reuses risk-high */
    --band-extreme:    #1A1A22;   /* near-black — NEW (navy-tinted) */

    /* --- Neutral surface --- */
    --colour-white:  #FFFFFF;   /* Card / panel surfaces against the ice base */

    /* --- Derived tones (alpha of navy — NOT new hues) --- */
    --tone-border:        rgba(26, 43, 76, 0.12);  /* hairline dividers, table rules */
    --tone-border-strong: rgba(26, 43, 76, 0.22);  /* input borders, emphasis */
    --tone-hover:         rgba(26, 43, 76, 0.05);   /* row / control hover wash */
    --tone-shadow:        rgba(26, 43, 76, 0.10);   /* card elevation */
    --tone-overlay:       rgba(26, 43, 76, 0.55);   /* modal scrim (future use) */

    /* --- Derived gold tones --- */
    --gold-soft:     rgba(212, 175, 55, 0.16);      /* subtle accent fill */

    /* --- Type scale (1.250 major-third ratio) --- */
    --font-display: Georgia, 'Times New Roman', serif;     /* wordmark & headings — built-in, no dependency */
    --font-body:    system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --font-mono:    ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

    --text-xs:   0.75rem;    /* 12px — captions, badges */
    --text-sm:   0.875rem;   /* 14px — secondary text */
    --text-base: 1rem;       /* 16px — body */
    --text-md:   1.25rem;    /* 20px — sub-headings */
    --text-lg:   1.563rem;   /* 25px — section headings */
    --text-xl:   1.953rem;   /* 31px — page titles */

    /* --- Spacing scale --- */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;

    /* --- Structural metrics --- */
    --header-height: 64px;
    --sidebar-width: 256px;
    --radius:        6px;
    --radius-sm:     4px;
    --transition:    150ms ease;
}


/* ----------------------------------------------------------------------------
   2. RESET & BASE
   ---------------------------------------------------------------------------- */
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html {
    font-size: 100%;
    -webkit-text-size-adjust: 100%;
}

body {
    font-family: var(--font-body);
    font-size: var(--text-base);
    line-height: 1.55;
    color: var(--colour-navy);
    background-color: var(--colour-ice);
    -webkit-font-smoothing: antialiased;
}


/* ----------------------------------------------------------------------------
   3. TYPOGRAPHY
   ---------------------------------------------------------------------------- */
h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-weight: 600;
    line-height: 1.2;
    color: var(--colour-navy);
}

h1 { font-size: var(--text-xl); }
h2 { font-size: var(--text-lg); }
h3 { font-size: var(--text-md); }
h4 { font-size: var(--text-base); }

p { margin-bottom: var(--space-4); }

a {
    color: var(--colour-steel);
    text-decoration: none;
    transition: color var(--transition);
}
a:hover { color: var(--colour-navy); }


/* ----------------------------------------------------------------------------
   4. APPLICATION LAYOUT
   CSS grid: fixed header row, then a sidebar + main content row.
   ---------------------------------------------------------------------------- */
.app {
    display: grid;
    grid-template-columns: var(--sidebar-width) 1fr;
    grid-template-rows: var(--header-height) 1fr auto;
    grid-template-areas:
        "header header"
        "sidebar main"
        "footer footer";
    min-height: 100vh;
}

.app__header  { grid-area: header; }
.app__sidebar { grid-area: sidebar; }
.app__main    { grid-area: main; }
.app__footer  { grid-area: footer; }


/* ----------------------------------------------------------------------------
   5. HEADER & BRAND WORDMARK
   Navy bar spanning full width, separated from the body by a gold hairline.
   ---------------------------------------------------------------------------- */
.app__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 var(--space-5);
    background-color: var(--colour-navy);
    border-bottom: 2px solid var(--colour-gold);   /* signature gold hairline */
}

/* Brand wordmark: serif "Percival" with a leading gold marker. */
.brand {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
}
.brand__mark {
    font-family: var(--font-display);
    font-size: var(--text-md);
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--colour-ice);
}
.brand__mark::before {
    content: "";
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: var(--space-3);
    background-color: var(--colour-gold);          /* gold vigilance dot */
    border-radius: 50%;
    vertical-align: middle;
}
.brand__tagline {
    font-size: var(--text-xs);
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--colour-steel);
}

/* Version label on the right of the header. */
.header__meta {
    font-size: var(--text-xs);
    letter-spacing: 0.04em;
    color: var(--colour-steel);
}

/* App shell footer — thin navy strip, gold hairline echoing the header,
   present on every authenticated view (Session 103). Version string only;
   no navigation, matches the login/share/status page footer precedent. */
.app__footer {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-3) var(--space-5);
    background-color: var(--colour-navy);
    border-top: 1px solid var(--colour-gold);
    font-size: var(--text-xs);
    letter-spacing: 0.06em;
    color: var(--colour-steel);
}


/* ----------------------------------------------------------------------------
   6. SIDEBAR NAVIGATION
   Navy column with grouped module links; gold marker shows the active route.
   ---------------------------------------------------------------------------- */
.app__sidebar {
    background-color: var(--colour-navy);
    border-right: 1px solid var(--colour-gold);
    padding: var(--space-5) 0;
    overflow-y: auto;
}

/* Group label (e.g. "Risk", "Compliance"). */
.nav__group-label {
    padding: var(--space-4) var(--space-5) var(--space-2);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--colour-gold);
}

.nav__list { list-style: none; }

/* Individual navigation link. */
.nav__link {
    display: block;
    padding: var(--space-3) var(--space-5);
    font-size: var(--text-sm);
    color: var(--colour-ice);
    border-left: 3px solid transparent;
    transition: background-color var(--transition), border-color var(--transition);
}
.nav__link:hover {
    background-color: rgba(244, 247, 249, 0.06);    /* faint ice wash on navy */
    color: var(--colour-ice);
}

/* Active route: gold left marker + soft fill. */
.nav__link.is-active {
    background-color: var(--gold-soft);
    border-left-color: var(--colour-gold);
    color: var(--colour-ice);
    font-weight: 600;
}


/* ----------------------------------------------------------------------------
   7. MAIN CONTENT & VIEW PANELS
   ---------------------------------------------------------------------------- */
.app__main {
    padding: var(--space-6) var(--space-6);
    overflow-y: auto;
}

/* Page header within a view: title + optional supporting line. */
.view__header {
    margin-bottom: var(--space-5);
    padding-bottom: var(--space-4);
    border-bottom: 1px solid var(--tone-border);
}
.view__title { margin-bottom: var(--space-1); }
.view__subtitle {
    font-size: var(--text-sm);
    color: var(--colour-steel);
}


/* ----------------------------------------------------------------------------
   8. COMPONENTS — CARDS
   ---------------------------------------------------------------------------- */
.card {
    background-color: var(--colour-white);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius);
    box-shadow: 0 1px 3px var(--tone-shadow);
    padding: var(--space-5);
}
.card__title {
    font-size: var(--text-md);
    margin-bottom: var(--space-3);
}

/* Responsive grid for laying out multiple cards. */
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-4);
}


/* ----------------------------------------------------------------------------
   9. COMPONENTS — BUTTONS
   ---------------------------------------------------------------------------- */
.btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1.4;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background-color var(--transition), border-color var(--transition);
}

/* Primary action — navy fill. */
.btn--primary {
    background-color: var(--colour-navy);
    color: var(--colour-ice);
}
.btn--primary:hover { background-color: var(--colour-steel); }

/* Secondary action — outlined. */
.btn--secondary {
    background-color: transparent;
    border-color: var(--tone-border-strong);
    color: var(--colour-navy);
}
.btn--secondary:hover { background-color: var(--tone-hover); }

/* Accent action — gold, reserved for sparing emphasis. */
.btn--accent {
    background-color: var(--colour-gold);
    color: var(--colour-navy);
}
.btn--accent:hover { filter: brightness(0.94); }


/* ----------------------------------------------------------------------------
   10. COMPONENTS — TABLES
   ---------------------------------------------------------------------------- */
.table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
}
.table th,
.table td {
    padding: var(--space-3) var(--space-4);
    text-align: left;
    border-bottom: 1px solid var(--tone-border);
    vertical-align: middle;   /* centre every cell so badge/action/multi-line cells share the row baseline */
}
.table th {
    font-weight: 600;
    color: var(--colour-steel);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-size: var(--text-xs);
}
.table tbody tr:hover { background-color: var(--tone-hover); }


/* ----------------------------------------------------------------------------
   11. COMPONENTS — FORMS
   ---------------------------------------------------------------------------- */
.field { margin-bottom: var(--space-4); }

.field__label {
    display: block;
    margin-bottom: var(--space-2);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--colour-navy);
}

.field__input,
.field__select,
.field__textarea {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    background-color: var(--colour-white);
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius-sm);
    transition: border-color var(--transition), box-shadow var(--transition);
}
.field__input:focus,
.field__select:focus,
.field__textarea:focus {
    outline: none;
    border-color: var(--colour-steel);
    box-shadow: 0 0 0 3px var(--gold-soft);
}
.field__textarea { min-height: 96px; resize: vertical; }


/* ----------------------------------------------------------------------------
   12. COMPONENTS — BADGES (status & risk)
   ---------------------------------------------------------------------------- */
.badge {
    display: inline-block;
    padding: 2px var(--space-3);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    border-radius: 999px;
    white-space: nowrap;
}

/* Build-status badges (used on the dashboard module grid). */
.badge--not-started {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}
.badge--in-progress {
    background-color: var(--gold-soft);
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--complete {
    background-color: rgba(45, 106, 79, 0.14);
    color: var(--risk-low);
    border: 1px solid var(--risk-low);
}

/* Risk-level badges — drive heat-map colour consistency across modules. */
.badge--risk-high {
    background-color: var(--risk-high);
    color: var(--colour-ice);
}
.badge--risk-medium {
    background-color: var(--risk-medium);
    color: var(--colour-ice);
}
.badge--risk-low {
    background-color: var(--risk-low);
    color: var(--colour-ice);
}

/* CSMP five-band IRV badges. Light bands carry navy text for contrast;
   dark bands carry ice text. Colours sourced from the band-* variables. */
.badge--band-negligible {
    background-color: var(--band-negligible);
    color: var(--colour-ice);
}
.badge--band-low {
    background-color: var(--band-low);
    color: var(--colour-navy);          /* dark text on yellow for legibility */
}
.badge--band-moderate {
    background-color: var(--band-moderate);
    color: var(--colour-ice);
}
.badge--band-high {
    background-color: var(--band-high);
    color: var(--colour-ice);
}
.badge--band-extreme {
    background-color: var(--band-extreme);
    color: var(--colour-ice);
}


/* ----------------------------------------------------------------------------
   13. UTILITIES
   ---------------------------------------------------------------------------- */
.u-muted      { color: var(--colour-steel); }
.u-mono       { font-family: var(--font-mono); }
.u-mt-4       { margin-top: var(--space-4); }
.u-mb-4       { margin-bottom: var(--space-4); }
.u-flex-between { display: flex; align-items: center; justify-content: space-between; }


/* ----------------------------------------------------------------------------
   14. RESPONSIVE (mobile)
   Below 860px the sidebar collapses above the content as a horizontal bar.
   ---------------------------------------------------------------------------- */
@media (max-width: 860px) {
    .app {
        grid-template-columns: 1fr;
        grid-template-rows: var(--header-height) auto 1fr auto;
        grid-template-areas:
            "header"
            "sidebar"
            "main"
            "footer";
    }
    .app__sidebar {
        border-right: none;
        border-bottom: 1px solid var(--colour-gold);
        padding: var(--space-3) 0;
    }
    .nav__list {
        display: flex;
        flex-wrap: wrap;
    }
    .nav__group-label { display: none; }
    .nav__link { border-left: none; border-bottom: 3px solid transparent; }
    .nav__link.is-active { border-left: none; border-bottom-color: var(--colour-gold); }
    .app__main { padding: var(--space-5) var(--space-4); }
}


/* ----------------------------------------------------------------------------
   15. ACCESSIBILITY (focus & reduced motion)
   ---------------------------------------------------------------------------- */
:focus-visible {
    outline: 2px solid var(--colour-gold);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    * {
        transition: none !important;
        scroll-behavior: auto !important;
    }
}


/* ----------------------------------------------------------------------------
   16. MODULE 2 — RISK REGISTER
   Layout and small components for the risk register view. Uses existing
   palette variables only — introduces no new colours.
   ---------------------------------------------------------------------------- */

/* Small button variant for inline table/form actions. */
.btn--sm {
    padding: var(--space-1) var(--space-3);
    font-size: var(--text-xs);
}

/* Horizontal scroll guard for the register table on narrow viewports. */
.risk-table-wrap { overflow-x: auto; }

/* Numeric cells and secondary sub-line in the risk table. */
.risk-num     { text-align: center; font-family: var(--font-mono); }
.risk-subline { font-size: var(--text-xs); margin-top: 2px; }

/* Action button cluster in the last table column. A <td> must NOT be
   display:flex (it stops behaving as a table-cell and misaligns the row);
   keep it a normal cell and space the buttons with inline-block + margin. */
.risk-actions {
    white-space: nowrap;
}
.risk-actions .btn {
    margin-right: var(--space-2);
}
.risk-actions .btn:last-child {
    margin-right: 0;
}

/* Monospace score chip — used in the table and the live form preview. */
.score-chip {
    display: inline-block;
    min-width: 28px;
    padding: 2px var(--space-2);
    font-family: var(--font-mono);
    font-weight: 600;
    text-align: center;
    color: var(--colour-navy);
    background-color: var(--tone-hover);
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius-sm);
}

/* Add / edit form: responsive field grid. */
.risk-form-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0 var(--space-4);
}
.risk-span-2 { grid-column: span 2; }
.risk-span-3 { grid-column: span 3; }

/* Required-field marker (uses the high-risk accent, an existing palette hue). */
.risk-req { color: var(--risk-high); font-weight: 700; }

/* Live inherent-risk preview (score chip + band badge). */
.irv-preview {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding-top: var(--space-1);
}

/* Form action row. */
.risk-form-actions {
    display: flex;
    gap: var(--space-3);
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}

/* Transient status / error line above the table. */
.risk-message {
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-4);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    border: 1px solid var(--tone-border-strong);
}
.risk-message--ok {
    color: var(--risk-low);
    background-color: rgba(45, 106, 79, 0.10);   /* alpha of existing low-risk green */
    border-color: var(--risk-low);
}
.risk-message--error {
    color: var(--risk-high);
    background-color: rgba(139, 26, 26, 0.08);   /* alpha of existing high-risk crimson */
    border-color: var(--risk-high);
}

/* Collapse the form grid to a single column on narrow viewports. */
@media (max-width: 860px) {
    .risk-form-grid { grid-template-columns: 1fr; }
    .risk-span-2,
    .risk-span-3 { grid-column: span 1; }
}


/* ----------------------------------------------------------------------------
   17. MODULE 3 — CONTROL LIBRARY
   Layout and components for the control library view. Reuses Module 2
   primitives (.btn--sm, .risk-table-wrap, .risk-num, .score-chip, .risk-form*,
   .risk-message) and introduces only the function/nature badges and the
   coverage strip.

   Colour discipline: function badges use the BRAND palette (navy / steel /
   gold / neutral tones) — NOT the risk heat-map colours. Control function and
   risk level are independent axes and must not be visually conflated. No new
   hues are introduced; all values resolve to existing :root variables.
   ---------------------------------------------------------------------------- */

/* Coverage strip: four tiles (one per protective function). */
.ctrl-coverage {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-4);
    margin-bottom: var(--space-5);
}
.ctrl-tile {
    background-color: var(--colour-white);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius);
    box-shadow: 0 1px 3px var(--tone-shadow);
    padding: var(--space-4);
}
/* A function with zero active controls is flagged as a coverage gap using the
   existing high-risk crimson as a left marker (an existing palette hue). */
.ctrl-tile--gap {
    border-left: 3px solid var(--risk-high);
}
.ctrl-tile__count {
    font-family: var(--font-mono);
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--colour-navy);
}
.ctrl-tile__gap-label {
    margin-top: var(--space-2);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--risk-high);
}

/* Function badges (Deter / Detect / Delay / Respond) — brand palette only.
   Four visually distinct treatments achieved without new hues:
     Deter   — gold accent fill (visible, vigilant deterrence)
     Detect  — steel fill
     Delay   — navy fill
     Respond — neutral outline (transparent fill, strong navy border) */
.badge--fn-deter {
    background-color: var(--gold-soft);
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--fn-detect {
    background-color: var(--colour-steel);
    color: var(--colour-ice);
}
.badge--fn-delay {
    background-color: var(--colour-navy);
    color: var(--colour-ice);
}
.badge--fn-respond {
    background-color: var(--tone-hover);
    color: var(--colour-navy);
    border: 1px solid var(--tone-border-strong);
}

/* Nature badges (Active / Passive) — subtle, secondary to the function badge. */
.badge--nature-active {
    background-color: var(--gold-soft);
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--nature-passive {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}

/* Retired controls are de-emphasised in the table. */
.ctrl-row--retired td { opacity: 0.55; }

/* Collapse the coverage strip to two columns, then one, on narrow viewports. */
@media (max-width: 860px) {
    .ctrl-coverage { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
    .ctrl-coverage { grid-template-columns: 1fr; }
}


/* ----------------------------------------------------------------------------
   17a. MODULE 3 — MULTI-FUNCTION ADDITIONS (Session 4)
   Checkbox group for selecting multiple protective functions, and wrapping
   for the multiple function badges shown per control. Existing variables only.
   ---------------------------------------------------------------------------- */

/* Function checkbox group in the add/edit form. */
.ctrl-fn-group {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    padding: var(--space-2) 0;
}
.ctrl-fn-option {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    cursor: pointer;
}
.ctrl-fn-option input { cursor: pointer; }

/* Table cell holding one-or-more function badges. A <td> must NOT be
   display:flex (it breaks table-cell row alignment); badges are inline-block
   and wrap naturally — space them with margins instead of a flex gap. */
.ctrl-fn-cell .badge {
    margin: 2px var(--space-2) 2px 0;
}


/* ----------------------------------------------------------------------------
   18. MODULE 4 — MITIGATION LAYER ENGINE
   Layout and components for the inherent->residual view. Reuses Module 2/3
   primitives (.btn--sm, .risk-table-wrap, .risk-num, .score-chip, .risk-form*,
   .risk-message, .ctrl-fn-cell, function badges).

   Colour discipline: treatment-priority badges map onto EXISTING tokens per
   Master Doc §8.1 — Low = steel, Medium = risk-medium, High = risk-high,
   Highest = band-extreme. Posture/function chips stay on neutral brand tones so
   the controls axis is never visually conflated with the risk heat map. No new
   hues are introduced.
   ---------------------------------------------------------------------------- */

/* Treatment-priority badges (§8.1 palette — existing tokens only). */
.badge--priority-low {
    background-color: var(--colour-steel);
    color: var(--colour-ice);
}
.badge--priority-medium {
    background-color: var(--risk-medium);
    color: var(--colour-ice);
}
.badge--priority-high {
    background-color: var(--risk-high);
    color: var(--colour-ice);
}
.badge--priority-highest {
    background-color: var(--band-extreme);
    color: var(--colour-ice);
}

/* Posture chip — neutral brand styling (NOT heat-mapped). */
.mit-posture {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--colour-navy);
    white-space: nowrap;
}
.mit-posture__vuln {
    font-weight: 400;
    color: var(--colour-steel);
}

/* Footnote under the overview table. */
.mit-note {
    margin-top: var(--space-3);
    font-size: var(--text-xs);
}

/* Gap figure: over target (crimson) vs met/under (green) — existing hues. */
.mit-gap--over { color: var(--risk-high); font-weight: 700; }
.mit-gap--met  { color: var(--risk-low);  font-weight: 700; }

/* Links not counting toward the posture (proposed/planned/removed) dimmed. */
.mit-link--muted td { opacity: 0.55; }

/* Detail panel summary: four analysis cells. */
.mit-detail { margin-top: var(--space-5); }
.mit-summary {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-4);
    padding-bottom: var(--space-4);
    margin-bottom: var(--space-4);
    border-bottom: 1px solid var(--tone-border);
}
.mit-summary__cell {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.mit-summary__label {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--colour-steel);
}

/* Per-function strength strip in the posture cell. */
.mit-fn-strip {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-1);
}
.mit-fn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
}
.mit-fn__score {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--colour-navy);
}
/* A function with zero in-place strength is a coverage gap. */
.mit-fn--gap .mit-fn__score {
    color: var(--risk-high);
    letter-spacing: 0.04em;
}
.mit-fn--gap .badge { opacity: 0.5; }

/* Sub-headings within the detail panel. */
.mit-subhead {
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--colour-navy);
    margin: var(--space-5) 0 var(--space-3);
}

/* Compact select variant for inline status changes in the applied table. */
.field__select--sm {
    padding: var(--space-1) var(--space-2);
    font-size: var(--text-sm);
}

/* Collapse the summary grid on narrow viewports. */
@media (max-width: 860px) {
    .mit-summary { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
    .mit-summary { grid-template-columns: 1fr; }
}


/* ----------------------------------------------------------------------------
   19. MODULE 5 — COMPLIANCE FRAMEWORK MAPPING
   Layout and components for the framework register, mapping workspace and §7.2
   gap analysis. Reuses Module 2/3/4 primitives (.card, .table, .risk-table-wrap,
   .risk-form*, .risk-message, .mit-subhead, .mit-note, .badge, .btn--sm).

   Colour discipline: framework lifecycle status uses NEUTRAL brand chips so the
   compliance axis is never conflated with the risk heat map. The risk palette is
   used ONLY for the coverage signal — a gap (an in-scope, unevidenced obligation)
   is itself a risk, so crimson is appropriate; covered is green. No new hues.
   ---------------------------------------------------------------------------- */

/* --- Framework lifecycle status chips (neutral brand tones) --- */
.badge--fw-draft {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}
.badge--fw-active {
    background-color: rgba(74, 105, 132, 0.14);   /* steel wash */
    color: var(--colour-navy);
    border: 1px solid var(--colour-steel);
}
.badge--fw-monitored {
    background-color: var(--gold-soft);
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--fw-reference {
    background-color: var(--tone-hover);
    color: var(--colour-navy);
    border: 1px solid var(--tone-border-strong);
}
/* Out-of-force states are de-emphasised. */
.badge--fw-superseded,
.badge--fw-repealed {
    background-color: transparent;
    color: var(--colour-steel);
    border: 1px dashed var(--tone-border-strong);
    text-decoration: line-through;
}

/* --- Coverage signal badges (risk palette — gap is a risk) --- */
.badge--cov-gap {
    background-color: var(--risk-high);
    color: var(--colour-ice);
}
.badge--cov-covered {
    background-color: var(--risk-low);
    color: var(--colour-ice);
}
.badge--cov-unscoped {
    background-color: var(--colour-steel);
    color: var(--colour-ice);
}

/* --- Global vs tenant-private provenance chip --- */
.cmp-scope {
    display: inline-block;
    margin-left: var(--space-2);
    padding: 1px var(--space-2);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    border-radius: 4px;
}
.cmp-scope--global {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
}
.cmp-scope--private {
    background-color: var(--gold-soft);
    color: var(--colour-navy);
}

/* --- Gap analysis summary strip --- */
.cmp-gap-summary {
    display: flex;
    gap: var(--space-5);
    flex-wrap: wrap;
    font-size: var(--text-sm);
    color: var(--colour-navy);
}
.cmp-gap-count--has  { color: var(--risk-high); }
.cmp-gap-count--none { color: var(--risk-low); }

/* Highlight an in-scope, unevidenced framework row in the gap table. */
.cmp-row--gap td { background-color: rgba(139, 26, 26, 0.06); }

/* --- Mapping workspace mode toggle --- */
.cmp-mode-toggle {
    display: inline-flex;
    gap: var(--space-2);
    margin-top: var(--space-2);
}
/* Active mode button reads as selected (gold accent, brand discipline). */
.cmp-mode-toggle .btn.is-active {
    background-color: var(--colour-navy);
    color: var(--colour-ice);
    border-color: var(--colour-navy);
}

/* --- Inline framework add/edit form panel --- */
.cmp-form-panel {
    margin-top: var(--space-4);
    padding: var(--space-4);
    background-color: var(--tone-hover);
    border: 1px solid var(--tone-border);
    border-radius: 8px;
}
.cmp-form-title {
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--colour-navy);
    margin: 0;
}


/* ----------------------------------------------------------------------------
   20. MODULE 13 — AUTHENTICATION & ACCOUNTS
   Login / password-change screens, header user block, and the users /
   organisations admin tables. Built entirely on existing tokens — no new
   colours introduced (palette is fixed, §4).
   ---------------------------------------------------------------------------- */

/* Header right-hand cluster: identity + environment meta. */
.header__right {
    display: flex;
    align-items: center;
    gap: var(--space-5);
}
.header-user {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}
.header-user__name {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--colour-ice);
}
.header-user__meta {
    font-size: var(--text-xs);
    color: var(--colour-gold);
}

/* The header bar is navy, but the default .btn--secondary is navy text on a
   transparent fill — i.e. navy-on-navy, invisible here. Invert it inside the
   header only so "Sign out" reads as a legible outlined button on the dark
   surface. Existing tokens only (ice / steel); the generic .btn--secondary
   used on light surfaces (tables, forms) is unchanged. */
.app__header .btn--secondary {
    color: var(--colour-ice);
    border-color: var(--colour-ice);
    background-color: transparent;
}
.app__header .btn--secondary:hover {
    color: var(--colour-ice);
    border-color: var(--colour-steel);
    background-color: var(--colour-steel);
}

/* Pre-authentication: collapse to a single full-bleed area — Section 74's
   login view supplies its own immersive chrome (see below), so the standard
   app header/sidebar are hidden entirely rather than framing it. Also
   applied for pending-password-change (S91): a forced rotation reached
   straight after login/MFA is already is-authenticated, but the gate
   screen (Section 74 reskin) still needs the same full-bleed treatment. */
body:not(.is-authenticated) .app,
body.pending-password-change .app {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr;
    grid-template-areas: "main";
}
body:not(.is-authenticated) .app__header,
body.pending-password-change .app__header { display: none; }
body:not(.is-authenticated) .app__sidebar,
body.pending-password-change .app__sidebar { display: none; }
body:not(.is-authenticated) .app__footer,
body.pending-password-change .app__footer { display: none; }

/* Auth screens (login + password change). */
.auth {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: var(--space-7);
}
.auth__card {
    width: 100%;
    max-width: 380px;
    padding: var(--space-6);
    background-color: var(--colour-white);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius);
    box-shadow: 0 2px 12px var(--tone-shadow);
}
.auth__title {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--text-xl);
    color: var(--colour-navy);
}
.auth__strapline {
    margin: var(--space-2) 0 var(--space-1);   /* tuck under the wordmark */
    font-family: var(--font-display);          /* echoes the Percival mark */
    font-size: var(--text-md);                 /* 20px — above body, below title */
    line-height: 1.3;
    color: var(--colour-navy);                 /* authority tone, fixed palette */
}
.auth__subtitle {
    margin: var(--space-1) 0 var(--space-5);
    font-size: var(--text-sm);
    color: var(--colour-steel);
}
.auth__hint {
    font-weight: 400;
    color: var(--colour-steel);
}
.auth__submit { width: 100%; margin-top: var(--space-2); }

/* Inline error banner (reuses the high-risk colour for emphasis). */
.auth__error {
    margin-bottom: var(--space-4);
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-sm);
    color: var(--colour-white);
    background-color: var(--risk-high);
    border-radius: var(--radius-sm);
}
/* Success variant of the same banner (S113 — e.g. "user suspended" confirmation). */
.auth__error--ok {
    background-color: var(--risk-low);
}

/* Admin add-forms: two-column field grid that collapses on narrow screens. */
.admin-form {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}
@media (max-width: 720px) {
    .admin-form { grid-template-columns: 1fr; }
}

/* Compact inline inputs used inside admin table rows. */
.field__input--inline,
.field__select--inline {
    padding: var(--space-1) var(--space-2);
    font-size: var(--text-sm);
}

/* Generic data table for the admin views. */
.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
}
.data-table th,
.data-table td {
    padding: var(--space-2) var(--space-3);
    text-align: left;
    border-bottom: 1px solid var(--tone-border);
    vertical-align: middle;
}
.data-table th {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colour-steel);
}
.data-table tbody tr:hover { background-color: var(--tone-hover); }


/* ----------------------------------------------------------------------------
   21. MODULE 6 — POLICY & DOCUMENT REPOSITORY
   Layout and components for the document register, inline form and the
   detail/linkage panel. Reuses Module 2/5 primitives (.card, .table,
   .risk-table-wrap, .field*, .risk-form-grid, .risk-span-*, .risk-form-actions,
   .risk-message, .badge, .btn--sm, .u-mono).

   Colour discipline: lifecycle status uses NEUTRAL brand chips (the same family
   as the framework status chips) so the governance axis is never conflated with
   the risk heat map. The risk palette is reused ONLY for the review-OVERDUE
   signal (.badge--risk-high) and the destructive .btn--danger — an out-of-date
   governing document, like a destructive delete, is a genuine risk. No new hues
   are introduced; every value resolves to an existing :root variable.
   ---------------------------------------------------------------------------- */

/* --- Lifecycle status chips (neutral brand tones; mirror .badge--fw-*) --- */
.badge--pol-draft {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}
.badge--pol-active {
    background-color: rgba(74, 105, 132, 0.14);    /* steel wash */
    color: var(--colour-navy);
    border: 1px solid var(--colour-steel);
}
.badge--pol-under_review {
    background-color: var(--gold-soft);            /* gold = attention/in-flight */
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
/* Out-of-use states are de-emphasised (retained for record). */
.badge--pol-superseded,
.badge--pol-archived,
.badge--pol-withdrawn {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px dashed var(--tone-border-strong);
}

/* --- Register: type group heading --- */
.pol-group {
    margin: var(--space-5) 0 var(--space-2);
    font-size: var(--text-sm);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colour-steel);
}
.pol-group:first-child { margin-top: var(--space-2); }

/* --- Register: link-count chips (R / C / F) --- */
.pol-count {
    display: inline-block;
    padding: 0 var(--space-2);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--colour-navy);
    background-color: var(--tone-hover);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
}

/* --- Register: file reference link --- */
.pol-file {
    font-size: var(--text-sm);
    word-break: break-all;          /* long paths/URLs wrap rather than overflow */
}

/* --- Inline form: hint line beneath the grid --- */
.pol-form-hint {
    margin: var(--space-3) 0 0;
    font-size: var(--text-xs);
}

/* --- Detail / linkage panel --- */
.pol-linksets {
    display: grid;
    grid-template-columns: repeat(3, 1fr);   /* risks | controls | frameworks */
    gap: var(--space-4);
}
.pol-linkset {
    padding: var(--space-3);
    background-color: var(--colour-white);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
}
.pol-linkset__head {
    margin: 0 0 var(--space-2);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    border-bottom: 1px solid var(--tone-border);
    padding-bottom: var(--space-2);
}
.pol-link-list {
    list-style: none;
    margin: 0 0 var(--space-3);
    padding: 0;
}
.pol-link {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--tone-border);
    font-size: var(--text-sm);
}
.pol-link:last-child { border-bottom: none; }
.pol-link--empty { color: var(--colour-steel); }
.pol-link__ref {
    flex: 0 0 auto;
    color: var(--colour-steel);
}
.pol-link__name {
    flex: 1 1 auto;
    color: var(--colour-navy);
}
/* The add-link row: picker + button. */
.pol-link-add {
    display: flex;
    gap: var(--space-2);
    align-items: center;
}
.pol-link-add .field__select,
.pol-link-add select {
    flex: 1 1 auto;
    width: auto;
    padding: var(--space-2) var(--space-3);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    background-color: var(--colour-white);
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius-sm);
}

/* --- Destructive action button (reuses --risk-high; no new hue) --- */
.btn--danger {
    background-color: var(--risk-high);
    color: var(--colour-ice);
}
.btn--danger:hover { filter: brightness(0.92); }

/* --- Utility: prevent action-cell button wrapping --- */
.u-nowrap { white-space: nowrap; }

/* Stack the linkage columns on narrow viewports. */
@media (max-width: 720px) {
    .pol-linksets { grid-template-columns: 1fr; }
}


/* ----------------------------------------------------------------------------
   22. MODULE 7 — DASHBOARD & HEAT MAPS
   ----------------------------------------------------------------------------
   Read-only overview. Reuses existing primitives (.card, .card-grid, .badge,
   .badge--cov-*, .u-muted, .risk-subline). All colour comes from existing
   tokens: the five-band CSMP IRV ramp (--band-*) drives the heat-map cells and
   band legend; the §8.1 priority palette (steel / --risk-medium / --risk-high /
   --band-extreme) drives the treatment-priority bar. No new hues are introduced.
   ---------------------------------------------------------------------------- */

/* --- KPI tiles ------------------------------------------------------------- */
.dash-kpi {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}
.dash-kpi__value {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    line-height: 1.1;
    color: var(--colour-navy);
}
.dash-kpi__label {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--colour-navy);
}
.dash-kpi__sub { font-size: var(--text-xs); }

/* Left accent rule signals the tile's state without introducing new hues:
   alert reuses the high-risk crimson, good reuses the low-risk green. */
.dash-kpi--alert   { border-left: 3px solid var(--risk-high); }
.dash-kpi--good    { border-left: 3px solid var(--risk-low); }
.dash-kpi--neutral { border-left: 3px solid var(--colour-steel); }

/* --- Two-column layout for heat maps and the gap/review panels ------------- */
.dash-grid-2 {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: var(--space-4);
}

/* --- Treatment-priority distribution bar ----------------------------------- */
.dash-prio-bar {
    display: flex;
    width: 100%;
    height: 28px;
    border-radius: var(--radius-sm);
    overflow: hidden;
    border: 1px solid var(--tone-border);
}
.dash-prio-seg {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--colour-ice);
}
/* §8.1 priority palette — existing tokens only (mirrors .badge--priority-*). */
.dash-prio-seg--low     { background-color: var(--colour-steel); }
.dash-prio-seg--medium  { background-color: var(--risk-medium); }
.dash-prio-seg--high    { background-color: var(--risk-high); }
.dash-prio-seg--highest { background-color: var(--band-extreme); }

/* --- Legends (shared by the priority bar and the heat-map band ramp) ------- */
.dash-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-4);
    font-size: var(--text-xs);
    color: var(--colour-navy);
}
.dash-legend__item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}
.dash-legend__swatch {
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 3px;
    border: 1px solid var(--tone-border-strong);
}
/* Marks the five-band IRV ramp legend, as against the treatment-priority one —
   both wear .dash-legend and are otherwise identical.

   IT DELIBERATELY SETS NOTHING, and that was measured rather than assumed. The
   obvious rule to reach for is max-width: 360px, to line the legend up with the
   .dash-heat block above it (which currently overhangs it by 10px). Applying it
   WRAPS THE LEGEND ONTO THREE LINES: its five items need 369px on one line, nine
   more than the grid is wide. A 10px overhang is a far better outcome than a
   legend three deep, so the modifier stays a semantic hook only. */
.dash-legend--bands { /* see above — capping this to the grid width wraps it */ }

/* --- Heat maps ------------------------------------------------------------- */
.dash-heat { max-width: 360px; }

/* 6-column grid: a leading Impact-axis column + the 5 likelihood columns. The
   final row carries the Likelihood-axis labels under a corner spacer. */
.dash-heat__grid {
    display: grid;
    grid-template-columns: 1.5rem repeat(5, 1fr);
    gap: 3px;
}
.dash-heat__cell {
    aspect-ratio: 1 / 1;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--colour-ice);
    border-radius: var(--radius-sm);
    background-color: var(--tone-hover);   /* neutral — unoccupied position */
    border: 1px solid var(--tone-border);
}
/* Occupied cells carry the SERVER-assigned band colour (five-band ramp). Light
   bands take navy text for contrast, matching the .badge--band-* convention. */
.dash-heat__cell--negligible { background-color: var(--band-negligible); border-color: var(--band-negligible); }
.dash-heat__cell--low        { background-color: var(--band-low);        border-color: var(--band-low); color: var(--colour-navy); }
.dash-heat__cell--moderate   { background-color: var(--band-moderate);   border-color: var(--band-moderate); }
.dash-heat__cell--high       { background-color: var(--band-high);       border-color: var(--band-high); }
.dash-heat__cell--extreme    { background-color: var(--band-extreme);    border-color: var(--band-extreme); }

/* Axis labels. */
.dash-heat__axis {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--colour-steel);
}
.dash-heat__axis--x { padding-top: var(--space-1); }
.dash-heat__corner { /* spacer beneath the impact-axis column */ }
/* The impact-axis modifier needs no rule of its own: the axis column is a fixed
   1.5rem grid track, so the digit already clears the cells by ~8px — the same
   separation --x buys with its padding-top. Declared, not deleted, so the two
   axes stay symmetrical in the markup and the modifier remains a live hook
   (the .dash-heat__corner convention above). */
.dash-heat__axis--y { /* no separation needed — the grid track supplies it */ }

.dash-heat__axis-titles {
    display: flex;
    justify-content: space-between;
    margin-top: var(--space-2);
    font-size: var(--text-xs);
    color: var(--colour-steel);
    letter-spacing: 0.04em;
}
/* The two axis NAMES ("Impact ↑", "Likelihood →"). They inherit size, colour and
   tracking from the wrapper above, but were inheriting weight 400 from the body
   while the axis NUMBERS (.dash-heat__axis) are 600 — so the scale read bolder
   than the thing it was labelling. Semibold restores the pairing. nowrap keeps
   the arrow on the same line as its word if the panel ever narrows or the label
   is translated into something longer. */
.dash-heat__axis-title {
    font-weight: 600;
    white-space: nowrap;
}
/* Positioned entirely by the wrapper's space-between — --y lands flush left and
   --x flush right against the grid's own edges. Nothing to add without
   inventing a layout the panel does not want. */
.dash-heat__axis-title--y,
.dash-heat__axis-title--x { /* placed by .dash-heat__axis-titles */ }

/* --- Gap / review detail lists --------------------------------------------- */
.dash-count {
    font-size: var(--text-sm);
    font-weight: 600;
    margin-bottom: var(--space-3);
}
.dash-count--alert { color: var(--risk-high); }

.dash-allclear {
    font-size: var(--text-sm);
    color: var(--risk-low);
    margin-bottom: 0;
}

.dash-list {
    list-style: none;
    display: flex;
    flex-direction: column;
}
.dash-list__item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--tone-border);
    font-size: var(--text-sm);
}
.dash-list__item:last-child { border-bottom: none; }
.dash-list__primary { color: var(--colour-navy); }
.dash-list__meta { font-size: var(--text-xs); }

.dash-note {
    font-size: var(--text-xs);
    margin-top: var(--space-3);
    margin-bottom: 0;
}

/* ----------------------------------------------------------------------------
   23. MODULE 8 — SITE & ASSET PROFILES
   Site register + per-site asset inventory. Reuses Module 2/6 primitives
   (.card, .table, .risk-table-wrap, .risk-form*, .risk-message, .badge,
   .btn--sm, .u-mono, .u-nowrap, .risk-subline). Two badge families are added,
   both on existing tokens — no new hues:
     - Criticality reuses the §8.1 treatment-priority palette (steel /
       --risk-medium / --risk-high / --band-extreme): criticality is a
       protection-priority axis, so it shares that idiom.
     - Lifecycle status uses NEUTRAL brand chips (mirrors .badge--pol-*):
       status is not a risk axis.
   ---------------------------------------------------------------------------- */

/* --- Criticality chips (mirror .badge--priority-*; §8.1 palette) --- */
.badge--crit-low {
    background-color: var(--colour-steel);
    color: var(--colour-ice);
}
.badge--crit-medium {
    background-color: var(--risk-medium);
    color: var(--colour-ice);
}
.badge--crit-high {
    background-color: var(--risk-high);
    color: var(--colour-ice);
}
.badge--crit-critical {
    background-color: var(--band-extreme);
    color: var(--colour-ice);
}

/* --- Lifecycle status chips (neutral brand tones; mirror .badge--pol-*) --- */
.badge--site-active {
    background-color: rgba(74, 105, 132, 0.14);    /* steel wash */
    color: var(--colour-navy);
    border: 1px solid var(--colour-steel);
}
.badge--site-inactive {
    background-color: var(--gold-soft);            /* gold = attention / mothballed */
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--site-decommissioned {
    background-color: var(--tone-hover);           /* de-emphasised, retained for record */
    color: var(--colour-steel);
    border: 1px dashed var(--tone-border-strong);
}

/* --- Register: asset / risk count chip --- */
.site-count {
    display: inline-block;
    padding: 0 var(--space-2);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--colour-navy);
    background-color: var(--tone-hover);
    border-radius: 4px;
}

/* --- Detail panel: address summary + asset sub-heading --- */
.site-detail-meta {
    font-size: var(--text-sm);
    margin: 0;
}
.site-subhead {
    margin: 0;
    font-size: var(--text-md);
    color: var(--colour-navy);
}

/* --- Inline field hint (e.g. legacy free-text site continuity note) --- */
.field__hint {
    font-size: var(--text-xs);
    margin: var(--space-1) 0 0;
}


/* ----------------------------------------------------------------------------
   24. MODULE 10 — INCIDENT LOG
   Incident register. Reuses Module 2/6/8 primitives (.card, .table,
   .risk-table-wrap, .risk-form*, .risk-message, .badge, .btn--sm, .u-mono,
   .u-nowrap, .risk-subline, .field*, .risk-span-*, .risk-form-actions). Two
   badge families are added, both on existing tokens — no new hues:
     - Severity reuses the §8.1 treatment-priority palette (steel /
       --risk-medium / --risk-high / --band-extreme): severity is a
       protection-priority axis, so it shares that idiom (mirrors
       .badge--priority-* and .badge--crit-*).
     - Lifecycle status uses NEUTRAL brand chips (mirrors .badge--site-*):
       status is not a risk axis.
   ---------------------------------------------------------------------------- */

/* --- Severity chips (mirror .badge--priority-*; §8.1 palette) --- */
.badge--sev-low {
    background-color: var(--colour-steel);
    color: var(--colour-ice);
}
.badge--sev-medium {
    background-color: var(--risk-medium);
    color: var(--colour-ice);
}
.badge--sev-high {
    background-color: var(--risk-high);
    color: var(--colour-ice);
}
.badge--sev-critical {
    background-color: var(--band-extreme);
    color: var(--colour-ice);
}

/* --- Lifecycle status chips (neutral brand tones; mirror .badge--site-*) --- */
.badge--inc-open {
    background-color: var(--gold-soft);            /* gold = live / needs attention */
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--inc-investigating {
    background-color: rgba(74, 105, 132, 0.14);    /* steel wash — in hand */
    color: var(--colour-navy);
    border: 1px solid var(--colour-steel);
}
.badge--inc-contained {
    background-color: rgba(74, 105, 132, 0.14);    /* steel wash — threat held */
    color: var(--colour-navy);
    border: 1px solid var(--colour-steel);
}
.badge--inc-closed {
    background-color: var(--tone-hover);           /* de-emphasised, retained for record */
    color: var(--colour-steel);
    border: 1px dashed var(--tone-border-strong);
}

/* --- Register: linked site / asset / risk cell --- */
.inc-links-cell {
    font-size: var(--text-sm);
    line-height: 1.5;
}
.inc-link {
    display: block;
    white-space: nowrap;
}
.inc-link__k {
    display: inline-block;
    min-width: 42px;
    font-size: var(--text-xs);
    font-weight: 700;
    color: var(--colour-steel);
}


/* ----------------------------------------------------------------------------
   25. MODULE 11 — UK LEGISLATION LIBRARY
   ----------------------------------------------------------------------------
   Read-only library over the Module 5 framework data. Reuses existing primitives
   (.card, .table, .badge, .badge--fw-* lifecycle chips, .cmp-scope provenance,
   .mit-subhead, .risk-table-wrap, .field*). All colour comes from existing
   tokens — neutral brand tones for the filter bar, mapping-count chips, the
   detail panel, the supersession chain and the reverse-mapping lists. Lifecycle
   status is the only "state" signal and it reuses the neutral Module 5 chips, so
   the compliance axis is never conflated with the risk heat map. No new hues.
   ---------------------------------------------------------------------------- */

/* --- Generic neutral badge (used for control/risk/policy status pips) ------ */
.badge--neutral {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}

/* --- Filter bar ------------------------------------------------------------ */
.leg-filter-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
    margin-top: var(--space-3);
    padding: var(--space-3);
    background-color: var(--tone-hover);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
}
.leg-filter-bar .field { margin-bottom: 0; }
/* Let the search field take the remaining row width. */
.leg-filter-search { flex: 1 1 220px; }
.leg-filter-reset { flex: 0 0 auto; }

/* --- Mapping-count chips (Controls / Risks / Policies) --------------------- */
.leg-maps-cell { white-space: nowrap; }
.leg-count {
    display: inline-block;
    margin-right: var(--space-1);
    padding: 1px var(--space-2);
    font-size: var(--text-xs);
    color: var(--colour-steel);
    background-color: transparent;
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius-sm);
}
/* Highlight a non-zero count: steel wash, navy text. */
.leg-count--has {
    color: var(--colour-navy);
    background-color: rgba(74, 105, 132, 0.14);
    border-color: var(--colour-steel);
}
.leg-count strong { font-weight: 700; }

/* In-force window cell keeps to one line where it can. */
.leg-inforce { white-space: nowrap; font-size: var(--text-sm); }

/* Highlight the row whose detail panel is open. */
.leg-row--open { background-color: var(--gold-soft); }

/* --- Detail panel ---------------------------------------------------------- */
.leg-detail { border-left: 3px solid var(--colour-gold); }

/* Meta strip: provenance + status chips and labelled facts. */
.leg-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-4);
}
.leg-meta__item { font-size: var(--text-sm); color: var(--colour-navy); }
.leg-meta__k {
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colour-steel);
    margin-right: var(--space-1);
}

/* Prose blocks (security relevance, notes). */
.leg-prose {
    margin-top: var(--space-1);
    color: var(--colour-navy);
    line-height: 1.55;
    white-space: pre-line;
}

/* In-panel deep link to Framework Mapping. */
.leg-link { color: var(--colour-steel); font-weight: 600; }
.leg-link:hover { color: var(--colour-navy); }

/* --- Supersession / amendment chain --------------------------------------- */
.leg-rel-list { list-style: none; margin: var(--space-1) 0 0; padding: 0; }
.leg-rel-item {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
    padding: var(--space-1) 0;
    border-bottom: 1px solid var(--tone-border);
    font-size: var(--text-sm);
}
.leg-rel-item:last-child { border-bottom: none; }
.leg-rel-verb {
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colour-steel);
    min-width: 110px;
}
.leg-rel-target { color: var(--colour-navy); font-weight: 600; }
.leg-rel-note { font-size: var(--text-sm); }

/* --- Reverse-mapping lists (Referenced by) -------------------------------- */
.leg-rev-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-4);
    margin-top: var(--space-2);
}
.leg-rev-block {
    background-color: var(--tone-hover);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
}
.leg-rev-title {
    margin: 0 0 var(--space-2);
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--colour-navy);
}
.leg-rev-list { list-style: none; margin: 0; padding: 0; }
.leg-rev-item {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
    padding: var(--space-1) 0;
    border-bottom: 1px solid var(--tone-border);
    font-size: var(--text-sm);
}
.leg-rev-item:last-child { border-bottom: none; }
.leg-rev-ref { font-size: var(--text-xs); color: var(--colour-steel); }
.leg-rev-name { color: var(--colour-navy); flex: 1 1 auto; }
.leg-rev-status { font-size: var(--text-xs); }

/* Stack the filter bar and reverse-mapping columns on narrow viewports. */
@media (max-width: 720px) {
    .leg-rev-grid { grid-template-columns: 1fr; }
    .leg-filter-search { flex-basis: 100%; }
}


/* ----------------------------------------------------------------------------
   26. MODULE 9 — REPORTING (+ print stylesheet)
   ----------------------------------------------------------------------------
   Read-only report pack aggregating every module. Reuses existing primitives
   (.card, .table, .risk-table-wrap, .badge families, .dash-kpi tiles, .btn,
   .mit-subhead). The only genuinely new chrome is the no-print control bar, the
   printed report masthead, and the @media print block that strips the app shell
   so the browser's native "Save as PDF" prints just the document. All colour
   comes from existing tokens — no new hues.
   ---------------------------------------------------------------------------- */

/* --- Print visibility utilities -------------------------------------------- */
.u-no-print   { /* visible on screen, removed when printing (see @media print) */ }
.u-print-only { display: none; }   /* hidden on screen, shown only when printing */

/* --- Control bar (screen only) --------------------------------------------- */
.rpt-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-4);
}
.rpt-toolbar__row { flex: 1 1 320px; }
.rpt-toolbar__label {
    display: block;
    margin-bottom: var(--space-2);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--colour-navy);
}
.rpt-toggles {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
}
.rpt-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    cursor: pointer;
}
.rpt-toolbar__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: flex-end;
}
.rpt-hint { margin: var(--space-3) 0; font-size: var(--text-sm); }

/* --- Report document ------------------------------------------------------- */
.rpt-doc { margin-top: var(--space-4); }

/* Printed masthead — serif wordmark + generation metadata. */
.rpt-dochead {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-4);
    padding-bottom: var(--space-4);
    margin-bottom: var(--space-5);
    border-bottom: 2px solid var(--colour-gold);   /* signature gold hairline */
}
.rpt-dochead__brand { display: flex; flex-direction: column; gap: var(--space-1); }
.rpt-dochead__mark {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--colour-navy);
}
.rpt-dochead__sub {
    font-size: var(--text-xs);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--colour-steel);
}
.rpt-dochead__meta {
    text-align: right;
    font-size: var(--text-sm);
    color: var(--colour-navy);
}

/* --- Sections -------------------------------------------------------------- */
.rpt-section { margin-bottom: var(--space-5); }
.rpt-section__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-3);
}
.rpt-count { margin-bottom: var(--space-3); font-size: var(--text-sm); }

/* Composite (estate) sub-tables. */
.rpt-sub { margin-top: var(--space-4); }
.rpt-sub__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}

/* Executive-summary tiles + treatment-priority line. */
.rpt-kpis { margin-bottom: var(--space-3); }
.rpt-prioline { font-size: var(--text-sm); }

/* ----------------------------------------------------------------------------
   PRINT STYLESHEET
   Strip the app chrome and all no-print controls so the browser prints only the
   report document. Used for "Save as PDF" — the zero-dependency PDF path on
   Stellar shared hosting (no server-side PDF library required).
   ---------------------------------------------------------------------------- */
@media print {

    /* Force background/badge colours to render in print/PDF. */
    *,
    *::before,
    *::after {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    /* Remove the screen chrome and every no-print control. */
    .app__header,
    .app__sidebar,
    .u-no-print {
        display: none !important;
    }
    .u-print-only { display: revert; }

    /* Collapse the app grid; let the main column own the full page width. */
    .app {
        display: block;
        min-height: 0;
    }
    .app__main {
        overflow: visible;
        padding: 0;
    }
    body { background: #fff; }

    /* Report cards print flat (no elevation / heavy borders eat ink). */
    .rpt-section,
    .card {
        box-shadow: none;
        border: 1px solid var(--tone-border);
        break-inside: auto;
    }

    /* Keep table rows intact across page breaks; let tables flow naturally. */
    .risk-table-wrap { overflow: visible; }
    .table { font-size: var(--text-xs); }
    thead { display: table-header-group; }   /* repeat headers on each page */
    tr    { break-inside: avoid; }

    /* Each major section starts on a fresh page after the summary. */
    #rpt-sec-risk,
    #rpt-sec-matrices,
    #rpt-sec-compliance,
    #rpt-sec-estate,
    #rpt-sec-incident,
    #rpt-sec-policy,
    #rpt-sec-legislation {
        break-before: page;
    }

    /* Sensible default page margins for the PDF. */
    @page { margin: 14mm; }
}


/* ----------------------------------------------------------------------------
   27. MODULE 12 — AUDIT TRAIL (read-only viewer)
   ----------------------------------------------------------------------------
   A read-only view over the append-only audit_log. Reuses existing primitives
   (.card, .table, .badge--neutral, .risk-table-wrap, .risk-subline, .field*,
   .u-mono, .u-muted, .mit-note). Neutral chrome throughout — the only colour
   signal is the existing crimson token on the security-relevant 'delete' and
   'login_failed' actions. No new hues.
   ---------------------------------------------------------------------------- */

/* --- Filter bar (mirrors the legislation filter bar) ----------------------- */
.aud-filter-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
    margin-top: var(--space-3);
    padding: var(--space-3);
    background-color: var(--tone-hover);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
}
.aud-filter-bar .field { margin-bottom: 0; }
.aud-filter-search { flex: 1 1 200px; }
.aud-filter-reset { flex: 0 0 auto; }

/* --- Event table ----------------------------------------------------------- */
.aud-table { font-size: var(--text-sm); }
.aud-time  { white-space: nowrap; font-size: var(--text-xs); color: var(--colour-navy); }
.aud-actor { font-size: var(--text-sm); color: var(--colour-navy); }
.aud-ip    { white-space: nowrap; font-size: var(--text-xs); }
.aud-summary { min-width: 240px; }

/* Action chip: neutral by default; crimson accent for security-signal actions.
   The accent is a left border + tinted text on the existing high-risk token —
   no fill, so it stays quiet but scannable. */
.aud-action { font-size: var(--text-xs); }
.aud-action--alert {
    color: var(--risk-high);
    border-color: var(--risk-high);
    background-color: rgba(139, 26, 26, 0.06);   /* alpha of existing high-risk crimson */
}

/* Entity cell: type label + monospace id. */
.aud-etype {
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--colour-steel);
}
.aud-eid { font-size: var(--text-xs); color: var(--colour-navy); }

/* Inline detail (JSON) toggle + block. */
.aud-detail-toggle {
    margin-left: var(--space-2);
    padding: 0;
    font-size: var(--text-xs);
    color: var(--colour-steel);
    background: none;
    border: none;
    border-bottom: 1px dotted var(--colour-steel);
    cursor: pointer;
}
.aud-detail-toggle:hover { color: var(--colour-navy); border-bottom-color: var(--colour-navy); }

/* Detail container (revealed under the summary). */
.aud-detail { margin-top: var(--space-2); }

/* Field-level change list for 'update' events: "Field  old → new". */
.aud-diff {
    margin: 0;
    padding: var(--space-2) var(--space-3);
    list-style: none;
    background-color: var(--tone-hover);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    font-size: var(--text-xs);
}
.aud-diff li {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-2);
    padding: 2px 0;
}
.aud-diff li + li { border-top: 1px dotted var(--tone-border); }
.aud-diff-field {
    min-width: 130px;
    font-weight: 700;
    color: var(--colour-steel);
}
.aud-diff-from { color: var(--colour-navy); text-decoration: line-through; opacity: 0.75; }
.aud-diff-arrow { color: var(--colour-steel); }
.aud-diff-to { color: var(--colour-navy); font-weight: 600; }

/* Export / print events: compact meta line. */
.aud-detail-meta {
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-xs);
    color: var(--colour-navy);
    background-color: var(--tone-hover);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
}

/* Fallback raw-JSON detail. */
.aud-detail-pre {
    margin: 0;
    padding: var(--space-2) var(--space-3);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--colour-navy);
    white-space: pre-wrap;
    word-break: break-word;
    background-color: var(--tone-hover);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
}


/* ============================================================================
   28. CAPABILITY-AWARE VIEWER MODE  (Session 16)
   ----------------------------------------------------------------------------
   Roles without can_write get a read-only render of the existing edit forms:
   the same fields, disabled, with no Save / Delete / Add / Remove / Map
   controls. Server-side gating (auth.php capability flags) is unchanged — this
   is the cosmetic layer that stops a role ever seeing a control it cannot use.
   Existing tokens only; no new hues.
   ---------------------------------------------------------------------------- */

/* Disabled field controls in a locked form: muted, clearly non-editable, but
   still fully legible. Applied by Percival.lock_inputs() via .is-readonly. */
.is-readonly .field__input:disabled,
.is-readonly .field__select:disabled,
.is-readonly .field__textarea:disabled {
    background-color: var(--tone-hover);          /* faint navy wash = inert */
    color: var(--colour-navy);                    /* keep text fully readable */
    border-color: var(--tone-border);             /* softer than an active field */
    cursor: default;
    opacity: 1;                                   /* override UA dimming — readability first */
    -webkit-text-fill-color: var(--colour-navy);  /* Safari keeps disabled text dark */
}

/* Neutral cue that the panel is a view of the record, not an editor. Reuses the
   brand neutral surface; deliberately NOT a risk hue (this is not a warning). */
.form-readonly-note {
    margin: 0 0 var(--space-3) 0;
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-sm);
    color: var(--colour-steel);
    background-color: var(--tone-hover);
    border-left: 3px solid var(--colour-steel);
    border-radius: var(--radius-sm);
}


/* ============================================================================
   29. SESSION EXPIRY WARNING  (Session 17)
   ----------------------------------------------------------------------------
   The "about to be signed out" modal raised by app.js (8A) when the idle or
   absolute session limit is within its warn window. Reuses the reserved
   --tone-overlay scrim and the standard card/button primitives; existing tokens
   only, no new hues. Hidden until app.js adds .is-visible.
   ---------------------------------------------------------------------------- */

/* Full-viewport scrim; sits above all app chrome. */
.session-timeout {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: none;                         /* shown via .is-visible */
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    background-color: var(--tone-overlay); /* navy scrim, reserved for modals */
}
.session-timeout.is-visible { display: flex; }

/* Centred dialogue panel — a card on the brand white surface. */
.session-timeout__panel {
    width: 100%;
    max-width: 420px;
    background-color: var(--colour-white);
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius);
    box-shadow: 0 8px 24px var(--tone-shadow);
    padding: var(--space-5);
}

.session-timeout__title {
    font-size: var(--text-md);
    margin-bottom: var(--space-3);
}

.session-timeout__body {
    font-size: var(--text-sm);
    color: var(--colour-steel);
    margin-bottom: var(--space-4);
}

/* The live countdown — gold accent for vigilance, navy text for legibility. */
.session-timeout__count {
    display: inline-block;
    min-width: 2ch;
    text-align: center;
    font-weight: 700;
    color: var(--colour-navy);
    background-color: var(--gold-soft);
    border-radius: var(--radius-sm);
    padding: 0 var(--space-1);
}

/* Action row — right-aligned, primary "Stay" leads. */
.session-timeout__actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
}


/* ============================================================================
   30. MODULE 10 — INCIDENT ATTACHMENTS  (Session 21)
   ----------------------------------------------------------------------------
   Supplementary-evidence panel inside the incident edit form: a file list with
   download / delete, plus an upload row (shown only to can_write roles). Reuses
   the shared primitives (.btn*, .field__input, .u-muted) and neutral brand
   tones throughout — NO new hues, NO risk heat-map colours (attachments are not
   a risk axis). The register's file-count chip mirrors the existing .inc-link
   key/value idiom.
   ---------------------------------------------------------------------------- */

/* --- Register: file-count chip (neutral; reuses the .inc-link layout) --- */
.inc-attach-chip .inc-link__k {
    color: var(--colour-steel);
}

/* --- Attachments panel: sits below the form actions, divided off --- */
.inc-attach {
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}
.inc-attach__title {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    margin: 0 0 var(--space-3);
}
.inc-attach__hint,
.inc-attach__empty {
    font-size: var(--text-sm);
    margin: 0;
}

/* --- File list --- */
.inc-att-list {
    list-style: none;
    margin: 0 0 var(--space-3);
    padding: 0;
}
.inc-att-item {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-2);
    background-color: var(--colour-white);
}
.inc-att-item:hover {
    background-color: var(--tone-hover);
}
.inc-att-item__main {
    min-width: 0;          /* allow the name to truncate rather than overflow */
}
.inc-att-item__name {
    font-weight: 600;
    color: var(--colour-navy);
    word-break: break-word;
}
.inc-att-item__desc {
    font-size: var(--text-sm);
    color: var(--colour-steel);
    margin-top: var(--space-1);
}
.inc-att-item__meta {
    font-size: var(--text-xs);
    margin-top: var(--space-1);
}
.inc-att-item__actions {
    display: flex;
    gap: var(--space-2);
    flex-shrink: 0;
    white-space: nowrap;
}

/* --- Upload row (can_write only) --- */
.inc-attach__upload {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding-top: var(--space-2);
}
.inc-attach__file {
    flex: 1 1 14rem;
    min-width: 12rem;
}
.inc-attach__desc {
    flex: 2 1 18rem;
    min-width: 12rem;
}
.inc-attach__limit {
    font-size: var(--text-xs);
}


/* ============================================================================
   31. REVIEW / APPROVAL SUBSYSTEM  (Session — review subsystem)
   ----------------------------------------------------------------------------
   Polymorphic second-pair-of-eyes review, surfaced first on the Risk Register:
   a current-state chip in the register, plus a review/approval panel inside the
   existing edit form (submit for review — can_write; record a decision —
   can_review). Review state is NOT a risk level, so the chips use neutral brand
   washes (the same idiom as the policy / framework lifecycle chips) — the risk
   heat-map crimson is reused ONLY for the live-on-read "re-review due" overdue
   flag, exactly as the policy module signals an overdue review. Existing tokens
   only; no new hues.
   ---------------------------------------------------------------------------- */

/* --- Review-state chips ---------------------------------------------------- */
/* Pending: gold wash = awaiting attention (mirrors .badge--in-progress). */
.badge--review-pending {
    background-color: var(--gold-soft);
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
/* Approved: green wash = settled (mirrors .badge--complete). */
.badge--review-approved {
    background-color: rgba(45, 106, 79, 0.14);    /* risk-low wash */
    color: var(--risk-low);
    border: 1px solid var(--risk-low);
}
/* Changes requested: steel wash = action needed, but not a failure. */
.badge--review-changes {
    background-color: rgba(74, 105, 132, 0.14);   /* steel wash */
    color: var(--colour-navy);
    border: 1px solid var(--colour-steel);
}
/* Rejected: crimson wash (NOT a solid risk-high fill — a decision, not a risk
   level), keeping the chip family visually consistent. */
.badge--review-rejected {
    background-color: rgba(139, 26, 26, 0.12);    /* risk-high wash */
    color: var(--risk-high);
    border: 1px solid var(--risk-high);
}

/* --- Review / approval panel (inside the risk edit form) ------------------- */
.rv-panel {
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}
.rv-panel__title {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    margin: 0 0 var(--space-3) 0;
}

/* Current-state summary block. */
.rv-state {
    margin-bottom: var(--space-2);
}
.rv-meta {
    font-size: var(--text-sm);
    margin: 0 0 var(--space-2) 0;
}
.rv-comments {
    font-size: var(--text-sm);
    color: var(--colour-navy);
    background-color: var(--tone-hover);
    border-left: 3px solid var(--colour-steel);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
    margin: 0 0 var(--space-3) 0;
    white-space: pre-wrap;          /* preserve reviewer line breaks */
}

/* Action blocks (submit / decision). */
.rv-action {
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px dashed var(--tone-border);
}
.rv-action__buttons {
    margin-top: var(--space-2);
    display: flex;
    gap: var(--space-2);
}
/* The decision block lays its small fields out in a responsive row. */
.rv-action--decision {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--space-3);
    align-items: end;
}
.rv-action--decision .rv-action__buttons {
    grid-column: 1 / -1;
}
/* The reviewer-comments field spans the full width of the decision grid. */
.rv-action--decision-comments {
    grid-column: 1 / -1;
}


/* ============================================================================
   32. MODULE 14 — CONTROL TEST & AUDIT CYCLE
   ----------------------------------------------------------------------------
   Tabbed view (Test Definitions / Active Audits / Past Audits), result and
   lifecycle badges, the audit working panel and its evidence rows. Reuses the
   fixed brand + risk tokens only (no new hues): result chips use the risk
   heat-map palette (a failed test IS a risk signal); audit lifecycle uses the
   neutral brand chips already established for build status.
   ============================================================================ */

/* --- Tab bar ------------------------------------------------------------- */
.at-tabs {
    display: flex;
    gap: var(--space-2);
    border-bottom: 1px solid var(--tone-border-strong);
    margin-bottom: var(--space-4);
}
.at-tab {
    appearance: none;
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    padding: var(--space-3) var(--space-4);
    font: inherit;
    font-weight: 600;
    color: var(--colour-steel);
    cursor: pointer;
}
.at-tab:hover { color: var(--colour-navy); }
.at-tab--active {
    color: var(--colour-navy);
    border-bottom-color: var(--colour-gold);
}

/* --- Result badges (risk heat-map palette, soft-fill chips) -------------- */
.badge--result-pass {
    background-color: rgba(45, 106, 79, 0.14);
    color: var(--risk-low);
    border: 1px solid var(--risk-low);
}
.badge--result-fail {
    background-color: rgba(139, 26, 26, 0.12);
    color: var(--risk-high);
    border: 1px solid var(--risk-high);
}
.badge--result-incon {
    background-color: rgba(193, 127, 36, 0.14);
    color: var(--risk-medium);
    border: 1px solid var(--risk-medium);
}

/* --- Audit lifecycle badges (neutral brand chips) ----------------------- */
.badge--audit-active {
    background-color: var(--gold-soft);
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--audit-complete {
    background-color: rgba(45, 106, 79, 0.14);
    color: var(--risk-low);
    border: 1px solid var(--risk-low);
}
.badge--audit-cancelled {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}

/* --- Overdue marker (inline next-due flag) ------------------------------- */
.at-overdue {
    display: inline-block;
    margin-left: var(--space-2);
    padding: 0 var(--space-2);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--risk-high);
    border: 1px solid var(--risk-high);
    border-radius: 999px;
}

/* --- Past-audit filter bar ----------------------------------------------- */
.at-filter { max-width: 280px; }
.at-filter__select { width: 100%; }

/* --- Audit working panel ------------------------------------------------- */
.at-audit-panel .card__title { display: flex; align-items: center; gap: var(--space-3); }
.at-audit-sub { margin: 0 0 var(--space-4); }

/* --- Evidence block ------------------------------------------------------ */
.at-ev-block { margin-top: var(--space-3); }
.at-ev-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
    padding: var(--space-3) 0;
}
.at-ev-name { font-weight: 600; }
.at-ev-empty { margin: var(--space-2) 0; }
.at-ev-upload {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-2);
}
.at-ev-file { max-width: 320px; }
.at-ev-hint { font-size: var(--text-xs); }


/* ============================================================================
   33. PHASE 3 — EXCEPTION REGISTER
   ----------------------------------------------------------------------------
   Tabbed register (Pending / Policy Exceptions / Control Exceptions), lifecycle
   status chips and the inline raise/edit panel. Reuses the fixed brand + risk
   tokens only (no new hues) and the shared form/table primitives (.card,
   .table, .risk-table-wrap, .risk-form-grid, .risk-span-*, .field*,
   .risk-form-actions). Only the exception-specific tab bar, status chips and
   inline markers are defined here; the tab bar mirrors Module 14's pattern.
   Status palette: pending = gold attention chip, approved = risk-low green,
   closed = neutral brand chip; overdue reuses the risk-high signal.
   ============================================================================ */

/* --- Tab bar (mirrors .at-tabs) ------------------------------------------ */
.exc-tabs {
    display: flex;
    gap: var(--space-2);
    border-bottom: 1px solid var(--tone-border-strong);
    margin-bottom: var(--space-4);
}
.exc-tab {
    appearance: none;
    background: transparent;
    border: 0;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    padding: var(--space-3) var(--space-4);
    font: inherit;
    font-weight: 600;
    color: var(--colour-steel);
    cursor: pointer;
}
.exc-tab:hover { color: var(--colour-navy); }
.exc-tab--active {
    color: var(--colour-navy);
    border-bottom-color: var(--colour-gold);
}

/* --- Lifecycle status chips (existing tokens only) ----------------------- */
.badge--exc-pending {
    background-color: var(--gold-soft);            /* gold = awaiting a decision */
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--exc-approved {
    background-color: rgba(45, 106, 79, 0.14);     /* green = accepted */
    color: var(--risk-low);
    border: 1px solid var(--risk-low);
}
.badge--exc-closed {
    background-color: var(--tone-hover);           /* neutral = resolved / ended */
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}

/* --- Closed rows are de-emphasised (mirror .ctrl-row--retired) ----------- */
.exc-row--closed td { opacity: 0.55; }

/* --- Overdue marker (expiry past, still open — mirror .at-overdue) -------- */
.exc-overdue {
    display: inline-block;
    margin-left: var(--space-2);
    padding: 0 var(--space-2);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--risk-high);
    border: 1px solid var(--risk-high);
    border-radius: 999px;
}

/* --- Deleted-subject marker (parent policy/control removed) --------------- */
.exc-gone {
    display: inline-block;
    margin-left: var(--space-2);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--colour-steel);
}

/* --- Subject-type sublabel ----------------------------------------------- */
.exc-subtype {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}


/* ============================================================================
   34. GLOBAL SEARCH  (Module 16 — Session 29)
   search.php · search.js
   ============================================================================ */

/* --- Search card and form ------------------------------------------------- */
.srch-card { padding: var(--space-6); }

.srch-form { display: flex; flex-direction: column; gap: var(--space-3); }

.srch-input-row {
    display: flex;
    gap: var(--space-3);
    align-items: center;
}

/* The search input stretches to fill available width beside the button. */
.srch-input {
    flex: 1 1 auto;
    padding: var(--space-3) var(--space-4);
    font-size: var(--text-base);
    font-family: var(--font-body);
    color: var(--colour-navy);
    background: var(--colour-white);
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius);
    outline: none;
    transition: border-color 0.15s;
}
.srch-input:focus {
    border-color: var(--colour-steel);
    box-shadow: 0 0 0 3px rgba(74, 105, 132, 0.18);
}
/* Remove the browser-native clear (×) button on search inputs. */
.srch-input::-webkit-search-cancel-button { display: none; }

.srch-btn { flex-shrink: 0; }

/* Hint line under the input row. */
.srch-hint { margin: 0; font-size: var(--text-sm); }

/* --- Result group cards --------------------------------------------------- */
.srch-group { margin-top: var(--space-5); }

.srch-group-heading {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

/* Count badge in the group heading — reuses existing badge token. */
.srch-count {
    font-size: var(--text-xs);
    font-weight: 700;
    padding: 0 var(--space-2);
    background: var(--gold-soft);
    border: 1px solid var(--colour-gold);
    color: var(--colour-navy);
    border-radius: 999px;
}

/* --- Result table --------------------------------------------------------- */
.srch-table {
    width: 100%;
    border-collapse: collapse;
}

.srch-row {
    border-bottom: 1px solid var(--tone-border);
}
.srch-row:last-child { border-bottom: none; }

.srch-result-cell {
    padding: var(--space-3) var(--space-2);
    vertical-align: middle;
}

/* Navigation link for each result — understated but clearly tappable. */
.srch-result-link {
    font-weight: 600;
    color: var(--colour-navy);
    text-decoration: none;
    transition: color 0.15s;
}
.srch-result-link:hover,
.srch-result-link:focus {
    color: var(--colour-steel);
    text-decoration: underline;
    outline: none;
}
.srch-result-link:focus-visible {
    outline: 2px solid var(--colour-gold);
    outline-offset: 2px;
    border-radius: 2px;
}

/* Meta context (status, IRV band, site, etc.) beside the title. */
.srch-meta {
    font-size: var(--text-sm);
}

/* --- Responsive ----------------------------------------------------------- */
@media (max-width: 640px) {
    .srch-input-row { flex-direction: column; align-items: stretch; }
    .srch-btn { width: 100%; }
}

/* ============================================================================
   35. PHASE 5 — CSV IMPORT  (Module 2 / G9a) + COMBINED EXPORT (Module 9 / G9b)
   ----------------------------------------------------------------------------
   Layout-only. All status colour is carried by reused badge families
   (.badge--band-low = create, .badge--band-moderate = update,
   .badge--risk-high = error, .badge--neutral = skipped) — no new hues. Reuses
   Module 2 primitives (.card, .table, .risk-table-wrap, .field__select,
   .risk-message, .mit-subhead, .risk-req, .btn*).
   ============================================================================ */

/* Header action cluster — Import sits beside New risk. */
.risk-head-actions {
    display: flex;
    gap: var(--space-2);
    align-items: center;
}

/* Import panel intro copy. */
.risk-import .imp-intro {
    max-width: 70ch;
    font-size: var(--text-sm);
    margin-bottom: var(--space-4);
}

/* File-choose / template / filename toolbar. */
.imp-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

/* The file input is hidden; its <label> is styled as a button. */
.imp-file-btn {
    cursor: pointer;
    margin: 0;
}

.imp-filename {
    font-size: var(--text-sm);
}

/* Sub-heading spacing within the panel (reuses .mit-subhead typography). */
.imp-section-head {
    margin: var(--space-5) 0 var(--space-3);
}

/* Column-mapping grid: field label + select per importable field. */
.imp-map-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-2) var(--space-4);
}

.imp-map-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: var(--space-2);
}

.imp-map-label {
    font-size: var(--text-sm);
    color: var(--colour-navy);
}

/* Action rows (Preview / Execute). */
.imp-actions {
    display: flex;
    gap: var(--space-3);
    margin-top: var(--space-4);
}

/* Preview summary chip row. */
.imp-summary {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

/* Preview table: keep it readable on long files. */
.imp-preview-table {
    max-height: 420px;
    overflow: auto;
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
}

/* Error rows get a faint emphasis (border only — colour stays on the badge). */
.imp-row-error {
    background: var(--tone-hover);
}

.imp-row-msgs {
    font-size: var(--text-sm);
}

/* Reporting section header: keep Export CSV + Combined export together. */
.rpt-section__actions {
    display: flex;
    gap: var(--space-2);
    flex-shrink: 0;
}

/* --- Responsive ----------------------------------------------------------- */
@media (max-width: 640px) {
    .imp-map-row { grid-template-columns: 1fr; }
    .imp-toolbar { align-items: stretch; }
    .risk-head-actions { flex-direction: column; align-items: stretch; }
}


/* ============================================================================
   36. RISK CLOSE / REOPEN MODAL  (Module 2 — G2 / G2b, deferred Phase 1)
   ----------------------------------------------------------------------------
   Focused lifecycle dialogue for closing a risk (a mandatory bounded reason +
   optional note) and for reopening a closed risk. Mirrors the Section 29
   session-expiry modal: the reserved --tone-overlay scrim plus the standard
   card / field / button primitives. Existing tokens only — no new hues.
   ---------------------------------------------------------------------------- */

/* Full-viewport scrim; sits above all app chrome. */
.risk-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: none;                         /* shown via .is-visible */
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    background-color: var(--tone-overlay); /* navy scrim, reserved for modals */
}
.risk-modal.is-visible { display: flex; }

/* Centred dialogue panel — a card on the brand white surface. */
.risk-modal__panel {
    width: 100%;
    max-width: 460px;
    background-color: var(--colour-white);
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius);
    box-shadow: 0 8px 24px var(--tone-shadow);
    padding: var(--space-5);
}

/* Dialogue heading. */
.risk-modal__title {
    font-size: var(--text-md);
    margin-bottom: var(--space-3);
}

/* Supporting copy beneath the heading. */
.risk-modal__body {
    font-size: var(--text-sm);
    color: var(--colour-steel);
    margin-bottom: var(--space-4);
}

/* Consistent vertical rhythm for the stacked reason / note fields. */
.risk-modal__panel .field { margin-bottom: var(--space-4); }

/* Action row — right-aligned; the primary action leads from the right. */
.risk-modal__actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-2);
}


/* ============================================================================
   37. REVIEW QUEUE  (Module 2 — G1f, deferred Phase 1)
   ----------------------------------------------------------------------------
   Layout for the dedicated reviewer work surface: two labelled buckets
   (awaiting decision / overdue re-review), each a count-pilled section over the
   standard .table. Reuses existing tokens and badge primitives — no new hues.
   The queue reuses the shared review panel, so no panel styles live here.
   ---------------------------------------------------------------------------- */

/* One bucket block; clear separation between the two sections. */
.queue-section {
    margin-bottom: var(--space-6);
}
.queue-section:last-child {
    margin-bottom: 0;
}

/* Section heading row — title plus a right-trailing count pill. */
.queue-section__head {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

/* Bucket title — card-title weight, kept below the view heading. */
.queue-section__title {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--text-lg);
    color: var(--colour-navy);
}

/* Count pill — inherits .badge sizing; centre the numerals. */
.queue-count {
    min-width: 1.5rem;
    text-align: center;
}

/* Empty bucket — a quiet single line in place of the table. */
.queue-empty {
    margin: 0;
    padding: var(--space-3) 0;
}


/* ============================================================================
   38. PHASE 6 — RISK INTELLIGENCE & ORGANISATION
       Tags (G22), filter bar + saved filters (G17), bulk toolbar + selection
       (G11), related-risk links modal (G24). Existing :root tokens only — no
       new hues introduced.
   ============================================================================ */

/* --- Tag chips (G22) — under a risk title and reused in pickers ------------ */
.risk-tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-top: var(--space-1);
}

.tag-chip {
    display: inline-block;
    padding: 0.1rem 0.5rem;
    font-size: var(--text-xs);
    line-height: 1.5;
    color: var(--colour-navy);
    background: var(--colour-ice);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
}

/* --- Filter bar (G17) ------------------------------------------------------ */
.risk-filter {
    margin-bottom: var(--space-4);
}

.risk-filter__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.risk-filter__row + .risk-filter__row {
    margin-top: var(--space-3);
}

.risk-filter__search {
    flex: 1 1 16rem;
    min-width: 12rem;
}

.risk-filter__check {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    white-space: nowrap;
}

.risk-filter__saved {
    padding-top: var(--space-3);
    border-top: 1px solid var(--tone-border);
}

/* --- Bulk toolbar (G11) ---------------------------------------------------- */
.risk-bulk {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
    border-left: 3px solid var(--colour-gold);
}

.risk-bulk__count {
    font-weight: 600;
    color: var(--colour-navy);
    margin-right: var(--space-1);
}

.risk-bulk__sep {
    width: 1px;
    align-self: stretch;
    margin: 0 var(--space-1);
    background: var(--tone-border);
}

.risk-bulk__tag {
    max-width: 12rem;
}

/* --- Selection column + selected row (G11) --------------------------------- */
.risk-check {
    width: 1%;
    white-space: nowrap;
    text-align: center;
}

tr.is-selected {
    background: var(--tone-hover);
}

/* --- Filtered result count ------------------------------------------------- */
.risk-result-count {
    margin: 0 0 var(--space-2);
    font-size: var(--text-sm);
}

/* --- Related-risk links modal (G24) --------------------------------------- */
.links-list {
    list-style: none;
    margin: 0 0 var(--space-3);
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.links-item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
}

.links-type {
    flex: 0 0 auto;
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colour-steel);
}

.links-target {
    flex: 1 1 auto;
}

.links-item .links-remove {
    margin-left: auto;
}

.links-empty {
    padding: var(--space-2) 0;
}

.links-add {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding-top: var(--space-3);
    border-top: 1px solid var(--tone-border);
}


/* ============================================================================
   39. MODULE 17 — PROJECT & PROGRAMME GROUPING (G10)
       Projects & Programmes view: project cards with a risk-profile bar,
       project/programme forms, the assigned-risk detail panel + assign picker,
       and the programme manager. Existing :root tokens only — no new hues
       (status/priority chips reuse the §8.1 priority palette; the profile bar
       reuses the five --band-* IRV colours).
   ============================================================================ */

/* --- View header actions + inline status line ----------------------------- */
.proj-head-actions {
    display: flex;
    gap: var(--space-2);
}
.proj-message {
    margin: var(--space-2) 0 0;
    min-height: 1.2em;
    font-size: var(--text-sm);
}
.proj-message--ok    { color: var(--risk-low); }
.proj-message--error { color: var(--risk-high); }

/* --- Project status chips (mirror the build/complete badge convention) ----- */
.badge--proj-planning {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}
.badge--proj-active {
    background-color: rgba(212, 175, 55, 0.16);   /* gold tint — derived, not a new hue */
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--proj-hold {
    background-color: var(--tone-hover);
    color: var(--colour-navy);
    border: 1px solid var(--tone-border-strong);
}
.badge--proj-complete {
    background-color: rgba(45, 106, 79, 0.14);    /* mirrors .badge--complete */
    color: var(--risk-low);
    border: 1px solid var(--risk-low);
}
.badge--proj-cancelled {
    background-color: transparent;
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
    text-decoration: line-through;
}

/* --- Priority chips (identical palette to .badge--priority-* / §8.1) -------- */
.badge--prio-low      { background-color: var(--colour-steel);  color: var(--colour-ice); }
.badge--prio-medium   { background-color: var(--risk-medium);   color: var(--colour-ice); }
.badge--prio-high     { background-color: var(--risk-high);     color: var(--colour-ice); }
.badge--prio-critical { background-color: var(--band-extreme);  color: var(--colour-ice); }

/* --- Project groups (one block per programme, then standalone) ------------- */
.proj-group {
    margin-bottom: var(--space-6);
}
.proj-group__title {
    font-size: var(--text-md);
    color: var(--colour-navy);
    margin: 0 0 var(--space-3);
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--tone-border);
}
.proj-group-meta { font-weight: 400; }

/* --- Project cards (responsive auto-fill grid) ----------------------------- */
.proj-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: var(--space-4);
}
.proj-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.proj-card__head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--space-2);
}
.proj-card__name {
    font-size: var(--text-md);
    margin: 0;
    color: var(--colour-navy);
}
.proj-card__badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    justify-content: flex-end;
}
.proj-card__desc {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--colour-steel);
}
.proj-card__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-5);
    margin: 0;
}
.proj-card__meta > div { min-width: 0; }
.proj-card__meta dt {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colour-steel);
}
.proj-card__meta dd {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--colour-navy);
}
.proj-card__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: auto;
    padding-top: var(--space-2);
    border-top: 1px solid var(--tone-border);
}

/* --- Risk-profile bar (open assigned risks by IRV band) -------------------- */
.proj-profile {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}
.proj-profile__bar {
    display: flex;
    height: 8px;
    border-radius: 999px;
    overflow: hidden;
    background-color: var(--tone-hover);
}
.proj-band { display: block; height: 100%; }
.proj-band--extreme    { background-color: var(--band-extreme); }
.proj-band--high       { background-color: var(--band-high); }
.proj-band--moderate   { background-color: var(--band-moderate); }
.proj-band--low        { background-color: var(--band-low); }
.proj-band--negligible { background-color: var(--band-negligible); }
.proj-profile__legend { font-size: var(--text-xs); }
.proj-profile-empty   { font-size: var(--text-sm); }

/* --- Project create / edit form ------------------------------------------- */
.proj-form__title,
.proj-detail__title,
.prog-panel__title,
.prog-form__title {
    font-size: var(--text-md);
    color: var(--colour-navy);
    margin: 0 0 var(--space-4);
}
.proj-form__grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-4);
}
.proj-span-2 { grid-column: 1 / -1; }
.proj-form__actions,
.proj-assign__actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-4);
}

/* --- Project detail (assigned risks + assignment) ------------------------- */
.proj-detail__head { margin-bottom: var(--space-3); }
.proj-table-wrap { overflow-x: auto; }
.proj-risk-actions { white-space: nowrap; }

.proj-assign {
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}
.proj-assign__title-head {
    font-size: var(--text-sm);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colour-steel);
    margin: 0 0 var(--space-2);
}
.proj-assign__hint { font-size: var(--text-sm); margin: 0 0 var(--space-3); }
.proj-assign__list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    max-height: 260px;
    overflow-y: auto;
    padding: var(--space-2);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
}
.proj-assign__item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
}
.proj-assign__title { flex: 1 1 auto; }
.proj-assign__cur   { font-size: var(--text-xs); }

/* --- Programme manager ----------------------------------------------------- */
.prog-panel__head { margin-bottom: var(--space-3); }
.prog-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}
.prog-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--tone-border);
}
.prog-row__main { min-width: 0; }
.prog-row__actions {
    display: flex;
    gap: var(--space-2);
    flex-shrink: 0;
}
.prog-form {
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}

/* --- Responsive: single-column forms / cards on narrow screens ------------- */
@media (max-width: 640px) {
    .proj-form__grid { grid-template-columns: 1fr; }
    .proj-cards      { grid-template-columns: 1fr; }
}


/* ============================================================================
   40. RISK MATRICES  (Module 9 — Reporting, G18 / G19)
       Two heat cross-tabs in the report pack: the inherent IRV matrix
       (Likelihood × Impact) and the §8.1 treatment-priority matrix (IRV band ×
       vulnerability posture), plus a programme/project scope selector. Existing
       :root tokens only — no new hues. Cell tints are soft washes of the five
       --band-* IRV colours (G18) and the §8.1 priority palette (G19), mixed over
       --colour-white via color-mix; a solid --colour-ice fallback paints first
       so engines without color-mix degrade to a clean neutral cell. The global
       print-color-adjust:exact rule (Section 26) carries the washes into the PDF.
   ============================================================================ */

/* --- Scope selector (sits in the section head) ----------------------------- */
.rpt-mx__scopesel {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
}
.rpt-mx__select {
    font: inherit;
    font-size: var(--text-sm);
    padding: var(--space-1) var(--space-2);
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius-sm);
    background-color: var(--colour-white);
    color: var(--colour-navy);
}

/* --- Scope caption (prints) ------------------------------------------------ */
.rpt-mx__scope {
    margin: var(--space-3) 0 var(--space-4);
    font-size: var(--text-sm);
}

/* --- Two grids side by side; stack on narrow / print ----------------------- */
.rpt-mx__grids {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: var(--space-5);
}

/* --- One matrix block ------------------------------------------------------ */
.rpt-mx__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-1);
}
.rpt-mx__head .mit-subhead { margin: 0; }
.rpt-mx__axislabel {
    margin: 0 0 var(--space-2);
    font-size: var(--text-xs);
}

/* --- The grid table -------------------------------------------------------- */
.rpt-mx__table {
    table-layout: fixed;
    border-collapse: collapse;
    width: 100%;
}
.rpt-mx__table th,
.rpt-mx__table td {
    text-align: center;
    vertical-align: middle;
    border: 1px solid var(--tone-border);
    padding: var(--space-2) var(--space-1);
}
.rpt-mx__table thead th {
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--colour-steel);
    background-color: var(--tone-hover);
    line-height: 1.2;
}
.rpt-mx__corner {
    background-color: var(--tone-hover);
    width: 2.6rem;
}
.rpt-mx__posture {
    display: block;
    font-weight: 400;
    font-size: 0.68rem;
    color: var(--colour-steel);
}

/* Row header (impact value / IRV band). */
.rpt-mx__rowhead {
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--colour-steel);
    background-color: var(--tone-hover);
    white-space: nowrap;
}
.rpt-mx__rowhead--total { color: var(--colour-navy); }

/* --- Heat cells ------------------------------------------------------------ */
.rpt-mx__cell {
    width: auto;
    height: 2.6rem;
}
.rpt-mx__n {
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--colour-navy);
}
.rpt-mx__cell--empty {
    background-color: var(--colour-white);
}
.rpt-mx__cell--empty .rpt-mx__n {
    color: var(--tone-border-strong);
    font-weight: 400;
}
/* Totals — neutral, slightly emphasised. */
.rpt-mx__cell--total {
    background-color: var(--tone-hover);
}
.rpt-mx__cell--total .rpt-mx__n { color: var(--colour-navy); }

/* G18 — inherent IRV band washes (soft tints of the five --band-* tokens).   */
.rpt-mx__cell--band-negligible { background-color: var(--colour-ice); background-color: color-mix(in srgb, var(--band-negligible) 18%, var(--colour-white)); }
.rpt-mx__cell--band-low        { background-color: var(--colour-ice); background-color: color-mix(in srgb, var(--band-low) 22%, var(--colour-white)); }
.rpt-mx__cell--band-moderate   { background-color: var(--colour-ice); background-color: color-mix(in srgb, var(--band-moderate) 22%, var(--colour-white)); }
.rpt-mx__cell--band-high       { background-color: var(--colour-ice); background-color: color-mix(in srgb, var(--band-high) 20%, var(--colour-white)); }
.rpt-mx__cell--band-extreme    { background-color: var(--colour-ice); background-color: color-mix(in srgb, var(--band-extreme) 20%, var(--colour-white)); }

/* G19 — §8.1 treatment-priority washes (soft tints of the priority palette).  */
.rpt-mx__cell--prio-low     { background-color: var(--colour-ice); background-color: color-mix(in srgb, var(--colour-steel) 16%, var(--colour-white)); }
.rpt-mx__cell--prio-medium  { background-color: var(--colour-ice); background-color: color-mix(in srgb, var(--risk-medium) 22%, var(--colour-white)); }
.rpt-mx__cell--prio-high    { background-color: var(--colour-ice); background-color: color-mix(in srgb, var(--risk-high) 20%, var(--colour-white)); }
.rpt-mx__cell--prio-highest { background-color: var(--colour-ice); background-color: color-mix(in srgb, var(--band-extreme) 20%, var(--colour-white)); }

/* --- Legend ---------------------------------------------------------------- */
.rpt-mx__legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-3);
    font-size: var(--text-xs);
}

/* --- Narrow screens: force a single column --------------------------------- */
@media (max-width: 880px) {
    .rpt-mx__grids { grid-template-columns: 1fr; }
}


/* ============================================================================
   41. RISK APPETITE  (Module 18 — G20)
   ----------------------------------------------------------------------------
   The appetite view: scoped tolerance statements measured against the live
   open-risk population. Reuses existing primitives (.card, .card-grid,
   .dash-kpi tiles, .badge families, .field, .table, .btn) — the rules below add
   only the appetite-specific scope badges, line display, within/over meter and
   the over-appetite drill-down. Existing tokens only; no new hues.
       within   -> risk-low (green)     over -> risk-high (crimson)
       unscored -> steel                breach pill -> risk-high
   ============================================================================ */

/* --- Header + inline message ----------------------------------------------- */
.appet-head-actions { display: flex; gap: var(--space-2); }

.appet-message { min-height: 1.25rem; margin: 0 0 var(--space-3); font-size: var(--text-sm); }
.appet-message--ok    { color: var(--risk-low); }
.appet-message--error { color: var(--risk-high); }

/* --- Empty state ----------------------------------------------------------- */
.appet-empty p { margin: 0 0 var(--space-2); }
.appet-empty p:last-child { margin-bottom: 0; }

/* --- Scope badges (org / programme / project) ------------------------------ */
.badge--scope-org {
    background-color: var(--colour-navy);
    color: var(--colour-ice);
}
.badge--scope-programme {
    background-color: var(--colour-steel);
    color: var(--colour-ice);
}
.badge--scope-project {
    background-color: var(--gold-soft);
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}

/* --- Statement card -------------------------------------------------------- */
.appet-card { margin-bottom: var(--space-4); }
/* A breached statement carries a crimson left rule, mirroring the alert KPI. */
.appet-card--breach { border-left: 3px solid var(--risk-high); }

.appet-card__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}
.appet-card__scope { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.appet-card__title {
    margin: 0;
    font-size: var(--text-md);
    color: var(--colour-navy);
}

/* Breach / within pill on the right of the head. */
.appet-pill {
    display: inline-block;
    padding: 2px var(--space-3);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    border-radius: 999px;
    white-space: nowrap;
}
.appet-pill--breach { background-color: var(--risk-high); color: var(--colour-ice); }
.appet-pill--ok     { background-color: rgba(45, 106, 79, 0.14); color: var(--risk-low); border: 1px solid var(--risk-low); }

/* The appetite line (max band + basis + tolerance). */
.appet-card__line {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
    font-size: var(--text-sm);
}
.appet-line__label { text-transform: uppercase; letter-spacing: 0.05em; font-size: var(--text-xs); }
.appet-line__val   { font-weight: 600; color: var(--colour-navy); }
.appet-line__sep   { color: var(--tone-border-strong); }

.appet-card__statement {
    margin: 0 0 var(--space-3);
    font-size: var(--text-sm);
    color: var(--colour-steel);
}

/* --- Within / over / unscored meter ---------------------------------------- */
.appet-meter {
    display: flex;
    width: 100%;
    height: 22px;
    border-radius: var(--radius-sm);
    overflow: hidden;
    background-color: var(--tone-hover);
}
.appet-seg {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--colour-ice);
}
.appet-seg--within   { background-color: var(--risk-low); }
.appet-seg--over     { background-color: var(--risk-high); }
.appet-seg--unscored { background-color: var(--colour-steel); }
.appet-meter-empty   { margin: 0; }

.appet-card__rollup { margin-top: var(--space-2); font-size: var(--text-sm); }

/* Per-band chips of the over-appetite risks. */
.appet-card__overbands {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
    margin-top: var(--space-3);
}
.appet-overchip { display: inline-flex; align-items: center; gap: var(--space-1); font-size: var(--text-sm); }

/* --- Foot (note + actions) ------------------------------------------------- */
.appet-card__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-top: var(--space-4);
}
.appet-card__overnote { font-size: var(--text-sm); }
.appet-card__overnote--breach { color: var(--risk-high); font-weight: 600; }
.appet-card__actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }

/* --- Over-appetite drill-down ---------------------------------------------- */
.appet-overlist { margin-top: var(--space-4); }
.appet-overlist__more { margin: var(--space-2) 0 0; font-size: var(--text-sm); }

/* --- Create / edit form ---------------------------------------------------- */
.appet-form { margin-bottom: var(--space-4); }
.appet-form__title { margin: 0 0 var(--space-4); font-size: var(--text-md); color: var(--colour-navy); }
.appet-form__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
}
.appet-span-2 { grid-column: 1 / -1; }
.appet-form__hint { margin: var(--space-4) 0 0; font-size: var(--text-sm); }
.appet-form__actions { display: flex; gap: var(--space-3); margin-top: var(--space-4); }

/* --- Narrow screens: single-column form ------------------------------------ */
@media (max-width: 880px) {
    .appet-form__grid { grid-template-columns: 1fr; }
}

/* ============================================================================
   42. INCIDENT ESCALATION → RISK  (Module 10 ⟶ Module 2 — G16)
   ----------------------------------------------------------------------------
   Two small surfaces for create-risk-from-incident:
     · the "Escalate to risk" affordance + hint on the incident form;
     · the provenance banner shown on the raised risk's edit form.
   Existing tokens only — no new hues. The provenance accent reuses the muted
   gold (--colour-gold) as a governance/heritage cue, consistent with the
   appetite-line treatment.
   ============================================================================ */

/* --- Incident form: escalate affordance ------------------------------------ */
/* The button itself reuses .btn / .btn--secondary; only the supporting hint is
   styled here so it reads as guidance rather than an error. */
.inc-escalate__hint {
    margin: var(--space-2) 0 0;
    font-size: var(--text-sm);
}

/* --- Raised-risk provenance banner (risk edit form) ------------------------- */
.risk-provenance {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    margin: var(--space-4) 0 0;
    padding: var(--space-3) var(--space-4);
    background: var(--colour-ice);
    border-left: 3px solid var(--colour-gold);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    color: var(--colour-navy);
}
.risk-provenance__icon {
    flex: 0 0 auto;
    font-size: var(--text-md);
    line-height: 1.2;
    color: var(--colour-gold);
}
.risk-provenance__text { line-height: 1.4; }


/* ============================================================================
   43. MODULE 10 — INCIDENT ACTIONS  (Session 38 — G14)
   ----------------------------------------------------------------------------
   The remedial / follow-up action workflow inside the incident edit form: a
   live remediation queue (open first, overdue first), an inline add/edit
   mini-form, a quick status select, plus the register's open/overdue chip.
   Reuses the shared primitives (.btn*, .field__*, .badge, .u-muted, .inc-link)
   and the §8.1 priority palette — NO new hues. Type and status are operational
   queue axes (neutral brand chips, NOT a risk heat-map); priority reuses the
   §8.1 .badge--priority-* palette; "overdue" is the only crimson cue and uses
   the existing --risk-high token. Mirrors the Section 30 attachments panel.
   ============================================================================ */

/* --- Action badges ---------------------------------------------------------- */
/* Type — neutral brand chips (operational axis, not a scoring input, §5.1). */
.badge--acttype-corrective,
.badge--acttype-preventive,
.badge--acttype-investigative,
.badge--acttype-follow_up {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}

/* Priority — identical palette to .badge--priority-* / §8.1 (existing tokens). */
.badge--actpri-low {
    background-color: var(--colour-steel);
    color: var(--colour-ice);
}
.badge--actpri-medium {
    background-color: var(--risk-medium);
    color: var(--colour-ice);
}
.badge--actpri-high {
    background-color: var(--risk-high);
    color: var(--colour-ice);
}

/* Status — neutral lifecycle chips ("overdue" is a live read, not a status). */
.badge--actstatus-open {
    background-color: var(--gold-soft);
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--actstatus-in_progress {
    background-color: rgba(74, 105, 132, 0.16);   /* steel wash */
    color: var(--colour-steel);
    border: 1px solid var(--colour-steel);
}
.badge--actstatus-blocked {
    background-color: rgba(139, 26, 26, 0.12);     /* faint crimson wash */
    color: var(--risk-high);
    border: 1px solid var(--risk-high);
}
.badge--actstatus-done {
    background-color: rgba(45, 106, 79, 0.14);     /* low-risk green wash */
    color: var(--risk-low);
    border: 1px solid var(--risk-low);
}
.badge--actstatus-cancelled {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}

/* --- Register: open / overdue action chip (reuses the .inc-link idiom) ------ */
.inc-action-chip .inc-link__k {
    color: var(--colour-steel);
}
.inc-action-chip--overdue .inc-link__k {
    color: var(--risk-high);
}

/* --- Actions panel: sits below the form, divided off (mirrors .inc-attach) -- */
.inc-actions {
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}
.inc-actions__head {
    margin-bottom: var(--space-3);
}
.inc-actions__title {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    margin: 0;
}
.inc-actions__hint,
.inc-actions__empty {
    font-size: var(--text-sm);
    margin: 0;
}

/* --- Action list ------------------------------------------------------------ */
.inc-act-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.inc-act-item {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-2);
    background-color: var(--colour-white);
}
.inc-act-item:hover {
    background-color: var(--tone-hover);
}
/* Overdue rows carry a crimson left rule (existing --risk-high token only). */
.inc-act-item--overdue {
    border-left: 3px solid var(--risk-high);
}
.inc-act-item__main {
    min-width: 0;          /* allow long titles to wrap rather than overflow */
}
.inc-act-item__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}
.inc-act-item__head strong {
    color: var(--colour-navy);
    word-break: break-word;
}
.inc-act-item__desc {
    font-size: var(--text-sm);
    color: var(--colour-steel);
    margin-top: var(--space-1);
}
.inc-act-item__meta {
    font-size: var(--text-xs);
    margin-top: var(--space-1);
}
.inc-act-item__side {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-shrink: 0;
    white-space: nowrap;
}

/* Due-date cue; the overdue variant reuses the crimson risk token. */
.inc-act-due--overdue {
    color: var(--risk-high);
    font-weight: 600;
}

/* Quick status <select> kept compact alongside the row buttons. */
.inc-act-status-select {
    width: auto;
    min-width: 9rem;
}

/* --- Inline add / edit mini-form ------------------------------------------- */
.inc-act-form {
    padding: var(--space-4);
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius-sm);
    background-color: var(--colour-ice);
    margin-bottom: var(--space-3);
}
.inc-act-form__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3);
}
/* A field that should span the full two-column width (title, detail). */
.inc-act-span-2 {
    grid-column: 1 / -1;
}
.inc-act-form__actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

/* Single column on narrow viewports. */
@media (max-width: 640px) {
    .inc-act-form__grid {
        grid-template-columns: 1fr;
    }
    .inc-act-item {
        flex-direction: column;
    }
    .inc-act-item__side {
        white-space: normal;
    }
}

/* --- Apply-playbook picker (incident actions panel — G15) ------------------- */
/* Shown inline above the action list when "Apply playbook" is toggled. */
.inc-actions__tools {
    display: flex;
    gap: var(--space-2);
}
.inc-act-playbook {
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--colour-gold);
    background-color: var(--gold-soft);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-3);
}
.inc-act-playbook__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-2);
}
.inc-act-playbook__row .field__select {
    flex: 1 1 16rem;
    min-width: 12rem;
    width: auto;
}
.inc-act-playbook__hint,
.inc-act-playbook__empty {
    font-size: var(--text-xs);
    margin: var(--space-2) 0 0;
}


/* ============================================================================
   44. MODULE 19 — INCIDENT PLAYBOOKS  (Session 39 — G15)
   ----------------------------------------------------------------------------
   The playbook library: a management view of reusable action templates, with an
   inline template-line editor. Reuses the shared primitives (.card, .btn*,
   .field__*, .badge, .u-muted) and the §43 action palette for the type/priority
   chips — NO new hues. Active/inactive reuse the existing build-status badges
   (.badge--complete / .badge--not-started). Mirrors the appetite (§41) and
   projects (§39) management layouts.
   ============================================================================ */

/* --- Header actions --------------------------------------------------------- */
.pb-head-actions {
    display: flex;
    gap: var(--space-2);
}

/* --- Empty state ------------------------------------------------------------ */
.pb-empty p {
    margin: 0 0 var(--space-2);
}
.pb-empty p:last-child {
    margin-bottom: 0;
}

/* --- Library cards ---------------------------------------------------------- */
.pb-card {
    margin-bottom: var(--space-4);
}
.pb-card__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
}
.pb-card__title {
    margin: var(--space-2) 0 0;
    color: var(--colour-navy);
}
.pb-card__actions {
    display: flex;
    gap: var(--space-2);
    flex-shrink: 0;
    white-space: nowrap;
}
.pb-card__meta {
    font-size: var(--text-sm);
    margin-top: var(--space-2);
}
.pb-card__desc {
    margin: var(--space-2) 0 0;
    color: var(--colour-steel);
}

/* --- Create / edit form ----------------------------------------------------- */
.pb-form {
    margin-bottom: var(--space-5);
    border-left: 3px solid var(--colour-gold);   /* edit-mode accent (existing token) */
}
.pb-form__title {
    margin: 0 0 var(--space-4);
    color: var(--colour-navy);
}
.pb-form__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3);
}
.pb-span-2 {
    grid-column: 1 / -1;
}
.pb-form__actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-4);
}

/* Inline "active" toggle (module-scoped, not a shared form primitive). */
.pb-check {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--colour-navy);
}

/* --- Template-line editor --------------------------------------------------- */
.pb-lines {
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}
.pb-lines__head {
    margin-bottom: var(--space-3);
}
.pb-lines__title {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    margin: 0;
}
.pb-lines__empty {
    font-size: var(--text-sm);
    margin: 0;
}
.pb-line {
    position: relative;
    padding: var(--space-3);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    background-color: var(--colour-white);
    margin-bottom: var(--space-2);
}
.pb-line__grid {
    display: grid;
    /* title spans wide; the management axes sit in a compact row beneath. */
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-3);
}
.pb-line__title {
    grid-column: 1 / -1;
}
.pb-line__desc {
    grid-column: 1 / -1;
}
.pb-line__remove {
    margin-top: var(--space-3);
}

/* Single column on narrow viewports. */
@media (max-width: 640px) {
    .pb-form__grid,
    .pb-line__grid {
        grid-template-columns: 1fr;
    }
    .pb-card__head {
        flex-direction: column;
    }
    .pb-card__actions {
        white-space: normal;
    }
}


/* ============================================================================
   43. INCIDENT ACTION WORKFLOW  (Module 10 — G14)
   ----------------------------------------------------------------------------
   The remedial / follow-up actions held against an incident, shown as a panel
   on the incident edit form (mirrors the attachments panel) plus an at-a-glance
   open/overdue chip in the register's links cell. Existing tokens only — no new
   hues. Action TYPE and STATUS use neutral brand chips (operational axes, not a
   risk score); action PRIORITY reuses the §8.1 priority palette exactly as
   incident severity does; OVERDUE borrows the high-risk crimson as an alert cue.
   ============================================================================ */

/* --- Register: open/overdue action chip (reuses the .inc-link layout) ------ */
.inc-action-chip .inc-link__k { color: var(--colour-steel); }
.inc-action-chip--overdue .inc-link__k,
.inc-action-chip--overdue { color: var(--risk-high); font-weight: 600; }

/* --- Actions panel: sits below the form actions, divided off (like Attachments) */
.inc-actions {
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}
.inc-actions__head { align-items: center; }
.inc-actions__title {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    margin: 0;
}
.inc-actions__hint { margin: var(--space-2) 0 0; font-size: var(--text-sm); }
.inc-actions__list { margin-top: var(--space-3); }
.inc-actions__empty { margin: var(--space-2) 0 0; }

/* --- Action list rows ------------------------------------------------------ */
.inc-act-list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.inc-act-item {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-2);
    background-color: var(--colour-white);
}
.inc-act-item:hover { background-color: var(--tone-hover); }
/* An overdue action carries a crimson left rule as a non-colour-only cue. */
.inc-act-item--overdue { border-left: 3px solid var(--risk-high); }
.inc-act-item__main { min-width: 0; }
.inc-act-item__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}
.inc-act-item__head strong { color: var(--colour-navy); word-break: break-word; }
.inc-act-item__desc {
    font-size: var(--text-sm);
    color: var(--colour-steel);
    margin-top: var(--space-1);
}
.inc-act-item__meta {
    font-size: var(--text-xs);
    margin-top: var(--space-1);
}
.inc-act-due { white-space: nowrap; }
.inc-act-due--overdue { color: var(--risk-high); font-weight: 600; }
.inc-act-item__side {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-shrink: 0;
    flex-wrap: wrap;
    justify-content: flex-end;
    white-space: nowrap;
}
.inc-act-status-select { min-width: 130px; }

/* --- Inline add/edit mini-form --------------------------------------------- */
.inc-act-form {
    margin: var(--space-3) 0;
    padding: var(--space-4);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    background-color: var(--colour-ice);
}
.inc-act-form__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-3);
}
.inc-act-span-2 { grid-column: span 2; }
.inc-act-form__actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

/* --- Action TYPE chips (neutral brand tones; mirror .badge--fw-*) ----------- */
.badge--acttype-corrective,
.badge--acttype-preventive,
.badge--acttype-investigative,
.badge--acttype-follow_up {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}

/* --- Action PRIORITY chips (reuse the §8.1 priority palette) ---------------- */
.badge--actpri-low {
    background-color: var(--colour-steel);
    color: var(--colour-ice);
}
.badge--actpri-medium {
    background-color: var(--risk-medium);
    color: var(--colour-ice);
}
.badge--actpri-high {
    background-color: var(--risk-high);
    color: var(--colour-ice);
}

/* --- Action STATUS chips (neutral lifecycle chips; read-only fallback) ------ */
.badge--actstatus-open {
    background-color: var(--gold-soft);             /* gold = live / needs attention */
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--actstatus-in_progress {
    background-color: rgba(74, 105, 132, 0.14);     /* steel wash — in hand */
    color: var(--colour-navy);
    border: 1px solid var(--colour-steel);
}
.badge--actstatus-blocked {
    background-color: rgba(139, 26, 26, 0.10);      /* faint crimson — stalled */
    color: var(--risk-high);
    border: 1px solid var(--risk-high);
}
.badge--actstatus-done {
    background-color: rgba(45, 106, 79, 0.14);      /* green wash — complete */
    color: var(--risk-low);
    border: 1px solid var(--risk-low);
}
.badge--actstatus-cancelled {
    background-color: var(--tone-hover);            /* de-emphasised, stood down */
    color: var(--colour-steel);
    border: 1px dashed var(--tone-border-strong);
}

/* --- Narrow screens: single-column action mini-form ------------------------ */
@media (max-width: 880px) {
    .inc-act-form__grid { grid-template-columns: 1fr; }
    .inc-act-span-2 { grid-column: span 1; }
}

/* ============================================================================
   45. MODULE 6 — POLICY APPROVAL WORKFLOW  (Session 40 — G25)
   ----------------------------------------------------------------------------
   Governance sign-off for a document, served by the shared review subsystem.
   Approval state chips are NEUTRAL brand tones (sign-off is not a risk axis);
   the only risk-palette reuse is the re-approval-OVERDUE cue, which reuses the
   solid .badge--risk-high (an out-of-date sign-off is itself a live exposure —
   crimson is apt), matching the file-review-overdue treatment in Section "policy
   lifecycle" above. Muted-gold accent on the panel header mirrors Section 42
   (incident→risk provenance). No new hues; all values resolve to :root tokens.
   ============================================================================ */

/* --- Approval state chips (latest review_record status) --- */
.badge--rev-pending {
    background-color: var(--gold-soft);             /* attention / in-flight */
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--rev-approved {
    background-color: rgba(45, 106, 79, 0.14);      /* green wash — signed off */
    color: var(--risk-low);
    border: 1px solid var(--risk-low);
}
.badge--rev-changes_requested {
    background-color: rgba(74, 105, 132, 0.14);     /* steel wash — back to author */
    color: var(--colour-navy);
    border: 1px solid var(--colour-steel);
}
.badge--rev-rejected {
    background-color: rgba(139, 26, 26, 0.10);      /* faint crimson outline — declined */
    color: var(--risk-high);
    border: 1px solid var(--risk-high);
}

/* --- Approval panel (top of the document detail card) --- */
.pol-appr {
    margin-bottom: var(--space-5);
    padding: var(--space-4);
    border: 1px solid var(--tone-border);
    border-left: 3px solid var(--colour-gold);      /* governance accent */
    border-radius: var(--radius-sm);
    background-color: var(--colour-ice);            /* faint inset against the white card */
}
.pol-appr__state {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
}
.pol-appr__label {
    font-size: var(--text-xs);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--colour-steel);
}
.pol-appr__meta {
    font-size: var(--text-sm);
    color: var(--colour-steel);
}
.pol-appr__comment {
    margin-top: var(--space-1);
    font-style: italic;
    color: var(--colour-navy);
}
.pol-appr__wait {
    margin-top: var(--space-3);
}

/* Submit / decision action blocks. */
.pol-appr__act,
.pol-appr__decide {
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}
.pol-appr__act .field__textarea,
.pol-appr__decide .field__textarea {
    margin-bottom: var(--space-3);
}
.pol-appr__nextrev {
    max-width: 260px;
    margin-bottom: var(--space-3);
}
.pol-appr__buttons {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* --- Approvals queue (reviewer surface above the register) --- */
.pol-queue {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-5);
}
.pol-queue__head {
    margin: 0 0 var(--space-2);
    font-size: var(--text-sm);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colour-steel);
}
.pol-queue__count {
    display: inline-block;
    min-width: 1.4em;
    padding: 0 var(--space-2);
    margin-left: var(--space-1);
    text-align: center;
    font-size: var(--text-xs);
    color: var(--colour-ice);
    background-color: var(--colour-steel);
    border-radius: 999px;
}
.pol-queue__list {
    list-style: none;
    margin: 0;
    padding: 0;
}
.pol-queue__item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--tone-border);
}
.pol-queue__ref {
    color: var(--colour-steel);
}
.pol-queue__title {
    flex: 1 1 auto;
    min-width: 8rem;
}

/* --- Narrow screens: stack the approval queue buckets --- */
@media (max-width: 880px) {
    .pol-queue { grid-template-columns: 1fr; }
    .pol-appr__nextrev { max-width: none; }
}

/* ============================================================================
   46. MODULE 8 — ASSET VALUATION, GROUPS & TAGS  (Session 42 — G21)
   ----------------------------------------------------------------------------
   Additive styles for the asset grouping / valuation / tagging surface. Existing
   tokens only — no new hues. Tag chips reuse .tag-chip (Section, G22); the asset
   group register reuses the site-register table primitives wholesale; valuation
   reuses .risk-num (right-aligned) with .risk-subline for the basis. The only
   new rule is the in-cell tag container (a tight flex row with no top margin,
   unlike .risk-tags which sits under a register row).
   ============================================================================ */

/* --- Asset tag chips: tight in-cell flex row (reuses .tag-chip) --- */
.asset-tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
}


/* ============================================================================
   47. MODULE 20 — ASSESSMENT QUESTIONNAIRES  (Session 43 — G13)
   ----------------------------------------------------------------------------
   Additive styles for the assessment surface (run + answer) and the
   questionnaire template builder. Existing tokens only — no new hues. The form
   grid / span-2 / actions / inline-check / line-editor idioms mirror the §44
   playbook builder; the instance list reuses .table / .risk-table-wrap. The
   genuinely new primitives are the segmented pane toggle (.as-tabs), the
   answered/total progress bar (.as-progress), the qualitative finding chip
   (.as-finding, tinted from the existing --risk-* band tokens: gap = high,
   concern = medium, ok = low, na = neutral steel) and the per-question answer
   row (.as-resp).
   ============================================================================ */

/* --- Segmented pane toggle (Assessments | Questionnaires) ------------------- */
.as-tabs {
    display: inline-flex;
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius-sm);
    overflow: hidden;
}
.as-tab {
    appearance: none;
    border: 0;
    background-color: var(--colour-white);
    color: var(--colour-steel);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    padding: var(--space-2) var(--space-4);
    cursor: pointer;
}
.as-tab + .as-tab {
    border-left: 1px solid var(--tone-border-strong);
}
.as-tab:hover {
    background-color: var(--tone-hover);
}
.as-tab--active {
    background-color: var(--colour-navy);
    color: var(--colour-white);
}

/* --- Pane scaffolding ------------------------------------------------------- */
.as-pane-head {
    margin-bottom: var(--space-3);
}
.as-pane-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    color: var(--colour-navy);
    margin: 0;
}
.as-empty p {
    margin: 0 0 var(--space-2) 0;
}

/* --- Shared form grid (mirrors the §44 playbook form) ----------------------- */
.as-form__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3);
}
.as-span-2 {
    grid-column: 1 / -1;
}
.as-form__actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-4);
}
.as-check {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--colour-navy);
}
.as-start__title,
.as-q-form__title {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    margin: 0 0 var(--space-3) 0;
}

/* --- Instance list: clickable subject + progress + action cluster ----------- */
.as-link {
    color: var(--colour-steel);
    font-weight: 600;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.as-link:hover {
    color: var(--colour-navy);
}
.as-row-actions {
    display: flex;
    gap: var(--space-2);
    white-space: nowrap;
}
.as-progress-cell {
    min-width: 120px;
}

/* --- Answered / total progress bar (live-on-read) --------------------------- */
.as-progress {
    display: inline-block;
    width: 84px;
    height: 8px;
    border-radius: 999px;
    background-color: var(--tone-border);
    vertical-align: middle;
    overflow: hidden;
}
.as-progress__bar {
    display: block;
    height: 100%;
    background-color: var(--colour-gold);
}
.as-progress__label {
    margin-left: var(--space-2);
    font-size: var(--text-xs);
}

/* --- Qualitative finding chips (tinted from existing band tokens) ----------- */
.as-finding {
    display: inline-block;
    padding: 1px var(--space-2);
    border-radius: var(--radius-sm);
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--colour-white);
    white-space: nowrap;
}
.as-finding--gap     { background-color: var(--risk-high); }
.as-finding--concern { background-color: var(--risk-medium); }
.as-finding--ok      { background-color: var(--risk-low); }
.as-finding--na      { background-color: var(--colour-steel); }

/* --- Answer surface: detail header + per-question rows ---------------------- */
.as-detail {
    margin-bottom: var(--space-4);
}
.as-detail__meta {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--tone-border);
}
.as-detail__prog {
    display: inline-flex;
    align-items: center;
}
.as-responses {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.as-resp {
    padding: var(--space-3) var(--space-4);
}
.as-resp__q {
    font-weight: 600;
    color: var(--colour-navy);
    margin-bottom: var(--space-3);
}
.as-resp__grid {
    display: grid;
    /* answer wide, finding + note compact alongside on a roomy viewport */
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 2fr);
    gap: var(--space-3);
    align-items: start;
}
.as-answer-actions {
    margin-top: var(--space-4);
}

/* --- Questionnaire library cards (mirror the §44 playbook card) ------------- */
.as-q-card {
    margin-bottom: var(--space-3);
}
.as-q-card__head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--space-3);
}
.as-q-card__title {
    font-family: var(--font-display);
    font-size: var(--text-base);
    color: var(--colour-navy);
    margin: var(--space-2) 0 0 0;
}
.as-q-card__actions {
    display: flex;
    gap: var(--space-2);
    white-space: nowrap;
}
.as-q-card__meta {
    margin-top: var(--space-2);
    font-size: var(--text-sm);
}
.as-q-card__desc {
    margin: var(--space-2) 0 0 0;
    font-size: var(--text-sm);
}

/* --- Questionnaire builder: inline question editor -------------------------- */
.as-q-form {
    margin-bottom: var(--space-4);
}
.as-q-lines {
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}
.as-q-lines__head {
    margin-bottom: var(--space-3);
}
.as-q-lines__title {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    margin: 0;
}
.as-q-lines__empty {
    font-size: var(--text-sm);
    margin: 0;
}
.as-lock-note {
    font-size: var(--text-sm);
    color: var(--colour-steel);
    background-color: var(--tone-hover);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
    margin: 0 0 var(--space-3) 0;
}
.as-q-line {
    position: relative;
    padding: var(--space-3);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    background-color: var(--colour-white);
    margin-bottom: var(--space-2);
}
.as-q-line__grid {
    display: grid;
    /* question text spans wide; response-type + guidance share the row beneath */
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3);
}
.as-q-line__text {
    grid-column: 1 / -1;
}
.as-q-line__remove {
    margin-top: var(--space-3);
}

/* --- Narrow viewports: collapse the multi-column grids --------------------- */
@media (max-width: 720px) {
    .as-form__grid,
    .as-resp__grid,
    .as-q-line__grid {
        grid-template-columns: minmax(0, 1fr);
    }
}


/* ============================================================================
   48. G13b — ASSESSMENT GAP -> RISK ESCALATION  (Session 44)
   ----------------------------------------------------------------------------
   Additive styles for the per-response escalation affordance on the answer
   surface (.as-resp__escalation): the "Escalate gap to risk" action for a saved
   gap finding, and the post-escalation chip (.as-escalated). Existing tokens
   only — the muted-gold accent and ice background mirror the §42 risk-
   provenance banner that the raised risk shows in return. The risk-side banner
   itself reuses .risk-provenance (Section 42) — no new rule needed here.
   ============================================================================ */

/* Escalation strip sits beneath the answer/finding/note grid, separated by a
   hairline so the gap action reads as a distinct, deliberate step. */
.as-resp__escalation {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--tone-border);
}
.as-resp__escalate-hint {
    font-size: var(--text-sm);
}

/* Post-escalation chip: gap already raised into a risk (read-only provenance). */
.as-resp__escalation--done {
    border-top-color: var(--colour-gold);
}
.as-escalated {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3);
    background: var(--colour-ice);
    border-left: 3px solid var(--colour-gold);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    color: var(--colour-navy);
}
.as-escalated strong { color: var(--colour-navy); }


/* ============================================================================
   49. G23 — ADDITIONAL STAKEHOLDERS  (Session 45)
   ----------------------------------------------------------------------------
   The wider set of people with a stake in a risk, beyond the single risk owner.
   Palette tokens only — no new hues. The in-form editor lists current
   stakeholders as removable chips with a RACI role; the register surfaces a
   compact "+N" count beside the owner. Roles are organisational only — the
   styling carries no risk-band semantics (never a scoring axis, §5.1).
   ============================================================================ */

/* --- In-form editor: current stakeholder chips --------------------------- */
.stakeholder-field .stakeholder-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: var(--space-2) 0;
}

/* A single stakeholder: name + role pill + remove control. */
.stakeholder-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-2);
    background: var(--colour-ice);
    border: 1px solid var(--tone-border);
    border-left: 3px solid var(--colour-steel);   /* steel = a person/relationship cue */
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    color: var(--colour-navy);
}

.stakeholder-chip__name { font-weight: 600; }

/* Role qualifier — quiet, uppercase, secondary tone. */
.stakeholder-chip__role {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colour-steel);
}

/* Remove (×) — inherits the chip; reddens on hover (high-risk hue as a delete cue). */
.stakeholder-chip__remove {
    border: 0;
    background: transparent;
    cursor: pointer;
    padding: 0;
    line-height: 1;
    font-size: var(--text-sm);
    color: var(--colour-steel);
}
.stakeholder-chip__remove:hover { color: var(--risk-high); }

/* --- In-form editor: the add row (user select + role select + button) ---- */
.stakeholder-field .stakeholder-add {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-2);
}
.stakeholder-field .stakeholder-add .field__select { width: auto; min-width: 12rem; }

/* --- Register: compact "+N" stakeholder count beside the owner ----------- */
.stakeholder-count {
    display: inline-block;
    padding: 0 0.4rem;
    font-size: var(--text-xs);
    font-weight: 600;
    line-height: 1.6;
    color: var(--colour-ice);
    background: var(--colour-steel);
    border-radius: var(--radius-sm);
    cursor: default;
}


/* ============================================================================
   50. MODULE 21 — NOTIFICATIONS  (Session 47 — G12)
   ----------------------------------------------------------------------------
   The per-user notification inbox and its sidebar unread badge. Palette tokens
   only — no new hues. Unread items carry a gold vigilance accent (dot + soft
   wash) reusing --colour-gold / --gold-soft; read items fall back to the muted
   neutral. A notification is a delivery artefact and carries NO risk-band
   semantics (never a scoring axis, §5.1). The sidebar badge floats right within
   the existing .nav__link (that base rule is untouched).
   ============================================================================ */

/* --- Sidebar unread badge ------------------------------------------------- */
.nav__badge {
    float: right;
    min-width: 1.25rem;
    padding: 0 var(--space-2);
    font-size: var(--text-xs);
    font-weight: 600;
    line-height: 1.25rem;
    text-align: center;
    color: var(--colour-navy);
    background: var(--colour-gold);
    border-radius: 999px;
}

/* --- Inbox toolbar: filter, email opt-in, mark-all ------------------------ */
.notif-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}
.notif-toolbar__spacer {
    flex: 1 1 auto;
}
.notif-filter {
    display: inline-flex;
    gap: var(--space-2);
}
/* Active filter button: gold accent, mirroring the active-nav treatment. */
.notif-filter .btn.is-active {
    background: var(--gold-soft);
    border-color: var(--colour-gold);
    color: var(--colour-navy);
    font-weight: 600;
}
.notif-emailpref {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    cursor: pointer;
}
.notif-emailpref input {
    cursor: pointer;
}

/* --- Notification list ---------------------------------------------------- */
.notif-list {
    display: flex;
    flex-direction: column;
}
.notif-item {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-2);
    border-bottom: 1px solid var(--tone-border);
}
.notif-item:last-child {
    border-bottom: 0;
}
.notif-item.is-clickable {
    cursor: pointer;
}
.notif-item.is-clickable:hover {
    background: var(--tone-hover);
}
/* Unread: soft gold wash so the queue reads at a glance. */
.notif-item.is-unread {
    background: var(--gold-soft);
}
.notif-item.is-unread.is-clickable:hover {
    background: var(--gold-soft);
}

/* Leading state dot — gold when unread, transparent when read. */
.notif-dot {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    margin-top: 0.4rem;
    border-radius: 50%;
    background: transparent;
}
.notif-item.is-unread .notif-dot {
    background: var(--colour-gold);
}

.notif-body {
    flex: 1 1 auto;
    min-width: 0;
}
.notif-summary {
    font-size: var(--text-sm);
    color: var(--colour-navy);
}
.notif-item.is-unread .notif-summary {
    font-weight: 600;
}
.notif-meta {
    margin-top: var(--space-1);
    font-size: var(--text-xs);
}
.notif-read-btn {
    flex: 0 0 auto;
    align-self: center;
}
.notif-empty {
    padding: var(--space-4) 0;
}
/* ============================================================================
   End of Section 50 — Notifications (G12)
   ============================================================================ */

/* ============================================================================
   SECTION 51 — Timezone preference selector (G27, Session 49)
   A compact inline display-zone picker in the Notifications toolbar, sitting
   beside the email opt-in. Existing tokens only; mirrors the .notif-emailpref
   treatment. The select is auto-width (not .field__select, which is 100%).
   ============================================================================ */
.notif-tzpref {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--colour-navy);
}
.notif-tzpref select {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    background-color: var(--colour-white);
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius-sm);
    padding: var(--space-1) var(--space-2);
    cursor: pointer;
}
/* ============================================================================
   End of Section 51 — Timezone preference (G27)
   ============================================================================ */

/* ============================================================================
   SECTION 52 — Platform Administration (S50)
   ----------------------------------------------------------------------------
   The cross-tenant Organisations view (Module 22, platform.js). Existing tokens
   only. The activation banner reuses the Section 42 left-accent idiom: muted
   gold for the open state, crimson (--risk-high) for the §4A.5 locked state.
   The one-time-password reveal reuses the ice surface + gold accent.
   ============================================================================ */

/* §4A.5 activation banner — left-accent panel, colour keyed to gate state. */
.platform-gate {
    margin: var(--space-4) 0 0;
    padding: var(--space-3) var(--space-4);
    background: var(--colour-ice);
    border-left: 3px solid var(--colour-steel);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    line-height: 1.45;
    color: var(--colour-navy);
}
/* Locked (onboarding disabled) — crimson accent + a soft crimson wash. */
.platform-gate--locked {
    border-left-color: var(--risk-high);
    background: color-mix(in srgb, var(--risk-high) 6%, var(--colour-white));
}
/* Open (onboarding enabled) — muted-gold governance accent. */
.platform-gate--open {
    border-left-color: var(--colour-gold);
    background: color-mix(in srgb, var(--colour-gold) 8%, var(--colour-white));
}

/* One-time password reveal after a successful onboard. */
.platform-reveal {
    padding: var(--space-3) var(--space-4);
    background: var(--colour-ice);
    border-left: 3px solid var(--colour-gold);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--colour-navy);
}
/* The generated password itself — emphasised, selectable, unmistakable. */
.platform-pw {
    display: inline-block;
    margin-top: var(--space-1);
    padding: var(--space-1) var(--space-2);
    background: var(--colour-white);
    border: 1px solid var(--colour-gold);
    border-radius: var(--radius-sm);
    font-weight: 600;
    letter-spacing: 0.04em;
    user-select: all;
}

/* End of Section 52 — Platform Administration (S50) */


/* ============================================================================
   SECTION 53 — MODULE 6 POLICY ATTACHMENTS  (Session 51, G26)
   ----------------------------------------------------------------------------
   Uploaded-document panel inside the policy edit form: a file list with
   download / delete, plus an upload row (shown only to can_write roles). Brings
   policies to parity with the Module 10 incident-attachment surface (Section 30)
   and mirrors its structure and idiom. Reuses the shared primitives (.btn*,
   .field__input, .u-muted) and NEUTRAL brand tones throughout — NO new hues, NO
   risk heat-map colours (attachments are not a risk axis). The register's
   file-count chip is a neutral steel pill.
   ============================================================================ */

/* --- Register: "Files N" chip (neutral; sits beside the file-reference link) - */
.pol-attach-chip {
    display: inline-block;
    padding: 0.05rem var(--space-2);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    font-size: var(--text-xs);
    color: var(--colour-steel);
    white-space: nowrap;
    vertical-align: middle;
}

/* --- Attachments panel: sits below the form actions, divided off --- */
.pol-attach {
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}
.pol-attach__title {
    font-family: var(--font-display);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    margin: 0 0 var(--space-3);
}
.pol-attach__hint,
.pol-attach__empty {
    font-size: var(--text-sm);
    margin: 0;
}

/* --- File list --- */
.pol-att-list {
    list-style: none;
    margin: 0 0 var(--space-3);
    padding: 0;
}
.pol-att-item {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    margin-bottom: var(--space-2);
    background-color: var(--colour-white);
}
.pol-att-item:hover {
    background-color: var(--tone-hover);
}
.pol-att-item__main {
    min-width: 0;          /* allow the name to truncate rather than overflow */
}
.pol-att-item__name {
    font-weight: 600;
    color: var(--colour-navy);
    word-break: break-word;
}
.pol-att-item__desc {
    font-size: var(--text-sm);
    color: var(--colour-steel);
    margin-top: var(--space-1);
}
.pol-att-item__meta {
    font-size: var(--text-xs);
    margin-top: var(--space-1);
}
.pol-att-item__actions {
    display: flex;
    gap: var(--space-2);
    flex-shrink: 0;
    white-space: nowrap;
}

/* --- Upload row (can_write only) --- */
.pol-attach__upload {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding-top: var(--space-2);
}
.pol-attach__file {
    flex: 1 1 14rem;
    min-width: 12rem;
}
.pol-attach__desc {
    flex: 2 1 18rem;
    min-width: 12rem;
}
.pol-attach__limit {
    font-size: var(--text-xs);
}

/* End of Section 53 — Module 6 Policy Attachments (G26) */


/* ============================================================================
   Section 54 — Module 24 Third-Party / Vendor Register (Session 54)
   ----------------------------------------------------------------------------
   The Vendors register + create/edit form + detail panel (profile + read-only
   assessment history). Reuses Module 2/8/17 primitives (.card, .table,
   .field__*, .btn, .badge) and existing tokens ONLY — no new hues:
     - Criticality reuses the shared .badge--crit-* chips (§8.1 palette,
       Section for sites/assets) — a protection-priority axis, not a risk score.
     - Lifecycle status uses NEUTRAL brand chips, mirroring .badge--site-*.
   ---------------------------------------------------------------------------- */

/* --- Inline status message (mirror .proj-message) --- */
.vendor-message {
    margin: var(--space-2) 0 0;
    min-height: 1.2em;
    font-size: var(--text-sm);
}
.vendor-message--ok    { color: var(--risk-low); }
.vendor-message--error { color: var(--risk-high); }

/* --- Header actions --- */
.vendor-head-actions {
    display: flex;
    gap: var(--space-2);
    align-items: center;
}

/* --- Lifecycle status chips (neutral brand tones; mirror .badge--site-*) --- */
.badge--vendor-active {
    background-color: rgba(74, 105, 132, 0.14);    /* steel wash */
    color: var(--colour-navy);
    border: 1px solid var(--colour-steel);
}
.badge--vendor-inactive {
    background-color: var(--gold-soft);            /* gold = attention / dormant */
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--vendor-decommissioned {
    background-color: var(--tone-hover);           /* de-emphasised, retained for record */
    color: var(--colour-steel);
    border: 1px dashed var(--tone-border-strong);
}

/* --- Register table --- */
.vendor-table-wrap { overflow-x: auto; }
.vendor-name { font-weight: 600; }
.vendor-contact-inline { font-size: var(--text-sm); }
.vendor-row-actions { white-space: nowrap; }
.vendor-row-actions .btn { margin-left: var(--space-1); }

/* --- Create / edit form (mirror .proj-form__grid) --- */
.vendor-form__title {
    margin: 0 0 var(--space-4);
    font-size: var(--text-lg);
    color: var(--colour-navy);
}
.vendor-form__grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-4);
}
.vendor-span-2 { grid-column: 1 / -1; }
.vendor-form__actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-4);
}

/* --- Detail panel (profile + assessment history) --- */
.vendor-detail__head { margin-bottom: var(--space-3); }
.vendor-detail__title {
    margin: 0;
    font-size: var(--text-lg);
    color: var(--colour-navy);
}
.vendor-detail__ref { font-weight: 400; }
.vendor-detail__meta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: var(--space-3);
    margin: 0 0 var(--space-3);
}
.vendor-detail__meta dt {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colour-steel);
    margin-bottom: 2px;
}
.vendor-detail__meta dd { margin: 0; }
.vendor-detail__desc  { margin: 0 0 var(--space-2); }
.vendor-detail__notes { margin: 0 0 var(--space-3); font-size: var(--text-sm); }
.vendor-detail__section {
    margin: var(--space-4) 0 var(--space-2);
    font-size: var(--text-base);
    color: var(--colour-navy);
}
.vendor-detail__hint { margin-top: var(--space-2); font-size: var(--text-sm); }

/* Single-column form on narrow viewports (mirror the register-wide breakpoint). */
@media (max-width: 720px) {
    .vendor-form__grid { grid-template-columns: 1fr; }
}

/* End of Section 54 — Module 24 Third-Party / Vendor Register (Session 54) */


/* ============================================================================
   SECTION 55 — Module 25 GRC Maturity Model (Session 56)
   ----------------------------------------------------------------------------
   The maturity view reuses the shared primitives (card, table, field, btn,
   risk-message, view__*, u-* helpers) exactly as the assessments view does.
   The genuinely new primitives here are the mat- prefixed tokens: the CMMI
   level chip (a tonal steel->navy wash keyed to the band — deliberately NOT the
   risk-band palette, because maturity is a capability posture, not risk
   severity), the domain-score table, the rollup strip and the framework
   builder. All colours are drawn from the existing palette tokens (no new
   colours). The segmented tab reuses the Section 49 .as-tabs idiom.
   ============================================================================ */

/* --- Segmented tab (mirror .as-tabs) --------------------------------------- */
.mat-tabs {
    display: inline-flex;
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius-sm);
    overflow: hidden;
}
.mat-tab {
    appearance: none;
    border: 0;
    background-color: var(--colour-white);
    color: var(--colour-steel);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    padding: var(--space-2) var(--space-4);
    cursor: pointer;
}
.mat-tab + .mat-tab {
    border-left: 1px solid var(--tone-border-strong);
}
.mat-tab:hover {
    background-color: var(--tone-hover);
}
.mat-tab--active {
    background-color: var(--colour-navy);
    color: var(--colour-white);
}

/* --- Pane scaffolding ------------------------------------------------------ */
.mat-pane__head {
    margin-bottom: var(--space-3);
}
.mat-pane-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    color: var(--colour-navy);
    margin: 0;
}
.mat-empty {
    padding: var(--space-5) 0;
    text-align: center;
}

/* --- Shared form grid (start form / framework builder / appraisal meta) ----- */
.mat-form__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-3);
    margin-top: var(--space-3);
}
.mat-span-2 { grid-column: span 2; }
.mat-span-3 { grid-column: span 3; }
.mat-form__actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-4);
}
.mat-start__title,
.mat-f-form__title {
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--colour-navy);
    margin: 0;
}
.mat-check {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--colour-steel);
    cursor: pointer;
}

/* --- Assessment list table ------------------------------------------------- */
.mat-table {
    margin-top: var(--space-3);
}
.mat-cell-centre {
    text-align: center;
}
.mat-link {
    color: var(--colour-navy);
    font-weight: 600;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.mat-link:hover {
    color: var(--colour-steel);
}
.mat-row-actions {
    display: flex;
    gap: var(--space-2);
    justify-content: flex-end;
    white-space: nowrap;
}

/* --- CMMI level chip (tonal steel->navy wash; NOT the risk palette) --------- */
.mat-chip {
    display: inline-block;
    min-width: 2.2em;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    border: 1px solid var(--tone-border);
    font-size: var(--text-sm);
    font-weight: 700;
    text-align: center;
    color: var(--colour-navy);
}
.mat-chip--none {
    color: var(--colour-steel);
    background-color: var(--colour-white);
    font-weight: 500;
}
.mat-chip--l1 { background-color: color-mix(in srgb, var(--colour-steel) 10%, var(--colour-white)); }
.mat-chip--l2 { background-color: color-mix(in srgb, var(--colour-steel) 22%, var(--colour-white)); }
.mat-chip--l3 { background-color: color-mix(in srgb, var(--colour-steel) 34%, var(--colour-white)); }
.mat-chip--l4 { background-color: color-mix(in srgb, var(--colour-navy) 26%, var(--colour-white)); }
.mat-chip--l5 {
    background-color: color-mix(in srgb, var(--colour-navy) 40%, var(--colour-white));
    border-color: var(--colour-gold);
}

/* --- Below-target attention flag (soft gold, not risk-red) ----------------- */
.mat-below {
    display: inline-block;
    min-width: 1.8em;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    background-color: color-mix(in srgb, var(--colour-gold) 22%, var(--colour-white));
    border: 1px solid color-mix(in srgb, var(--colour-gold) 55%, var(--colour-white));
    color: var(--colour-navy);
    font-weight: 700;
    text-align: center;
}

/* --- Status pill ----------------------------------------------------------- */
.mat-status {
    display: inline-block;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    font-size: var(--text-xs);
    font-weight: 600;
    border: 1px solid var(--tone-border);
}
.mat-status--complete {
    background-color: color-mix(in srgb, var(--colour-navy) 12%, var(--colour-white));
    color: var(--colour-navy);
}
.mat-status--progress {
    background-color: var(--colour-white);
    color: var(--colour-steel);
}

/* --- Appraisal surface ----------------------------------------------------- */
.mat-appraisal__meta {
    margin-top: var(--space-4);
}
.mat-rollup {
    display: flex;
    gap: var(--space-5);
    flex-wrap: wrap;
    margin: var(--space-3) 0;
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    background-color: color-mix(in srgb, var(--colour-ice) 40%, var(--colour-white));
}
.mat-rollup__item {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}
.mat-rollup__label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--colour-steel);
}
.mat-rollup__value {
    font-size: var(--text-md);
    font-weight: 700;
    color: var(--colour-navy);
}
.mat-score-table {
    margin-top: var(--space-3);
}
.mat-score__domain {
    font-weight: 600;
    color: var(--colour-navy);
}
.mat-score__level,
.mat-score__target {
    min-width: 6em;
}

/* --- Framework library cards ----------------------------------------------- */
.mat-f-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-4);
    margin-top: var(--space-3);
}
.mat-f-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.mat-f-card--inactive {
    opacity: 0.72;
}
.mat-f-card__title {
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--colour-navy);
    margin: 0;
}
.mat-f-card__meta {
    font-size: var(--text-sm);
    margin: 0;
}
.mat-f-card__desc {
    font-size: var(--text-sm);
    color: var(--colour-steel);
    margin: 0;
}
.mat-f-card__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    margin-top: auto;
    padding-top: var(--space-2);
}
.mat-tag {
    display: inline-block;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-sm);
    font-size: var(--text-xs);
    font-weight: 600;
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border);
}
.mat-tag--locked {
    background-color: color-mix(in srgb, var(--colour-gold) 18%, var(--colour-white));
    border-color: color-mix(in srgb, var(--colour-gold) 50%, var(--colour-white));
    color: var(--colour-navy);
}

/* --- Framework builder: inline domain lines -------------------------------- */
.mat-f-lines {
    margin-top: var(--space-4);
}
.mat-f-lines__head {
    margin-bottom: var(--space-2);
}
.mat-f-lines__title {
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--colour-navy);
    margin: 0;
}
.mat-f-lines__empty {
    padding: var(--space-3) 0;
}
.mat-lock-note {
    font-size: var(--text-sm);
    color: var(--colour-steel);
    background-color: color-mix(in srgb, var(--colour-gold) 12%, var(--colour-white));
    border: 1px solid color-mix(in srgb, var(--colour-gold) 40%, var(--colour-white));
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
    margin: var(--space-2) 0;
}
.mat-f-line {
    display: flex;
    align-items: flex-end;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-top: 1px solid var(--tone-border);
}
.mat-f-line__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
    gap: var(--space-3);
    flex: 1;
}
.mat-f-line__remove {
    flex: 0 0 auto;
}

/* End of Section 55 — Module 25 GRC Maturity Model (Session 56) */


/* ============================================================================
   SECTION 56 — Module 7 Dashboard Sharing (Session 58)
   ----------------------------------------------------------------------------
   Two surfaces, existing palette tokens only (no new hues):
     1. The in-dashboard share-management panel (.dash-share__*) — layout only;
        chips/buttons/tables reuse existing components.
     2. The standalone external posture page (.share-page__* / .share-tile__* /
        .share-band__* / .share-legend__*) served by share.php's token path. It
        links this stylesheet but has no app shell, so it carries its own light
        page frame. Band colours reuse the .dash-heat__cell--<band> ramp.
   ============================================================================ */

/* --- 1. In-dashboard share panel ------------------------------------------- */

/* Panel header: title left, "Create share link" action right. */
.dash-share__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}

/* Create form — a bordered well below the intro copy. */
.dash-share__form {
    margin-top: var(--space-4);
    padding: var(--space-4);
    border: 1px solid var(--colour-ice);
    border-radius: var(--radius-sm);
    background-color: var(--colour-ice);
}

/* Field row: wraps on narrow viewports; each field grows to share the width. */
.dash-share__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
}
.dash-share__field {
    flex: 1 1 12rem;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* Form action row. */
.dash-share__actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-4);
}

/* One-time new-link reveal. */
.dash-share__newlink {
    margin-top: var(--space-4);
    padding: var(--space-4);
    border: 1px solid var(--colour-gold);
    border-radius: var(--radius-sm);
    background-color: var(--colour-white);
}
.dash-share__newlbl {
    margin: 0 0 var(--space-3) 0;
}
.dash-share__linkrow {
    display: flex;
    gap: var(--space-2);
    align-items: center;
}
.dash-share__linkrow .field__input {
    flex: 1 1 auto;
    font-family: var(--font-mono);
}

/* Share list table spacing. */
.dash-share__table {
    margin-top: var(--space-2);
}

/* --- 2. Standalone external posture page ----------------------------------- */

/* Full-page frame (the page links style.css, so body already carries the ice
   base + base typography). */
.share-page {
    min-height: 100vh;
    padding: var(--space-6) var(--space-4);
    box-sizing: border-box;
}
.share-page__wrap {
    max-width: 60rem;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* Brand header. */
.share-page__header {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding-bottom: var(--space-3);
    border-bottom: 3px solid var(--colour-gold);
}
.share-page__brand {
    font-family: var(--font-display);
    font-size: 1.6rem;
    font-weight: 700;
    color: var(--colour-navy);
    letter-spacing: 0.02em;
}
.share-page__brandsub {
    font-size: 0.8rem;
    color: var(--colour-steel);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}
/* status.php reuses .brand__mark (not .share-page__brand) for the gold
   vigilance dot — scoped override matches the prior share-page__brand
   size/weight/colour so only the dot changes, nothing else. */
.share-page__header .brand__mark {
    font-size: 1.6rem;
    font-weight: 700;
    color: var(--colour-navy);
}

/* Card + typography on the standalone page. */
.share-page__card {
    /* inherits .card surface; overrides only what the shell would otherwise set */
}
.share-page__title {
    margin: 0 0 var(--space-2) 0;
    font-family: var(--font-display);
    color: var(--colour-navy);
}
.share-page__h2 {
    margin: 0 0 var(--space-1) 0;
    font-family: var(--font-display);
    font-size: 1.1rem;
    color: var(--colour-navy);
}
.share-page__scope {
    margin: 0 0 var(--space-2) 0;
    font-weight: 600;
    color: var(--colour-steel);
}
.share-page__asof {
    margin: 0;
    font-size: 0.85rem;
}
.share-page__footer {
    text-align: center;
    font-size: 0.8rem;
    padding-top: var(--space-3);
}

/* Headline tiles (mirrors the dashboard KPI tile, standalone). */
.share-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    gap: var(--space-4);
}
.share-tile {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    text-align: center;
    align-items: center;
}
.share-tile__value {
    font-family: var(--font-display);
    font-size: 2rem;
    font-weight: 700;
    color: var(--colour-navy);
    line-height: 1;
}
.share-tile__label {
    font-weight: 600;
    color: var(--colour-steel);
}
.share-tile__sub {
    font-size: 0.8rem;
}

/* Proportional band bar (colours from the --band-* ramp via dash-heat cells). */
.share-band {
    display: flex;
    width: 100%;
    height: 2.25rem;
    border-radius: var(--radius-sm);
    overflow: hidden;
    border: 1px solid var(--colour-ice);
}
.share-band__seg {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    color: var(--colour-white);
    font-weight: 700;
    font-size: 0.85rem;
}
.share-band__seg--empty {
    width: 100%;
    color: var(--colour-steel);
    background-color: var(--colour-ice);
    font-weight: 400;
}

/* Band legend. */
.share-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    align-items: center;
}
.share-legend__item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 0.9rem;
    color: var(--colour-navy);
}
.share-legend__swatch {
    width: 0.9rem;
    height: 0.9rem;
    border-radius: 3px;
    display: inline-block;
}

/* End of Section 56 — Module 7 Dashboard Sharing (Session 58) */


/* ============================================================================
   SECTION 57 — Favourites / Personalisation (Session 59)
   ----------------------------------------------------------------------------
   Cross-entity per-user pins. Existing palette tokens only (no new hues):
     - .fav-star  : the per-row pin control (hollow steel ☆ → filled gold ★).
     - .fav-cell  : the ref cell hosting the star inline with the ref text.
     - .fav-bar   : the thin toolbar above a register table.
     - .fav-facet : the "Favourites only" toggle (gold-soft when active).
   Served for risk, control, policy, incident and vendor registers by the shared
   assets/favourites.js helper. Personal UI state — no scoring, no methodology.
   ============================================================================ */

/* --- Row pin control ------------------------------------------------------- */

/* Borderless star button; steel hollow by default, gold filled when pinned. */
.fav-star {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    padding: 0;
    margin-right: var(--space-1);
    font-size: 1rem;
    line-height: 1;
    color: var(--colour-steel);          /* hollow ☆ tone */
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    vertical-align: middle;
    transition: color var(--transition), background-color var(--transition);
}

.fav-star:hover {
    color: var(--colour-gold);
    background-color: var(--gold-soft);
}

/* Pinned: gold vigilance accent. */
.fav-star.is-fav {
    color: var(--colour-gold);
}

.fav-star:disabled {
    opacity: 0.5;
    cursor: default;
}

/* Ref cell: keep the star inline with the ref text without wrapping. */
.fav-cell {
    white-space: nowrap;
}

/* --- Favourites facet toolbar ---------------------------------------------- */

/* Thin toolbar row above a register table carrying the facet toggle. */
.fav-bar {
    display: flex;
    justify-content: flex-end;
    margin-bottom: var(--space-3);
}

/* The "Favourites only" toggle. Neutral outline off; gold-soft fill on. */
.fav-facet {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3);
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--colour-steel);
    background: var(--colour-white);
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius);
    cursor: pointer;
    transition: color var(--transition), background-color var(--transition),
                border-color var(--transition);
}

.fav-facet:hover {
    color: var(--colour-navy);
    border-color: var(--colour-steel);
}

/* Active: gold outline + soft gold wash, matching the pinned star accent. */
.fav-facet.is-on {
    color: var(--colour-navy);
    background: var(--gold-soft);
    border-color: var(--colour-gold);
}

/* Live pin count pill inside the toggle. */
.fav-facet__count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.25rem;
    height: 1.25rem;
    padding: 0 var(--space-1);
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--colour-navy);
    background: var(--colour-ice);
    border-radius: 999px;
}

.fav-facet.is-on .fav-facet__count {
    background: var(--colour-white);
}

/* End of Section 57 — Favourites / Personalisation (Session 59) */


/* ----------------------------------------------------------------------------
   58. MODULE 8 — ASSET VISIBILITY & TEAMS (S62 / S63)
   The per-asset visibility gate surfaces: the Assets register visibility chip,
   the can_manage_org Visibility section on the asset form, the Asset Teams
   directory, and shared toolbar/inline-select primitives for the split views.
   Fixed palette only — every value resolves to an existing :root variable; no
   new hues. Visibility uses NEUTRAL chips (visibility is an access axis, not a
   risk axis): Open = de-emphasised steel (the permissive default); Gated = gold
   attention wash (mirrors .badge--site-inactive — "restricted / needs care").
   ---------------------------------------------------------------------------- */

/* --- Visibility state chips (Assets register, can_manage_org only) --- */
.badge--vis-open {
    background-color: var(--tone-hover);           /* de-emphasised: open to all */
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}
.badge--vis-gated {
    background-color: var(--gold-soft);            /* gold = attention / restricted */
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}

/* --- Toolbar row (asset site filter, group-member add) --- */
.asset-toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-top: var(--space-3);
}
.asset-toolbar .field__label {
    margin: 0;
    white-space: nowrap;
}

/* --- Inline select (auto width, sits within a toolbar row) --- */
.field__select--inline {
    width: auto;
    min-width: 14rem;
    max-width: 100%;
}

/* --- Visibility section on the asset form (bordered sub-panel) --- */
.asset-visibility {
    padding: var(--space-4);
    border: 1px solid var(--tone-border-strong);
    border-radius: 6px;
    background-color: var(--tone-hover);
}
.asset-visibility .site-subhead {
    margin-bottom: var(--space-2);
}
.asset-visibility .risk-form-grid {
    margin-top: var(--space-2);
}

/* End of Section 58 — Module 8 Asset Visibility & Teams (S62 / S63) */


/* ----------------------------------------------------------------------------
   59. MODULE 8 — ASSET VERIFICATION (S64)
   The verified/unverified facet on the Assets register: the toolbar toggle +
   count, and the Verified/Unverified state chip. Fixed palette only. Verified
   reuses the SAME visual language as .badge--vis-open (de-emphasised — the
   expected, no-action-needed state); Unverified reuses the SAME gold attention
   wash as .badge--vis-gated (a curation decision is pending). No new hues.
   ---------------------------------------------------------------------------- */

/* --- Verification state chips (Assets register, can_manage_org only) --- */
.badge--verified {
    background-color: var(--tone-hover);           /* de-emphasised: expected state */
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}
.badge--unverified {
    background-color: var(--gold-soft);            /* gold = attention / needs review */
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}

/* --- Toolbar "Unverified only" toggle --- */
.asset-unverified-toggle {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    margin: 0;
    white-space: nowrap;
    font-size: 0.875rem;
    color: var(--colour-steel);
    cursor: pointer;
}
.asset-unverified-count {
    font-weight: 700;
    color: var(--colour-navy);
}

/* End of Section 59 — Module 8 Asset Verification (S64) */

/* ============================================================================
   SECTION 60 — Asset-group-as-risk-subject (Session 65)
   ----------------------------------------------------------------------------
   A risk may name an asset GROUP as its subject (risk_register.asset_group_id).
   The register marks it with a compact chip in the Asset cell; the risk detail
   (edit form) expands the group into its CURRENT member assets — a live,
   server-gated read (attach_asset_group_members). Existing tokens only; no new
   colours. The chip reuses the muted-gold accent to read as a curated subject
   marker, distinct from the neutral .tag-chip.
   ========================================================================== */

/* Register chip: the group-subject marker beside the free-text asset. */
.asset-group-chip {
    display: inline-block;
    padding: 0.05rem 0.4rem;
    font-size: var(--text-xs);
    line-height: 1.5;
    color: var(--colour-navy);
    background: var(--colour-ice);
    border: 1px solid var(--colour-gold);
    border-radius: var(--radius-sm);
    white-space: nowrap;
}

/* Detail expansion: the group's current visible members on the risk form. */
.asset-group-members {
    padding: var(--space-3);
    background: var(--colour-ice);
    border: 1px solid var(--tone-border);
    border-left: 3px solid var(--colour-gold);
    border-radius: var(--radius-sm);
}

.asset-group-members .agm-head {
    margin: 0 0 var(--space-2) 0;
}

.asset-group-members .agm-empty {
    margin: 0;
}

.asset-group-members .agm-list {
    margin: 0;
    padding-left: var(--space-4);
    columns: 2;
    column-gap: var(--space-4);
}

.asset-group-members .agm-item {
    break-inside: avoid;
    margin-bottom: var(--space-1);
}

/* Single column on narrow viewports. */
@media (max-width: 640px) {
    .asset-group-members .agm-list { columns: 1; }
}

/* End of Section 60 — Asset-group-as-risk-subject (Session 65) */

/* ============================================================================
   SECTION 61 — My Profile (Module 13 self view, Session 67)
   ----------------------------------------------------------------------------
   Read-only account page (modules/account/account.js). A single card with an
   identity header and a label/value definition grid. Existing tokens only; the
   admin badges reuse the shared .badge base with navy / gold / steel accents
   from the fixed palette. No new colours introduced.
   ============================================================================ */

/* The profile card sits in a constrained column for comfortable reading. */
.acct-card {
    max-width: 720px;
}

/* Identity header — name over email, separated from the grid by a hairline. */
.acct-identity {
    padding-bottom: var(--space-4);
    margin-bottom: var(--space-4);
    border-bottom: 1px solid var(--tone-border);
}
.acct-identity__name {
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--colour-navy);
}
.acct-identity__meta {
    font-size: var(--text-sm);
    margin-top: var(--space-1);
}

/* Label/value definition grid: a fixed label column, value fills the rest. */
.acct-grid {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: var(--space-3) var(--space-5);
    margin: 0;
}
.acct-row {
    display: contents;
}
.acct-row__label {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--colour-steel);
    padding-top: 2px;
}
.acct-row__value {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--colour-navy);
}

/* Chip rows (capabilities, teams) wrap freely within the value column. */
.acct-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}
.acct-chip {
    display: inline-block;
    padding: 2px var(--space-3);
    font-size: var(--text-xs);
    font-weight: 600;
    border-radius: 999px;
    background-color: var(--colour-ice);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border);
    white-space: nowrap;
}

/* Admin-capability badges — reuse the .badge base with palette accents. */
.acct-badge--platform {
    background-color: var(--colour-navy);
    color: var(--colour-ice);
}
.acct-badge--org {
    background-color: var(--colour-gold);
    color: var(--colour-navy);
}
.acct-badge--system {
    background-color: transparent;
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}

/* Footnote beneath the grid. */
.acct-note {
    margin-top: var(--space-4);
    font-size: var(--text-xs);
    line-height: 1.5;
}

/* Single-column grid on narrow viewports (labels stack above values). */
@media (max-width: 640px) {
    .acct-grid { grid-template-columns: 1fr; gap: var(--space-1) 0; }
    .acct-row__label { padding-top: var(--space-2); }
}

/* End of Section 61 — My Profile (Session 67) */

/* ============================================================================
   SECTION 62 — Multi-Factor Authentication (Session 69)
   ----------------------------------------------------------------------------
   The Two-factor card on My Profile (enrolment, one-time recovery-code reveal,
   password step-up for disable/regenerate) plus two shared button variants used
   by the security card and the login second-step screen. Existing tokens only —
   no new colours.
   ============================================================================ */

/* The security card sits below the profile card with a clear gap. */
.mfa-card {
    margin-top: var(--space-5);
}

/* Card heading, shared by the security sub-panels. */
.acct-section__title {
    margin: 0 0 var(--space-3) 0;
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--colour-navy);
}

/* Numbered setup steps. */
.mfa-steps {
    margin: 0 0 var(--space-3) var(--space-4);
    padding: 0;
    font-size: var(--text-sm);
    color: var(--colour-navy);
    line-height: 1.6;
}
.mfa-steps li { margin-bottom: var(--space-1); }

/* The base32 setup key — monospace, boxed, easy to read and select. */
.mfa-secret {
    font-family: var(--font-mono);
    font-size: var(--text-md);
    letter-spacing: 0.15em;
    word-break: break-all;
    padding: var(--space-3) var(--space-4);
    background-color: var(--colour-ice);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    color: var(--colour-navy);
    user-select: all;
}

/* The otpauth setup link, collapsed inside a <details>. */
.mfa-uri {
    margin-top: var(--space-3);
    font-size: var(--text-xs);
}
.mfa-uri summary { cursor: pointer; }
.mfa-uri__text {
    display: block;
    margin-top: var(--space-2);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    word-break: break-all;
    color: var(--colour-steel);
}

/* The confirming-code input — centred, spaced digits. */
.mfa-input {
    letter-spacing: 0.3em;
    text-align: center;
    font-family: var(--font-mono);
}

/* One-time recovery-code reveal. */
.mfa-codes {
    display: grid;
    grid-template-columns: repeat(2, max-content);
    gap: var(--space-2) var(--space-5);
    margin: var(--space-3) 0;
    padding: var(--space-4);
    list-style: none;
    background-color: var(--colour-ice);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
}
.mfa-code {
    font-family: var(--font-mono);
    font-size: var(--text-md);
    letter-spacing: 0.08em;
    color: var(--colour-navy);
}

/* A link-style button (transparent) — used for "Back to sign in". */
.btn--link {
    background-color: transparent;
    border-color: transparent;
    color: var(--colour-steel);
    padding: var(--space-2);
}
.btn--link:hover {
    color: var(--colour-navy);
    text-decoration: underline;
}
.auth__link {
    width: 100%;
    margin-top: var(--space-2);
    justify-content: center;
}

/* Recovery-code grid stacks on narrow viewports. */
@media (max-width: 640px) {
    .mfa-codes { grid-template-columns: 1fr; }
}

/* End of Section 62 — Multi-Factor Authentication (Session 69) */


/* ----------------------------------------------------------------------------
   SECTION 63 — Collapsible sidebar groups + categorised Reporting (Session 70)
   Two additions, existing tokens only (no new hues):
     (a) The sidebar groups become collapsible — a toggle button (heading +
         chevron) over each link list. Collapse state persists per user (app.js
         localStorage); the base .nav__group-label / .nav__link rules are reused
         untouched.
     (b) Reporting (Module 9) is reorganised into separately-navigable category
         pages via a tab bar (.rpt-tabs / .rpt-tab).
   ---------------------------------------------------------------------------- */

/* (a) Collapsible navigation groups ---------------------------------------- */
.nav__group { display: block; }

/* The group heading is now a full-width toggle button. It carries no chrome of
   its own — the nested .nav__group-label supplies the type + left/vertical
   padding (base rule), and the button adds the right gutter for the chevron. */
.nav__group-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 0 var(--space-5) 0 0;
    background: none;
    border: none;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}
.nav__group-toggle:hover {
    background-color: rgba(244, 247, 249, 0.06);   /* faint ice wash — matches .nav__link:hover */
}
.nav__group-toggle:focus-visible {
    outline: 2px solid var(--colour-gold);
    outline-offset: -2px;
}

/* Chevron: a small rotated caret drawn from two borders. Points down when the
   group is expanded, right when collapsed. */
.nav__group-chevron {
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-right: 2px solid var(--colour-gold);
    border-bottom: 2px solid var(--colour-gold);
    transform: rotate(45deg);                      /* expanded → pointing down */
    transition: transform var(--transition);
}
.nav__group.is-collapsed .nav__group-chevron {
    transform: rotate(-45deg);                     /* collapsed → pointing right */
}

/* (b) Reporting category tabs ---------------------------------------------- */
.rpt-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}
.rpt-tab {
    padding: var(--space-2) var(--space-4);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--colour-navy);
    background-color: var(--colour-white);
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background-color var(--transition), border-color var(--transition), color var(--transition);
}
.rpt-tab:hover {
    background-color: var(--tone-hover);
}
.rpt-tab:focus-visible {
    outline: 2px solid var(--colour-gold);
    outline-offset: 2px;
}
.rpt-tab.is-active {
    color: var(--colour-navy);
    font-weight: 600;
    background-color: var(--gold-soft);
    border-color: var(--colour-gold);
}

/* Narrow layout: the sidebar becomes a horizontal bar (§14). Dissolve the group
   wrapper so the link lists flow as one bar (as before collapsibility), and drop
   the now-meaningless group toggle. */
@media (max-width: 860px) {
    .nav__group { display: contents; }
    .nav__group-toggle { display: none; }
}

/* End of Section 63 — Collapsible nav + categorised Reporting (Session 70) */

/* ============================================================================
   SECTION 64 — Reports Hub (Module 9 catalog / category pages / tiles, S71)
   ----------------------------------------------------------------------------
   The Reporting sidebar group resolves to a Report Catalog landing, one page per
   category, and per-report pages (#report/<id>). The report DOCUMENT itself
   (masthead, sections, matrices, KPI tiles) reuses the Module 9 report styles
   from Sections 26 / 63 unchanged — this section styles only the NEW catalog and
   category surfaces (grouped launch tiles). Fixed palette only — every value
   resolves to an existing :root variable; no new hues.
   ============================================================================ */

/* A category block on the catalog landing: heading over its tile grid. */
.rpt-catgroup {
    margin-bottom: var(--space-6);
}
.rpt-catgroup__head {
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--colour-navy);
    margin: 0 0 var(--space-3) 0;
    padding-bottom: var(--space-2);
    border-bottom: 1px solid var(--tone-border);
}
/* A linked category heading (jumps to the dedicated category page). */
.rpt-catgroup__link {
    color: var(--colour-navy);
    text-decoration: none;
}
.rpt-catgroup__link:hover {
    color: var(--colour-steel);
    text-decoration: underline;
}

/* Responsive grid of report launch tiles (catalog + category pages). */
.rpt-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: var(--space-4);
}

/* One report tile — a card-styled anchor to the report's dedicated page. */
.rpt-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-4);
    background: var(--colour-white);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius);
    box-shadow: 0 1px 2px var(--tone-shadow);
    text-decoration: none;
    transition: border-color 0.12s ease, box-shadow 0.12s ease, transform 0.12s ease;
}
.rpt-tile:hover {
    border-color: var(--colour-gold);
    box-shadow: 0 3px 8px var(--tone-shadow);
    transform: translateY(-1px);
}
.rpt-tile__title {
    font-weight: 600;
    color: var(--colour-navy);
    font-size: var(--text-base);
    /* Leave room for the seniority chip in the top-right. */
    padding-right: var(--space-6);
}
.rpt-tile__blurb {
    font-size: var(--text-sm);
    line-height: 1.4;
}
/* Seniority chip (Manager+ / Executive+) — soft gold accent, no new hue. */
.rpt-tile__rank {
    position: absolute;
    top: var(--space-3);
    right: var(--space-3);
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--colour-navy);
    background: var(--gold-soft);
    border-radius: var(--radius-sm);
    padding: 0.05rem var(--space-2);
    white-space: nowrap;
}

/* ============================================================================
   SECTION 65 — Risk Posture Trend (Session 74, §4.3 gap 1)
   ----------------------------------------------------------------------------
   The hand-rolled SVG line chart on the Risk Posture Trend report page. Zero
   dependency (pure inline SVG). Every stroke reads from a LOCKED palette token
   (Section 0 :root) — no new hues. Line colours:
     total   -> --colour-navy   (dominant base)
     open    -> --colour-gold   (accent — the working population)
     highest -> --risk-high     (top treatment tier)
     high    -> --risk-medium   (second treatment tier)
   ============================================================================ */

/* Chart frame — responsive; the SVG scales to the card width. */
.rps-chart {
    width: 100%;
    margin: 0.5rem 0 0.75rem;
}
.rps-svg {
    display: block;
    width: 100%;
    height: auto;
    max-height: 360px;
}

/* Gridlines + axes. */
.rps-grid {
    stroke: rgba(26, 43, 76, 0.12);   /* navy @ low alpha — subtle grid */
    stroke-width: 1;
}
.rps-grid--axis {
    stroke: rgba(26, 43, 76, 0.35);   /* darker for the L-shaped axis */
}

/* Axis tick labels. */
.rps-axis {
    fill: var(--colour-steel);
    font-size: 0.66rem;
    font-family: inherit;
}
.rps-axis--y { text-anchor: end; }
.rps-axis--x { text-anchor: middle; }

/* Series polylines — colour by token, no fill. */
.rps-line {
    fill: none;
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
}
.rps-line--total   { stroke: var(--colour-navy); }
.rps-line--open    { stroke: var(--colour-gold); }
.rps-line--highest { stroke: var(--risk-high); }
.rps-line--high    { stroke: var(--risk-medium); }

/* Series point markers — same token per series. */
.rps-dot          { stroke: none; }
.rps-dot--total   { fill: var(--colour-navy); }
.rps-dot--open    { fill: var(--colour-gold); }
.rps-dot--highest { fill: var(--risk-high); }
.rps-dot--high    { fill: var(--risk-medium); }

/* Legend — swatch + label per plotted series. */
.rps-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 1.1rem;
    margin: 0 0 0.9rem;
    font-size: 0.8rem;
    color: var(--colour-steel);
}
.rps-legend__item {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}
.rps-legend__swatch {
    display: inline-block;
    width: 0.85rem;
    height: 0.85rem;
    border-radius: 2px;
}
.rps-legend__swatch--total   { background-color: var(--colour-navy); }
.rps-legend__swatch--open    { background-color: var(--colour-gold); }
.rps-legend__swatch--highest { background-color: var(--risk-high); }
.rps-legend__swatch--high    { background-color: var(--risk-medium); }

/* End of Section 65 — Risk Posture Trend (Session 74) */

/* ============================================================================
   SECTION 66 — Risk Comments / Discussion (Session 76, §4.3 gap 6)
   Append-only discussion thread on the risk detail (edit) form, plus a compact
   count pill in the register. Locked palette tokens only — no new hue. A comment
   is a qualitative record, never a scoring surface, so nothing here borrows a
   risk-band colour.
   ============================================================================ */

/* Register pill — signals a risk carries discussion. Muted, unobtrusive, sits
   beside the title/tags. Mirrors the neutral weight of the tag chip. */
.comment-count {
    display: inline-block;
    margin-left: var(--space-1);
    padding: 0.05rem var(--space-2);
    font-size: var(--text-xs);
    line-height: 1.4;
    color: var(--colour-steel);
    background-color: var(--colour-ice);
    border: 1px solid var(--colour-steel);
    border-radius: var(--radius-sm);
    white-space: nowrap;
    vertical-align: middle;
}

/* Form field wrapper for the discussion block. */
.comment-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* The thread container — scrolls once the conversation grows. */
.comment-thread {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    max-height: 20rem;
    overflow-y: auto;
    padding: var(--space-2);
    background-color: var(--colour-ice);
    border: 1px solid var(--colour-steel);
    border-radius: var(--radius);
}

/* A single comment card. */
.comment {
    padding: var(--space-2) var(--space-3);
    background-color: var(--colour-white);
    border-left: 3px solid var(--colour-gold);
    border-radius: var(--radius-sm);
}
.comment__meta {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--space-3);
    margin-bottom: var(--space-1);
}
.comment__author {
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--colour-navy);
}
.comment__time {
    font-size: var(--text-xs);
    white-space: nowrap;
}
.comment__body {
    font-size: var(--text-sm);
    color: var(--colour-navy);
    word-break: break-word;
}

/* The post-comment control (can_write only). */
.comment-add {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    align-items: flex-start;
}
.comment-add__body {
    width: 100%;
    resize: vertical;
}

/* End of Section 66 — Risk Comments / Discussion (Session 76) */

/* ============================================================================
   SECTION 67 — Asset ↔ Control Mapping (Session 77, §4.3 gap 8)
   The edit-form Controls panel on an asset (live map/unmap) plus a compact
   count pill in the Assets register. Locked palette tokens only — no new hue. A
   mapping is an organisational relationship, never a scoring surface, so nothing
   here borrows a risk-band colour.
   ============================================================================ */

/* Register pill — signals an asset carries directly-mapped controls. Muted,
   unobtrusive, sits beside the asset name. Mirrors the Section 66 count pill. */
.asset-ctrl-pill {
    display: inline-block;
    margin-left: var(--space-1);
    padding: 0.05rem var(--space-2);
    font-size: var(--text-xs);
    line-height: 1.4;
    color: var(--colour-steel);
    background-color: var(--colour-ice);
    border: 1px solid var(--colour-steel);
    border-radius: var(--radius-sm);
    white-space: nowrap;
    vertical-align: middle;
}

/* The edit-form Controls panel container. */
.asset-controls {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* The list of mapped controls. */
.asset-ctrl-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}
.asset-ctrl-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    background-color: var(--colour-white);
    border-left: 3px solid var(--colour-gold);
    border-radius: var(--radius-sm);
}
.asset-ctrl-name {
    font-size: var(--text-sm);
    color: var(--colour-navy);
    word-break: break-word;
}

/* The map-a-control row (picker select + Map button). */
.asset-ctrl-add {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
}
.asset-ctrl-add .field__select {
    flex: 1 1 16rem;
    min-width: 12rem;
}

/* End of Section 67 — Asset ↔ Control Mapping (Session 77) */

/* ============================================================================
   SECTION 68 — Relationship Graph (Session 78, §4.3 gap 7)
   ----------------------------------------------------------------------------
   The hand-rolled zero-dependency SVG network view on the Reporting relationship
   -graph report page. Node fills and the relation-edge accent use the LOCKED
   palette tokens ONLY (§ design) — no new hues:
     risk        -> --colour-navy      control     -> --colour-steel
     asset       -> --colour-gold      asset_group -> --risk-medium
     site        -> --risk-low         relation    -> --colour-gold (dashed)
   ============================================================================ */

.rgraph {
    position: relative;
    margin-top: 12px;
    border: 1px solid var(--colour-steel);
    border-radius: 6px;
    background: var(--colour-white);
    overflow: hidden;
}
.rgraph-svg {
    display: block;
    width: 100%;
    height: 620px;
    max-height: 78vh;
    touch-action: none;               /* pointer pan / zoom own the gestures */
    cursor: grab;
    background:
        linear-gradient(var(--colour-ice) 1px, transparent 1px) 0 0 / 100% 32px,
        var(--colour-white);
}
.rgraph-svg:active { cursor: grabbing; }

/* -- Edges ---------------------------------------------------------------- */
.rgraph-edge            { stroke: var(--colour-steel); stroke-width: 1; opacity: 0.55; }
.rgraph-edge--subject   { stroke: var(--colour-steel); opacity: 0.6; }
.rgraph-edge--protects  { stroke: var(--colour-steel); opacity: 0.4; stroke-dasharray: 2 3; }
.rgraph-edge--member    { stroke: var(--risk-medium);  opacity: 0.45; }
.rgraph-edge--relation  { stroke: var(--colour-gold);  opacity: 0.85; stroke-width: 1.4; stroke-dasharray: 5 3; }

/* -- Nodes ---------------------------------------------------------------- */
.rgraph-node { cursor: grab; }
.rgraph-node:active { cursor: grabbing; }
.rgraph-dot {
    fill: var(--colour-steel);
    stroke: var(--colour-white);
    stroke-width: 1.5;
    -webkit-print-color-adjust: exact;
            print-color-adjust: exact;
}
.rgraph-node--risk        .rgraph-dot { fill: var(--colour-navy); }
.rgraph-node--control     .rgraph-dot { fill: var(--colour-steel); }
.rgraph-node--asset       .rgraph-dot { fill: var(--colour-gold); }
.rgraph-node--asset_group .rgraph-dot { fill: var(--risk-medium); }
.rgraph-node--site        .rgraph-dot { fill: var(--risk-low); }

.rgraph-label {
    fill: var(--colour-navy);
    font-size: 10px;
    pointer-events: none;
    user-select: none;
    -webkit-user-select: none;
}

/* -- Legend (clickable node-type toggles) --------------------------------- */
.rgraph-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    align-items: center;
    margin: 10px 0 2px;
}
.rgraph-legend__item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.82rem;
    color: var(--colour-navy);
    background: none;
    border: 0;
    padding: 2px 4px;
    cursor: pointer;
    border-radius: 4px;
}
.rgraph-legend__item--edge { cursor: default; }
.rgraph-legend__item.is-off { opacity: 0.4; text-decoration: line-through; }
.rgraph-legend__swatch {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    vertical-align: middle;
    -webkit-print-color-adjust: exact;
            print-color-adjust: exact;
}
.rgraph-legend__swatch.rgraph-node--risk        { background: var(--colour-navy); }
.rgraph-legend__swatch.rgraph-node--control     { background: var(--colour-steel); }
.rgraph-legend__swatch.rgraph-node--asset       { background: var(--colour-gold); }
.rgraph-legend__swatch.rgraph-node--asset_group { background: var(--risk-medium); }
.rgraph-legend__swatch.rgraph-node--site        { background: var(--risk-low); }
.rgraph-legend__swatch--relation {
    width: 16px;
    height: 0;
    border-radius: 0;
    border-top: 2px dashed var(--colour-gold);
}

/* -- Type toggles: hide a node type + every edge that touches it ----------- */
.rgraph--hide-risk        .rgraph-node--risk,
.rgraph--hide-risk        line[data-st="risk"],
.rgraph--hide-risk        line[data-tt="risk"],
.rgraph--hide-control     .rgraph-node--control,
.rgraph--hide-control     line[data-st="control"],
.rgraph--hide-control     line[data-tt="control"],
.rgraph--hide-asset       .rgraph-node--asset,
.rgraph--hide-asset       line[data-st="asset"],
.rgraph--hide-asset       line[data-tt="asset"],
.rgraph--hide-asset_group .rgraph-node--asset_group,
.rgraph--hide-asset_group line[data-st="asset_group"],
.rgraph--hide-asset_group line[data-tt="asset_group"],
.rgraph--hide-site        .rgraph-node--site,
.rgraph--hide-site        line[data-st="site"],
.rgraph--hide-site        line[data-tt="site"] {
    display: none;
}

/* End of Section 68 — Relationship Graph (Session 78) */


/* ============================================================================
   SECTION 69 — Report Builder (Session 79, §4.3 gap 5)
   ----------------------------------------------------------------------------
   The dynamic / ad-hoc report builder view (reporting.js view 'report-builder').
   Layout only; LOCKED palette tokens throughout (navy/steel/gold/ice/white +
   the neutral tone-* set) — no new hues. Inputs mirror .field__input / __select.
   ============================================================================ */

.rbuilder-config {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* Top row: entity / view-mode / saved-report loader. */
.rbuilder-toprow {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    align-items: flex-end;
}
.rbuilder-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 12rem;
}
.rbuilder-field--grow { flex: 1 1 16rem; }
.rbuilder-label {
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--colour-steel);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* Selects + free-text value / name inputs — mirror .field__select. */
.rbuilder-sel,
.rbuilder-fval,
.rbuilder-name {
    padding: var(--space-2) var(--space-3);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    background-color: var(--colour-white);
    border: 1px solid var(--tone-border-strong);
    border-radius: var(--radius-sm);
}
.rbuilder-sel:focus,
.rbuilder-fval:focus,
.rbuilder-name:focus {
    outline: none;
    border-color: var(--colour-gold);
    box-shadow: 0 0 0 3px var(--gold-soft);
}
.rbuilder-name { flex: 1 1 16rem; min-width: 12rem; }

/* Grouped sub-blocks (columns / filters / sort) with a divider above. */
.rbuilder-group {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}
.rbuilder-h {
    margin: 0;
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--colour-navy);
}
.rbuilder-h-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}

/* Column / group-by checkbox grid. */
.rbuilder-checks {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
    gap: var(--space-2) var(--space-4);
}
.rbuilder-chk {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--colour-navy);
    cursor: pointer;
}
.rbuilder-chk input { flex: none; }

/* Filter rows: field / operator / value / remove. */
.rbuilder-filters {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.rbuilder-frow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}
.rbuilder-frow .rbuilder-sel { min-width: 10rem; }
.rbuilder-fval { flex: 1 1 12rem; min-width: 8rem; }

/* Sort row: field + direction inline. */
.rbuilder-sortrow {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
}
.rbuilder-sortrow .rbuilder-h { margin-right: var(--space-2); }

/* Primary action row + save row. */
.rbuilder-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    padding-top: var(--space-4);
    border-top: 1px solid var(--tone-border);
}
.rbuilder-saverow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
}

/* Status + notes. */
.rbuilder-status { margin: 0; font-size: var(--text-sm); }
.rbuilder-note   { margin: var(--space-1) 0 0; font-size: var(--text-sm); }

/* End of Section 69 — Report Builder (Session 79) */


/* ============================================================================
   SECTION 70 — Budget Practicability (ALARP) (Session 83, Phase-7 item 1)
   ----------------------------------------------------------------------------
   Tokens for the mitigation practicability overlay: the three band badges, the
   over-budget / low-value flag chips, and the over-budget row wash. Per §2
   colour discipline the risk heat-map hues (crimson / amber / green) are RESERVED
   for IRV bands — practicability is a SEPARATE axis, so it uses BRAND + neutral
   tones ONLY (navy for Essential, steel for Balance, neutral for Negligible; gold
   for the over-budget attention flag). No new hues — every value is an alpha of
   an existing palette colour or an existing token.
   ============================================================================ */

/* Practicability band badges (extend .badge). Brand/neutral — NOT heat-map. */
.badge--prac-essential {
    background-color: rgba(26, 43, 76, 0.14);   /* navy tint — strongest signal */
    color: var(--colour-navy);
    border: 1px solid var(--tone-border-strong);
}
.badge--prac-balance {
    background-color: rgba(74, 105, 132, 0.14);  /* steel tint — weigh it */
    color: var(--colour-steel);
    border: 1px solid rgba(74, 105, 132, 0.30);
}
.badge--prac-negligible {
    background-color: var(--tone-hover);         /* neutral — lowest concern */
    color: var(--colour-steel);
    border: 1px solid var(--tone-border);
}

/* Flag chips beneath a practicability badge (over-budget / low-value spend). */
.prac-flags {
    margin-top: 4px;
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}
.prac-flag {
    display: inline-block;
    padding: 1px var(--space-2);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.03em;
    border-radius: 999px;
    white-space: nowrap;
}
/* Over budget — gold attention flag (gold = attention throughout the app). */
.prac-flag--over {
    background-color: var(--gold-soft);
    color: #7a6414;                              /* darkened gold for text contrast */
    border: 1px solid rgba(212, 175, 55, 0.45);
}
/* Low-value spend — neutral advisory chip (softer than the over-budget flag). */
.prac-flag--lowvalue {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}

/* Over-budget row wash on the budgets table (a subtle gold attention tint). */
.budget-row--over {
    background-color: var(--gold-soft);
}

/* Small inline number input (budget amount / mitigation cost edits). Mirrors
   .field__select--sm; defined here as the first .field__input--sm consumer. */
.field__input--sm {
    padding: 2px var(--space-2);
    font-size: var(--text-sm);
    max-width: 8.5rem;
}

/* End of Section 70 — Budget Practicability (Session 83) */

/* ============================================================================
   SECTION 71 — Financial Exposure (ALE / ROI) (Session 84, Phase-7 item 2)
   ----------------------------------------------------------------------------
   Tokens for the OPT-IN financial-quantification overlay: the basis identity
   badge, neutral numeric figures, ROI advisory chips, the per-basis input grid
   and the totals rollup. Per §2/§5 colour discipline the risk heat-map hues
   (crimson / amber / green) are RESERVED for IRV bands and MUST NOT appear here
   — financial exposure is a SEPARATE axis. It takes GOLD as its own identity
   accent (money / value = the app's gold), with neutral tones for figures. ROI
   is NEVER coloured green/red (that would read as a risk band); its only accent
   is a gold "positive return" chip and a neutral "below break-even" chip. No new
   hues — every value is an existing palette token or an alpha of one.
   ============================================================================ */

/* Gold identity accent for the financial axis (an alias of the brand gold). */
:root {
    --fin-accent: var(--colour-gold);   /* money / value identity — NOT a heat-map hue */
}

/* Basis identity badge (Inherent / Residual) — gold-tinted, brand not heat-map. */
.badge--fin {
    background-color: var(--gold-soft);
    color: #7a6414;                              /* darkened gold for text contrast */
    border: 1px solid rgba(212, 175, 55, 0.45);
}

/* A financial figure (SLE / ALE / cost / recoveries / ROI). Neutral + tabular,
   deliberately NOT a risk-band colour — a plain, authoritative numeral. */
.fin-figure {
    font-variant-numeric: tabular-nums;
    color: var(--colour-navy);
    font-weight: 600;
}

/* ROI advisory chips beneath / beside a ROI figure. Gold attention + neutral
   only — NEVER green/red (ROI is a financial figure, not a risk band). */
.fin-flag {
    display: inline-block;
    padding: 1px var(--space-2);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.03em;
    border-radius: 999px;
    white-space: nowrap;
}
.fin-flag--positive {
    background-color: var(--gold-soft);
    color: #7a6414;
    border: 1px solid rgba(212, 175, 55, 0.45);
}
.fin-flag--sub {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}

/* The financial-exposure card in the mitigation detail panel. */
.fin-card {
    border: 1px solid var(--tone-border);
    border-left: 3px solid var(--fin-accent);    /* gold identity spine */
    border-radius: var(--radius-sm);
    padding: var(--space-3);
    margin-bottom: var(--space-3);
}

/* Two side-by-side basis columns (inherent | residual). */
.fin-bases {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: var(--space-3);
}
.fin-basis {
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    padding: var(--space-2) var(--space-3);
}
.fin-basis__head {
    margin-bottom: var(--space-2);
}
.fin-basis__grid {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

/* One labelled input / derived-figure row inside a basis column. */
.fin-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
}
.fin-row__label {
    font-size: var(--text-sm);
    color: var(--colour-steel);
}
/* Derived (read-only) rows — SLE / ALE — separated from the editable inputs. */
.fin-row--derived {
    border-top: 1px dashed var(--tone-border);
    padding-top: 6px;
    margin-top: 2px;
}

/* Totals / rollup strip (ALE reduction · cost · recoveries · ROI). Reuses the
   mit-summary label style; a responsive auto-fit grid of neutral cells. */
.fin-rollup {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: var(--space-3);
    margin: var(--space-3) 0;
    padding: var(--space-3);
    background-color: var(--tone-hover);
    border-radius: var(--radius-sm);
}
.fin-rollup__cell {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* End of Section 71 — Financial Exposure (Session 84) */


/* ============================================================================
   SECTION 72 — Workflow Rules (Session 86, Phase-7 item 4)
   ----------------------------------------------------------------------------
   Card/form layout for the Workflow Rules admin view — a byte-for-byte layout
   mirror of Section (Module 19 Playbooks) .pb-* pattern, renamed .wfr-*. One
   NEW badge variant (the trigger-entity chip); everything else reuses existing
   brand/neutral tokens — no new hues (§2).
   ============================================================================ */

/* Trigger-entity chip (Incident/Risk/Exception) — brand steel, distinct from
   the Active/Inactive status badge it sits beside. */
.badge--wfr-entity {
    background-color: rgba(74, 105, 132, 0.14);
    color: var(--colour-steel);
    border: 1px solid rgba(74, 105, 132, 0.30);
}

.wfr-head-actions {
    display: flex;
    gap: var(--space-2);
}

/* --- Empty state ------------------------------------------------------------ */
.wfr-empty p {
    margin: 0 0 var(--space-2);
}
.wfr-empty p:last-child {
    margin-bottom: 0;
}

/* --- Rule cards --------------------------------------------------------------- */
.wfr-card {
    margin-bottom: var(--space-4);
}
.wfr-card__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
}
.wfr-card__title {
    margin: var(--space-2) 0 0;
    color: var(--colour-navy);
}
.wfr-card__actions {
    display: flex;
    gap: var(--space-2);
    flex-shrink: 0;
    white-space: nowrap;
}
.wfr-card__body {
    margin-top: var(--space-2);
}
.wfr-card__condition {
    margin: 0;
    color: var(--colour-navy);
    font-weight: 600;
}
.wfr-card__action,
.wfr-card__msg {
    margin: var(--space-1) 0 0;
    font-size: var(--text-sm);
}

/* --- Create / edit form ----------------------------------------------------- */
.wfr-form {
    margin-bottom: var(--space-5);
    border-left: 3px solid var(--colour-gold);   /* edit-mode accent (existing token) */
}
.wfr-form__title {
    margin: 0 0 var(--space-4);
    color: var(--colour-navy);
}
.wfr-form__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3);
}
.wfr-span-2 {
    grid-column: 1 / -1;
}
.wfr-form__actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-4);
}

/* Inline "active" toggle (module-scoped, not a shared form primitive). */
.wfr-check {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--colour-navy);
}

/* Narrow-viewport collapse — mirrors the Section 44 (Playbooks) breakpoint. */
@media (max-width: 640px) {
    .wfr-form__grid {
        grid-template-columns: 1fr;
    }
    .wfr-card__head {
        flex-direction: column;
    }
    .wfr-card__actions {
        width: 100%;
    }
}

/* End of Section 72 — Workflow Rules (Session 86) */

/* ============================================================================
   SECTION 73 — Scoped External Auditor Portal (Session 87)
   ----------------------------------------------------------------------------
   Two surfaces:
     1. Evidence entity picker in the dashboard share panel (.evidence-pick__*) —
        uses <details>/<summary> for collapsible groups; checkbox list.
     2. Evidence public page (.evidence-table / .evidence-badge / .evidence-func /
        .evidence-bar / .evidence-fw) served by share.php's token path. Extends
        the .share-page__* layout from Section 56. Colours reuse existing palette
        tokens only — no new hues.
   ============================================================================ */

/* --- 1. Evidence entity picker (dashboard share form) ---------------------- */

.evidence-pick {
    margin-top: var(--space-4);
    padding: var(--space-4);
    border: 1px solid var(--colour-ice);
    border-radius: var(--radius-sm);
    background-color: var(--colour-ice);
}

.evidence-pick__group {
    margin-top: var(--space-3);
    border: 1px solid var(--colour-border, #dee2e6);
    border-radius: var(--radius-sm);
    background-color: var(--colour-bg, #ffffff);
}

.evidence-pick__head {
    padding: var(--space-2) var(--space-3);
    font-weight: 600;
    font-size: 0.875rem;
    color: var(--colour-navy);
    cursor: pointer;
    user-select: none;
}

.evidence-pick__list {
    padding: var(--space-2) var(--space-3) var(--space-3);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    max-height: 200px;
    overflow-y: auto;
}

.evidence-pick__item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 0.8125rem;
    color: var(--colour-text, #2d3748);
    cursor: pointer;
}

.evidence-pick__item input[type="checkbox"] {
    flex-shrink: 0;
}

/* --- 2. Evidence public page ----------------------------------------------- */

/* Table wrapper — horizontal scroll on narrow viewports. */
.evidence-table-wrap {
    overflow-x: auto;
    margin-top: var(--space-3);
}

.evidence-table {
    width: 100%;
    font-size: 0.8125rem;
}

/* Test status badges — reuse existing palette; no new hues. */
.evidence-badge {
    display: inline-block;
    padding: 0.125rem 0.5rem;
    border-radius: var(--radius-sm);
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
}

.evidence-badge--pass {
    background-color: var(--colour-low, #2D6A4F);
    color: #ffffff;
}

.evidence-badge--fail {
    background-color: var(--colour-high, #8B1A1A);
    color: #ffffff;
}

.evidence-badge--not-tested {
    background-color: var(--colour-ice);
    color: var(--colour-steel);
}

/* Protective function tags (Deter / Detect / Delay / Respond). */
.evidence-func {
    display: inline-block;
    padding: 0.0625rem 0.375rem;
    margin: 0.0625rem 0.125rem;
    border-radius: var(--radius-sm);
    font-size: 0.6875rem;
    font-weight: 600;
    background-color: var(--colour-navy);
    color: #ffffff;
    white-space: nowrap;
}

/* Framework cards in the evidence page. */
.evidence-fw-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

.evidence-fw {
    padding: var(--space-3);
    border: 1px solid var(--colour-border, #dee2e6);
    border-radius: var(--radius-sm);
    background-color: var(--colour-bg, #ffffff);
}

.evidence-fw__head {
    margin-bottom: var(--space-2);
}

.evidence-fw__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* Compliance posture bar (pass / fail / not tested — framework card). */
.evidence-bar {
    display: flex;
    height: 1.5rem;
    border-radius: var(--radius-sm);
    overflow: hidden;
    font-size: 0.6875rem;
    font-weight: 600;
    line-height: 1.5rem;
    text-align: center;
    color: #ffffff;
}

.evidence-bar__seg--pass {
    background-color: var(--colour-low, #2D6A4F);
}

.evidence-bar__seg--fail {
    background-color: var(--colour-high, #8B1A1A);
}

.evidence-bar__seg--not-tested {
    background-color: var(--colour-steel);
}

/* End of Section 73 — Scoped External Auditor Portal (Session 87) */

/* ============================================================================
   SECTION 74 — Login View Reskin · Concept D "The Circumscription" (Session 102)
   ----------------------------------------------------------------------------
   Full-bleed pre-authentication screen (login card, MFA second factor, forced
   password change). Ported from login_concept_d.html, gated in front of the
   existing SPA shell — no change to account.php, to auth.js control flow, or
   to the session model.

   A seal's circumscription is the ring of words engraved around its edge. Two
   SVG text-on-path rings replace the S90 orrery: the outer ring carries the
   strategic vocabulary and drifts; the inner ring carries the operational
   cycle and is static. Both are declarative markup.

   NO color-mix() IN THIS SECTION — it is unguarded here by construction
   (the values feed custom properties, which have no fallback slot). Every
   colour is a root token or a literal rgba() of a root hue. Do not
   reintroduce a mix without a solid preceding declaration.

   PALETTE (Session 102 — the S90 EXCEPTION IS REMOVED):
   the S90 --login-ink / --login-brass / --login-parchment sub-palette was a
   deliberate one-off departure from the locked Deep Navy / Steel Blue / Muted
   Gold / Ice White set. It is now GONE. Every colour below derives from the
   :root brand tokens — no new hues. The scoped custom properties in
   .login-view are DERIVATIONS of those tokens (the --tone-* precedent), not a
   second palette: change the root tokens and this screen follows.

   FONTS: the app's local stack only (--font-display serif for display type,
   --font-mono for the engraved uppercase labels). No web font fetch (§2).

   MOTION: all of it is CSS. The guides draw in, the words fade in, the outer
   ring settles like a bezel being set, then carries an OPTIONAL slow ambient
   drift — one composited transform, no JS, no repaint. There is no interval
   and there are no mote nodes to clean up (the S89 cleanup-on-seal contract
   survives but has nothing left to tear down). Remove the .drift class from
   #login-ring-outer in auth.js build_login_shell to make the screen fully
   one-shot. prefers-reduced-motion disables everything regardless.

   CEREMONY STATES (the real api() promise drives these, not a timer):
     .verifying — the drift accelerates and the engraving brightens while
                  credentials are checked.
     .sealed    — the assembly stops dead and the whole engraving comes up to
                  full gold: the seal is struck. Then the welcome overlay.
   ============================================================================ */

.login-view {
    /* --- Derived from :root — NOT a sub-palette (see header) -------------
       Every value below is a root brand hue at alpha, written as literal
       rgba() channels: #D4AF37 = 212,175,55 (gold) and #F4F7F9 = 244,247,249
       (ice). This is the :root --tone-* / --gold-soft idiom ("derived tones —
       alpha of a brand hue, NOT new hues"), and it is deliberately NOT
       color-mix(): a color-mix() inside a custom property has no fallback
       path, so on an engine that cannot parse it EVERY consumer of that
       property goes invalid-at-computed-value at once — background-color
       falls back to transparent and SVG fill falls back to the root
       fill="none", taking the whole screen out. See the standing note at
       Section 68's matrix cells: solid value first, never an unguarded mix. */
    --login-ground:     var(--colour-navy);          /* stage */
    --login-surface:    var(--colour-navy);          /* card — separated by its border + shadow, not a tint */
    --login-line:       rgba(212, 175, 55, .30);     /* gold @30% — engraved rule / card edge */
    --login-line-faint: var(--gold-soft);            /* gold @16% — root token */
    --login-engraving:  rgba(212, 175, 55, .50);     /* outer circumscription */
    --login-engraving-hi: rgba(212, 175, 55, .70);   /* inner circumscription / verifying */
    --login-ink-dim:    rgba(244, 247, 249, .50);    /* ice @50% — secondary text */
    --login-shade:      rgba(0, 0, 0, .55);          /* depth only — a shade, not a hue */
    --login-ring-drift: 240s;   /* one full ambient revolution */

    position: fixed;
    inset: 0;
    z-index: 50;
    display: grid;
    place-items: center;
    padding-bottom: 76px;
    overflow: hidden;
    background-color: var(--login-ground);
    color: var(--colour-ice);
    font-family: var(--font-body);
}
.login-view__vignette {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(1200px 800px at 50% 42%, var(--gold-soft), transparent 60%),
        radial-gradient(closest-side at 50% 50%, transparent 55%, var(--login-shade) 100%);
}

/* --- Ring assembly (the circumscription) ---------------------------------- */
.login-rings {
    position: fixed;
    top: 50%;
    left: 50%;
    width: min(120vmin, 1000px);
    height: min(120vmin, 1000px);
    transform: translate(-50%, -50%);
    z-index: 0;
    pointer-events: none;
}
.login-rings svg { width: 100%; height: 100%; display: block; overflow: visible; }

/* Engraved guide circles — stroke-dashoffset draws them in once on load.
   3000 comfortably exceeds the longest circumference (r=452 ≈ 2840). */
.login-guide {
    fill: none;
    stroke: var(--login-line-faint);
    stroke-width: 1;
    stroke-dasharray: 3000;
    stroke-dashoffset: 3000;
    animation: login-draw 2.2s cubic-bezier(.4, 0, .2, 1) forwards;
    transition: stroke .6s ease;
}
.login-guide--accent { stroke: var(--login-line); animation-delay: .3s; }
@keyframes login-draw { to { stroke-dashoffset: 0; } }

/* Cardinal ticks between the two word rings. */
.login-tick {
    stroke: var(--login-line);
    stroke-width: 1;
    opacity: 0;
    animation: login-fade-in .8s ease 1.6s forwards;
    transition: stroke .6s ease;
}

/* The engraved circumscription text itself. */
.login-words {
    font-family: var(--font-mono);
    text-transform: uppercase;
    fill: var(--login-engraving);
    opacity: 0;
    animation: login-fade-in 1.2s ease forwards;
    transition: fill .6s ease;
}
.login-words--outer { font-size: 14px;   letter-spacing: .2em;  animation-delay: .9s; }
.login-words--inner { font-size: 12.5px; letter-spacing: .18em; animation-delay: 1.3s; fill: var(--login-engraving-hi); }
@keyframes login-fade-in { to { opacity: 1; } }

/* One-shot settle: the outer word ring rotates a few degrees into rest on
   load — the ring "seats" like a bezel being set. */
#login-ring-outer {
    transform-origin: 500px 500px;
    will-change: transform;
    animation: login-settle 2s cubic-bezier(.2, .8, .2, 1) forwards;
}
@keyframes login-settle { from { transform: rotate(-6deg); } to { transform: rotate(0deg); } }

/* Optional ambient drift — runs after the settle. Drop the .drift class in
   auth.js build_login_shell to make the screen fully one-shot. */
#login-ring-outer.drift {
    animation: login-settle 2s cubic-bezier(.2, .8, .2, 1) forwards,
               login-drift var(--login-ring-drift) linear 2s infinite;
}
@keyframes login-drift { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* Verifying — the drift winds up and the engraving brightens while the real
   account.php call is in flight. Replaces the S90 sweep arc.
   Sealed shares this exact declaration deliberately: seal() swaps .verifying
   for .sealed in one frame, so keeping the animation-name/duration identical
   means the animation is never restarted and the ring freezes precisely where
   it stood. Give .sealed its own animation and the ring snaps back to the
   settle keyframe's origin on the most conspicuous frame of the ceremony. */
.login-rings.verifying #login-ring-outer,
.login-rings.verifying #login-ring-outer.drift,
.login-rings.sealed    #login-ring-outer,
.login-rings.sealed    #login-ring-outer.drift {
    animation: login-drift 6s linear infinite;
}
.login-rings.verifying .login-words { fill: var(--login-engraving-hi); }
.login-rings.verifying .login-guide,
.login-rings.verifying .login-tick  { stroke: var(--login-line); }

/* Sealed — the assembly stops dead and the engraving comes up to full gold.
   Both selectors are needed: the shorthand above matches .drift at a higher
   specificity and would reset animation-play-state back to running. */
.login-rings.sealed #login-ring-outer,
.login-rings.sealed #login-ring-outer.drift { animation-play-state: paused; }
.login-rings.sealed .login-words { fill: var(--colour-gold); }
.login-rings.sealed .login-guide,
.login-rings.sealed .login-tick  { stroke: var(--colour-gold); }

/* --- Card ------------------------------------------------------------------ */
.login-card {
    position: relative;
    z-index: 3;
    width: min(420px, calc(100vw - 40px));
    background: var(--login-surface);
    border: 1px solid var(--login-line);
    box-shadow: 0 30px 80px var(--login-shade);
    padding: 44px 40px 38px;
    animation: login-card-in 1.1s cubic-bezier(.2, .8, .2, 1) both;
    animation-delay: .25s;
}
@keyframes login-card-in {
    from { opacity: 0; transform: translateY(22px) scale(.985); }
    to   { opacity: 1; transform: none; }
}

/* --- Wordmark -------------------------------------------------------------- */
.login-mark { text-align: center; margin-bottom: 8px; }
.login-mark h1 {
    font-family: var(--font-display);
    font-weight: 400;
    font-size: 30px;
    letter-spacing: .34em;
    text-indent: .34em;
    color: var(--colour-ice);
}
.login-mark h1 span { color: var(--colour-gold); }
.login-mark__rule {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 14px 0 10px;
    color: var(--colour-gold);
}
.login-mark__rule::before,
.login-mark__rule::after {
    content: "";
    flex: 1;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--login-line));
}
.login-mark__rule::after { background: linear-gradient(90deg, var(--login-line), transparent); }
.login-mark__rule svg { width: 14px; height: 14px; flex: none; }
.login-tagline {
    text-align: center;
    font-family: var(--font-mono);
    font-size: 10.5px;
    letter-spacing: .22em;
    color: var(--login-ink-dim);
    text-transform: uppercase;
    margin-bottom: 34px;
}

/* --- Fields ---------------------------------------------------------------- */
.login-field { position: relative; margin-bottom: 26px; }
.login-field__input {
    width: 100%;
    background: transparent;
    border: none;
    outline: none;
    border-bottom: 1px solid var(--login-ink-dim);
    color: var(--colour-ice);
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 400;
    padding: 10px 34px 10px 2px;
    transition: border-color .3s;
}
.login-field__input:-webkit-autofill {
    -webkit-text-fill-color: var(--colour-ice);
    transition: background-color 99999s;
}
.login-field__label {
    position: absolute;
    left: 2px;
    top: 10px;
    color: var(--login-ink-dim);
    font-size: 16px;
    font-weight: 400;
    pointer-events: none;
    transition: all .28s cubic-bezier(.2, .8, .2, 1);
}
.login-field__input:focus + .login-field__label,
.login-field__input:not(:placeholder-shown) + .login-field__label {
    top: -13px;
    font-size: 10.5px;
    font-family: var(--font-mono);
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--colour-gold);
}
.login-field__draw {
    position: absolute;
    left: 0;
    bottom: 0;
    height: 1px;
    width: 100%;
    background: var(--colour-gold);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform .45s cubic-bezier(.2, .8, .2, 1);
}
.login-field__input:focus ~ .login-field__draw { transform: scaleX(1); }
/* Error uses the locked risk-high hue — the S90 scoped heraldic red is gone. */
.login-field.error .login-field__input { border-bottom-color: var(--risk-high); }
.login-field.error .login-field__label { color: var(--risk-high); }

.login-peek {
    position: absolute;
    right: -6px;
    top: 2px;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--login-ink-dim);
    padding: 10px;
    transition: color .2s;
}
.login-peek:hover, .login-peek:focus-visible { color: var(--colour-gold); }
.login-peek svg { width: 18px; height: 18px; display: block; }

.login-row { margin: -6px 0 30px; font-size: 13px; color: var(--login-ink-dim); }
.login-row a {
    color: var(--login-ink-dim);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: all .2s;
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: .04em;
}
.login-row a:hover, .login-row a:focus-visible {
    color: var(--colour-gold);
    border-bottom-color: var(--colour-gold);
}

/* --- Submit button ---------------------------------------------------------- */
.login-enter {
    position: relative;
    width: 100%;
    overflow: hidden;
    background: var(--colour-gold);
    cursor: pointer;
    border: 1px solid var(--colour-gold);
    color: var(--colour-navy);
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: 12px;
    letter-spacing: .18em;
    text-indent: .18em;
    text-transform: uppercase;
    padding: 15px 0 14px;
    transition: box-shadow .25s ease, transform .25s ease;
}
/* The concept's button is a solid gold slab, so the S90 wipe-fill is retired:
   the span stays in the markup (auth.js) as an inert layer, not a mechanism. */
.login-enter__fill { display: none; }
.login-enter__lbl { position: relative; z-index: 1; }
.login-enter:hover, .login-enter:focus-visible {
    transform: translateY(-1px);
    box-shadow: 0 10px 24px var(--login-line);
}
.login-enter:focus-visible { outline: 2px solid var(--colour-gold); outline-offset: 3px; }
.login-enter:disabled { cursor: default; opacity: .7; transform: none; box-shadow: none; }

.login-back {
    display: block;
    width: 100%;
    margin-top: 14px;
    background: none;
    border: none;
    cursor: pointer;
    color: var(--login-ink-dim);
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: .12em;
    text-transform: uppercase;
    text-align: center;
    transition: color .2s;
}
.login-back:hover, .login-back:focus-visible { color: var(--colour-gold); }

/* --- Status line ------------------------------------------------------------- */
.login-status {
    min-height: 20px;
    margin-top: 20px;
    text-align: center;
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--login-ink-dim);
    transition: color .3s;
}
.login-status.err { color: var(--risk-high); }
.login-status.ok  { color: var(--colour-gold); }
.login-status .login-dots::after {
    content: "";
    animation: login-dots 1.2s steps(4, end) infinite;
}
@keyframes login-dots {
    0%  { content: ""; }
    25% { content: "."; }
    50% { content: ".."; }
    75% { content: "..."; }
}

/* --- Footer -------------------------------------------------------------------- */
.login-foot {
    position: fixed;
    bottom: 22px;
    left: 0;
    right: 0;
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px 26px;
    padding: 0 24px;
    font-family: var(--font-mono);
    font-size: 10px;
    letter-spacing: .2em;
    text-transform: none;
    color: var(--login-ink-dim);
    text-align: center;
}
.login-foot a { color: inherit; text-decoration: none; border-bottom: 1px solid transparent; transition: all .2s; }
.login-foot a:hover, .login-foot a:focus-visible { color: var(--colour-gold); border-bottom-color: var(--colour-gold); }
/* Separator lives inside its following item so a wrap never strands a bare dot. */
.login-foot__sep { margin-right: 10px; opacity: .7; }
/* Forces App Status onto its own line, independent of wrap width. */
.login-foot__break { flex-basis: 100%; height: 0; }

/* --- Deny shake / success ceremony ------------------------------------------------ */
.login-card.deny { animation: login-deny .45s cubic-bezier(.36, .07, .19, .97); }
@keyframes login-deny {
    10%, 90% { transform: translateX(-1px); }
    20%, 80% { transform: translateX(2px); }
    30%, 50%, 70% { transform: translateX(-4px); }
    40%, 60% { transform: translateX(4px); }
}
.login-card.granted { animation: login-card-out .8s cubic-bezier(.6, 0, .8, 1) both; }
@keyframes login-card-out {
    to { opacity: 0; transform: translateY(-16px) scale(.97); filter: blur(2px); }
}
.login-welcome {
    position: fixed;
    z-index: 3;
    inset: 0;
    display: grid;
    place-items: center;
    opacity: 0;
    pointer-events: none;
    text-align: center;
}
.login-welcome.show { animation: login-welcome-in 1s .5s cubic-bezier(.2, .8, .2, 1) both; }
@keyframes login-welcome-in {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: none; }
}
.login-welcome h2 {
    font-family: var(--font-display);
    font-weight: 400;
    font-size: 26px;
    letter-spacing: .3em;
    text-indent: .3em;
    color: var(--colour-gold);
}
.login-welcome p {
    margin-top: 14px;
    font-family: var(--font-mono);
    font-size: 11px;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--login-ink-dim);
}

/* --- Reduced motion / narrow viewport ----------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    .login-view *, .login-view *::before, .login-view *::after {
        animation: none !important;
        transition: none !important;
    }
    .login-guide { stroke-dashoffset: 0 !important; }
    .login-words, .login-tick { opacity: 1 !important; }
    #login-ring-outer { transform: rotate(0deg) !important; }
}
@media (max-width: 640px) {
    /* Ring words stay legible; the card dominates. */
    .login-rings { width: 170vmin; height: 170vmin; }
}
@media (max-width: 480px) {
    .login-card { padding: 38px 26px 32px; }
    .login-mark h1 { font-size: 24px; }
    .login-foot { bottom: 14px; padding: 0 16px; }
}

/* End of Section 74 — Login View Reskin · Concept D (Session 102) */


/* ============================================================================
   SECTION 75 — Static Legal / Info Pages (privacy.html, future status.html)
   ----------------------------------------------------------------------------
   Standalone unauthenticated pages served outside the SPA shell, linked from
   auth.js login-foot. Locked palette only (§2) — no exception here, unlike
   Section 74's login-view.
   ============================================================================ */
.legal-page {
    min-height: 100vh;
    background-color: var(--colour-ice);
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: var(--space-6) var(--space-4);
}
.legal-page__header {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    margin-bottom: var(--space-6);
}
/* .brand__mark defaults to --colour-ice (Section 5) for the navy header bar —
   wrong contrast on this page's ice background. Override scoped here only. */
.legal-page__header .brand__mark {
    color: var(--colour-navy);
}
.legal-page__body {
    width: 100%;
    max-width: 720px;
    color: var(--colour-navy);
}
.legal-page__body h1 {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    margin-bottom: var(--space-2);
}
.legal-page__body h2 {
    font-family: var(--font-display);
    font-size: var(--text-md);
    margin: var(--space-5) 0 var(--space-2);
    color: var(--colour-steel);
}
.legal-page__body p {
    font-size: var(--text-sm);
    line-height: 1.6;
    color: var(--colour-navy);
}
.legal-page__meta {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--colour-steel);
    margin-bottom: var(--space-4);
}
.legal-page__back {
    margin-top: var(--space-6);
}
.legal-page__foot {
    margin-top: var(--space-6);
    font-size: var(--text-xs);
    color: var(--colour-steel);
}

/* Mobile responsive — Section 75 */
@media (max-width: 640px) {
    .legal-page {
        padding: var(--space-4) var(--space-3);
    }
    .legal-page__header {
        flex-wrap: wrap;
        margin-bottom: var(--space-4);
    }
    .legal-page__header .brand__tagline {
        width: 100%;
        font-size: var(--text-xs);
        margin-top: var(--space-1);
    }
    .legal-page__body {
        max-width: 100%;
    }
    .legal-page__body h1 {
        font-size: var(--text-lg);
        margin-bottom: var(--space-3);
    }
    .legal-page__body h2 {
        font-size: var(--text-base);
        margin: var(--space-4) 0 var(--space-2);
    }
    .legal-page__body p {
        font-size: var(--text-sm);
    }
    .legal-page__back {
        width: 100%;
        min-height: 48px;
        display: flex;
        align-items: center;
        justify-content: center;
    }
}

/* End of Section 75 — Static Legal / Info Pages */


/* ============================================================================
   SECTION 76 — Module 24 SCRM Expansion (Session 97)
   ----------------------------------------------------------------------------
   Tab navigation, SCRM-specific layout, and risk-band badges for vendor risks.
   Reuses existing palette tokens and Section 54 vendor primitives throughout.
   No new colours — IRV bands reuse the §8.1 risk-band badge classes.
   ---------------------------------------------------------------------------- */

/* --- SCRM tab navigation --- */
.scrm-tabs {
    display: flex;
    gap: var(--space-1);
    margin-bottom: var(--space-4);
    border-bottom: 2px solid var(--tone-border);
    padding-bottom: 0;
}
.scrm-tab {
    padding: var(--space-2) var(--space-3);
    border: none;
    background: transparent;
    color: var(--colour-steel);
    font-size: var(--text-sm);
    font-weight: 500;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -2px;
    transition: color 0.15s, border-color 0.15s;
}
.scrm-tab:hover {
    color: var(--colour-navy);
}
.scrm-tab--active {
    color: var(--colour-navy);
    border-bottom-color: var(--colour-gold);
}

/* --- Tab header row (filter + action button) --- */
.scrm-tab-head {
    display: flex;
    align-items: flex-end;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
    flex-wrap: wrap;
}
.scrm-tab-head .field--inline {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
.scrm-tab-head .field--inline .field__label {
    margin-bottom: 0;
    white-space: nowrap;
    font-size: var(--text-sm);
}

/* --- Detail panel SCRM summary counts --- */
.scrm-detail-counts {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: var(--space-3) 0;
}
.scrm-count-chip {
    font-size: var(--text-xs);
    padding: 2px var(--space-2);
    background: rgba(74, 105, 132, 0.08);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm, 4px);
    color: var(--colour-navy);
}

/* --- Overdue row tint for SCAR actions --- */
.scrm-overdue {
    background-color: rgba(139, 26, 26, 0.06);
}

/* --- Narrow-viewport: stack tabs horizontally scrollable --- */
@media (max-width: 720px) {
    .scrm-tabs {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    .scrm-tab {
        white-space: nowrap;
        flex-shrink: 0;
    }
    .scrm-tab-head {
        flex-direction: column;
        align-items: stretch;
    }
    .scrm-tab-head .field--inline {
        flex-direction: column;
        align-items: stretch;
    }
}

/* End of Section 76 — Module 24 SCRM Expansion (Session 97) */

/* ----------------------------------------------------------------------------
   SECTION 77 — Pillar 4 Intelligence and Feeds (Session 98)
   ----------------------------------------------------------------------------
   Styling for the Intelligence tab (vendor_intel) and Feeds tab (vendor_feed).
   Reuses existing palette tokens and badge classes throughout.
   No new colours introduced.
   ---------------------------------------------------------------------------- */

/* --- Intelligence summary cell — prevent table blowout --- */
.intel-summary-cell {
    max-width: 320px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* --- Feed card (built-in feeds list) --- */
.feed-card {
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm, 4px);
    padding: var(--space-3);
    margin-bottom: var(--space-2);
    background: transparent;
    transition: border-color 0.15s;
}
.feed-card--enabled {
    border-color: var(--risk-low);
    background: rgba(45, 106, 79, 0.03);
}
.feed-card__head {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-1);
}
.feed-card__foot {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-2);
    flex-wrap: wrap;
}

/* --- Feed status badges --- */
.badge--feed-success { background: rgba(45, 106, 79, 0.12); color: var(--risk-low); }
.badge--feed-partial { background: rgba(193, 127, 36, 0.12); color: var(--risk-medium); }
.badge--feed-error   { background: rgba(139, 26, 26, 0.12); color: var(--risk-high); }

/* --- Narrow viewport: intel table and feed cards --- */
@media (max-width: 720px) {
    .intel-summary-cell {
        max-width: 160px;
    }
    .feed-card__foot {
        flex-direction: column;
        align-items: flex-start;
    }
}

/* End of Section 77 — Pillar 4 Intelligence and Feeds (Session 98) */

/* ----------------------------------------------------------------------------
   Section 78 — SCRM Enhancements (Session 99)
   Feed vendor-assignment checklist; vendor control-posture summary.
   ---------------------------------------------------------------------------- */

/* --- Vendor assignment checklist (feed scoping picker) --- */
.checklist {
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm, 4px);
    padding: var(--space-2);
}
.checklist__row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) 0;
    font-size: var(--text-sm);
    cursor: pointer;
}
.checklist__row:not(:last-child) {
    border-bottom: 1px solid rgba(74, 105, 132, 0.1);
}

/* --- Vendor control-posture summary (posture derivation) --- */
.posture-summary {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm, 4px);
    margin-bottom: var(--space-2);
}
.posture-summary__pct {
    font-size: var(--text-lg);
    font-weight: 600;
}
.posture-summary__pct--good { color: var(--risk-low); }
.posture-summary__pct--fair { color: var(--risk-medium); }
.posture-summary__pct--poor { color: var(--risk-high); }

/* End of Section 78 — SCRM Enhancements (Session 99) */

/* ----------------------------------------------------------------------------
   Section 79 — SCRM Close-out (Session 100)
   Vendor controls panel, force-directed graph, posture chip tinting.
   ---------------------------------------------------------------------------- */

/* --- Vendor controls list (detail panel, mirrors asset-ctrl pattern) --- */
.vendor-ctrl-list {
    list-style: none;
    padding: 0;
    margin: var(--space-2) 0;
}
.vendor-ctrl-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) 0;
    font-size: var(--text-sm);
}
.vendor-ctrl-item:not(:last-child) {
    border-bottom: 1px solid rgba(74, 105, 132, 0.1);
}
.vendor-ctrl-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.vendor-ctrl-add {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-2);
}
.vendor-ctrl-add .field__select { flex: 1; }

/* --- Posture chip tinting (count chips bar) --- */
.scrm-posture--good { background: var(--risk-low);    color: var(--ice-white); }
.scrm-posture--mixed { background: var(--risk-medium); color: var(--ice-white); }
.scrm-posture--poor  { background: var(--risk-high);   color: var(--ice-white); }

/* --- Force-directed dependency graph canvas --- */
.dep-graph-canvas-wrap {
    width: 100%;
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm, 4px);
    margin-bottom: var(--space-3);
    background: var(--ice-white);
}
.dep-graph-canvas-wrap canvas {
    display: block;
    width: 100%;
}
.dep-graph-table-toggle summary {
    cursor: pointer;
    font-size: var(--text-sm);
}

/* End of Section 79 — SCRM Close-out (Session 100) */

/* ----------------------------------------------------------------------------
   Section 80 — Location Intelligence (Session 104, Module 27)
   Vector grid, score chips, inheritance/lock flags, threat-zone and briefing
   list states, feed adapter cards.

   NO NEW COLOURS. Every rule below draws on the fixed brand palette and the
   CSMP five-band heat-map variables already defined at the top of this file.
   The band classes (.badge--band-*) are reused for the 1–5 location chips
   because the palette is fixed and shared — a location score is NOT an IRV
   band and carries no methodology (MPD §5.1). The tab chrome, cards, tables and
   message line are reused wholesale from the SCRM sections (77–79).
   ---------------------------------------------------------------------------- */

/* --- Tab-head filter control (sits beside the primary action button) --- */
.loc-filter {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-left: var(--space-3);
}
.loc-filter select { min-width: 12rem; }

/* --- Explanatory note under a table or panel (small, quiet, never a warning) --- */
.loc-note {
    margin-top: var(--space-3);
    font-size: 0.85rem;
    line-height: 1.5;
}

/* --- Location profile panel ------------------------------------------------ */
.loc-profile__summary {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-5);
    margin: var(--space-3) 0 var(--space-4);
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--tone-border);
}
.loc-stat {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
.loc-stat__label {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--colour-steel);
}

/* ---- S147: the risk index opens INSIDE the register row ------------------
   It previously rendered as a full card ABOVE the list, which listed a scored
   country twice and filled the page with 27 vectors. The expanded row is
   indented and washed so it reads as belonging to the row above it. */
.loc-row-detail > td {
    padding: 0 var(--space-4) var(--space-4);
    background-color: var(--tone-hover);
    border-top: none;
    box-shadow: inset 3px 0 0 var(--colour-gold);
}
/* The expanded profile body. Until S147 this rode on .card for its styling and
   carried no rule of its own; with the card wrapper gone it owns its spacing. */
.loc-profile { padding-top: var(--space-3); }

/* Disclosure chevron on the location name. */
.loc-toggle { text-align: left; }
.loc-toggle__chev {
    display: inline-block;
    width: 1em;
    margin-right: var(--space-1);
    color: var(--colour-steel);
}
.loc-notes {
    margin: 0 0 var(--space-4);
    padding: var(--space-3);
    background-color: var(--tone-hover);
    border-left: 3px solid var(--colour-steel);
    font-size: 0.9rem;
}

/* --- Vector group heading (one per category group; six groups, 27 vectors) --- */
.loc-group { margin-bottom: var(--space-4); }
.loc-group-head {
    margin: var(--space-4) 0 var(--space-2);
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--colour-steel);
    border-bottom: 1px solid var(--tone-border);
    padding-bottom: var(--space-1);
}

/* --- Vector grid: the 27-vector read-only display on the profile panel --- */
.loc-vector-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    gap: var(--space-2);
}
.loc-vector {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    background-color: var(--colour-ice);
}
/* An unscored vector is stated plainly rather than hidden — a gap in coverage
   is information, not an absence to paper over. */
.loc-vector--unscored { opacity: 0.6; }
.loc-vector__label {
    flex: 1;
    font-size: 0.85rem;
}
.loc-vector__meta {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    font-size: 0.7rem;
}

/* --- Provenance flags ------------------------------------------------------
   `inherited`: shown live-on-read from the nearest scored ancestor, never stored.
   `locked`   : a manual override a feed must not overwrite.
   Both are quiet steel/gold chips — status markers, not risk signals, so neither
   borrows the heat-map hues. */
.loc-inherited,
.loc-locked {
    display: inline-block;
    padding: 1px var(--space-1);
    border-radius: var(--radius-sm);
    font-size: 0.7rem;
    letter-spacing: 0.02em;
    white-space: nowrap;
}
.loc-inherited {
    border: 1px dashed var(--colour-steel);
    color: var(--colour-steel);
}
.loc-locked {
    border: 1px solid var(--colour-gold);
    color: var(--colour-navy);
    background-color: rgba(212, 175, 55, 0.14);   /* --colour-gold at low alpha */
}

/* --- Risk Index tab -------------------------------------------------------- */
.loc-index-head { margin-bottom: var(--space-3); }
/* A row with no own score reads back a shade lighter. */
.loc-row--unscored td { opacity: 0.65; }
/* Inline editor row inside the vectors table. */
.loc-score-form > td {
    background-color: var(--tone-hover);
    padding: var(--space-3);
}

/* --- Threat zones ---------------------------------------------------------- */
.loc-zone-list,
.loc-child-list,
.loc-adapter-list {
    list-style: none;
    padding: 0;
    margin: var(--space-2) 0;
}
.loc-zone-item,
.loc-child-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--tone-border);
}
.loc-zone-item__name { font-weight: 600; }
/* A zone outside its active window stays visible but is plainly historic. */
.loc-zone-item--historic { opacity: 0.55; }
.loc-row--historic td { opacity: 0.55; }

/* --- Briefings ------------------------------------------------------------- */
.loc-row--overdue td { background-color: rgba(139, 26, 26, 0.06); }  /* --risk-high at low alpha */
.loc-overdue {
    color: var(--risk-high);
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.loc-purpose {
    margin: 0 0 var(--space-2);
    font-size: 0.9rem;
}
/* Category multi-select for scoping a briefing to a subset of the 27 vectors. */
.loc-cat-picker {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
    gap: var(--space-1);
    max-height: 14rem;
    overflow-y: auto;
    padding: var(--space-2);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    background-color: var(--colour-ice);
}
.loc-cat-opt {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    font-size: 0.85rem;
    font-weight: 400;
}

/* --- Feeds: the adapter catalog an administrator may switch on --- */
.loc-adapter {
    padding: var(--space-3);
    margin-bottom: var(--space-2);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    background-color: var(--colour-ice);
}
.loc-adapter p {
    margin: var(--space-1) 0 0;
    font-size: 0.85rem;
}

/* --- Form chrome (mirrors .vendor-form__* — same two-column grid idiom) --- */
.loc-form__title {
    margin: 0 0 var(--space-4);
    font-size: var(--text-lg);
    color: var(--colour-navy);
}
.loc-form__grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-4);
}
/* A control that needs the full width of the two-column form grid. */
.loc-span-2 { grid-column: 1 / -1; }
.loc-form__actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-4);
}

/* --- Score cell inside the profile vector grid --- */
.loc-vector__score { flex: 0 0 auto; }

/* End of Section 80 — Location Intelligence (Session 104) */


/* ----------------------------------------------------------------------------
   Section 81 — Physical Security Assessment (Session 106, Module 28)
   The module's OWN section sidebar, its survey form grid, and the survey
   status chips.

   NO NEW COLOURS. Every rule below draws on the fixed brand palette and the
   derived tones already defined at the top of this file. The survey status
   chips are this module's own modifiers (the .badge--proj-* convention,
   Section 32) and deliberately do NOT reuse the .badge--band-* heat-map
   palette: a survey status is a lifecycle position, not a risk band, and a
   survey finding is never a scoring input (MPD §5.1). Cards, fields, tables,
   the tab-head action row and the message line are reused wholesale from the
   SCRM / Location sections (77–80). Session 110 (build session 5, the
   Heatmap section) is the ONE deliberate exception to the status-chip rule
   above: its tiles DO draw on the --band-* ramp, as an owner-directed
   aggregate posture indicator computed locally in survey.php — see that
   block's own comment further down this section for the full rationale.
   ---------------------------------------------------------------------------- */

/* --- Module layout: the module's own sidebar beside its panel ---------------
   Owner-directed (S105): navigation between Module 28's internal sections
   happens HERE, inside the module's own screen. The surveyor never leaves for
   Sites & Assets, Controls, Mitigation or Assessment Questionnaires mid-survey.
   Collapses to a single column on narrow viewports, sidebar first. */
.svy-layout {
    display: grid;
    grid-template-columns: 13rem 1fr;
    gap: var(--space-5);
    align-items: start;
    margin-top: var(--space-4);
}
@media (max-width: 900px) {
    .svy-layout { grid-template-columns: 1fr; }
}

/* --- The module's own section sidebar --- */
.svy-nav {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-2);
    background-color: var(--colour-white);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius);
    box-shadow: 0 1px 2px var(--tone-shadow);
}
.svy-nav__item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    width: 100%;
    padding: var(--space-2) var(--space-3);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    text-align: left;
    color: var(--colour-navy);
    background-color: transparent;
    border: none;
    border-left: 3px solid transparent;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background-color var(--transition), border-color var(--transition);
}
.svy-nav__item:hover { background-color: var(--tone-hover); }

/* The active section — gold marker, the accent's established role. */
.svy-nav__item--active {
    background-color: var(--gold-soft);
    border-left-color: var(--colour-gold);
    font-weight: 600;
}

/* A section declared but not yet built. Quiet by design: it states what is
   coming, it is not a warning. */
.svy-nav__flag {
    font-size: var(--text-xs);
    color: var(--colour-steel);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* --- Panel column --- */
.svy-panel { min-width: 0; }   /* lets a wide table scroll inside the grid cell */

/* --- Survey form ----------------------------------------------------------- */
.svy-form__title {
    margin: 0 0 var(--space-4);
    font-family: var(--font-display);
    font-size: var(--text-md);
    color: var(--colour-navy);
}
.svy-form__grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-4);
}
/* A control that needs the full width of the two-column form grid. */
.svy-span-2 { grid-column: 1 / -1; }
.svy-form__actions {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-4);
}
@media (max-width: 720px) {
    .svy-form__grid { grid-template-columns: 1fr; }
}

/* --- Explanatory note under a table (small, quiet, never a warning) --- */
.svy-note {
    margin: var(--space-3) 0 0;
    font-size: var(--text-xs);
}

/* --- Survey status chips (the .badge--proj-* convention, Section 32) -------- */
.badge--svy-planned {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}
.badge--svy-in-progress {
    background-color: rgba(212, 175, 55, 0.16);   /* gold tint — derived, not a new hue */
    color: var(--colour-navy);
    border: 1px solid var(--colour-gold);
}
.badge--svy-complete {
    background-color: rgba(45, 106, 79, 0.14);    /* mirrors .badge--complete */
    color: var(--risk-low);
    border: 1px solid var(--risk-low);
}
.badge--svy-cancelled {
    background-color: transparent;
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
    text-decoration: line-through;
}

/* --- Conduct: the single-screen survey flow (Session 107, build session 2) ---
   Owner-directed (S105): the subject picker, the questions and the responses sit
   on ONE screen inside this module. These rules carry no colours of their own —
   they are layout only, over the same cards, fields and chips already defined
   above. A finding is never tinted by the risk-band palette (§5.1). */

/* The survey chooser sits above the flow, so the section is reachable directly
   as well as from a register row's Conduct action. */
.svy-conduct__pick { max-width: 34rem; }

/* Title row of the subject strip — name on the left, state on the right. */
.svy-conduct__head { align-items: flex-start; gap: var(--space-4); }
.svy-conduct__head .svy-form__title { margin-bottom: var(--space-4); }

.svy-conduct__chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
}

/* Gap count beside the progress figure. Deliberately UNTINTED: a finding is a
   qualitative record, not a risk band (§5.1). */
.svy-conduct__gaps { color: var(--colour-navy); font-weight: 600; }

.svy-conduct__qhead { margin-top: var(--space-5); }
.svy-conduct__qhead .svy-form__title { margin-bottom: 0; }
.svy-conduct__qhead .svy-note { margin-top: var(--space-2); }

/* The answer stack. Each question is its own card, as in Module 20. */
.svy-responses {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-top: var(--space-4);
}
.svy-resp { padding: var(--space-4); }

.svy-resp__q {
    margin-bottom: var(--space-3);
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--colour-navy);
}

/* Answer · finding · note across one row, stacking on a narrow viewport. */
.svy-resp__grid {
    display: grid;
    grid-template-columns: 2fr 1fr 2fr;
    gap: var(--space-4);
    align-items: start;
}
@media (max-width: 900px) {
    .svy-resp__grid { grid-template-columns: 1fr; }
}

/* The escalation seam (G13b) — present on the survey screen because the module
   forbids sending a surveyor to Module 20 to act on a gap (S105). */
.svy-resp__escalation {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-3);
    padding-top: var(--space-3);
    border-top: 1px solid var(--tone-border);
}
.svy-resp__escalation .svy-note { margin-top: 0; }

.svy-conduct__actions { margin-top: var(--space-4); }

/* --- Evidence: capture + chain of custody (Session 108, build session 3) -----
   Layout only. The list reuses the shared .table / .card / .btn surfaces; these
   rules only size the evidence-specific cells. No new colours — every value is
   an existing token, and a hash / filename is neutral chrome, never a band. --- */
.svy-ev__name {
    font-weight: 600;
    color: var(--colour-steel);
    word-break: break-word;
}
.svy-ev__caption {
    margin-top: var(--space-1);
    font-size: var(--text-sm);
    color: var(--colour-steel);
}
.svy-ev__tags {
    font-size: var(--text-sm);
    line-height: 1.4;
}
/* The SHA-256 cell is a fixed-width fingerprint: monospace, non-wrapping, with
   the full digest on hover (title attribute). */
.svy-ev__hash {
    white-space: nowrap;
    font-size: var(--text-sm);
    cursor: help;
}

/* --- Schedule: recurring cadence + escalation (Session 109, build session 4) --
   Owner-directed (S105): the cadence list and its form sit on ONE screen inside
   this module. These rules are LAYOUT ONLY, over the same cards, tables, fields
   and status chips already defined above — a schedule's On/Off state reuses the
   .badge--svy-complete / .badge--svy-cancelled chips, carrying no new colour. */

/* The enabled toggle spans the form grid so its label sits on its own line. */
.svy-sched__enable { grid-column: 1 / -1; }

/* Inline checkbox + label row for the enabled toggle. */
.field__check {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    cursor: pointer;
}
.field__check input[type="checkbox"] { flex: 0 0 auto; }

/* --- Heatmap: enterprise-to-facility drill-down (Session 110, build session 5)
   A SITE-tile grid, drilling into an ASSET-tile grid for one site. Filters
   mirror the .leg-filter-bar / .aud-filter-bar convention (flex row, fields
   with margin-bottom zeroed). Legend markup is the EXISTING .dash-legend /
   .dash-legend__swatch pair (Section 70), reused verbatim — not redeclared.

   NO NEW COLOURS: tile colour rules below reference ONLY the --band-* custom
   properties already defined at the top of this file (§1) — the same five
   values the org-wide risk heat-map (dashboard.js Section 70) draws on. The
   band value itself is computed server-side in survey.php from this module's
   OWN gap/concern ratio, never from scoring.php (§5.1) — see the
   SVY_POSTURE_BANDS docblock there. This is a DELIBERATE, owner-directed
   (S110) extension of the band ramp to a second, unrelated aggregate: it does
   NOT reverse the survey-status-chip discipline stated at the top of this
   section (a status is a lifecycle position, never a band). */
.svy-heat__filters {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
    padding: var(--space-3);
    background-color: var(--tone-hover);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
}
.svy-heat__filters .field { margin-bottom: 0; }

.svy-heat__summary {
    color: var(--colour-steel);
    font-size: var(--text-sm);
    margin-bottom: var(--space-3);
}

.svy-heat__crumb {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}
.svy-heat__crumb-name {
    font-weight: 600;
    color: var(--colour-navy);
}

.svy-heat__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: var(--space-3);
}

/* A tile is a plain <button> — reset the default chrome, then style as a
   card. Text sits on the band colour, so it takes the ice/navy pairing the
   .dash-heat__cell rules already use for the same ramp. */
.svy-heat__tile {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
    padding: var(--space-3);
    font: inherit;
    text-align: left;
    cursor: pointer;
    border-radius: var(--radius);
    border: 1px solid var(--tone-border);
    box-shadow: 0 1px 2px var(--tone-shadow);
    background-color: var(--tone-hover);
    color: var(--colour-navy);
}
.svy-heat__tile:hover  { filter: brightness(1.06); }
.svy-heat__tile:focus-visible { outline: 2px solid var(--colour-gold); outline-offset: 2px; }
.svy-heat__tile-name { font-weight: 600; font-size: var(--text-sm); }
.svy-heat__tile-band { font-size: var(--text-xs); opacity: 0.9; }
.svy-heat__tile-meta { font-size: var(--text-xs); opacity: 0.85; }

/* Unscored — no answered responses yet. Neutral, never a band colour: an
   unscored tile must never read as "clean" (mirrors the risk_register
   no-sentinel discipline, §2.1). */
.svy-heat__tile--none {
    background-color: var(--colour-white);
    border-style: dashed;
}

/* Occupied tiles draw the five-band ramp (§1) — light bands take navy text
   for contrast, exactly as .dash-heat__cell--low does. */
.svy-heat__tile--negligible { background-color: var(--band-negligible); color: var(--colour-ice); }
.svy-heat__tile--low        { background-color: var(--band-low); }
.svy-heat__tile--moderate   { background-color: var(--band-moderate); color: var(--colour-ice); }
.svy-heat__tile--high       { background-color: var(--band-high); color: var(--colour-ice); }
.svy-heat__tile--extreme    { background-color: var(--band-extreme); color: var(--colour-ice); }

/* --- Reports: framework-mapped templates (Session 111, build session 6) ------
   User-uploaded report templates (ASIS/FEMA/NIST-PE/custom). LAYOUT ONLY — the
   section tree, its item lists and the inline section/mapping forms sit over the
   same cards, fields and chips already defined above. No new hues: the two new
   status chips reuse the SAME derived tints as the survey-status chips (§2). A
   template is a presentation artefact, never tinted by the risk-band palette. */

/* Two new lifecycle chips for a template's draft/active/archived status. These
   reuse the exact tints of the survey-status chips above — no new colour. */
.badge--svy-draft {
    background-color: var(--tone-hover);
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}
.badge--svy-active {
    background-color: rgba(45, 106, 79, 0.14);    /* mirrors .badge--svy-complete */
    color: var(--risk-low);
    border: 1px solid var(--risk-low);
}
.badge--svy-archived {
    background-color: transparent;
    color: var(--colour-steel);
    border: 1px solid var(--tone-border-strong);
}

/* The section tree. Indentation for nested sections comes from __children; the
   whole surface is neutral chrome over the module's existing card styling. */
.svy-tpl__tree { display: flex; flex-direction: column; gap: var(--space-3); }

.svy-tpl__section {
    border: 1px solid var(--tone-border);
    border-radius: var(--radius);
    padding: var(--space-3) var(--space-4);
    background-color: var(--colour-white);
}

/* A section's title row — reference + title on the left, actions on the right. */
.svy-tpl__section-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
    justify-content: space-between;
}
.svy-tpl__section-actions { display: inline-flex; gap: var(--space-3); }

/* The mapped-item list under a section. */
.svy-tpl__items { list-style: none; margin: var(--space-2) 0 0; padding: 0; }
.svy-tpl__item {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-1) 0;
}

/* Nested subsections indent from their parent. */
.svy-tpl__children {
    margin-top: var(--space-3);
    padding-left: var(--space-4);
    border-left: 2px solid var(--tone-border);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* An inline create/edit form (section or mapping) sits inside a section card. */
.svy-tpl__inline-form { margin-top: var(--space-3); }

/* A destructive link button (remove tag / delete section) — the same link
   button as elsewhere, tinted with the locked High-risk red for affordance
   only; no new colour token. */
.svy-tpl__del { color: var(--risk-high); }

/* A form field that should span the full width of the form grid. */
.svy-form__wide { grid-column: 1 / -1; }

/* End of Section 81 — Physical Security Assessment (Sessions 106, 107, 108, 109, 110, 111) */

/* ============================================================================
   SECTION 82 — Assessment Question Bank Import  (Session 112, Module 28 build 7/7)
   ----------------------------------------------------------------------------
   Layout-only additions for the bulk question-import surface and the new
   per-question SECTION grouping in the questionnaire builder. NO new colours —
   every rule draws on existing palette / tone / spacing tokens. The import
   panel reuses the shared .card, .field, .table, .btn and .u-* primitives; the
   rules below are only the spacing/structure the shared primitives do not give.
   ============================================================================ */

/* Pane-head action cluster: the "Import questions" + "New questionnaire" pair
   sit together, right-aligned, sharing the pane header with the title. */
.as-pane-head__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* --- Section grouping in the builder -------------------------------------- */
/* The per-question section input spans the full builder-row width, above the
   question text, so the grouping reads clearly as you scroll a long bank. */
.as-q-line__section {
    grid-column: 1 / -1;
}
/* A read-only subheader shown when the section value changes between rows —
   a quiet steel label, not a band (a questionnaire is never a scoring input). */
.as-q-section-head {
    margin: var(--space-3) 0 var(--space-2);
    padding-bottom: var(--space-1);
    border-bottom: 1px solid var(--tone-border);
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--colour-steel);
}

/* --- Import panel ---------------------------------------------------------- */
.as-import {
    margin-bottom: var(--space-4);
    border-left: 3px solid var(--colour-steel);
}
.as-import__title {
    margin: 0;
    font-size: var(--text-lg);
    color: var(--colour-navy);
}
.as-import__help,
.as-import__note {
    font-size: var(--text-sm);
    margin: var(--space-2) 0;
}
.as-import__note {
    margin-top: var(--space-3);
}

/* Preview table: reuses .table; just constrain the count column. */
.as-import__table {
    margin-top: var(--space-2);
}
.as-import__table .u-right,
.as-import__preview .u-right {
    text-align: right;
}

/* Post-run result block + its warning list (neutral chrome, no band tint). */
.as-import__result {
    margin-top: var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--tone-border);
    border-radius: var(--radius-sm);
    background-color: var(--colour-ice);
}
.as-import__warnings {
    margin: var(--space-2) 0 0;
    padding-left: var(--space-4);
    font-size: var(--text-sm);
    color: var(--colour-steel);
}
.as-import__warnings li {
    margin-bottom: var(--space-1);
}

/* End of Section 82 — Assessment Question Bank Import (Session 112) */

/* ============================================================================
   SECTION 83 — ROLE-COMPOSED DASHBOARD GRID + CUSTOMISE DRAWER  (Session 118)
   ----------------------------------------------------------------------------
   APPEND to assets/style.css. LAYOUT ONLY — no new colours. Every colour
   reference reuses an existing brand/structural token (--colour-*, --space-*);
   the widget cards, KPI tiles, badges and buttons keep their existing chrome
   from earlier sections. The dashboard moved from a fixed layout to a
   role-composed widget grid (dashboard.php resolves which widgets a role sees);
   these rules only place and space those widgets and style the administrator's
   customise drawer.
   ============================================================================ */

/* Header row — title block on the left, the "Customise role view" control on
   the right (wraps beneath on narrow viewports). */
.view__header--row {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--space-4, 1rem);
    flex-wrap: wrap;
}

/* The widget grid. Column count is driven by --dash-cols (set inline from the
   server-resolved `columns`); widgets flow in resolved order. A --dash-widget--full
   widget spans the full width (KPIs, priority bar, posture tables, trend). */
.dash-grid {
    display: grid;
    grid-template-columns: repeat(var(--dash-cols, 2), minmax(0, 1fr));
    gap: var(--space-4, 1rem);
    align-items: start;
}
.dash-widget {
    /* Grid children must be allowed to shrink or wide tables force overflow. */
    min-width: 0;
}
.dash-widget--full {
    grid-column: 1 / -1;
}
/* Single column on narrow screens — the practitioner density fix the evaluation
   flagged is worst on small viewports. */
@media (max-width: 900px) {
    .dash-grid {
        grid-template-columns: 1fr;
    }
}

/* ----------------------------------------------------------------------------
   CUSTOMISE DRAWER (can_manage_org) — pick a role, toggle/reorder widgets, save.
   Reuses card / field / btn chrome; these rules are structure only.
   ---------------------------------------------------------------------------- */
.dash-cust__head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-4, 1rem);
}
.dash-cust__row {
    display: flex;
    gap: var(--space-4, 1rem);
    flex-wrap: wrap;
    margin-top: var(--space-4, 1rem);
}
.dash-cust__row .field {
    flex: 1 1 220px;
    min-width: 0;
}

/* The toggle/reorder list — one row per widget the viewer may include. */
.dash-cust__list {
    list-style: none;
    margin: var(--space-4, 1rem) 0 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2, 0.5rem);
}
.dash-cust__item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-4, 1rem);
    padding: var(--space-2, 0.5rem) 0;
}
.dash-cust__toggle {
    display: flex;
    align-items: center;
    gap: var(--space-2, 0.5rem);
    cursor: pointer;
    min-width: 0;
}
.dash-cust__title {
    /* Truncate a long widget title rather than push the reorder controls off. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dash-cust__move {
    display: flex;
    gap: var(--space-2, 0.5rem);
    flex-shrink: 0;
}
.dash-cust__actions {
    display: flex;
    gap: var(--space-2, 0.5rem);
    align-items: center;
    flex-wrap: wrap;
    margin-top: var(--space-4, 1rem);
}

/* ============================================================================
   SECTION 84 — REGISTER PAGINATION + SORTABLE HEADERS  (Session 119)
   ----------------------------------------------------------------------------
   APPEND to assets/style.css. LAYOUT ONLY — no new colours. Chrome for the
   risk register's server-side pagination pager, the per-page selector and the
   clickable sort headers. Every colour token below already exists (§1); this
   section introduces none. Sibling registers reuse these classes when they
   adopt the same pattern.
   ========================================================================== */

/* Pager row beneath the register table — prev / position / next + page size. */
.risk-pager {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3, 0.75rem);
    margin-top: var(--space-4, 1rem);
    padding-top: var(--space-3, 0.75rem);
    border-top: 1px solid var(--tone-border, #d4dce4);
}
/* Current position ("Page 2 of 9") — muted, sits between the nav buttons. */
.risk-pager__pos {
    font-size: 0.85rem;
    color: var(--colour-steel, #5a6b7b);
    white-space: nowrap;
}
/* Per-page selector label + its select; nudged to the right of the controls. */
.risk-pager__size {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2, 0.5rem);
    margin-left: auto;
    font-size: 0.85rem;
    color: var(--colour-steel, #5a6b7b);
}
.risk-pager__size .field__select {
    width: auto;
    min-width: 4.5rem;
}

/* Sortable column header — a clickable/keyboard-focusable <th>. */
.risk-sort {
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
.risk-sort:hover {
    /* Subtle affordance using the existing steel tint — no new hue. */
    color: var(--colour-steel, #4A6984);
}
.risk-sort:focus-visible {
    /* Visible keyboard focus (accessibility) using the brand gold ring token. */
    outline: 2px solid var(--colour-gold, #D4AF37);
    outline-offset: -2px;
}
/* The active sort column, carrying its ▲/▼ direction glyph. */
.risk-sort.is-sorted {
    color: var(--colour-navy, #1A2B4C);
    font-weight: 700;
}

/* "All N selected across every page" note in the bulk bar. */
.risk-bulk__all {
    font-size: 0.85rem;
    color: var(--colour-steel, #5a6b7b);
    white-space: nowrap;
}

/* End of Section 84 — Register Pagination + Sortable Headers (Session 119) */

/* ----------------------------------------------------------------------------
   Section 85 — Access Scope + User Profile Fields (Session 141, redesigned
   Session 142, office address restructured Session 143, address search
   restored Session 144, Module 13)
   The Access Scope picker (Users admin — auth.js module_scope_fieldset), the
   structured office-address group with its Nominatim address-search assist,
   and the expandable per-user details/edit panel they live in. Layout only —
   fixed palette, no new colours. Reuses .admin-form / .field / .btn* / .badge
   chrome throughout; this section adds only what those don't already cover.
   ---------------------------------------------------------------------------- */

/* A clean, sorted, filterable, scrollable checklist — replaces the S141
   grouped grid per owner feedback (S142): one column, one row per module,
   a filter box and a one-click "give this person everything" clear. */
.scope-picker {
    margin-top: 0.5rem;
    border: 1px solid var(--colour-steel, #4A6984);
    border-radius: 6px;
    overflow: hidden;
    max-width: 420px;
}
.scope-picker__toolbar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem;
    background: var(--colour-ice, #F4F7F9);
    border-bottom: 1px solid var(--colour-steel, #4A6984);
}
.scope-picker__search {
    flex: 1 1 auto;
    margin: 0;
}
.scope-picker__list {
    max-height: 220px;
    overflow-y: auto;
    padding: 0.25rem 0;
}
.scope-picker__row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.75rem;
    font-size: 0.9rem;
    cursor: pointer;
}
.scope-picker__row:hover {
    background: var(--colour-ice, #F4F7F9);
}
.scope-picker__row input[type="checkbox"] {
    accent-color: var(--colour-navy, #1A2B4C);
}

/* Office-address search suggestions (auth.js wire_office_address_search,
   Nominatim addressdetails=1) — S142's dropdown pattern, RESTORED S144 after
   S143 mistakenly replaced it with a postcode-only assist that could never
   fill the address line. Positioned directly under its input via normal flow
   (a bordered dropdown that pushes layout rather than overlaying it, avoiding
   a new stacking-context/z-index rule for one small widget). */
.addr-suggest {
    border: 1px solid var(--colour-steel, #4A6984);
    border-top: none;
    border-radius: 0 0 6px 6px;
    max-height: 200px;
    overflow-y: auto;
    background: var(--colour-white, #FFFFFF);
}
.addr-suggest__item {
    padding: 0.5rem 0.75rem;
    font-size: 0.85rem;
    cursor: pointer;
    border-top: 1px solid var(--colour-ice, #F4F7F9);
}
.addr-suggest__item:hover {
    background: var(--colour-ice, #F4F7F9);
}

/* The Details expansion row (auth.js render_user_details_row) — same
   full-width-cell idiom as .pw-row, no bespoke box model needed beyond this. */
.user-details-row td {
    background: var(--colour-ice, #F4F7F9);
}

/* End of Section 85 — Access Scope + User Profile Fields (Sessions 141, 142, 143) */



/* ==========================================================================
   SECTION 86 — TRAVEL RISK MANAGEMENT  (Module 29; build 1/4 S145, build 2/4 S146,
   build 3/4 S148, build 4/4 S149 — the map and the briefing pack, layout only)
   ----------------------------------------------------------------------------
   RENUMBERED S146: this section shipped at S145 numbered 85, which Section 85
   (Access Scope + User Profile Fields, S141) already held. Two sections carrying
   one number is a documentation fault, not a rendering one — no selector changed
   and no rule was touched by the renumber.

   LAYOUT ONLY — NO NEW COLOURS. Every token used below already exists in §1;
   this section introduces none.

   COLOUR NOTE, and it matters: a travel risk level renders through the EXISTING
   .badge--sev-low / --sev-medium / --sev-high / --sev-critical classes (§32),
   deliberately NOT the .badge--band-* heat-map ramp. The four severity classes
   map one-to-one onto Moderate / Medium / High / Very High, and keeping travel
   off the band ramp is what stops a duty-of-care classification from reading as
   a CSMP IRV band on screen (§5.1). travel.php supplies the class name; this
   file defines no level-to-colour mapping of its own.

   The module's registers reuse the §84 pager/sort chrome (.risk-pager,
   .risk-sort, .risk-result-count) and the existing .risk-filter bar as-is, so
   nothing here restates them.
   ========================================================================== */

/* S147: the two-column module shell (.trv-shell) and its section sidebar
   (.trv-nav, .trv-nav__item, .trv-nav__flag) were REMOVED. Module 29's sections
   are now individual items in the APP sidebar (assets/app.js MODULES), so an
   in-module nav duplicated them. Nothing references those selectors any more. */

/* The section's content wrapper. */
.trv-main { min-width: 0; }

/* Form grid + action row. Each module defines its OWN pair (the appet-form__ /
   as-form__ / inc-act-form__ convention) rather than sharing a global one. */
.trv-form__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}
/* A field that should span the full grid width (purpose, notes, advisory). */
.trv-field--wide { grid-column: 1 / -1; }

.trv-form__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding-top: var(--space-3);
    border-top: 1px solid var(--tone-border);
}

/* Section header row: title/blurb on the left, primary action on the right. */
.trv-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

/* Secondary line inside a table cell (traveller type, region, coordinates). */
.trv-sub {
    display: block;
    font-size: var(--text-xs);
}

/* Inline badge sitting alongside cell text — nudged clear of the label. */
.trv-flag { margin-left: var(--space-2); }

/* Checkbox + label sitting inline within the filter bar. */
.trv-inline-check {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    white-space: nowrap;
}

/* Create/edit form card, and the open-itinerary detail card. */
.trv-form,
.trv-detail { margin-bottom: var(--space-4); }

/* Sub-heading inside a detail or form card (Legs, Line manager, Emergency). */
.trv-subhead {
    margin: var(--space-4) 0 var(--space-2);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--colour-navy);
}

/* Purpose-of-travel paragraph on the detail card. */
.trv-purpose {
    margin: 0 0 var(--space-3);
    color: var(--colour-steel);
}

/* Declared-but-unbuilt section placeholder. */
.trv-pending { border-left: 3px solid var(--colour-gold); }

/* ---- Build session 2 (S146) additions. Two classes, layout only. --------- */

/* A grouped block inside a card: the approval panel and the governing-rules
   panel on the itinerary detail, and the response-action doctrine editor. Spaced
   and ruled off from what precedes it so a detail card reads as sections rather
   than one run of text. */
.trv-panel {
    margin-top: var(--space-4);
    padding-top: var(--space-3);
    border-top: 1px solid var(--tone-border);
}
.trv-panel:first-child {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

/* The standing "nothing here has been evaluated" note under the governing-rules
   panel. Set apart deliberately: it is the line that stops a governing rule from
   being read as a fired one, so it must not disappear into the surrounding copy. */
.trv-note {
    margin-top: var(--space-3);
    padding-left: var(--space-3);
    border-left: 2px solid var(--tone-border);
    font-size: var(--text-xs);
}

/* S148 — the org-wide outstanding-alert tally above the Alerts register. One
   badge and its count per level, laid out inline so four levels read as a strip
   rather than a list. Layout only: the badge itself carries the colour, and the
   server chooses which badge class that is. */
.trv-tally {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    margin-right: var(--space-3);
    white-space: nowrap;
}

/* S148 fix — the response-action row's status control and its Remove link.
   .field__select is width:100% because it is built for a FORM FIELD; dropped
   into a table cell it takes the whole width and pushes anything beside it out
   of the cell. Scoped here rather than by touching .field__select, which every
   form in the app depends on. Layout only. */
.trv-act-cell {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.trv-act-cell .field__select {
    width: auto;
    min-width: 9rem;
    max-width: 100%;
}

/* --------------------------------------------------------------------------
   S149 — THE MAP AND THE BRIEFING PACK.  LAYOUT ONLY, NO NEW COLOURS.

   Every colour on this screen still comes from somewhere else: a map pin wears
   the SERVER-supplied .badge--sev-* class (§32), and the threat-zone fill is
   read back off that same class at runtime by travel_map.js rather than being
   declared here. So the map introduces no palette of its own, and a change to
   §32 moves the map with it.
   -------------------------------------------------------------------------- */

/* The map beside its trip list. One column on a narrow viewport, because a
   400px-wide map is not a map. */
.trv-map__wrap {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: var(--space-4);
    align-items: start;
}

@media (max-width: 900px) {
    .trv-map__wrap { grid-template-columns: minmax(0, 1fr); }
}

/* The canvas holder. MapLibre needs a resolved height on its container or it
   renders into a zero-height box and looks like a failed load. */
.trv-map {
    min-height: 32rem;
    height: 60vh;
    width: 100%;
    border-radius: var(--radius);
    overflow: hidden;
}

/* The trip list. Scrolls independently so a long list does not push the map
   off the screen. */
.trv-map__side {
    max-height: 60vh;
    overflow-y: auto;
}

.trv-map__ctrl {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-right: var(--space-4);
}

.trv-map__note { margin-bottom: var(--space-3); }

.trv-map__trip {
    padding: var(--space-3);
    border-bottom: 1px solid var(--tone-border);
    cursor: pointer;
}

.trv-map__trip:last-child { border-bottom: none; }

.trv-map__trip.is-selected { background: var(--tone-hover); }

.trv-map__trip-title { margin: 0 0 var(--space-1) 0; }

.trv-map__trip p { margin: 0; }

/* A marker. Circular, so it reads as a position rather than as a badge that has
   escaped a table — the colour still arrives from the badge class beside it. */
.trv-map__pin {
    display: block;
    width: 0.9rem;
    height: 0.9rem;
    padding: 0;
    border-radius: 50%;
    border: 2px solid #fff;
    box-shadow: 0 1px 3px rgb(0 0 0 / 0.4);
    cursor: pointer;
}

/* A trip with nothing raised against it. No severity class applies, so it takes
   the neutral badge surface the base .badge rule already provides. */
.trv-map__pin--quiet { opacity: 0.75; }

.trv-map__legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

.trv-map__legend-item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

/* The briefing pack. It is a DOCUMENT, not a register, so it takes a reading
   measure on screen rather than running the full width of a wide monitor —
   which is also what makes the on-screen view resemble the printed one. */
.trv-pack {
    max-width: 60rem;
}

/* Each place is one block, kept off a page break where the browser can manage
   it. */
.trv-pack__place {
    margin-bottom: var(--space-5);
    break-inside: avoid;
}

/* Print: the briefing pack (build session 4) is produced by printing the pack
   view, so app chrome is dropped and the record fills the page. Declared here
   with the rest of the module's layout so session 4 adds no new CSS section. */
@media print {
    .trv-form,
    .trv-form__actions,
    .risk-filter,
    .risk-pager,
    .trv-head .btn { display: none !important; }
    .trv-detail {
        border: none;
        box-shadow: none;
        margin: 0;
    }
    /* The map is a WebGL canvas — it prints as a grey rectangle at best, so the
       whole screen is dropped rather than wasting a page on it. */
    .trv-map__wrap,
    .trv-map__legend { display: none !important; }
    /* Keep a place's heading with the table beneath it. */
    .trv-pack__place { break-inside: avoid; }
    .trv-subhead { break-after: avoid; }
}

/* ============================================================================
   GEO PICKER  (S149, assets/geopicker.js)
   ----------------------------------------------------------------------------
   The shared coordinate picker used by Module 27 (locations) and Module 29
   (itinerary legs, accommodation). It replaces two bare lat/lng number inputs,
   so the styling job is to make four routes to one coordinate read as ONE
   control rather than four competing ones.

   Reuses the existing .field / .badge / .u-muted vocabulary throughout — no new
   colour tokens are introduced here.
   ============================================================================ */

.geo-pick {
    border: 1px solid var(--colour-border, #d8dee5);
    border-radius: 6px;
    padding: 0.9rem 1rem 0.75rem;
    margin: 0 0 1rem;
    /* A fieldset carries a default min-width that breaks CSS grid children in
       Firefox; this is the standard reset for that. */
    min-width: 0;
}

.geo-pick__legend {
    font-weight: 600;
    font-size: 0.9rem;
    padding: 0 0.4rem;
    color: var(--colour-steel, #4a5c6a);
}

.geo-pick__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 0.75rem 1rem;
    align-items: start;
}

/* The search and address boxes span the row: their result lists need the width,
   and a hit label is often long ("12 Station Road, Westminster, London, …"). */
.geo-pick__wide { grid-column: 1 / -1; }

/* Result lists sit directly beneath their input and are capped in height —
   a typeahead that pushes the rest of the form down the page on every
   keystroke is worse than no typeahead. */
.geo-pick__results {
    list-style: none;
    margin: 0.35rem 0 0;
    padding: 0;
    max-height: 14rem;
    overflow-y: auto;
    border: 1px solid var(--colour-border, #d8dee5);
    border-radius: 4px;
    background: var(--colour-surface, #fff);
}

.geo-pick__results:empty { display: none; }

.geo-pick__results li {
    padding: 0.35rem 0.6rem;
    border-bottom: 1px solid var(--colour-border-light, #eef2f5);
    font-size: 0.88rem;
    line-height: 1.35;
}

.geo-pick__results li:last-child { border-bottom: 0; }
.geo-pick__results li:hover      { background: var(--colour-hover, #f4f7fa); }

/* The hit itself is a real button (keyboard reachable); .btn--link gives it the
   app's link treatment. Left-aligned because these are labels, not actions. */
.geo-pick__results .btn--link {
    text-align: left;
    padding: 0;
}

/* The status line is the honest bit: it states the coordinate AND how it was
   obtained, so an approximate geocoded position never reads as a surveyed one. */
.geo-pick__status {
    margin: 0.6rem 0 0;
    font-size: 0.85rem;
    line-height: 1.5;
}

.geo-pick__status:empty { display: none; }

@media (max-width: 640px) {
    .geo-pick__grid { grid-template-columns: 1fr; }
    .geo-pick { padding: 0.75rem 0.75rem 0.6rem; }
}

@media print {
    /* The picker is an input control — it has no meaning on a printed pack. */
    .geo-pick { display: none !important; }
}
