/**
 * CIS Assessment Engine v2 — Component Styles
 * SANS-inspired: authoritative, clean, sharp, information-dense.
 * Compatible with Bootstrap 5 / Joomla / SPPB.
 * (C) 2026 Certified Information Security. All rights reserved.
 */

:root {
    --cis-navy: #1B3A6B;
    --cis-navy-dark: #142d54;
    --cis-navy-rgb: 27, 58, 107;
    --cis-dark-text: #344054;
    --cis-grey: #595F6E;
    --cis-grey-dark: #4A5568;
    --cis-page-bg: #e8edf3;
    --cis-card-bg: #f7f9fc;
    --cis-card-bg-muted: #f0f2f6;
    --cis-card-bg-selected: #eef1f6;
    --cis-border: #768090;
    --cis-shadow: 0 1px 2px rgba(0,0,0,0.06), 0 1px 3px rgba(0,0,0,0.10);
    --cis-red: #D3212C;
    --cis-amber: #FF681E;
    --cis-green: #28A745;
    --cis-dkgreen: #06402B;
    --cis-red-text: #9E1820;
    --cis-amber-text: #9A3F0B;
    --cis-green-text: #047040;
    --cis-info-text: #0B5ED7;          /* v2.5.1: info tint companion text */
    /* v2.2.55 canonical admin surface tints (Group 1C) */
    --cis-tint-info: #EFF6FF;
    --cis-tint-success: #F0FDF4;
    --cis-tint-warn: #FFF7ED;
    --cis-tint-danger: #FEF2F2;
    --cis-tint-navy: #EAF1FB; /* selected-card tint (v2.3.4 #1a) */
    /* v2.5.1 canonical tint-border companions for Step-6 pills/banners */
    --cis-tint-neutral:      #F4F5F7; /* neutral pill surface (Partial bucket) */
    --cis-tint-neutral-soft: #FAFBFC; /* softer neutral (Untouched bucket) */
    --cis-border-success:    #A6E4BF; /* success-tint border */
    --cis-border-info:       #B6D4FF; /* info-tint border */
    --cis-border-warn:       #FFCFA5; /* amber-tint border */
    --cis-border-danger:     #F6B6BA; /* danger-tint border */
    --cis-border-neutral:    #D7DCE3; /* neutral pill border */
    --cis-border-neutral-soft:#E1E5EB;/* softer neutral border */
    --cis-border-navy-soft:  #CBD8EC; /* navy-tint card border */
}

/* ═══════════════════════════════════════════════════════
   ALL VIEWS — Shared Layout
   ═══════════════════════════════════════════════════════ */

[class^="com-cisassess-"] {
    background: var(--cis-page-bg);
    padding: 20px;
    border-radius: 6px;
    max-width: 100%;
    overflow-x: clip;
    box-sizing: border-box;
    /* Content protection (Lesson 128) */
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}
/* Re-enable selection for form inputs within the tool */
[class^="com-cisassess-"] input,
[class^="com-cisassess-"] textarea,
[class^="com-cisassess-"] select,
[class^="com-cisassess-"] [contenteditable="true"] {
    -webkit-user-select: text;
    -moz-user-select: text;
    -ms-user-select: text;
    user-select: text;
}

/* Focus indicators — WCAG 2.4.7 (Group 6C, v2.2.55) */
[class^="com-cisassess-"] a:focus-visible,
[class^="com-cisassess-"] .btn:focus-visible,
[class^="com-cisassess-"] button:focus-visible,
[class^="com-cisassess-"] input:focus-visible,
[class^="com-cisassess-"] select:focus-visible,
[class^="com-cisassess-"] textarea:focus-visible,
[class^="com-cisassess-"] [tabindex]:focus-visible,
[class^="com-cisassess-"] [role="button"]:focus-visible {
    outline: 2px solid var(--cis-navy);
    outline-offset: 2px;
    box-shadow: none; /* override Bootstrap default focus shadow */
}
/* Navy-background contexts — inverted for ≥3:1 contrast */
[class^="com-cisassess-"] .card-header a:focus-visible,
[class^="com-cisassess-"] .card-header button:focus-visible,
[class^="com-cisassess-"] .card-header .btn:focus-visible,
[class^="com-cisassess-"] .cisassess-header a:focus-visible,
[class^="com-cisassess-"] .cisassess-header button:focus-visible,
[class^="com-cisassess-"] .cisassess-header .btn:focus-visible,
[class^="com-cisassess-"] [style*="background:#1B3A6B"] button:focus-visible,
[class^="com-cisassess-"] [style*="background:#1B3A6B"] a:focus-visible {
    outline-color: #ffffff;
}

/* Cards */
[class^="com-cisassess-"] .card {
    border: 1px solid var(--cis-border) !important;
    border-radius: 6px !important;
    box-shadow: var(--cis-shadow);
    overflow: clip;
}
[class^="com-cisassess-"] .card > .card-header {
    background: var(--cis-navy) !important;
    border-bottom: none !important;
    border-radius: 0 !important;
    padding: 12px 18px;
}
[class^="com-cisassess-"] .card > .card-header h2,
[class^="com-cisassess-"] .card > .card-header h3,
[class^="com-cisassess-"] .card > .card-header h5 {
    color: #fff !important;
    font-weight: 600;
    font-size: 0.9rem !important;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}
[class^="com-cisassess-"] .card > .card-body {
    padding: 18px 20px;
    background: var(--cis-card-bg);
    overflow: hidden;
}

/* Forms */
[class^="com-cisassess-"] .form-control {
    border-radius: 4px;
    border-color: var(--cis-border);
    font-size: 0.88rem;
}
[class^="com-cisassess-"] .form-control:focus {
    border-color: var(--cis-navy);
    box-shadow: 0 0 0 2px rgba(var(--cis-navy-rgb), 0.15);
}
[class^="com-cisassess-"] .form-label {
    font-size: 0.82rem;
    color: var(--cis-dark-text);
    margin-bottom: 4px;
}
[class^="com-cisassess-"] .form-check-input:checked {
    background-color: var(--cis-navy);
    border-color: var(--cis-navy);
}
[class^="com-cisassess-"] .form-check-label {
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--cis-dark-text);
}

/* ═══════════════════════════════════════════════════════
   HEADER + FOOTER
   ═══════════════════════════════════════════════════════ */

.cisassess-header {
    background: var(--cis-navy) !important;
    border-radius: 6px;
}
.cisassess-header h1 {
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #fff;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cisassess-header .badge {
    flex-shrink: 0;
    white-space: nowrap;
}
.cisassess-header .btn { transition: all 0.15s ease; }
.cisassess-header .btn:hover { background: rgba(255,255,255,0.3) !important; color: #fff !important; }

/* Footer (setup) */
.cisassess-footer-bar {
    background: var(--cis-navy);
    border-radius: 0 0 6px 6px;
    padding: 10px 18px;
    margin-top: 20px;
}

/* Email modal */
.cisassess-email-modal .modal-header { background: var(--cis-navy); color: #fff; }

/* ═══════════════════════════════════════════════════════
   SETUP PAGE
   ═══════════════════════════════════════════════════════ */

/* Framework / Role cards */
.fw-card, .role-card {
    transition: all 0.2s ease;
    border-width: 2px !important;
    border-radius: 4px !important;
    background: var(--cis-card-bg);
    overflow-wrap: break-word;
    word-wrap: break-word;
    overflow: hidden;
}
.fw-card:hover:not(.opacity-50), .role-card:hover {
    border-color: var(--cis-navy) !important;
    box-shadow: 0 2px 8px rgba(var(--cis-navy-rgb), 0.15);
    transform: translateY(-1px);
}
/* #1a (v2.3.4): Selected framework / role card — stronger visual state so the
   selection is unmistakable vs. the hover state (previously identical). Uses a
   3px accent-left border + tinted background + 3px navy ring on the card. */
.fw-card.border-primary, .role-card.border-primary {
    border-color: var(--cis-navy) !important;
    border-width: 3px !important;
    background: var(--cis-tint-navy, #eaf1fb);
    box-shadow: 0 0 0 3px rgba(var(--cis-navy-rgb), 0.18),
                0 6px 16px rgba(var(--cis-navy-rgb), 0.22);
    transform: translateY(-1px);
    position: relative;
}
.fw-card.border-primary::before, .role-card.border-primary::before {
    content: "\2713"; /* check mark */
    position: absolute;
    top: 8px;
    right: 10px;
    width: 22px;
    height: 22px;
    line-height: 22px;
    text-align: center;
    background: var(--cis-navy);
    color: #fff;
    border-radius: 50%;
    font-size: 13px;
    font-weight: 700;
    box-shadow: 0 1px 3px rgba(0,0,0,0.25);
    z-index: 2;
}
.fw-card.opacity-50 { background: var(--cis-card-bg-muted); }

/* CTA button */
.com-cisassess-setup #btnStart {
    background: var(--cis-navy);
    color: #fff;
    border: 2px solid var(--cis-navy);
    padding: 10px 32px;
    font-size: 0.95rem;
    font-weight: 700;
    border-radius: 4px;
    letter-spacing: 0.02em;
    transition: all 0.2s ease;
    box-shadow: 0 1px 3px rgba(var(--cis-navy-rgb), 0.2);
}
.com-cisassess-setup #btnStart:hover {
    background: var(--cis-navy-dark);
    border-color: var(--cis-navy-dark);
    box-shadow: 0 2px 8px rgba(var(--cis-navy-rgb), 0.3);
}

/* Terms scrollable */
.com-cisassess-setup .card-body[style*="max-height:220px"] { background: var(--cis-card-bg-muted); }

/* Previous assessments */
.com-cisassess-setup .table { font-size: 0.84rem; }
.com-cisassess-setup .progress { border-radius: 3px; height: 16px !important; }

/* ═══════════════════════════════════════════════════════
   ASSESSMENT VIEW
   ═══════════════════════════════════════════════════════ */

#t2-section .card { transition: border-color 0.2s; }
#t2-section .card:focus-within { border-color: var(--cis-navy) !important; }
#t2-section select.form-select-sm { font-size: 0.8rem; }
#t1-overlay { transition: opacity 0.4s ease; }
#t1-section { min-height: 120px; }

/* N/A ALERT overlay (Lesson 113) */
.cisassess-na-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1050;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}
.cisassess-na-overlay-backdrop {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.55);
}
.cisassess-na-overlay-panel {
    position: relative;
    background: #fff;
    border: 2px solid #FF681E;
    border-radius: 8px;
    overflow: hidden;
    max-width: 640px;
    width: 100%;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
    animation: cisNaSlideIn 0.25s ease-out;
}
@keyframes cisNaSlideIn {
    from { opacity: 0; transform: translateY(-20px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ═══════════════════════════════════════════════════════
   RESULTS VIEW
   ═══════════════════════════════════════════════════════ */

/* CIS badge — Bootstrap-independent badge base (Lesson 122) */
.cis-badge {
    display: inline-block;
    padding: .2em .5em;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
    vertical-align: baseline;
    border-radius: 4px;
}

/* Risk badges — text-safe variants (Lesson 114), !important to override SPPB/Bootstrap */
.cisassess-risk-high { background: #fde8e9 !important; color: var(--cis-red-text) !important; border: 1px solid #f5b5b8; }
.cisassess-risk-medium { background: #fff1e8 !important; color: var(--cis-amber-text) !important; border: 1px solid #ffbe8f; }
.cisassess-risk-low { background: #e8f7ef !important; color: var(--cis-green-text) !important; border: 1px solid #84dbb0; }
.cisassess-risk-verylow { background: #e5f0eb !important; color: var(--cis-dkgreen) !important; border: 1px solid #6dc99e; }

/* Evidence */
#evidence-section .table { font-size: 0.85rem; }
#evidence-section .ev-checkbox { cursor: pointer; }
#evidence-section .ev-checkbox:checked + td { text-decoration: line-through; color: var(--cis-grey); }

/* Training panel */
.cisassess-training-panel {
    background: var(--cis-card-bg);
    border: 1px solid var(--cis-border);
    border-left: 4px solid var(--cis-navy);
    border-radius: 4px;
    padding: 16px 16px 16px 20px;
    margin-bottom: 20px;
}
.cisassess-training-panel .training-heading { font-size: 15px; font-weight: 700; color: var(--cis-navy); margin-bottom: 10px; }
.cisassess-training-panel p { font-size: 13px; color: var(--cis-dark-text); line-height: 1.7; margin-bottom: 10px; }
.cisassess-training-panel .training-cta { font-weight: 600; }
.cisassess-training-panel ul { font-size: 13px; line-height: 1.8; margin: 0 0 8px 16px; padding-left: 8px; }
.cisassess-training-panel ul a { color: var(--cis-navy); font-weight: 600; }
.cisassess-training-panel .training-roles { font-size: 12.5px; line-height: 1.6; margin-top: 8px; margin-bottom: 0; }
.cisassess-training-panel .training-roles span { color: var(--cis-navy); }

/* Email buttons */
.cisassess-email-buttons .btn { transition: all 0.15s ease; }

/* ═══════════════════════════════════════════════════════
   RESPONSIVE
   ═══════════════════════════════════════════════════════ */

@media (max-width: 991px) {
    .cisassess-header .d-flex.gap-2 { flex-wrap: wrap; }
    [class^="com-cisassess-"] { padding: 14px; }
}

@media (max-width: 767px) {
    .cisassess-header { padding: 12px !important; }
    .cisassess-header h1 { font-size: 1rem !important; }
    .cisassess-header .d-flex.gap-2 { flex-wrap: wrap; justify-content: center; }
    .cisassess-training-panel { padding: 12px; }
    .cisassess-training-panel .training-heading { font-size: 14px; }
    #t2-section select.form-select-sm { min-width: 160px !important; }
    #t1-panel .col-md-3 { margin-bottom: 0.5rem; }
    .cisassess-email-buttons { flex-direction: column; }
    .cisassess-email-buttons .btn { max-width: 100% !important; }
    [class^="com-cisassess-"] { padding: 10px; }
    [class^="com-cisassess-"] .card > .card-body { padding: 14px 16px; }
}

@media (max-width: 575px) {
    /* v2.5.12 — S-31 WCAG 2.5.8 AA: lift XS header .btn tap-target from ~21px to ≥32px. */
    .cisassess-header .btn { font-size: 0.75rem; padding: 8px 10px; min-height: 32px; }
    /* v2.5.17 — S-32: dropped the XS-only training-panel font reductions (was p/ul 12px,
       training-roles 11px). Letting the base sizes inherit (13/13/12.5 px) lifts every
       label above the 12 px legibility floor without forcing a uniform 16 px override.
       Panel copy is short enough that the lift does not reflow at 320 px. */
    .cisassess-metrics .col-3 { flex: 0 0 50%; max-width: 50%; margin-bottom: 8px; }
    .cisassess-metrics .col-3 .fs-3,
    .cisassess-metrics .col-3 .fs-4 { font-size: 1.2rem !important; }
    #evidence-section th[style*="width:120px"] { width: 80px !important; }
    #evidence-section th[style*="width:70px"] { width: 50px !important; }
    [class^="com-cisassess-"] { padding: 8px; }
    [class^="com-cisassess-"] .card > .card-header { padding: 10px 14px; }
}

/* ═══════════════════════════════════════════════════════
   Control Navigator — always-visible directory (Lesson 203)
   Four states: current (blue), done (green), pending (outlined), N/A (muted)
   All meet WCAG AA contrast (4.5:1 minimum)
   ═══════════════════════════════════════════════════════ */
.cis-ctrl-current,
.cis-ctrl-done,
.cis-ctrl-pending,
.cis-ctrl-na {
    font-size: 0.75rem;
    padding: 4px 7px;
    cursor: pointer;
    font-weight: 600;
    transition: opacity 0.15s;
}
.cis-ctrl-current:hover,
.cis-ctrl-done:hover,
.cis-ctrl-pending:hover,
.cis-ctrl-na:hover { opacity: 0.85; }

/* Current control — navy blue, white text */
.cis-ctrl-current {
    background-color: #1B3A6B;
    color: #ffffff !important;
    border: 1px solid #1B3A6B;
}

/* Completed control — green, white text */
.cis-ctrl-done {
    background-color: #28A745;
    color: #ffffff !important;
    border: 1px solid #28A745;
}

/* Pending (not yet assessed) — white bg, navy border, navy text */
.cis-ctrl-pending {
    background-color: #ffffff;
    color: #1B3A6B !important;
    border: 1.5px solid #1B3A6B;
}

/* Not Applicable — light grey bg, dark grey text, dashed border */
.cis-ctrl-na {
    background-color: #F0F1F3;
    color: var(--cis-grey) !important;
    border: 1px dashed var(--cis-border);
}

/* ═══════════════════════════════════════════════════════
   v2.5.0 Step 3 — Grouping tab strip (desktop-first, ≥ 992 px)
   -------------------------------------------------------
   WAI-ARIA tablist/tab/tabpanel pattern. Framework-agnostic: ISO 42001
   (levelCount=1) and NIST AI RMF (levelCount=2) render through the same
   surface per PLAN §8 SOLID-O/L. Accordion reveal of level-2 is Step 4.
   Phone/tablet collapse (tab→select ≤ 767 px) is Step 9.

   Tokens are sourced from the :root block above — no new hexes. The three
   semantic states (untouched / partial / completed) use --cis-border,
   --cis-amber, --cis-green respectively, matching the project's canonical
   palette documented in PROJECT_CONFIG.md line 45.
   ═══════════════════════════════════════════════════════ */



/* Tab — neutral baseline. The left/right siblings share a 1px hairline
   divider so the strip reads as a single control at rest. */



/* Hover + focus-visible state. The focus outline uses the navy token for
   ≥ 3:1 contrast against both the default and active tab backgrounds
   (audited by QA-48 at Step 12). Hover fill reuses the canonical navy
   tint so we stay inside the QA-28 token palette. */

/* Active tab — white fill, navy title, amber 4px bottom border. The
   roving-tabindex and aria-selected toggle are managed by grouping_nav.js. */

/* Three-state border semantics per Step 3 brief. The state- class is
   emitted on the tab itself and drives a left-edge accent so the state
   remains legible independent of the active/inactive background. */

/* Tabpanels — Step 3 ships empty shells that Steps 4–5 populate. The
   focus outline keeps keyboard users oriented when arrowing through the
   tablist lands focus on the panel. */

/* ═══════════════════════════════════════════════════════
   v2.5.0 Step 4 — Level-2 accordion (desktop ≥ 992 px only)
   ─────────────────────────────────────────────────────────
   The accordion lives inside an active tabpanel when the framework
   declares levelCount=2 (NIST AI RMF today). For levelCount=1
   (ISO 42001) the server emits NO accordion DOM — per PLAN §8 Liskov
   absence is the contract. These rules therefore apply only when the
   server has emitted the markup.

   Canonical tokens only (--cis-navy / --cis-amber / --cis-green /
   --cis-border / --cis-tint-navy / --cis-dark-text / --cis-grey /
   --cis-green-text) — zero rogue hex. Three-state left-edge accent
   mirrors the Step 3 tab-strip semantics at 3 px width.

   No media queries below 992 px — Step 9 owns responsive collapse.
   ═══════════════════════════════════════════════════════ */


/* One card per L2 category. The heading is a real <h3>, required by
   WAI-ARIA Authoring Practices + QA-32 (heading-styled-as-body scans
   flag *-title/*-heading class names on NON-h* tags; a genuine <h3>
   satisfies the a11y contract). The card border gives visual
   separation on the white tabpanel background. */

/* Accordion header button — full-width clickable row. Slightly
   smaller visual weight than the L1 tab labels to establish hierarchy
   (12 px vs 13 px, still bold). Rendered as a card-like row with
   1 px border and a 3 px left-edge accent driven by state-*. */

/* Chevron — CSS-rendered right-pointing triangle; rotates 90 deg on
   aria-expanded=true. No SVG sprite dependency (component has none). */



/* Hover + focus-visible. The focus ring reuses the Step 3 pattern
   (2 px navy, -2 px offset) for ≥ 3:1 contrast on both white and the
   navy-tint hover fill — audited by QA-48 at Step 12. */

/* Expanded state — aria-expanded=true is authoritative. Chevron
   rotates 90 deg (points down). Header background stays white to
   maintain the card appearance; the open state is communicated by
   the rotated chevron + the visible panel below. */

/* Three-state left-edge accent — mirrors the Step 3 tab-strip rule
   so the state remains legible independent of expand/collapse or
   hover. 3 px width matches Step 3. */

/* Region panel — hidden when aria-expanded=false via the [hidden]
   attribute (authoritative). When visible, indented below the header
   and carrying the leaf list. */

/* Leaf list inside an expanded category. Step 4 ships a static
   breadcrumb (id + title per leaf); Step 5 replaces this with the
   filter-wired incomplete list. */

/* ═══════════════════════════════════════════════════════
   v2.5.0 Step 5 — Inner body grid + right-rail navigator
   ═══════════════════════════════════════════════════════
   Desktop-first 2-col layout (1fr / 320px) ONLY at ≥ 992 px.
   Below the breakpoint the grid collapses to single column
   (rail flows after the Control Card per source order).
   Phone/tablet refinement (sheet/drawer) is Step 9 scope.

   Tokens are sourced from the :root block — no new hexes
   per QA-28 rogue-hex scan. Class vocabulary is template-
   driven per QA-29 orphaned-CSS scan.
   ═══════════════════════════════════════════════════════ */

.cis-assess-body-grid {
    /* mobile-first single column; grid kicks in at ≥ 992 px below */
    display: block;
}

/* v2.5.41.44 §1.1 — dead 320px right-rail reservation retired per AR plan-doc §3.3.
   Pre-fix: grid declared `1fr / 320px` reserving a column for a right-rail that
   was removed in v2.5.41.16 (template lines 1203-1226 commented out as Step 5
   tombstone). The body.cnm-mounted block at §2.2 then flipped grid back to 1-col
   post-mount, causing a two-pass layout resolution + visible reflow window.
   Post-fix: grid is 1-col by default; body.cnm-mounted block at §2.2 is now
   redundant and retired. */
@media (min-width: 992px) {
    .cis-assess-body-grid {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        column-gap: 0;
        align-items: start;
    }
}


/* Sub-block 1: "Next incomplete →" CTA button (global scope) */

/* Sub-block 2: Filter pill group (WAI-ARIA radiogroup; single-active) */

/* Sub-block 3: Scoped title (aria-live region; updated on filter change) */

/* Sub-block 4: Ordered list of incomplete controls */


/* Sub-block 5: Skip-to-grouping nav (chip-style anchors) */

/* ═══════════════════════════════════════════════════════
   v2.5.1 Step 6 — Per-grouping completion modal
   Celebratory-but-authoritative ribbon header, KPI strip,
   strongest/weakest two-column body, uneven-maturity
   advisory, next-up footer. Framework-agnostic (ISO 42001
   one-level + NIST AI RMF two-level). ≥ 992 px baseline;
   mobile adjustments below.
   ═══════════════════════════════════════════════════════ */
.cis-completion-bravo {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--cis-green);
    color: #fff;
    font-size: 1.1rem;
    font-weight: 700;
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.25);
}
.cis-completion-time-chip {
    display: inline-flex;
    gap: 10px;
    align-items: center;
    font-size: 0.85rem;
    color: rgba(255, 255, 255, 0.92);
    background: rgba(255, 255, 255, 0.10);
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 999px;
    padding: 4px 12px;
    margin-left: auto;
}
.cis-completion-time-chip .cis-completion-slot:empty {
    display: none;
}

/* KPI strip + distribution pills */
.cis-completion-strip {
    display: grid;
    grid-template-columns: repeat(3, minmax(120px, 1fr)) 2fr;
    gap: 14px;
    padding: 18px 4px 22px;
    border-bottom: 1px solid var(--cis-border);
    align-items: stretch;
}
.cis-completion-kpi,
.cis-completion-dist {
    background: var(--cis-tint-navy);
    border: 1px solid var(--cis-border-navy-soft);
    border-radius: 8px;
    padding: 10px 14px;
}
/* KPI + distribution column labels (section <h6> inside each card). Styled
   as small-caps to match the "tier" and "risk" KPI cards elsewhere in the
   component (Assess summary tiles, v2.3.x). */
.cis-completion-kpi h6,
.cis-completion-dist h6 {
    display: block;
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--cis-grey);
    margin: 0 0 4px;
}
.cis-completion-big {
    font-size: 1.6rem;
    font-weight: 700;
    color: var(--cis-navy-dark);
    line-height: 1.1;
}
.cis-completion-big small {
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--cis-grey);
}
.cis-completion-pill-row {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.cis-completion-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.78rem;
    font-weight: 600;
    padding: 4px 10px;
    border-radius: 999px;
    border: 1px solid var(--cis-border);
    background: #fff;
    color: var(--cis-dark-text);
}
.cis-completion-pill::before {
    content: "";
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.85;
}
/* Pill variants — class suffixes match the short CSS codes emitted by
   grouping_nav.js::DIST_BUCKETS (sc, ofi, mnc, MNC, par, na) so the row
   can use 6 buckets without the JS knowing the bucket→color mapping. */
.cis-completion-pill-sc   { color: var(--cis-green-text);  background: var(--cis-tint-success);      border-color: var(--cis-border-success); }
.cis-completion-pill-ofi  { color: var(--cis-info-text);   background: var(--cis-tint-info);         border-color: var(--cis-border-info); }
.cis-completion-pill-mnc  { color: var(--cis-amber-text);  background: var(--cis-tint-warn);         border-color: var(--cis-border-warn); }
.cis-completion-pill-MNC  { color: var(--cis-red-text);    background: var(--cis-tint-danger);       border-color: var(--cis-border-danger); }
.cis-completion-pill-par  { color: var(--cis-grey-dark);   background: var(--cis-tint-neutral);      border-color: var(--cis-border-neutral); }
.cis-completion-pill-na   { color: var(--cis-grey);        background: var(--cis-tint-neutral-soft); border-color: var(--cis-border-neutral-soft); }

/* Strongest / Weakest two-column body */
.cis-completion-two-col {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px;
    padding-top: 16px;
}
.cis-completion-col h5 {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--cis-navy-dark);
    margin: 0 0 10px;
    display: flex;
    align-items: center;
    gap: 8px;
}
.cis-completion-count-tag {
    font-size: 0.72rem;
    font-weight: 500;
    color: var(--cis-grey);
    background: var(--cis-card-bg-muted);
    border: 1px solid var(--cis-border);
    border-radius: 999px;
    padding: 1px 8px;
}
.cis-completion-ctrl-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.cis-completion-ctrl-list li {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 10px;
    align-items: baseline;
    padding: 8px 10px;
    background: var(--cis-card-bg);
    border: 1px solid var(--cis-border);
    border-radius: 6px;
    font-size: 0.88rem;
    color: var(--cis-dark-text);
}
.cis-completion-ctrl-list li .cis-completion-ctrl-id {
    font-weight: 600;
    color: var(--cis-navy);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.82rem;
}
.cis-completion-ctrl-list li .cis-completion-ctrl-title {
    color: var(--cis-dark-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.cis-completion-ctrl-list li .cis-completion-ctrl-score {
    font-size: 0.76rem;
    color: var(--cis-grey);
    white-space: nowrap;
}
.cis-completion-ctrl-list li.cis-completion-ctrl-warn {
    background: var(--cis-tint-warn);
    border-color: var(--cis-border-warn);
}
.cis-completion-ctrl-list li.cis-completion-ctrl-bad {
    background: var(--cis-tint-danger);
    border-color: var(--cis-border-danger);
}
.cis-completion-ctrl-list li.cis-completion-ctrl-bad .cis-completion-ctrl-id {
    color: var(--cis-red-text);
}

/* Uneven-maturity advisory */
.cis-completion-uneven-banner {
    margin-top: 12px;
    padding: 10px 12px;
    background: var(--cis-tint-warn);
    border: 1px solid var(--cis-border-warn);
    border-left: 4px solid var(--cis-amber);
    border-radius: 6px;
    font-size: 0.85rem;
    color: var(--cis-amber-text);
}
.cis-completion-uneven-banner strong {
    font-weight: 700;
    color: var(--cis-amber-text);
    margin-right: 4px;
}

/* Footer — next up + actions */
.cis-completion-footer {
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    padding-top: 14px;
    border-top: 1px solid var(--cis-border);
}
.cis-completion-next {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: 0.9rem;
    color: var(--cis-grey-dark);
    flex: 1 1 auto;
    min-width: 0;
}
.cis-completion-next-label {
    font-weight: 600;
    color: var(--cis-navy);
    text-transform: uppercase;
    font-size: 0.72rem;
    letter-spacing: 0.05em;
}
.cis-completion-actions {
    display: inline-flex;
    gap: 8px;
    flex: 0 0 auto;
}

/* Responsive — < 992 px collapses the strip + two-col layout. */
@media (max-width: 991.98px) {
    .cis-completion-strip {
        grid-template-columns: repeat(2, minmax(140px, 1fr));
    }
    .cis-completion-strip .cis-completion-dist {
        grid-column: 1 / -1;
    }
    .cis-completion-two-col {
        grid-template-columns: 1fr;
    }
}
@media (max-width: 575.98px) {
    .cis-completion-strip {
        grid-template-columns: 1fr;
    }
        .cis-completion-time-chip {
        margin-left: 0;
        margin-top: 4px;
        flex-basis: 100%;
    }
    .cis-completion-big {
        font-size: 1.35rem;
    }
}

/* Respect reduced-motion: Bootstrap's modal fade already gates transitions,
   but ensure no custom motion is introduced here. */
@media (prefers-reduced-motion: reduce) {
    }

/* ═══════════════════════════════════════════════════════════════════════
 * v2.5.2 Step 7 — Results gap banner + Complete column + dynamic header.
 * PLAN_v2.5.0.md §9 (scope), §5 (responsive baseline — ≥ 992 px only; Step 9
 * owns mobile stacking), §7 (all assessor-authored strings are server-side
 * escaped in the template; CSS here has zero interpolation surface).
 *
 * Token contract: every color resolves through a canonical :root var or an
 * existing risk-tint in PALETTE_NEUTRAL. Zero new tokens introduced; zero
 * rogue hex.
 * ═══════════════════════════════════════════════════════════════════════ */

/* ─── Gap banner (top of <main id="results-main">) ───────────────────── */
.cis-results-gap-banner {
    /* Compose on top of Bootstrap's .alert-warning without overriding the
       Bootstrap color tokens — we want the amber family from Bootstrap but
       the CIS layout. The banner sits above the Overall Risk Box so the
       assessor sees the "partial results" framing before reading metrics. */
    display: flex;
    align-items: center;
    gap: 0.75rem;
    border-left: 4px solid var(--cis-amber);
    border-radius: 4px;
    padding: 0.65rem 0.85rem;
    margin-bottom: 1rem;
    /* Tint surface: use the canonical warn-tint token (already in palette). */
    background: var(--cis-tint-warn);
    border-top:    1px solid var(--cis-border-warn);
    border-right:  1px solid var(--cis-border-warn);
    border-bottom: 1px solid var(--cis-border-warn);
}

.cis-results-gap-banner-icon {
    flex: 0 0 auto;
    font-size: 1.25rem;
    line-height: 1;
    color: var(--cis-amber-text);
}

.cis-results-gap-banner-text {
    flex: 1 1 auto;
    line-height: 1.45;
    color: var(--cis-dark-text);
}

.cis-results-gap-banner-cta {
    /* Override Bootstrap's .btn-warning text color to the canonical CIS
       amber-text variable — keeps the visual weight without pulling in
       another token. */
    flex: 0 0 auto;
    color: #ffffff;
    background-color: var(--cis-amber);
    border-color: var(--cis-amber);
    font-weight: 600;
}

.cis-results-gap-banner-cta:hover,
.cis-results-gap-banner-cta:focus {
    color: #ffffff;
    background-color: var(--cis-amber-text);
    border-color: var(--cis-amber-text);
}

/* Matches Step-3/4/5/6 focus-outline precedent (2 px navy, offset −2 px). */
.cis-results-gap-banner-cta:focus-visible {
    outline: 2px solid var(--cis-navy);
    outline-offset: -2px;
}

/* ─── Dynamic first-column header (Maturity by Section table) ────────── */
.cis-first-col {
    color: var(--cis-navy);
    font-weight: 700;
}

/* ─── Complete column (Control-by-Control Summary table) ─────────────── */
.cis-complete-yes {
    color: var(--cis-green-text);
    font-weight: 700;
    font-size: 1.05rem;
}

.cis-complete-no {
    color: var(--cis-grey);
    font-weight: 700;
    font-size: 1.05rem;
}

/* ═══════════════════════════════════════════════════════════════════════
   STEP 9 · v2.5.4 — Responsive collapse (375 / 768 / 1280 / 1680)
   Presentation-only. No JS viewport detection. No framework branching.
   Breakpoints:
     • 575.98  — xs/sm boundary (banner icon collapse)
     • 767.98  — sm/md boundary (tablist→select, table→cards)
     • 991.98  — md/lg boundary (FAB hides, rail un-offcanvases)
   ═══════════════════════════════════════════════════════════════════════ */

/* ─── Surface A · Grouping tablist ⇄ mobile <select> ─────────────────── */
/* Mobile-first: select visible, tablist hidden. At ≥ 768 px invert. */
@media (min-width: 768px) {
    }
@media (max-width: 767.98px) {
    }

/* ─── Surface C · Right-rail FAB (floating action button) ────────────── */
/* Visible < 992 px; Bootstrap's d-lg-none hides it ≥ 992 px.
   44×44 touch target per WCAG 2.5.5. Navy theme with amber focus. */

/* ─── Surface C · Offcanvas host presentation ────────────────────────── */
/* Ensure the rail inside the offcanvas body has no double-margin when
   rendered in offcanvas mode (< 992 px). At ≥ 992 px the offcanvas-lg
   wrapper becomes a normal block and the existing rail styles apply. */
@media (max-width: 991.98px) {
        }

/* ─── Surface F · Results table ⇄ card mode ──────────────────────────── */
/* Mobile-first: cards block visible, table wrapper hidden. At ≥ 768 px
   invert so desktop retains the full Step-6 table UI. */
.cis-result-cards {
    display: block;
}
.cis-results-controls-table-wrapper {
    display: none;
}
@media (min-width: 768px) {
    .cis-result-cards {
        display: none;
    }
    .cis-results-controls-table-wrapper {
        display: block;
    }
}

/* Card presentation — mirrors Step-6 Control-by-Control table tokens. */
.cis-result-card {
    background: var(--cis-card-bg);
    border: 1px solid var(--cis-border);
    border-radius: 6px;
    padding: 12px 14px;
    margin-bottom: 10px;
    box-shadow: var(--cis-shadow);
}
.cis-result-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 6px;
}
.cis-result-card-head .cis-result-card-id {
    color: var(--cis-navy);
    font-weight: 700;
    font-size: 0.95rem;
    text-decoration: none;
}
.cis-result-card-head .cis-result-card-id:hover {
    text-decoration: underline;
}
.cis-result-card-title {
    font-weight: 600;
    font-size: 0.92rem;
    color: var(--cis-ink, #212529);
    margin: 0 0 10px 0;
    line-height: 1.35;
}
.cis-result-card-fields {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 10px;
    row-gap: 4px;
    margin: 0;
    font-size: 0.88rem;
}
.cis-result-card-fields dt {
    font-weight: 700;
    color: var(--cis-navy);
}
.cis-result-card-fields dd {
    margin: 0;
    color: var(--cis-ink, #212529);
}

/* ─── Surface E · Results gap banner · icon collapse ≤ 575.98 ────────── */
@media (max-width: 575.98px) {
    .cis-results-gap-banner-icon {
        display: none;
    }
    .cis-results-gap-banner-cta {
        text-align: center;
    }
}

/* ─── v2.5.30 · Gap banner overflow + responsive CTA hardening ─────────
 * Replaces Bootstrap width utilities (w-100 w-md-auto) removed from the
 * template in v2.5.30 because BS5 responsive width utilities are not
 * enabled in this project (see Lesson 263). Equivalent behavior is now
 * delivered via explicit CSS — no opt-in utilities required.
 *
 * Fixes:
 *   a) Button overflow past page edge  →  max-width + flex shrink
 *   b) Text span collapse into narrow column  →  min-width:0
 *   c) XS stacking — button sits full-width under stacked text
 *   d) Denominator alignment is handled at the PHP layer (default.php)
 * ──────────────────────────────────────────────────────────────────── */
.cis-results-gap-banner {
    max-width: 100%;
    box-sizing: border-box;
    flex-wrap: wrap;
}

.cis-results-gap-banner-text {
    min-width: 0;
    overflow-wrap: anywhere;
    word-break: break-word;
}

.cis-results-gap-banner-cta {
    max-width: 100%;
    white-space: normal;
    overflow-wrap: anywhere;
}

/* md+ (≥ 768 px): CTA keeps its natural width on the right.
 * ≤ sm (≤ 767.98 px): CTA becomes full-bleed under the stacked text. */
@media (max-width: 767.98px) {
    .cis-results-gap-banner-cta {
        display: block;
        width: 100%;
        text-align: center;
    }
}

/* ─── Surface D · Completion modal · fullscreen helper ≤ md ──────────── */
/* Bootstrap's modal-fullscreen-md-down class handles presentation; this
   block merely ensures long content scrolls comfortably on small screens. */
@media (max-width: 767.98px) {
    .modal-fullscreen-md-down .modal-body {
        max-height: none;
    }
}

/* ═══════════════════════════════════════════════════════════════════════
   v2.5.5 Step 10 — Session lifecycle surfaces
   Canonical mockup: mockups/v2.5.0/10_session_lifecycle_mocks.html
   Tokens: canonical --cis-navy / --cis-amber / --cis-red / --cis-tint-warn
   / --cis-border-warn / --cis-dark-text (from :root above). No rogue hex.
   ═══════════════════════════════════════════════════════════════════════ */

/* ─── Warning modal · amber accent, ≥ 44 px tap targets (WCAG 2.5.5) ─── */
.cis-session-warning-modal .modal-content {
    border-top: 4px solid var(--cis-amber);
    border-radius: 8px;
}
.cis-session-warning-modal .cis-session-warning-header {
    background: var(--cis-tint-warn);
    border-bottom: 1px solid var(--cis-border-warn);
}
.cis-session-warning-modal .cis-session-warning-countdown {
    margin-top: 1rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
.cis-session-warning-modal [data-cis-session-keep],
.cis-session-warning-modal [data-cis-session-logoff] {
    min-height: 44px;
    min-width: 44px;
    padding-inline: 1.25rem;
}

/* ─── v2.5.41.92 § 1.6.D mockup-locked: warning modal layout + countdown ─── */
.cis-session-warning-modal .modal-dialog { max-width: 520px; }
.cis-session-warning-modal .modal-body { text-align: center; padding: 18px 20px; }
.cis-session-warning-modal .modal-footer { justify-content: center; gap: 10px; padding: 14px 20px; }
.cis-session-warning-header { justify-content: center; text-align: center; }

.cis-session-warning-copy { margin: 0 0 12px; font-size: 14px; line-height: 1.6; }
.cis-session-warning-close-hint {
    margin: 0 0 12px;
    font-size: 13px;
    color: var(--bs-secondary-color, #6c757d);
    font-style: italic;
    line-height: 1.6;
}
.cis-session-warning-countdown {
    display: flex;
    align-items: baseline;
    justify-content: center;
    flex-wrap: wrap;
    gap: 12px;
    padding: 16px 0 8px;
    border-top: 1px solid #dee2e6;
    margin-top: 12px;
}
.cis-session-warning-label {
    font-size: 28px;
    font-weight: 500;
    line-height: 1.1;
    color: #212529;
}
.cis-session-warning-time {
    font-size: 28px;
    font-weight: 500;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.5px;
    color: #BA7517;
}


/* ─── Terminal full-page lock · red scrim, centered card ─────────────── */
.cis-session-ended-lock {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 2050; /* above Bootstrap modal-backdrop (1050) */
    background: rgba(15, 23, 42, 0.72);
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}
.cis-session-ended-lock.is-visible,
.cis-session-ended-lock:not([hidden]) {
    display: flex;
}
.cis-session-ended-lock .cis-session-ended-card {
    max-width: 560px;
    width: 100%;
    background: #ffffff;
    border-top: 4px solid var(--cis-red);
    border-radius: 10px;
    box-shadow: 0 24px 48px rgba(0, 0, 0, 0.35);
    padding: 2rem 2rem 1.75rem;
    text-align: center;
}
.cis-session-ended-lock .cis-session-ended-icon {
    font-size: 2.5rem;
    color: var(--cis-red);
    line-height: 1;
    margin-bottom: 0.75rem;
}
.cis-session-ended-lock .cis-session-ended-title {
    color: var(--cis-navy);
    margin-bottom: 0.75rem;
}
.cis-session-ended-lock .cis-session-ended-body {
    color: var(--cis-dark-text);
    margin-bottom: 1.5rem;
    line-height: 1.5;
}
.cis-session-ended-lock .cis-session-ended-signin {
    min-height: 44px;
    min-width: 160px;
    padding-inline: 1.5rem;
}

/* v2.5.12 — §5 inline re-auth form. Replaces the v2.5.11 redirect CTA so
   users can sign back in without losing their /assessments context. Form
   lives inside the terminal-lock card; fields stack on every breakpoint to
   stay legible at 320 px. Status region is announced via aria-live=polite
   and colour-coded by data-cis-session-login-state (invalid/pending/error). */
.cis-session-ended-lock .cis-session-ended-form {
    text-align: left;
    display: flex;
    flex-direction: column;
    gap: 0.875rem;
    margin-top: 0.25rem;
}
.cis-session-ended-lock .cis-session-ended-field .form-label {
    font-weight: 600;
    color: var(--cis-navy);
    margin-bottom: 0.35rem;
    font-size: 0.925rem;
}
.cis-session-ended-lock .cis-session-ended-field .form-control {
    width: 100%;
    min-height: 44px;       /* WCAG 2.5.5 AAA target size */
    font-size: 1rem;
    padding: 0.5rem 0.75rem;
}
.cis-session-ended-lock .cis-session-ended-status {
    min-height: 1.25rem;
    font-size: 0.925rem;
    line-height: 1.35;
    color: var(--cis-dark-text);
}
.cis-session-ended-lock .cis-session-ended-status[data-cis-session-login-state="pending"] {
    color: var(--cis-navy);
    font-style: italic;
}
.cis-session-ended-lock .cis-session-ended-status[data-cis-session-login-state="error"],
.cis-session-ended-lock .cis-session-ended-status[data-cis-session-login-state="invalid"] {
    color: var(--cis-red);
    font-weight: 600;
}
.cis-session-ended-lock .cis-session-ended-form .cis-session-ended-signin {
    width: 100%;
    margin-top: 0.25rem;
}
.cis-session-ended-lock .cis-session-ended-form .cis-session-ended-signin:disabled {
    opacity: 0.65;
    cursor: wait;
}

/* Narrow viewports — the lock card fills the viewport with a comfortable
   gutter; parity with modal-fullscreen-md-down so the two surfaces feel
   consistent at < 768 px. */
@media (max-width: 767.98px) {
    .cis-session-ended-lock {
        padding: 1rem;
    }
    .cis-session-ended-lock .cis-session-ended-card {
        padding: 1.5rem 1.25rem;
    }
}

/* XS (< 576 px) — tighten padding further and keep the form from
   spilling at 320 px. Label/input stack already works because the
   default flex direction is column. */
@media (max-width: 575.98px) {
    .cis-session-ended-lock {
        padding: 0.75rem;
    }
    .cis-session-ended-lock .cis-session-ended-card {
        padding: 1.25rem 1rem;
    }
    .cis-session-ended-lock .cis-session-ended-form {
        gap: 0.75rem;
    }
}

/* v2.5.5 Step 10 note: the save-before-nav scrim surface was scoped but
   has no current template consumer, so its speculative classes were
   removed (QA-29). When a consumer is wired in a later step, re-add the
   CSS alongside the template markup rather than shipping dead rules. */

/* ═══════════════════════════════════════════════════════════════════════
 * v2.5.26 · GenAI Profile scope surfacing (Results dashboard)
 *
 * Three surfaces mirror the PDF v2.5.25 overlay banner/badge system:
 *   1. .cisassess-scope-ribbon   — dashboard-wide scope announcement
 *   2. .cis-genai-chip           — per-section rollup chip on
 *                                  Maturity-by-Section rows (shows N)
 *   3. .cis-genai-badge          — per-Subcategory "GenAI Profile"
 *                                  badge (table + card variants)
 *
 * Tokens reuse existing --cis-* custom properties where possible.
 * Color scheme draws from the Assess-view ai600-1 overlay palette
 * (teal/blue family) so ribbon + chart chips + per-row badges share
 * a single visual language across Assess and Results.
 * ═══════════════════════════════════════════════════════════════════════ */

/* — Dashboard-wide scope ribbon — renders only when scope_id === standard_plus_genai */
.cisassess-scope-ribbon {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    margin-bottom: 16px;
    background: var(--cis-tint-navy);
    border: 1px solid var(--cis-navy);
    border-left-width: 5px;
    border-radius: 4px;
    color: var(--cis-navy-dark);
    font-size: 0.925rem;
    line-height: 1.4;
}
.cisassess-scope-ribbon-badge {
    display: inline-block;
    padding: 3px 10px;
    background: var(--cis-navy);
    color: #fff;
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-radius: 3px;
    white-space: nowrap;
    flex-shrink: 0;
}
.cisassess-scope-ribbon-text {
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: break-word;
}

/* — Per-section rollup chip on Maturity-by-Section rows — */
.cis-genai-chip {
    display: inline-block;
    padding: 1px 7px;
    margin-left: 6px;
    background: var(--cis-tint-navy);
    color: var(--cis-navy);
    border: 1px solid var(--cis-navy);
    border-radius: 10px;
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
    vertical-align: middle;
    line-height: 1.3;
}

/* — Per-Subcategory "GenAI Profile" badge — table + card shared base — */
.cis-genai-badge {
    display: inline-block;
    padding: 1px 6px;
    margin-left: 6px;
    background: var(--cis-navy);
    color: #fff;
    border-radius: 3px;
    font-size: 0.58rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
    vertical-align: middle;
    line-height: 1.5;
}
.cis-genai-badge-card {
    margin-left: 8px;
    padding: 2px 8px;
    font-size: 0.6rem;
}

/* Small-breakpoint ribbon stacking — keep badge on its own line below text */
@media (max-width: 575.98px) {
    .cisassess-scope-ribbon {
        flex-direction: column;
        align-items: flex-start;
        gap: 6px;
    }
    .cisassess-scope-ribbon-badge {
        align-self: flex-start;
    }
}
/* ═══════════════════════════════════════════════════════════════════════ */

/* ---------------------------------------------------------------------------
 * v2.5.27 · Responsive width utilities (R-01 hotfix)
 *
 * Bootstrap 5 ships only w-25 / w-50 / w-75 / w-100 / w-auto in its default
 * utility set. Responsive-breakpoint width utilities (w-{bp}-*) are NOT
 * emitted unless the utility API is extended at build time. The Results gap
 * banner CTA (results/default.php) renders:
 *
 *     <a class="btn ... cis-results-gap-banner-cta w-100 w-md-auto">
 *
 * and this kept the button to stay at w-100 ≥768px and spill 67-87px past
 * its flex-md-row parent at 900px / 1100px iframe widths.
 *
 * Root-cause confirmed: .w-md-auto had zero definitions in this stylesheet
 * before this release; the class name was inert. This stanza defines the
 * utility at the md breakpoint (≥768px) so any future w-{bp}-* additions
 * belong in the same block.
 *
 * Pair: build_verify.sh Rule 12 (w-{bp}-* template-to-CSS parity gate).
 * ------------------------------------------------------------------------- */
@media (min-width: 768px) {
    .w-md-auto { width: auto !important; }
}

/* ══════════════════════════════════════════════════════════════════════
 * v2.5.31 — Training-Relevance CTA (Feature B)
 * Shared stanza: Assess view (full card, dismissible) + Results view (compact
 * expandable badge). PDF uses inline mpdf-safe CSS in the renderer.
 * Neutral-voice design per project_iso19011_assessor_voice — card sits
 * visually separate from the auditor's comment textarea.
 * ══════════════════════════════════════════════════════════════════════ */

.cis-training-relevance-card {
    margin: 0.75rem 0 1rem;
    padding: 0.75rem 1rem;
    background: var(--cis-card-bg);
    border: 1px solid var(--cis-border);
    border-left: 3px solid #1B3A6B;
    border-radius: 4px;
    font-size: 0.85rem;
    line-height: 1.45;
    color: var(--cis-navy-dark);
    position: relative;
}

.cis-training-relevance-card .cis-tr-eyebrow {
    display: block;
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #1B3A6B;
    margin-bottom: 0.35rem;
}

.cis-training-relevance-card .cis-tr-blurb {
    margin: 0 0 0.5rem;
    color: var(--cis-navy-dark);
}

.cis-training-relevance-card .cis-tr-cta {
    display: inline-block;
    font-weight: 600;
    color: #1B3A6B;
    text-decoration: none;
    border-bottom: 1px solid #1B3A6B;
    padding-bottom: 1px;
}
.cis-training-relevance-card .cis-tr-cta:hover,
.cis-training-relevance-card .cis-tr-cta:focus {
    color: var(--cis-navy-dark);
    border-bottom-color: var(--cis-navy-dark);
    outline: none;
}

.cis-training-relevance-card .cis-tr-dismiss {
    position: absolute;
    top: 0.35rem;
    right: 0.5rem;
    background: transparent;
    border: none;
    color: #768090;
    font-size: 0.75rem;
    cursor: pointer;
    padding: 0.15rem 0.4rem;
}
.cis-training-relevance-card .cis-tr-dismiss:hover,
.cis-training-relevance-card .cis-tr-dismiss:focus {
    color: #1B3A6B;
    outline: none;
}

/* Results-view compact badge variant — expandable on hover/focus */
.cis-tr-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    margin-top: 0.4rem;
    padding: 0.15rem 0.5rem;
    background: var(--cis-card-bg);
    border: 1px solid var(--cis-border);
    border-radius: 10px;
    color: #1B3A6B;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    text-decoration: none;
    line-height: 1.2;
}
.cis-tr-badge::before {
    content: "◆";
    font-size: 0.55rem;
    color: #1B3A6B;
}
.cis-tr-badge:hover,
.cis-tr-badge:focus {
    background: var(--cis-tint-navy);
    color: var(--cis-navy-dark);
    outline: none;
}

/* Viewport safety — prevent overflow at narrow breakpoints */
@media (max-width: 480px) {
    .cis-training-relevance-card {
        padding: 0.6rem 0.75rem 0.75rem;
        font-size: 0.8rem;
    }
    .cis-training-relevance-card .cis-tr-dismiss {
        position: static;
        display: block;
        text-align: right;
        margin-top: 0.4rem;
    }
}

/* ==========================================================================
   v2.5.38.1 — Sticky-header z-index war fix
   --------------------------------------------------------------------------
   Helix Ultimate switches #sp-header to position:fixed with z-index:9999 once
   the page is scrolled past the sticky-trigger threshold. The default
   Bootstrap modal z-index is 1055, which means our component modals (the
   maturity-level guidance and scoring-rubric panels) get clipped at the top
   by the sticky site navigation when opened from a scrolled position.
   Reproduced 2026-04-25 on /assessments/assess/68 at scrollY > 1200.
   Fix: bump the two component modals plus their backdrop above #sp-header.
   ========================================================================== */
#maturityInfoModal,
#scoringRubricModal,
#overrideConfirmModal,
#cisGroupingCompleteModal,
#cisSessionExpiryModal,
/* v2.5.41.75 § 1.4 — results-view modals (same-class L275 closure per AR
   D-AR-v2.5.41.73 sweep finding; smaller blast radius than assess-view but
   identical risk pattern). regression_spec_id pending: REG-v2.5.41.75-01-
   results-modal-clears-site-nav (queued v2.5.41.76 mandatory VB Tier 2
   Group C/D candidate). */
#guidanceModal,
#depInfoModal,
#emailReportModal {
    z-index: 10100;
}

/* Use :has() to bump the backdrop ONLY when a component modal is open, so we
   do not perturb other site modals' stacking. :has() is supported across all
   modern browsers required by Bootstrap 5.3. v2.5.41.73 — bump rule extended
   to all 5 assess-view component modals per AR D-AR-v2.5.41.73-class-c-dual-
   audit; Lesson 275 enforcement; closes BUG-v2.5.41.71-001 + 2 latent same-
   class instances. regression_spec_id: REG-v2.5.41.73-001-override-modal-
   clears-site-nav. */
body:has(#maturityInfoModal.show) .modal-backdrop,
body:has(#scoringRubricModal.show) .modal-backdrop,
body:has(#overrideConfirmModal.show) .modal-backdrop,
body:has(#cisGroupingCompleteModal.show) .modal-backdrop,
body:has(#cisSessionExpiryModal.show) .modal-backdrop,
/* v2.5.41.75 § 1.4 — results-view modal backdrops (same-class L275 closure). */
body:has(#guidanceModal.show) .modal-backdrop,
body:has(#depInfoModal.show) .modal-backdrop,
body:has(#emailReportModal.show) .modal-backdrop {
    z-index: 10090;
}

/* ==========================================================================
   v2.5.40.1 — Per-question iso_sources[] inline source-attribution pills
   --------------------------------------------------------------------------
   Renders directly under the T1 question text in the Assess workspace for any
   framework whose JSON declares iso_sources[] per control + an iso_source_meta{}
   lookup table (currently iso_31000_erm.json; pattern is reusable for future
   composite/aggregated frameworks). Locked by design doc §12.2:
     - Pill-style, low chrome
     - Label "Sourced from:" + short standard tokens (e.g. "ISO 31000 · ISO/IEC 23894")
     - ARIA-label expansion to full standard name + role on hover/focus
     - Inline pills on all viewports per Allen 2026-04-25 (no mobile collapse)
   Tokens are sourced from the :root block above — no new hexes.
   ========================================================================== */
.cis-iso-sources {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.5rem;
    line-height: 1.4;
}

.cis-iso-sources__label {
    font-size: 0.72rem;
    font-weight: 500;
    color: var(--cis-grey);
    margin-right: 0.15rem;
}

.cis-iso-source-pill {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 10px;
    background: var(--cis-tint-navy);
    color: var(--cis-navy);
    font-size: 0.72rem;
    font-weight: 500;
    border: 1px solid var(--cis-border-navy-soft);
    line-height: 1.4;
    white-space: nowrap;
    cursor: help;
    transition: background-color 120ms ease, box-shadow 120ms ease;
}

.cis-iso-source-pill:hover,
.cis-iso-source-pill:focus-visible {
    background: var(--cis-tint-info);
    box-shadow: 0 0 0 2px var(--cis-border-info);
    outline: none;
}

/* Reduced-motion: keep visual change but skip transition */
@media (prefers-reduced-motion: reduce) {
    .cis-iso-source-pill { transition: none; }
}

/* ==========================================================================
   v2.5.40.1 — UX hotfix bundle (carryover from v2.5.39.1 brief)
   --------------------------------------------------------------------------
   Four issues flagged by Allen on the v2.5.38.1-on-PROD Assess workspace:
     1) Horizontal section tablist redundancy → hide tablist; promote the
        existing mobile-only <select> to a breadcrumb-style dropdown that
        is visible at all viewports. CSS-only — keeps the JS event-bus
        wiring intact (grouping_nav.js still receives select-change events).
     2) Header bar not sticky → make the Control-Card header sticky below
        the Helix sticky site header (#sp-header z-index 9999).
     3) Right sidebar not sticky at desktop → already sticky via Step 5
        (top: 12px) but the offset puts it under #sp-header on scroll.
        Adjust top to clear the site header.
     4) Bottom whitespace — diagnosed live in Chrome; capped via
        cis-assess-page-wrap min-height override (see §1.4 below).
   Tokens are sourced from the :root block — no new hexes.
   ========================================================================== */

/* §1.1 — Tablist hidden at all viewports; <select> visible at all viewports */


@media (min-width: 768px) {
    }

@media (max-width: 767.98px) {
    }

/* §1.2 — Sticky Control-Card header on the Assess workspace.
   The Helix Ultimate sticky site header (#sp-header) reaches z-index:9999 once
   scrolled past the trigger threshold (~80 px). The Control-Card header must
   sit below it (z-index 100 — below modals 1055 and #sp-header 9999, above
   non-modal content) and offset by the site-header height.
   Target selector is scoped to the Assess workspace body class so the rule
   does not bleed into other views. */
body.view-assess .card.border-0.shadow-sm > .card-header.border-bottom.py-3,
body.view-assess .cis-assess-control-card-header {
    position: sticky;
    top: var(--cis-site-header-height, 80px);
    /* v2.5.41.27.2 — z-index lowered 100→90 so the in-component sticky stack
       loses to Helix #sp-header pre-sticky z=99 at body level, freeing the
       megamenu dropdown. cisassess-header at z=91 still wins this band
       (91 > 90). Pairs with the cisassess-header lowering below. */
    z-index: 90;
    background: var(--cis-navy);
    color: #fff;
}

/* §1.3 — Sidebar offset adjustment so it clears #sp-header when scrolling.
   Step-5 originally pinned at top:12px which hides under the Helix sticky
   site header on scroll. Bump the offset by --cis-site-header-height. Cap
   the sidebar height so it scrolls internally rather than overflowing. */
@media (min-width: 992px) {
    }

/* §1.4 — Bottom-whitespace cap on the Assess workspace.
   Diagnosed live in Chrome 2026-04-25 against PROD v2.5.40: the empty band
   between the Save button and the site footer is sourced from Helix Ultimate's
   `#sp-main-body { padding-bottom: 100px; }` baked into the template. Override
   the rule scoped to the Assess workspace (view-assess body class) so other
   views (Setup, Results, Dashboard) keep the Helix breathing room. Also drop
   any inherited #sp-component min-height that may have been set by a parent. */
body.view-assess #sp-main-body {
    padding-bottom: 1.5rem !important;
}

body.view-assess #sp-component {
    min-height: auto !important;
}

/* §1.5 — Page-level Assess banner sticky + z-index ordering (v2.5.41.3 §5.2)
   ---------------------------------------------------------------------------
   Diagnosed live in Chrome 2026-04-25 against PROD v2.5.41.2.2:
   1. Empty 80-pixel white band between Joomla #sp-header and the pinned
      .cis-assess-control-card-header — the page-level dark-blue assessment
      banner (.cisassess-header) was position:relative and scrolled away,
      leaving the offset reserved by the control-card sticky rule unfilled.
   2. Tier 2 — Practice Maturity Assessment H5 visually obscured by the
      pinned control-card header due to z-index:100 overlay.

   Fix: pin the .cisassess-header at top:var(--cis-site-header-height,80px)
   with z-index:101 (one above the control-card header at 100; well below
   modals at 1055 and Helix #sp-header at 9999). Push the control-card
   header offset down by the banner's measured height (--cis-page-banner-h,
   default 64px) so the two pin in a clean stack instead of overlapping.

   Scope: body.view-assess only — Setup / Results / Dashboard untouched.
   Memory: project_assess_workspace_ux_findings_v2_5_38_1.md scoped this for
   v2.5.39.1; live DOM showed it was never landed. Closes the carryover. */

body.view-assess {
    /* v2.5.41.44 §1.1 — banner-h sync 64→126 per AR plan-doc §3.3.
       Pre-fix: pre-measure default 64px diverged from inline-script post-measure
       value (~126px) by 62 px, causing first-paint subheader pin-offset jump.
       Post-fix: default matches measured truth within ~5 px race-window. */
    --cis-page-banner-h: 126px;
}

body.view-assess .cisassess-header {
    position: sticky;
    top: var(--cis-site-header-height, 80px);
    /* v2.5.41.27.2 — z-index lowered 101→91 so this sticky banner loses to
       Helix #sp-header pre-sticky z=99 at body level (megamenu dropdown
       wins). Still wins over .cis-assess-control-card-header z=90 inside
       the in-component sticky stack (91 > 90). Replaces the v2.5.41.27.1
       isolation:isolate fix, which broke modal-above-Helix-sticky for
       Maturity Info / Scoring Rubric / session-timeout login modals
       (z=10100/10090/11000). See planning log 2026-04-29T22:50Z. */
    z-index: 91;
    margin-top: 0;
}

body.view-assess .card.border-0.shadow-sm > .card-header.border-bottom.py-3,
body.view-assess .cis-assess-control-card-header {
    /* v2.5.41.44 §1.1 — fallback 64→126 to match the body.view-assess default. */
    top: calc(var(--cis-site-header-height, 80px) + var(--cis-page-banner-h, 126px));
}

/* v2.5.41.4.2 — When the v2.5.41.4 mega-menu navigator is mounted (body.cnm-mounted),
   the .cnm-bar (height ~58 px) inserts itself between the page banner and the
   control-card subheader as a NEW sticky band. The subheader's pinned offset
   must therefore push down by the bar's height so the 4-band sticky stack
   pins flush (sp-header → cisassess-header → .cnm-bar → control-card subheader).
   --cnm-bar-h is published by the inline measurement script in
   site/tmpl/assess/default.php (extended in v2.5.41.4.2) so the offset adapts
   to mobile (taller wrapped bar) and to any future bar-height changes. */
body.view-assess.cnm-mounted .card.border-0.shadow-sm > .card-header.border-bottom.py-3,
body.view-assess.cnm-mounted .cis-assess-control-card-header {
    /* v2.5.41.44 §1.1 — fallback 64→126 to match the body.view-assess default. */
    top: calc(var(--cis-site-header-height, 80px) + var(--cis-page-banner-h, 126px) + var(--cnm-bar-h, 58px));
}

/* §1.6 — Sticky-overflow correction (v2.5.41.3.1)
   ---------------------------------------------------------------------------
   Diagnosed live in Chrome 2026-04-25 against PROD v2.5.41.3 at 1829×868
   desktop viewport (Allen-rendered, NOT iframe — same-origin iframe trick
   masks this bug because the iframe body becomes the sticky reference frame).

   Symptom: two empty bands on the Assess workspace at scrollY = 0:
     1. ~80 px gap between the page top and the dark-blue assessment banner
     2. ~144 px gap inside the white control card above the question text
        (control-card subheader pushed below where it should sit)

   Root cause: `position: sticky` resolves its `top` value against the nearest
   scrolling ancestor. Two CSS rules above (line 56 wrap + line 106 .card)
   originally specified `overflow: hidden` / `overflow-x: hidden`. The CSS
   spec coerces the orthogonal axis from `visible` to `auto` whenever one
   axis is non-visible — quietly turning each container into a scroll
   context. Consequence: the page-banner sticky (top:80) and the control-
   card-header sticky (top:144) engaged immediately, pushing each element
   down by exactly its `top` value.

   Fix: the two rules above changed `hidden` → `clip`. `overflow: clip`
   clips identically to `hidden` (preserves rounded-corner masking on
   .card and viewport-safety on the wrap) but does NOT establish a scroll
   container, so descendant sticky elements resolve `top` against the
   viewport as intended.

   Browser support for `overflow: clip` (Sep 2022 baseline):
     Chrome / Edge 90+   (April 2021)
     Firefox 81+         (Sep 2020)
     Safari 16.0+        (Sep 2022) */

/* §1.7 — Tier 1 Maturity Determination card layout (v2.5.41.3.2)
   ---------------------------------------------------------------------------
   Diagnosed live in Chrome 2026-04-26 against PROD v2.5.41.3.1: the 6 maturity
   cards (rendered at site/tmpl/assess/default.php ~line 1037) used a `.d-flex
   align-items-start gap-2` layout with inline radio + label-string. At
   col-md-2 (~127 px wide), labels like "Quantitatively Managed / Predictable"
   wrapped to 4 lines, with broken-mid-word artifacts ("Quantitativel\\ny
   Managed") from default `hyphens: auto`. The "N — " prefix was redundant
   with the colored bar segment number directly above each card.

   Fix (paired with PHP markup change in assess/default.php):
   - The PHP template now splits the label on " / " into a primary span + a
     synonym span, and drops the "N — " prefix entirely.
   - This CSS lays out each card vertically: radio centered above; primary
     label (bold) and synonym (normal weight) stacked below, both at 0.85rem.
   - word-break: keep-all + hyphens: none keeps multi-word names intact.
   - 6-across grid (col-md-2) preserved so each card aligns directly under
     its color segment in the maturity bar above. */
.cisassess-mat-card .cisassess-mat-card-inner {
    display: block;
    text-align: center;
}
.cisassess-mat-card .cisassess-mat-radio {
    display: block !important;
    margin: 0 auto 6px auto !important;
    float: none !important;
}
.cisassess-mat-card .cisassess-mat-label {
    display: block;
    width: 100%;
    font-size: 0;       /* zero-out so child spans control text sizing */
    line-height: 1.2;
}
.cisassess-mat-card .cisassess-mat-primary {
    display: block;
    font-size: 0.85rem;
    font-weight: 700;
    line-height: 1.2;
    hyphens: none;
    word-break: keep-all;
    overflow-wrap: normal;
}
.cisassess-mat-card .cisassess-mat-synonym {
    display: block;
    margin-top: 3px;
    font-size: 0.85rem;
    font-weight: 400;
    line-height: 1.2;
    hyphens: none;
    word-break: keep-all;
    overflow-wrap: normal;
}
/* v2.5.41.6 §1.0 — full prose description, mirrors conformance-card description
   density (0.7rem / line-height 1.3). text-align center under the radio +
   stacked label. Color follows the parent grey-dark token used by conformance
   cards so spec/risk frameworks read at the same visual weight. */
.cisassess-mat-card .cisassess-mat-description {
    display: block;
    margin-top: 6px;
    font-size: 0.7rem;
    font-weight: 400;
    line-height: 1.3;
    color: var(--cis-grey-dark);
    text-align: left;
    hyphens: auto;
    word-break: normal;
    overflow-wrap: anywhere;
}
.cisassess-mat-card .cisassess-mat-risk {
    display: block;
    margin-top: 4px;
    font-size: 0.65rem;
    font-weight: 700;
}

/* §1.8 — Sticky-pin enablement on Assess workspace (v2.5.41.3.2)
   ---------------------------------------------------------------------------
   Diagnosed live in Chrome 2026-04-26 against PROD v2.5.41.3.1:
   `.cisassess-header` (page banner, position:sticky top:80) and
   `.cis-assess-control-card-header` (control-card subheader, position:sticky
   top:144) never engaged on document scroll. Root cause: Helix Ultimate
   wraps the page in `.body-innerwrapper` (overflow-y: auto) and the
   document `body` itself (overflow: hidden), both of which become the
   nearest scroll container for descendant sticky elements per CSS Overflow
   Module Level 3. With sticky resolved against those non-scrolling
   containers, top: N produces a static offset instead of viewport pinning.

   Fix: scope an `overflow-x: clip; overflow-y: visible` override to
   body.view-assess for both wrappers so descendant stickies resolve
   against html (the actual scroll container) and pin properly.

   Companion: an inline script in site/tmpl/assess/default.php measures
   #sp-header and .cisassess-header heights at runtime and publishes them
   as --cis-site-header-height + --cis-page-banner-h on body. The two
   sticky rules in §1.2 + §1.5 already read those vars via top:var(...)
   so the three-band stack (Joomla site-header → page banner → control-card
   subheader) stays flush with no gap and no overlap. Re-measures on
   scroll (Helix shrinks #sp-header on scroll) and on resize (banner can
   wrap on narrow viewports).

   Closes carryover from v2.5.41.3.1 §1.6: that release closed the gap-at-
   rest bug; this release closes the no-pin-on-scroll bug. */
body.view-assess,
body.view-assess .body-innerwrapper {
    overflow-x: clip !important;
    overflow-y: visible !important;
}

/* §1.10 — Navigator card host (v2.5.41.4 — repurposed)
   ---------------------------------------------------------------------------
   In v2.5.41.3.3 this block styled the clause-tabstrip + chip-strip stacked
   inside .cis-assess-nav-card. v2.5.41.4 replaces that DOM with the Vanta-
   style nested mega-menu (see §2 below). The card frame survives as a thin
   shell that the mega-menu mounts inside; the legacy children (tabstrip +
   chip-strip + offcanvas rail) are tagged [cnm-fallback] and hidden by §2
   on successful JS init.

   We retain a soft border/padding fallback for the no-JS state so the legacy
   server-rendered chrome still looks contained if the mega-menu fails to
   mount (graceful degradation). On successful mount, the .cnm-bar's own
   styling (§2) takes over visually. */
.cis-assess-nav-card {
    border: 0;
    border-radius: 6px;
    box-shadow: none;
    overflow: visible;
    padding: 0;
    background: transparent;
    margin-bottom: 12px;
}
body.view-assess.cnm-mounted .cis-assess-nav-card {
    /* Ensure the card frame is invisible when the mega-menu is mounted —
       the .cnm-bar carries its own backing surface. */
    background: transparent !important;
    border: 0 !important;
    box-shadow: none !important;
    padding: 0 !important;

    /* v2.5.41.44.1 §1.1 — STICKY-CHAIN HOTFIX. Post-v2.5.41.44 D3 the .cnm-bar
       is appended directly INTO this card (the JS reparent block was deleted).
       That makes this card the bar's containing block. With this card at
       position:relative (Bootstrap .card default) and only ~58px tall, the
       inner sticky bar can only pin within the 58px parent — once the user
       scrolls past the parent's bottom edge, the bar follows it above the
       viewport, breaking the 3-band sticky stack. Promote THIS card itself
       to position:sticky so the inner bar pins with its parent across the
       full body-grid scroll range. Verified live in PROD via JS-injection
       sweep at scrollY=1922 — gap_banner_to_navCard=0 and
       gap_navCard_to_subhead=0 (perfect flush). */
    position: sticky;
    top: calc(var(--cis-site-header-height, 80px) + var(--cis-page-banner-h, 126px));
    z-index: 1050;
}


/* ═══════════════════════════════════════════════════════════════════════════
   §2 — VANTA-STYLE NESTED MEGA-MENU NAVIGATOR (v2.5.41.4)
   ═══════════════════════════════════════════════════════════════════════════
   Replaces the v2.5.0 grouping tabstrip + chip-strip + offcanvas right-rail
   with a single mega-menu drop-down anchored to a compact bar. Adapted from
   the Vanta-spec captured at com_cisassess/docs/design/nested-mega-menu-skill.md
   and the working mockup at com_cisassess/docs/design/v2_5_41_4_navigator_mockup.css.

   Brand-adapted to cisassess navy palette (rgb(27,58,107) / #1B3A6B). Audit
   findings P0/P1/P2 from com_cisassess/docs/design/v2_5_41_4_navigator_design.md
   are folded in (sticky bar, idle trigger fill, mobile direction-aware slide,
   debounced search, keyboard navigation styling).
   ═══════════════════════════════════════════════════════════════════════════ */

/* §2.1 — Tombstone (v2.5.41.16): The legacy assessor chrome that this rule
   used to hide on successful mega-menu mount — [cis-grouping-tabstrip],
   [cis-assess-chip-strip] <nav>, #cisRightRailDrawer (.offcanvas-lg
   [cis-right-rail-host]), and [cis-rail-fab] — was REMOVED from
   site/tmpl/assess/default.php in v2.5.41.16 because the mega-menu
   navigator (.cnm-bar) reliably mounts in PROD and the always-render-then-
   hide pattern was per-page-load wasted work across all 5 frameworks.
   Selectors retained as no-op tombstones below for archaeological clarity;
   they target nothing and have zero render cost. */

/* §2.2 — Retired in v2.5.41.44 §1.1 per AR plan-doc §3.3.
   The body-grid 1-col layout is now the default (see desktop grid block above);
   the body.cnm-mounted grid-flip is no longer needed. The cnm-mounted class
   itself is still set by JS (cisassess-nav-megamenu.js mount()) and consumed
   by §1.5 subheader offset and §1.7 nav-card backing rules — those remain. */

/* §2.3 — Body-innerwrapper overflow override (v2.5.41.24 brace-imbalance fix).
   The page-level body-innerwrapper override at line ~2340 (from v2.5.41.3.1)
   covers the document layer; we only need to ensure the nav card's own
   children container doesn't clip. */
body.view-assess .cis-assess-nav-card,
body.view-assess #sp-component,
body.view-assess .com-cisassess-assess { overflow: visible !important; }

/* §2.4 — Compact bar (sticky under page banner per P0 #1, v2.5.41.4.1 fix).
   Sticky offset must clear BOTH the Helix #sp-header (--cis-site-header-height,
   80 px) AND the cisassess page banner (--cis-page-banner-h, 126 px) so the
   3-band sticky stack pins flush. v2.5.41.4 used only --cis-page-banner-h which
   put the bar at top:126 — overlapping the page banner that pins at top:80
   with bottom 206. v2.5.41.4.1 sums both vars so the bar pins at top:206
   directly below the banner. Default fallback values match the production
   measured heights (80 + 126 = 206 px) for race-safety on first paint. */
.cnm-bar {
    position: sticky;
    top: calc(var(--cis-site-header-height, 80px) + var(--cis-page-banner-h, 126px));
    /* v2.5.41.4.2 — z-index bumped 99 → 1050. The bar's children (.cnm-dropdown
       at z-index 9999) inherit a stacking context anchored at the bar's z-index;
       at 99 the bar lost to the control-card subheader (z-index:100) and page
       banner (z-index:101), so the dropdown was clipped under them. 1050 sits
       above all sticky chrome (subheader 100, banner 101) but below Bootstrap
       modal-backdrop (1055) so modals still cover the bar correctly. */
    z-index: 1050;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 10px 14px;
    background: #fff;
    border: 1px solid #d2d6dc;
    border-radius: 6px;
    box-shadow: 0 1px 2px rgba(0,0,0,0.06), 0 1px 3px rgba(0,0,0,0.10);
    font-size: 15px;
    color: rgb(43, 44, 63);
}
.cnm-crumbs {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    min-width: 0;
    flex: 1 1 auto;
    overflow: hidden;
}
.cnm-folder { color: rgb(27, 58, 107); font-size: 1rem; flex-shrink: 0; }
.cnm-crumb {
    color: rgb(43, 44, 63);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 220px;
}
.cnm-crumb.is-current { color: rgb(27, 58, 107); font-weight: 700; max-width: 320px; }
.cnm-sep { color: #cbd5e0; flex-shrink: 0; }
.cnm-actions { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }

/* §2.5 — Browse-controls trigger (idle/hover/active per P1 #4) */
.cnm-trigger {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border-radius: 4px;
    background: #f8f9fc;             /* P1 #4 — light fill so it reads as clickable */
    color: rgb(43, 44, 63);
    border: 1px solid #d2d6dc;
    cursor: pointer;
    font-size: 15px;
    font-weight: 500;
    line-height: 1.2;
    transition: all 0.2s ease;
}
.cnm-trigger:hover { background: rgb(245, 245, 246); border-color: rgb(27, 58, 107); }
.cnm-trigger:focus-visible {
    outline: 2px solid rgb(27, 58, 107);
    outline-offset: 2px;
}
.cnm-trigger[aria-expanded="true"] {
    background: rgb(27, 58, 107);
    color: #fff;
    border-color: rgb(27, 58, 107);
}
.cnm-caret {
    display: inline-block;
    transition: transform 0.2s ease;
    font-size: 0.85em;
}
.cnm-trigger[aria-expanded="true"] .cnm-caret { transform: rotate(180deg); }

/* §2.6 — Next-incomplete CTA (solid navy fill) */
.cnm-cta {
    display: inline-flex;
    align-items: center;
    background: rgb(27, 58, 107);
    color: #fff;
    padding: 8px 16px;
    border-radius: 4px;
    font-size: 15px;
    font-weight: 600;
    text-decoration: none;
    line-height: 1.2;
    transition: all 0.2s ease;
}
.cnm-cta:hover { background: rgb(15, 36, 70); color: #fff; text-decoration: none; }
.cnm-cta:focus-visible { outline: 2px solid #fff; outline-offset: -3px; box-shadow: 0 0 0 4px rgba(27,58,107,0.4); }
.cnm-cta.is-disabled,
.cnm-cta[aria-disabled="true"] {
    pointer-events: none;
    background: #cbd5e0;
    color: #ffffff;
    cursor: not-allowed;
}

/* §2.7 — Drop-down anchored below trigger (NOT a centered modal) */
.cnm-dropdown {
    position: absolute;
    left: 0; right: 0;
    top: calc(100% + 8px);
    z-index: 9999;
    background: transparent;
    animation: cnm-fade 0.18s ease-out;
}
.cnm-dropdown[hidden] { display: none; }
@keyframes cnm-fade {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* §2.8 — Drop-down card */
.cnm-dd-card {
    background: #fff;
    border-radius: 16px;
    box-shadow: 0 12px 32px rgba(20, 30, 50, 0.12), 0 2px 6px rgba(20, 30, 50, 0.06);
    max-height: 580px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* §2.9 — Header row: search + close */
.cnm-dd-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px 20px 12px 20px;
}
.cnm-search {
    width: 100%;
    flex: 1;
    max-width: 400px;
    padding: 10px 14px;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
    font-size: 15px;
    outline: none;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.cnm-search:focus {
    border-color: rgb(27, 58, 107);
    box-shadow: 0 0 0 3px rgba(27, 58, 107, 0.12);
}
.cnm-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    margin-left: auto;
    flex-shrink: 0;
    background: transparent;
    border: 0;
    border-radius: 50%;
    color: #94a3b8;
    cursor: pointer;
    transition: background 0.2s ease, color 0.2s ease, transform 0.2s ease;
}
.cnm-close:hover {
    background: rgb(245, 245, 246);
    color: rgb(27, 58, 107);
    transform: scale(1.05);
}
.cnm-close:active { transform: scale(0.95); }
.cnm-close:focus-visible { outline: 2px solid rgb(27, 58, 107); outline-offset: 2px; }
.cnm-close svg { display: block; }

/* §2.10 — Three-rail cascade (or two-rail for 1-tier frameworks).
   Differentiated by background TONE shifts, not hard borders. */
.cnm-dd-cols {
    flex: 1;
    min-height: 0;
    display: grid;
    grid-template-columns: 320px 320px 1fr;
}
.cnm-2col .cnm-dd-cols { grid-template-columns: 420px 1fr; }
.cnm-rail {
    padding: 28px 18px;
    overflow-y: auto;
    min-height: 0;
}
.cnm-rail-l1 { background: rgb(245, 245, 246); border-radius: 16px 0 0 16px; }
.cnm-rail-l2 { background: rgb(250, 251, 252); }
.cnm-rail-l3 { background: #fff; padding: 24px 28px; }

/* §2.11 — L1/L2 items — button-style fills (Vanta spec) */
.cnm-item {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 8px 12px;
    margin-bottom: 4px;
    border-radius: 6px;
    cursor: pointer;
    font-size: 18px;
    color: rgb(43, 44, 63);
    background: transparent;
    text-decoration: none;
    transition: all 0.2s ease;
    border: 0;
    width: 100%;
    text-align: left;
}
.cnm-item:hover { background: rgba(27, 58, 107, 0.04); color: rgb(27, 58, 107); }
.cnm-item:focus-visible { outline: 2px solid rgb(27, 58, 107); outline-offset: 2px; }
.cnm-item.is-active {
    background: rgb(27, 58, 107);
    color: #fff;
    font-weight: 600;
}
.cnm-item.is-active:hover { background: rgb(15, 36, 70); color: #fff; }
.cnm-item-label { flex: 1; font-weight: 500; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cnm-item-stack { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cnm-item-stack .cnm-item-label { white-space: normal; }
.cnm-item-sub { font-size: 13px; opacity: 0.7; font-weight: 400; }
.cnm-item-meta {
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    opacity: 0.75;
    flex-shrink: 0;
    padding: 2px 7px;
    border-radius: 4px;
}
.cnm-item.is-active .cnm-item-meta { background: rgba(255, 255, 255, 0.16); opacity: 1; }

/* §2.12 — Arrow icon (drill-in affordance) */
.cnm-item-arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    opacity: 0.5;
    transition: opacity 0.2s ease;
    flex-shrink: 0;
}
.cnm-svg-arrow {
    display: block;
    transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.cnm-item:hover .cnm-item-arrow,
.cnm-item.is-active .cnm-item-arrow { opacity: 1; }
.cnm-item:hover .cnm-svg-arrow { transform: translateX(3px); }
.cnm-item.is-active .cnm-svg-arrow { transform: translateX(2px); }

/* §2.13 — L3 leaves (title + subtitle pattern, Vanta spec hover) */
.cnm-leaf {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 10px 14px;
    margin-bottom: 2px;
    cursor: pointer;
    text-decoration: none;
    border-radius: 8px;
    transition: background 0.2s ease, transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
.cnm-leaf:hover {
    background: rgb(245, 245, 246);
    text-decoration: none;
    transform: translateX(2px);
}
.cnm-leaf:focus-visible { outline: 2px solid rgb(27, 58, 107); outline-offset: 2px; }
.cnm-leaf-icon {
    flex-shrink: 0;
    width: 22px;
    text-align: center;
    font-size: 1rem;
    font-weight: 700;
    padding-top: 3px;
    transition: transform 0.2s ease;
}
.cnm-leaf:hover .cnm-leaf-icon { transform: scale(1.1); }
.cnm-leaf.is-done .cnm-leaf-icon       { color: rgb(4, 112, 64); }
.cnm-leaf.is-current .cnm-leaf-icon    { color: rgb(27, 58, 107); }
.cnm-leaf.is-partial .cnm-leaf-icon    { color: rgb(154, 63, 11); }
.cnm-leaf.is-na .cnm-leaf-icon         { color: #a0aec0; }
.cnm-leaf.is-untouched .cnm-leaf-icon  { color: #cbd5e0; }
.cnm-leaf-stack { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.cnm-leaf-title { font-size: 16px; font-weight: 600; color: rgb(27, 58, 107); }
.cnm-leaf-sub   { font-size: 13.5px; color: rgb(74, 85, 104); line-height: 1.45; }
.cnm-leaf.is-current { background: rgba(27, 58, 107, 0.06); }

/* §2.14 — Empty L3 state */
.cnm-empty {
    padding: 24px 14px;
    text-align: center;
    font-size: 14px;
    color: rgb(74, 85, 104);
    font-style: italic;
}

/* §2.15 — Mobile back-button (drill-up navigation) */
.cnm-mobile-back {
    display: none;                        /* shown only at mobile breakpoint */
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 10px 12px;
    margin-bottom: 8px;
    background: rgb(245, 245, 246);
    color: rgb(27, 58, 107);
    border: 0;
    border-radius: 6px;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.2s ease;
}
.cnm-mobile-back:hover { background: rgb(232, 232, 236); }
.cnm-mobile-back svg { transition: transform 0.2s ease; }
.cnm-mobile-back:hover svg { transform: translateX(-3px); }

/* §2.16 — RESPONSIVE — tablet (768-991 px) */
@media (max-width: 991px) and (min-width: 768px) {
    .cnm-dd-cols { grid-template-columns: 200px 220px 1fr; }
    .cnm-2col .cnm-dd-cols { grid-template-columns: 280px 1fr; }
    .cnm-item, .cnm-item-label { font-size: 14px !important; }
    .cnm-leaf-title { font-size: 14px !important; }
    .cnm-leaf-sub { font-size: 12.5px !important; }
}

/* §2.17 — RESPONSIVE — mobile (<=767 px): single-panel drilldown */
@media (max-width: 767px) {
    .cnm-dd-cols { grid-template-columns: 1fr !important; }
    .cnm-rail { padding: 16px !important; }
    /* Hide non-active rails — JS controls which one is visible */
    .cnm-mobile-l1-active .cnm-rail-l2,
    .cnm-mobile-l1-active .cnm-rail-l3 { display: none; }
    .cnm-mobile-l2-active .cnm-rail-l1,
    .cnm-mobile-l2-active .cnm-rail-l3 { display: none; }
    .cnm-mobile-l3-active .cnm-rail-l1,
    .cnm-mobile-l3-active .cnm-rail-l2 { display: none; }
    /* Show back button on inner panels (L2 and L3 in mobile) */
    .cnm-mobile-l2-active .cnm-rail-l2 .cnm-mobile-back,
    .cnm-mobile-l3-active .cnm-rail-l3 .cnm-mobile-back { display: flex; }
    /* Direction-aware slide animations (P1 #5) */
    .cnm-rail { animation: cnm-slide-in 0.22s ease-out; }
    .cnm-mobile-back-slide .cnm-rail { animation: cnm-slide-back 0.22s ease-out; }
    @keyframes cnm-slide-in {
        from { opacity: 0; transform: translateX(20px); }
        to   { opacity: 1; transform: translateX(0); }
    }
    @keyframes cnm-slide-back {
        from { opacity: 0; transform: translateX(-20px); }
        to   { opacity: 1; transform: translateX(0); }
    }
    /* Compact bar wraps on mobile */
    .cnm-bar { flex-wrap: wrap; gap: 8px; padding: 8px 10px; }
    .cnm-actions { flex-wrap: wrap; }
    .cnm-trigger, .cnm-cta { font-size: 14px !important; padding: 6px 10px !important; }
    .cnm-crumbs { font-size: 13px !important; flex-basis: 100%; }
    .cnm-item, .cnm-item-label { font-size: 16px !important; }
    .cnm-leaf-title { font-size: 16px !important; }
    /* Drop-down occupies near-full viewport on mobile */
    .cnm-dd-card { max-height: calc(100vh - 200px); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   §3 — PAGE BANNER SHRINK ON SCROLL (P1 #3 from audit)
   ═══════════════════════════════════════════════════════════════════════════
   Body class .is-scrolled is added/removed by inline scroll listener in
   site/tmpl/assess/default.php (existing v2.5.41.3.2 mechanism is extended
   in v2.5.41.4 to also flip .is-scrolled at scrollY > 50). Saves ~70 px of
   viewport real estate when scrolled, freeing room for the sticky compact
   bar + content. Only activated on view-assess so other surfaces are
   unaffected. */
/* v2.5.41.4.1 — bump selector specificity (.cisassess-header.p-3) so the
   padding override beats Bootstrap utility .p-3 (padding: 1rem !important),
   which v2.5.41.4 §3 was tied with by specificity but lost on cascade order.
   Use `padding` shorthand to override .p-3 atomically. */
body.view-assess.is-scrolled .cisassess-header.p-3,
body.view-assess.is-scrolled .cisassess-header,
body.view-assess.is-scrolled #cisassess-header,
body.view-assess.is-scrolled #cisassess-header.p-3,
body.view-assess.is-scrolled .com-cisassess-page-banner {
    min-height: 56px !important;
    padding: 8px 16px !important;
    transition: min-height 0.18s ease, padding 0.18s ease;
}
body.view-assess .cisassess-header,
body.view-assess #cisassess-header,
body.view-assess .com-cisassess-page-banner {
    transition: min-height 0.18s ease, padding 0.18s ease;
}

/* ═══════════════════════════════════════════════════════════════════════════
   §4 — CONTROL CARD CONFORMANCE STATUS BAR (v2.5.41.4.4)
   ═══════════════════════════════════════════════════════════════════════════
   Allen design lock 2026-04-26: in v2.5.41.4 / .4.1 / .4.2 / .4.3 the conformance
   badge ("Major Non-Conformity", "Minor Non-Conformity", "Substantially Conforming",
   etc.) sat inline-right inside the dark navy .cis-assess-control-card-header,
   crowding the title text and forcing truncation in conformance-mode frameworks
   (NIST AI RMF / NIST CSF / ISO 27001). Maturity-mode frameworks (ISO 42001)
   didn't render the badge at all, so their titles always had full width.

   Fix: PHP template moves the conformance badge OUT of the inline d-flex into
   a NEW full-width status strip ABOVE the dark navy header. The strip's bg +
   text color come inline from the conformance-level palette via PHP. This CSS
   styles the strip layout (full width, centered text, ~28-32 px tall, rounded
   top to match the card's rounded corners). The strip is non-sticky — it
   scrolls away with the rest of the card on scroll. Ongoing status visibility
   comes from the T2 maturity rubric below.

   Title in the dark navy header now spans the full width minus the ID badge
   on the left and the Not Applicable button (when applicable) on the right —
   far less crowded, no truncation in any framework, responsive at narrow
   viewports.
   ═══════════════════════════════════════════════════════════════════════════ */
.cis-control-status-bar {
    width: 100%;
    text-align: center;
    padding: 6px 16px;
    font-weight: 600;
    font-size: 14px;
    line-height: 1.3;
    letter-spacing: 0.02em;
    border-top-left-radius: calc(0.375rem - 1px);
    border-top-right-radius: calc(0.375rem - 1px);
}
.cis-control-status-label {
    display: inline-block;
}
@media (max-width: 575px) {
    .cis-control-status-bar { font-size: 13px; padding: 5px 10px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   §2/§3/§4 END (v2.5.41.4 — Vanta-style nested mega-menu navigator + status bar)
   ═══════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════════
   §5 — v2.5.41.18 Helix mega-menu dropdown z-index hotfix
   ───────────────────────────────────────────────────────────────────────────
   Bug surfaced 2026-04-28 on /assess/30: when the user hovers the Helix
   Ultimate site mega-menu at low scrollY (below #sp-header sticky threshold,
   typically ~80-100 px), the revealed dropdown (.sp-megamenu-parent .sp-dropdown)
   renders BEHIND the component sticky chrome — .cisassess-header (z:101),
   control-card subheader (z:100), .cnm-bar (z:1050) — because Helix's
   pre-sticky #sp-header has no explicit z-index, so the dropdown inherits
   z-index:auto in document root and our chrome paints on top.

   Above the sticky threshold #sp-header becomes position:fixed with
   z-index:9999 and the dropdown inherits the higher context, which is why
   the bug self-resolves on scroll. The fix below covers BOTH states:
   in pre-sticky, the explicit z-index:1100 places the dropdown above
   all our chrome (highest is .cnm-bar at 1050) but below Bootstrap
   modal-backdrop (1055) so modals still occlude correctly; in post-sticky
   #sp-header's 9999 context renders the entire dropdown above us anyway.

   `!important` is required because we are overriding the site template's
   own stylesheet (Helix Ultimate) which lives in a different cascade
   namespace; source-order between component CSS and template CSS is
   non-deterministic across Joomla template variations.

   Authority: governance/PHASE1_PILOT.md D1 Walkthrough Validator diagnosis;
   v2.5.41.4.2 .cnm-bar 99→1050 precedent for the same class of problem.
   ═══════════════════════════════════════════════════════════════════════════ */
.sp-megamenu-parent .sp-dropdown {
    z-index: 1100 !important;
}

/* v2.5.41.24 — STACKING-CONTEXT FIX
   The v2.5.41.18 hotfix raised .sp-dropdown to z-index:1100, but Helix's own
   stylesheet sets .sp-megamenu-parent { position: relative; z-index: 99 } —
   that creates a stacking context that TRAPS the child .sp-dropdown's 1100
   inside it. From outside, the entire menu tree paints at level 99, losing
   to .cisassess-header (101), control-card subheader (100), and .cnm-bar
   (1050). The previous fix never actually took effect.

   Live diagnosis (Allen-reported screenshot, /assess/75 NIST AI RMF):
   .sp-megamenu-parent { zIndex: "99", position: "relative" }
   .sp-dropdown        { zIndex: "1100", position: "absolute" } — trapped

   Fix: bump the parent's z-index above all chrome so the child's 1100 has a
   stacking context anchored ABOVE the chrome. 1100 is below Bootstrap
   modal-backdrop (1055) — wait, modal-backdrop is 1055 and our component
   modals are 10100, so 1100 is safely between cnm-bar (1050) and modals.

   Originally reported ~v2.5.41.4 era; carry-forward through 15+ releases.
   ═══════════════════════════════════════════════════════════════════════ */
.sp-megamenu-parent {
    z-index: 1100 !important;
}



/* ═══════════════════════════════════════════════════════════════════════════
   v2.5.41.25 — WCAG 2.1 AA accessibility improvements
   ───────────────────────────────────────────────────────────────────────────
   §6.1 — Skip-link (WCAG 2.4.1).
   §6.2 — Double-ring focus indicator (WCAG 1.4.11) for buttons on dark bg.
   §6.3 — Black text on saturated --cis-amber / --cis-green fills (WCAG 1.4.3).
          Brand palette is gate-enforced (PALETTE_FILL contract enforced by
          qa_gate.py QA-28). White text on those fills computes 2.90:1 / 3.13:1
          and fails AA. Auditor's alternative: black text on those fills passes
          (#000 on #FF681E = 6.0:1; #000 on #28A745 = 5.6:1). The PHP renderer
          (MpdfReportRenderer) already routes ORANGE+GREEN to black text via
          textOnFillHex(); CSS now mirrors that contract.
   ═══════════════════════════════════════════════════════════════════════════ */

.cis-skip-link {
    position: absolute;
    top: -40px;
    left: 8px;
    z-index: 11000;
    padding: 12px 16px;
    background: #1B3A6B;
    color: #ffffff !important;
    font-weight: 600;
    text-decoration: none;
    border-radius: 4px;
    transition: top 0.15s ease-out;
}
.cis-skip-link:focus,
.cis-skip-link:focus-visible {
    top: 8px;
    outline: 3px solid #ffffff;
    outline-offset: 2px;
}

.cisassess-header .btn:focus-visible,
.btn-primary:focus-visible,
.btn-cis-navy:focus-visible {
    outline: 2px solid #1B3A6B;
    outline-offset: 0;
    box-shadow: 0 0 0 4px #ffffff, 0 0 0 6px #1B3A6B;
}

/* §6.3 — Force BLACK text on saturated amber + green fills (WCAG 1.4.3).
   Mirrors PHP renderer's textOnFillHex() routing. Bootstrap utility classes
   .bg-warning + .bg-success are covered alongside the cisassess-specific
   chips, so any descendant text whose computed background is one of those
   colors gets contrast-safe foreground. */
.bg-warning,
.bg-warning *,
[style*="background:#FF681E"],
[style*="background-color:#FF681E"] {
    color: #000000 !important;
}
.bg-success,
.bg-success *,
[style*="background:#28A745"],
[style*="background-color:#28A745"] {
    color: #000000 !important;
}

/* ─────────────────────────────────────────────────────────────────────────
   §X.1 — v2.5.41.27.1 isolation:isolate fix REVERTED 2026-04-29T22:50Z.

   The isolation approach correctly fixed the megamenu-clipping bug pre-sticky
   but broke modal-above-Helix-sticky post-sticky (Maturity Info, Scoring
   Rubric, session-timeout login modals at z=10100/10090/11000 could no
   longer outrank Helix #sp-header post-sticky at z=9999 because the
   isolation scoped them inside a body z=1 wrapper). v2.5.41.27.2 replaces
   the approach with z-index reduction on the two in-component sticky bands
   (cisassess-header 101→91, control-card-header 100→90). See the rules
   above for the in-place replacements; this comment block stands as the
   canonical record of why isolation was tried and why it was reverted.

   DECISION block: planning log 2026-04-29T22:50Z.
   Memory: project_v2_5_41_27_2_shipped.md.
   ───────────────────────────────────────────────────────────────────────── */

/* ═══════════════════════════════════════════════════════════════════════════
   v2.5.41.55.1 — User Guide Remediation Phase 1 D7 — navy circle arrow
   progression connectors between certification stage cards.

   Recovers the v2.2.32 design ("navy circle arrow progression connectors
   between cards", per PROJECT_CONFIG.md change-log row 78). PDF-side chrome
   has been continuously preserved in MpdfReportRenderer.php since v2.5.30
   (lines 1510-1512 + 1710 + 1743 — table-cell <td class="arrow-col"> with
   <span class="circle-arrow">›</span>); this rule restores HTML-side parity
   on the live results-page training panel.

   Selector scope. Applies to .cisassess-certification-panel > .row.g-4 >
   .col-md-4 — the Bootstrap 5 row of three .col-md-4 stage cards inside the
   #certificationContent panel. Three of five frameworks emit this layout:
   ISO 42001, NIST AI RMF, ISO 27001 (per com_cisassess/script.php DB-seeded
   certification_cards bodies). ISO 31000 ERM Family and NIST CSF 2.0 emit a
   single-CTA banner panel without .row.g-4, so this selector naturally does
   not match — connector chrome is only added where the 3-stage layout exists.

   Breakpoint. md and above (≥768 px Bootstrap-5 default). Below md the cards
   stack vertically and connectors are hidden — vertically-adjacent cards
   render without visual chrome between them, which is the desired narrow
   layout.

   Color tokens. background var(--cis-ltblue) / color var(--cis-navy) —
   matches the PDF .circle-arrow declaration exactly so PDF + HTML stay
   visually consistent. The fallback hex literals are committed because
   --cis-ltblue may not resolve in older Joomla template overrides; the var
   form is the canonical reference, the literals are belt-and-suspenders.

   Reference design doc: com_cisassess/docs/design/v2_5_41_57_user_guide_phase2_design.md § 1.4.
   Reference PDF chrome: com_cisassess/site/src/Pdf/MpdfReportRenderer.php lines 1510-1512, 1710, 1743.
   Reference defect row: governance/REGRESSION_VERIFICATION_MATRIX.md BUG-v2.5.41.50-004.
   ───────────────────────────────────────────────────────────────────────── */

@media (min-width: 768px) {
    .cisassess-certification-panel .row.g-4 {
        position: relative;
    }
    .cisassess-certification-panel .row.g-4 > .col-md-4 {
        position: relative;
    }
    .cisassess-certification-panel .row.g-4 > .col-md-4:not(:last-child)::after {
        content: '\203A'; /* › U+203A SINGLE RIGHT-POINTING ANGLE QUOTATION MARK — same glyph as PDF .circle-arrow */
        position: absolute;
        top: 50%;
        right: -15px;
        transform: translateY(-50%);
        z-index: 2;
        width: 28px;
        height: 28px;
        border-radius: 50%;
        background-color: var(--cis-ltblue, #d0dff0); /* matches PDF .circle-arrow background */
        color: var(--cis-navy, #1B3A6B);             /* matches PDF .circle-arrow color */
        font-size: 18px;
        font-weight: 700;
        line-height: 28px;
        text-align: center;
        box-shadow: 0 1px 3px rgba(27, 58, 107, 0.18);
        pointer-events: none;
    }
}
