/* ==========================================================================
   Inn at Laurel Point - Office 365 Assessment Tool
   main.css

   Organization (per STYLE_GUIDE.md):
   1. CSS custom properties (:root)
   2. Reset and base element styles
   3. Layout primitives
   4. Components (alphabetical)
   5. Utilities
   6. Media queries (mobile-first, scaling up)
   ========================================================================== */


/* ---------- 1. Custom Properties ---------- */

:root {
    /* Primary Palette */
    --ilp-navy: #1F3A5F;
    --ilp-sage: #93B86E;
    --ilp-sage-soft: #E8F0DC;
    --wgit-black: #1A1A1A;

    /* Neutrals */
    --cream: #FBFAF6;
    --paper: #FFFFFF;
    --stone-100: #F4F2EC;
    --stone-200: #E8E4DA;
    /* coder-090 flagged --stone-300 as undefined at six usages while the ramp
       itself skipped from 200 to 400. The gap WAS the bug: a 300 is what a
       hairline on a tinted ground wants. Interpolated midway between 200 and
       400 on each channel, so the ramp is now even. */
    --stone-300: #C8C3BA;
    --stone-400: #A8A39A;
    --stone-600: #5A554C;

    /* Functional */
    --accent-amber: #C89B3C;
    --accent-rust: #B5552E;
    --focus-ring: rgba(31, 58, 95, 0.25);

    /* Typography */
    --font-display: 'Playfair Display', Georgia, 'Times New Roman', serif;
    --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;

    /* Type Scale */
    --text-xs: 0.75rem;
    --text-sm: 0.875rem;
    --text-base: 1rem;
    --text-lg: 1.125rem;
    --text-xl: 1.375rem;
    --text-2xl: 1.75rem;
    --text-3xl: 2.5rem;
    --text-4xl: 3.5rem;

    /* Spacing (4px grid) */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-8: 3rem;
    --space-10: 4rem;
    --space-12: 6rem;

    /* Container Widths */
    --container-narrow: 640px;
    --container-medium: 960px;
    --container-wide: 1200px;
}


/* ---------- 2. Reset and Base Styles ---------- */

*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

body {
    font-family: var(--font-body);
    font-size: var(--text-base);
    color: var(--ilp-navy);
    background: var(--cream);
    line-height: 1.6;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    animation: pageFadeIn 300ms ease-out;
}

@keyframes pageFadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

h1, h2, h3 {
    font-family: var(--font-display);
    font-weight: 400;
    line-height: 1.2;
    letter-spacing: -0.01em;
    color: var(--ilp-navy);
}

h4, h5, h6 {
    font-family: var(--font-body);
    font-weight: 600;
    line-height: 1.3;
    color: var(--ilp-navy);
}

h1 { font-size: var(--text-3xl); line-height: 1.15; }
h2 { font-size: var(--text-2xl); }
h3 { font-size: var(--text-xl); }
h4 { font-size: var(--text-lg); }
h5 { font-size: var(--text-base); }
h6 { font-size: var(--text-sm); }

a {
    color: var(--ilp-navy);
    text-decoration: underline;
    transition: color 200ms ease-out;
}

a:hover {
    color: var(--ilp-sage);
}

img, svg {
    display: block;
    max-width: 100%;
}

fieldset {
    border: none;
    padding: 0;
    margin: 0;
}

legend {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 400;
    color: var(--ilp-navy);
    margin-bottom: var(--space-4);
}


/* ---------- 3. Layout Primitives ---------- */

.container {
    max-width: var(--container-medium);
    margin: 0 auto;
    padding: 0 var(--space-6);
}

.container--narrow {
    max-width: var(--container-narrow);
}

.container--wide {
    max-width: var(--container-wide);
}

main {
    flex: 1;
    padding: var(--space-12) var(--space-6) var(--space-10);
}

.card-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-5);
}

.page-intro {
    margin-bottom: var(--space-10);
    max-width: var(--container-narrow);
}


/* ---------- 4. Components (alphabetical) ---------- */

/* --- Badges --- */

.badge {
    display: inline-flex;
    align-items: center;
    padding: var(--space-1) var(--space-3);
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.badge--not-started {
    background: var(--stone-100);
    color: var(--stone-600);
}

.badge--in-progress {
    background: rgba(200, 155, 60, 0.15);
    /* branding token: color_accent (BRANDING.md §2), platform default --accent-amber */
    color: var(--color-accent, var(--accent-amber));
}

.badge--complete {
    background: var(--ilp-sage-soft);
    color: #5C8E3A;
}

.badge--admin {
    background: rgba(31, 58, 95, 0.1);
    color: var(--ilp-navy);
}

/* Warning-family badge: colours match .flash--warning so the amber "needs
   attention" treatment is consistent between flash messages and pills. */
.badge--warning {
    background: rgba(200, 155, 60, 0.1);
    color: #8A6D1B;
}


/* --- Catalog cache staleness indicator (P215, Wave 14 Task .6) --- */
/* The V3-catalog staleness badge/banner the admin context processor injects
   into the admin base layout (CATALOG_V3_CLIENT_SYNC.md v1.2 "Admin UI surfaces
   staleness"). Grouped here so the two `.badge--catalog-*` modifiers sit beside
   the `.badge` base above. Colours via classes only (no inline styles); the copy
   informs without alarming (spec: "should not panic the admin, just inform"). */
.catalog-staleness {
    max-width: var(--container-medium);
    margin: 0 auto var(--space-4);
}

/* Aging / stale: an inline badge row (badge + optional last-sync detail). */
.catalog-staleness--bar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0 var(--space-6);
}

.catalog-staleness__detail {
    font-size: var(--text-sm);
    color: var(--stone-600);
}

/* Aging -> yellow info badge (the amber info treatment, cf. .badge--in-progress). */
.badge--catalog-aging {
    background: rgba(200, 155, 60, 0.15);
    color: var(--accent-amber);
}

/* Stale -> orange warning badge. */
.badge--catalog-stale {
    background: rgba(181, 85, 46, 0.12);
    color: var(--accent-rust);
}

/* Critical -> red banner across the admin UI. Muted bordered fill: it informs,
   it does not panic (spec). */
.catalog-staleness--critical {
    padding: var(--space-3) var(--space-5);
    border: 1px solid #A02D22;
    border-radius: 4px;
    background: rgba(160, 45, 34, 0.08);
    color: #8F2820;
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1.5;
}

/* Never-synced -> neutral "first sync pending" banner (cf. .flash--info). */
.catalog-staleness--pending {
    padding: var(--space-3) var(--space-5);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    background: rgba(31, 58, 95, 0.06);
    color: var(--ilp-navy);
    font-size: var(--text-sm);
    line-height: 1.5;
}


/* --- Breadcrumbs --- */

.breadcrumb {
    font-size: var(--text-sm);
    color: var(--ilp-navy);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-5);
}

.breadcrumb:hover {
    text-decoration: underline;
}


/* --- Buttons --- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-5);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    letter-spacing: 0.05em;
    line-height: 1.4;
    border-radius: 8px;
    cursor: pointer;
    transition: all 200ms ease-out;
    text-decoration: none;
}

.btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--focus-ring);
}

.btn--primary {
    /* branding token: color_primary (BRANDING.md §2), platform default --ilp-navy */
    background: var(--color-primary, var(--ilp-navy));
    color: var(--cream);
    border: none;
}

.btn--primary:hover {
    background: #2A4A75;
    box-shadow: 0 2px 8px rgba(31, 58, 95, 0.2);
    color: var(--cream);
}

.btn--secondary {
    background: transparent;
    color: var(--ilp-navy);
    border: 1.5px solid var(--ilp-navy);
}

.btn--secondary:hover {
    background: rgba(31, 58, 95, 0.08);
    color: var(--ilp-navy);
}

/* coder-295 -- no dedicated red/danger token exists; --accent-rust is the
   codebase's established error/destructive color (.flash--error, .form-error,
   error-state borders throughout). Declared after .btn--secondary so it wins
   when both classes are combined on one button (tenant_module.html,
   tenant_source.html: class="btn btn--secondary btn--danger"). */
.btn--danger {
    background: transparent;
    color: var(--accent-rust);
    border: 1.5px solid var(--accent-rust);
}

.btn--danger:hover {
    background: rgba(181, 85, 46, 0.08);
    color: var(--accent-rust);
}

.btn--tertiary {
    background: transparent;
    color: var(--ilp-navy);
    border: none;
    padding: var(--space-2) var(--space-3);
}

.btn--tertiary:hover {
    text-decoration: underline;
    color: var(--ilp-navy);
}

/* coder-235 -- compact size modifier, usable on any .btn variant. One
   padding step and one type-scale step down from the base .btn; declared
   after .btn--tertiary so it also overrides that variant's own padding,
   keeping --sm the same size regardless of variant. */
.btn--sm {
    padding: var(--space-2) var(--space-4);
    font-size: var(--text-xs);
}


/* --- Card (surface for forms and content blocks) --- */

.card {
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-6);
}


/* --- Cards --- */

.action-card {
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-6);
    text-decoration: none;
    color: inherit;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    min-height: 160px;
    transition: all 200ms ease-out;
    cursor: pointer;
    position: relative;
    overflow: hidden;
}

.action-card:hover {
    background: var(--ilp-sage-soft);
    border-color: var(--ilp-sage);
    transform: translateY(-2px);
    color: inherit;
}

.action-card:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--focus-ring);
}

.action-card--featured {
    background: var(--ilp-navy);
    border-color: var(--ilp-navy);
    color: var(--cream);
    grid-column: 1 / -1;
    min-height: 180px;
}

.action-card--featured:hover {
    background: #2A4A75;
    border-color: var(--ilp-sage);
    color: var(--cream);
}

.action-card--featured .card-eyebrow {
    color: var(--ilp-sage);
}

/* Required because the global h1-h3 rule (color: --ilp-navy) wins over
   the cream color inherited from the featured card. Without this the
   title renders near-invisible on the navy background. */
.action-card--featured .card-title {
    color: var(--cream);
}

.action-card--featured .card-meta {
    color: rgba(251, 250, 246, 0.7);
}

.action-card--featured .card-description {
    color: rgba(251, 250, 246, 0.85);
}

.action-card--featured .card-cta {
    color: var(--cream);
}

.card-eyebrow {
    font-size: var(--text-xs);
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--ilp-sage);
    font-weight: 600;
}

.card-title {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 400;
    line-height: 1.2;
    letter-spacing: -0.01em;
}

.card-description {
    font-size: 0.9375rem;
    color: var(--stone-600);
    line-height: 1.55;
    margin-top: auto;
}

.card-meta {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 0.8125rem;
    color: var(--stone-400);
    margin-top: var(--space-2);
}

.card-cta {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    font-weight: 500;
    letter-spacing: 0.05em;
    color: var(--ilp-navy);
    margin-top: auto;
}

.card-cta::after {
    content: '\2192';
    transition: transform 200ms ease-out;
}

.action-card:hover .card-cta::after {
    transform: translateX(4px);
}


/* --- Form Actions (submit row at the bottom of a form) --- */

.form-actions {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    margin-top: var(--space-6);
}

.form-help {
    font-size: var(--text-sm);
    color: var(--stone-400);
    margin-top: var(--space-5);
}


/* --- Eyebrow (page-level) --- */

.eyebrow {
    font-size: var(--text-xs);
    color: var(--ilp-sage);
    letter-spacing: 0.15em;
    text-transform: uppercase;
    font-weight: 600;
    margin-bottom: var(--space-3);
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.eyebrow::before {
    content: '';
    display: inline-block;
    width: 24px;
    height: 1px;
    background: var(--ilp-sage);
}


/* --- Flash Messages --- */

.flash-messages {
    max-width: var(--container-medium);
    margin: 0 auto;
    padding: 0 var(--space-6);
}

.flash {
    padding: var(--space-3) var(--space-5);
    border-radius: 4px;
    font-size: var(--text-sm);
    line-height: 1.5;
    margin-bottom: var(--space-4);
    border: 1px solid transparent;
}

.flash--success {
    background: var(--ilp-sage-soft);
    color: #3D6B1E;
    border-color: var(--ilp-sage);
}

.flash--error {
    background: rgba(181, 85, 46, 0.1);
    border-color: var(--accent-rust);
    color: var(--accent-rust);
}

.flash--info {
    background: rgba(31, 58, 95, 0.06);
    border-color: var(--stone-200);
    color: var(--ilp-navy);
}

.flash--warning {
    background: rgba(200, 155, 60, 0.1);
    border-color: var(--accent-amber);
    color: #8A6D1B;
}

/* coder-305: the Operations edge-provisioning script's captured stdout, flashed
   inline on the page (§2.2 "Inline output on the page"). Reuses `.flash`'s base
   styling; only adds what raw multi-line script output needs that a one-line
   message doesn't -- preserved line breaks and a monospace face. */
.flash--edge-output {
    background: var(--stone-100, #f5f4f2);
    border-color: var(--stone-300);
    color: var(--ilp-navy);
    white-space: pre-wrap;
    font-family: ui-monospace, "SF Mono", Consolas, monospace;
    font-size: var(--text-xs, 0.8rem);
}


/* --- Footer --- */

.site-footer {
    background: var(--wgit-black);
    color: rgba(251, 250, 246, 0.7);
    padding: var(--space-6) 0;
    margin-top: var(--space-12);
}

.footer-inner {
    max-width: var(--container-wide);
    margin: 0 auto;
    padding: 0 var(--space-6);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}

.footer-text {
    font-size: 0.8125rem;
    letter-spacing: 0.02em;
}

.footer-brand {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.footer-logo {
    width: 32px;
    height: 32px;
    background: var(--paper);
    color: var(--wgit-black);
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: 500;
    border-radius: 2px;
    letter-spacing: -0.02em;
}

.footer-brand-text {
    font-size: 0.8125rem;
    color: var(--cream);
    font-weight: 500;
    letter-spacing: 0.02em;
}


/* --- Forms --- */

.form-group {
    margin-bottom: var(--space-5);
}

.form-label {
    display: block;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--ilp-navy);
    margin-bottom: var(--space-2);
}

.form-input,
.form-select,
.form-textarea {
    display: block;
    width: 100%;
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-bottom: 2px solid var(--stone-400);
    border-radius: 2px;
    padding: var(--space-3) var(--space-4);
    font-family: var(--font-body);
    font-size: var(--text-base);
    color: var(--ilp-navy);
    transition: border-color 200ms ease-out, box-shadow 200ms ease-out;
}

/* coder-236 -- compact size modifier for .form-input, applied alongside the base
   class (e.g. class="form-input form-input--sm") so :focus/:placeholder/border
   rules keyed on .form-input still apply. One padding step and one type-scale
   step down from the base .form-input, mirroring the .btn -> .btn--sm relationship. */
.form-input--sm {
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-sm);
}

/* The `display: block` above beats the UA `[hidden] { display: none }` rule, so a
   textarea the JS hides via the `hidden` attribute (the composer's steps-JSON source)
   would stay visible. Scope the override to `.form-textarea[hidden]` -- lowest blast
   radius -- so `hidden` wins for this control (CODER-057 §D Fix 1). */
.form-textarea[hidden] {
    display: none;
}

.form-input::placeholder,
.form-textarea::placeholder {
    color: var(--stone-400);
}

.form-input:focus,
.form-select:focus,
.form-textarea:focus {
    outline: none;
    border-bottom-color: var(--ilp-sage);
    box-shadow: 0 0 0 3px var(--focus-ring);
}

.form-textarea {
    resize: vertical;
    min-height: 100px;
}

.form-select {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1L6 6L11 1' stroke='%235A554C' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--space-4) center;
    padding-right: var(--space-8);
}

.form-error {
    font-size: var(--text-xs);
    color: var(--accent-rust);
    margin-top: var(--space-1);
}

.form-hint {
    font-size: var(--text-xs);
    color: var(--stone-400);
    margin-top: var(--space-1);
}

/* The key hint under an agent compose box (coder-146).
 *
 * It lives HERE and not in agent.css deliberately: agent.css is linked by three
 * templates, but the floating "Ask IT" widget is injected from base.html on EVERY
 * page, so a hint styled there would be unstyled almost everywhere it renders.
 *
 * --stone-600 rather than the --stone-400 that .form-help and .form-hint use.
 * #A8A39A is 2.51:1 on --paper and 2.40:1 on --cream, both well under the 4.5:1
 * WCAG AA floor for body text; #5A554C is 7.40:1 and 7.08:1 on the same two
 * grounds. Still muted, still quieter than the button, and actually readable.
 *
 * No `display` is set, so the UA's `[hidden] { display: none }` stands unopposed
 * (the trap .form-textarea documents above) -- the server renders this element
 * hidden and agent_compose.js unhides it only where Enter-to-send really bound.
 * All three compose forms are `flex-direction: column` with a `gap`, so the
 * spacing is the container's; a margin here would double it. */
.compose-hint {
    font-size: var(--text-xs);
    color: var(--stone-600);
    margin: 0;
}

/* Radio and checkbox groups */
.form-option {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3) 0;
}

.form-option input[type="radio"],
.form-option input[type="checkbox"] {
    margin-top: 0.2em;
    accent-color: var(--ilp-sage);
    flex-shrink: 0;
}

.form-option label {
    font-size: var(--text-base);
    color: var(--ilp-navy);
    line-height: 1.5;
    cursor: pointer;
}

/* Input in error state */
.form-input--error,
.form-select--error,
.form-textarea--error {
    border-color: var(--accent-rust);
    border-bottom-color: var(--accent-rust);
}

@keyframes formShake {
    0%, 100% { transform: translateX(0); }
    25% { transform: translateX(-4px); }
    75% { transform: translateX(4px); }
}

.form-group--error {
    animation: formShake 300ms ease-out;
}

/* Checkbox panel (coder-259, onboarding/CHECKBOX_PANEL_DESIGN.md) -- inset
   panel wrapper for the onboarding selection lists (assignable items,
   internal items, shared folders, email groups) and any other user of the
   retired .form-checkbox-list / .form-checkbox-item / .form-select-all
   classes. Colors are derived neutrals per the design doc, not new branding
   tokens; navy text reuses --ilp-navy directly (the file's existing
   convention for navy body/label text, e.g. .form-label, .form-option label). */
.form-checkbox-panel {
    border: 1px solid #E7E1D5;
    border-radius: 10px;
    background: #FDFCF9;
    overflow: hidden;
}

.form-checkbox-panel__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: #F3EFE5;
    border-bottom: 1px solid #E7E1D5;
}

.form-checkbox-panel__count {
    display: inline-flex;
    align-items: center;
    background: var(--paper);
    border: 1px solid #E7E1D5;
    border-radius: 999px;
    padding: var(--space-1) var(--space-3);
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--ilp-navy);
}

.form-checkbox-panel__select-all {
    background: none;
    border: none;
    padding: 0;
    font-family: var(--font-body);
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--ilp-navy);
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}

.form-checkbox-panel .form-hint {
    padding: var(--space-4);
    margin: 0;
}

.form-checkbox {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    padding: 0.8125rem var(--space-4);
    border-bottom: 1px solid #EFEADD;
    cursor: pointer;
}

.form-checkbox:last-child {
    border-bottom: none;
}

.form-checkbox:has(input:checked) {
    background: #F1F6E9;
}

.form-checkbox input[type="checkbox"] {
    width: 19px;
    height: 19px;
    accent-color: #6E9A48;
    flex-shrink: 0;
}


/* --- Header --- */

.site-header {
    /* branding token: color_header_bg (BRANDING.md §2), platform default --paper */
    background: var(--color-header-bg, var(--paper));
    border-bottom: 1px solid var(--stone-200);
    padding: var(--space-4) 0;
}

.header-inner {
    max-width: var(--container-wide);
    margin: 0 auto;
    padding: 0 var(--space-6);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
}

.brand {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    text-decoration: none;
    color: inherit;
}

.brand:hover {
    color: inherit;
}

/* The viewed tenant's branding logo (BRANDING.md §2), when set. */
.brand-logo {
    display: block;
    height: 40px;
    width: auto;
}

.brand-text {
    display: flex;
    flex-direction: column;
    line-height: 1.1;
}

.brand-name {
    font-family: var(--font-display);
    font-size: 1.25rem;
    /* branding token: color_header_fg (BRANDING.md §2), platform default --ilp-navy */
    color: var(--color-header-fg, var(--ilp-navy));
}

.brand-sub {
    font-size: var(--text-xs);
    color: var(--stone-400);
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.ilp-leaf {
    width: 36px;
    height: 36px;
    background: var(--ilp-sage-soft);
    border-radius: 2px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.ilp-leaf svg {
    width: 22px;
    height: 22px;
}

.user-menu {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    font-size: var(--text-sm);
}

.user-name {
    color: var(--stone-600);
}

.user-name strong {
    color: var(--ilp-navy);
    font-weight: 500;
}

.logout-link {
    color: var(--ilp-navy);
    text-decoration: none;
    font-weight: 500;
    letter-spacing: 0.05em;
}

.logout-link:hover {
    text-decoration: underline;
}


/* --- Page Title --- */

.page-title {
    font-family: var(--font-display);
    font-size: clamp(2rem, 5vw, 3.5rem);
    font-weight: 400;
    line-height: 1.15;
    letter-spacing: -0.01em;
    color: var(--ilp-navy);
    margin-bottom: var(--space-4);
}

.page-lede {
    font-size: var(--text-lg);
    line-height: 1.6;
    color: var(--stone-600);
}


/* --- Progress Bar (assessment screens) --- */

.progress-bar {
    background: var(--stone-200);
    height: 3px;
    width: 100%;
    position: relative;
}

.progress-bar__fill {
    background: var(--ilp-sage);
    height: 100%;
    transition: width 300ms ease-out;
}

.progress-label {
    font-size: var(--text-sm);
    color: var(--stone-400);
    padding: var(--space-2) var(--space-6);
}


/* --- Rating Tool (assessment question tiles, coder-215) --- */

.rating-tool__name {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 400;
    color: var(--ilp-navy);
    padding-bottom: var(--space-4);
    border-bottom: 1px solid var(--stone-200);
    margin-bottom: var(--space-4);
}

.rating-question {
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-5) var(--space-6);
    margin-bottom: var(--space-4);
}

.rating-question:last-child {
    margin-bottom: 0;
}

.rating-question__label {
    display: block;
    font-size: var(--text-base);
    font-weight: 500;
    color: var(--ilp-navy);
    margin-bottom: var(--space-3);
}

.rating-question__sublabel {
    display: block;
    font-size: var(--text-xs);
    color: var(--stone-400);
    margin-bottom: var(--space-2);
}

.rating-question__learn-more {
    border-top: 1px solid var(--stone-100);
    margin-top: var(--space-4);
    padding-top: var(--space-3);
}

/* Answer tiles: equal-width rectangular tiles for the primary comfort/
   proficiency answer row (replaces the old comfort-bubble and frequency-pill
   idioms for that row only). The learn-more axis keeps the .freq-option pill
   treatment (below) unchanged. */
.answer-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: var(--space-2);
}

.tile-option {
    position: relative;
}

.tile-option input[type="radio"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.tile-option label {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    text-align: center;
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    background: var(--paper);
    padding: 14px 10px;
    font-size: var(--text-sm);
    color: var(--stone-600);
    cursor: pointer;
    transition: all 200ms ease-out;
}

.tile-option label:hover {
    border-color: var(--ilp-sage);
    background: var(--ilp-sage-soft);
    color: var(--ilp-navy);
}

.tile-option label:hover .comfort-bubble,
.tile-option label:hover .comfort-hint {
    color: var(--ilp-navy);
}

.tile-option input:checked + label {
    background: var(--ilp-navy);
    border-color: var(--ilp-navy);
    color: var(--cream);
    font-weight: 500;
}

.tile-option input:checked + label .comfort-bubble,
.tile-option input:checked + label .comfort-hint {
    color: var(--cream);
}

.tile-option input:focus-visible + label {
    box-shadow: 0 0 0 3px var(--focus-ring);
}

/* Comfort tiles carry a number above a hint (the hint wording is P203-guarded). */
.comfort-bubble {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--stone-600);
}

.comfort-hint {
    font-size: var(--text-xs);
    color: var(--stone-400);
    text-align: center;
    line-height: 1.25;
}

/* Frequency options: pill-shaped radio buttons.
   .choice-pill-row is the frequency-neutral alias used by the Basics/Cyber
   Section-1 learn-more radios (P559 dropped the frequency question there). */
.frequency-options,
.choice-pill-row {
    display: flex;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.freq-option {
    position: relative;
}

.freq-option input[type="radio"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.freq-option label {
    display: block;
    padding: var(--space-2) var(--space-4);
    border: 1px solid var(--stone-200);
    border-radius: 999px;
    font-size: var(--text-sm);
    color: var(--stone-600);
    cursor: pointer;
    transition: all 200ms ease-out;
    white-space: nowrap;
}

.freq-option input:checked + label {
    background: var(--ilp-navy);
    border-color: var(--ilp-navy);
    color: var(--cream);
}

.freq-option label:hover {
    border-color: var(--ilp-sage);
    color: var(--ilp-navy);
}

.rating-errors {
    margin-top: var(--space-2);
}


/* --- Scenario Cards (Section 2) --- */
/* coder-268 (assessment/SCENARIO_FORMAT_DESIGN.md): the "Scenario N" label and prompt
   moved to the page-level idiom (eyebrow + serif treatment); the card now wraps only
   the options. .scenario-card__number and .scenario-card__prompt were removed --
   templates reuse .eyebrow directly and .scenario-prompt below. */

.scenario-prompt {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 400;
    color: var(--ilp-navy);
    line-height: 1.35;
    padding-bottom: var(--space-4);
    border-bottom: 1px solid var(--stone-200);
    margin-bottom: var(--space-4);
}

.scenario-card {
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-5) var(--space-6);
    margin-bottom: var(--space-5);
}

.scenario-options {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.scenario-option {
    position: relative;
}

.scenario-option input[type="radio"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.scenario-option label {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    cursor: pointer;
    transition: all 200ms ease-out;
    font-size: 0.9375rem;
    line-height: 1.5;
    color: var(--ilp-navy);
}

.scenario-option label:hover {
    border-color: var(--ilp-sage);
    background: var(--ilp-sage-soft);
}

.scenario-option input:checked + label {
    border-color: #6E9A48;
    background: var(--ilp-sage-soft);
    color: var(--ilp-navy);
    font-weight: 500;
}

.scenario-option__letter {
    font-weight: 600;
    color: var(--stone-400);
    flex-shrink: 0;
    min-width: 18px;
    line-height: 1.5;
}

.scenario-option input:checked + label .scenario-option__letter {
    color: #6E9A48;
}

/* coder-269: keyboard focus ring, mirrors .tile-option input:focus-visible + label */
.scenario-option input:focus-visible + label {
    box-shadow: 0 0 0 3px var(--focus-ring);
}

.scenario-errors {
    margin-top: var(--space-2);
}


/* --- Tool Checklist (Section 4) --- */

.tool-group {
    margin-bottom: var(--space-8);
}

.tool-group__heading {
    font-size: var(--text-xs);
    letter-spacing: 0.15em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--stone-400);
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--stone-200);
}

.tool-checklist {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2);
}

.tool-check {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    cursor: pointer;
    transition: border-color 200ms ease-out, background 200ms ease-out;
}

.tool-check:hover {
    border-color: var(--ilp-sage);
    background: var(--ilp-sage-soft);
}

.tool-check input[type="checkbox"] {
    accent-color: var(--ilp-sage);
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    cursor: pointer;
}

.tool-check label {
    font-size: var(--text-base);
    color: var(--ilp-navy);
    cursor: pointer;
    line-height: 1.4;
}


/* --- Assessment Completion Screen --- */

.completion {
    text-align: center;
    padding: var(--space-10) 0;
}

.completion__check {
    width: 64px;
    height: 64px;
    background: var(--ilp-sage-soft);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto var(--space-6);
}

.completion__check svg {
    width: 32px;
    height: 32px;
    color: #5C8E3A;
}

.completion__title {
    font-family: var(--font-display);
    font-size: clamp(2rem, 5vw, 3rem);
    font-weight: 400;
    color: var(--ilp-navy);
    margin-bottom: var(--space-4);
}

.completion__lede {
    font-size: var(--text-lg);
    color: var(--stone-600);
    max-width: 480px;
    margin: 0 auto var(--space-8);
    line-height: 1.6;
}

.level-display {
    display: inline-block;
    background: var(--ilp-sage-soft);
    border: 1px solid var(--ilp-sage);
    border-radius: 4px;
    padding: var(--space-4) var(--space-8);
    margin-bottom: var(--space-8);
}

.level-display__label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.15em;
    font-weight: 600;
    color: #5C8E3A;
    margin-bottom: var(--space-2);
}

.level-display__band {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 400;
    color: #3D6B1E;
    text-transform: capitalize;
}

.completion__actions {
    display: flex;
    gap: var(--space-4);
    justify-content: center;
    flex-wrap: wrap;
}


/* --- Admin card list (CODER-017) --- */
/* A general "list of things" component for the WGIT admin surface: each row has a
   title, some read-only meta, a status badge, and drills in (the whole row is the
   link -- not a trailing action). Namespaced `admin-` so it stays off the
   tenant-facing pages that also load main.css (the `.admin-subnav` precedent).
   Built only on the existing design tokens -- no new token, no new colour literal;
   the badge state colours are the same values the base `.badge--*` modifiers use.
   Reused by tasks 018 (sources / connections) and 019 (tenant hub card grid), so
   it is deliberately module-agnostic. Additive only -- no existing selector edited. */

.admin-card-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-bottom: var(--space-8);
}

/* The row is an <a>: the whole card drills in (hover mirrors .action-card). */
.admin-card-list__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-4) var(--space-5);
    text-decoration: none;
    color: inherit;
    transition: all 200ms ease-out;
}

.admin-card-list__row:hover {
    background: var(--ilp-sage-soft);
    border-color: var(--ilp-sage);
    color: inherit;
}

.admin-card-list__row:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--focus-ring);
}

/* Left column: title over its read-only meta. min-width:0 lets long meta wrap. */
.admin-card-list__main {
    flex: 1;
    min-width: 0;
}

.admin-card-list__title {
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--ilp-navy);
}

.admin-card-list__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-3);
    margin-top: var(--space-1);
    font-size: var(--text-sm);
    color: var(--stone-600);
}

/* Right column: status badge + the drill-in chevron. */
.admin-card-list__aside {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    flex-shrink: 0;
}

.admin-card-list__chevron {
    color: var(--stone-400);
    transition: transform 200ms ease-out, color 200ms ease-out;
}

.admin-card-list__row:hover .admin-card-list__chevron {
    transform: translateX(4px);
    color: var(--ilp-navy);
}

.admin-card-list__empty {
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-5);
    color: var(--stone-600);
    font-size: var(--text-sm);
}

/* Status badge: the pill shape of the base `.badge`, namespaced for the admin
   surface. The three state colours reuse the exact values the base
   `.badge--complete` / `.badge--in-progress` / `.badge--not-started` modifiers
   use -- no new literal is introduced. */
.admin-badge {
    display: inline-flex;
    align-items: center;
    padding: var(--space-1) var(--space-3);
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    white-space: nowrap;
}

.admin-badge--active {
    background: var(--ilp-sage-soft);
    color: #5C8E3A;
}

.admin-badge--suspended {
    background: rgba(200, 155, 60, 0.15);
    /* branding token: color_accent (BRANDING.md §2), platform default --accent-amber */
    color: var(--color-accent, var(--accent-amber));
}

.admin-badge--not-licensed {
    background: var(--stone-100);
    color: var(--stone-600);
}

/* Expired (CODER-018): "was licensed, then lapsed" -- a different fact from
   "never licensed" (the neutral --not-licensed) and the one worth catching while
   scanning. Additive; the three modifiers above are untouched. Reuses the exact
   rust wash + colour the base `.badge--catalog-stale` uses (main.css) -- no new
   colour literal is introduced. */
.admin-badge--expired {
    background: rgba(181, 85, 46, 0.12);
    color: var(--accent-rust);
}

/* --- Admin card list: grid layout (CODER-020) --- */
/* The tenant hub (§2.2) lays its eight section cards in a grid, not a single
   stacked column -- a column would reintroduce the scroll this whole sequence set
   out to remove. This is a single additive modifier on the same component; the
   __row is reused UNCHANGED. Additive only -- no existing selector edited, no new
   literal. */
.admin-card-list--grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-4);
}

/* --- Admin content toggle rows (CODER-022) --- */
/* The Content-tags and Hide-list pages render one row per item: a label, the
   item's current state as an `admin-badge`, and a single contextual op button
   (never a pair, never a checkbox -- there is no set to post, the control is
   per-item). A flex row is the whole need: label grows on the left, badge + the
   one action sit at the right. This replaces the misused `form-option` idiom
   (that class is for checkbox lists that post as a set; these pages post
   per-item). Additive, admin-namespaced, existing tokens only -- no existing
   selector edited, no new colour literal. */
.admin-content-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) 0;
}

.admin-content-row__label {
    flex: 1 1 auto;
    color: var(--ilp-navy);
}

/* A tiny colour chip for the Branding card summary. The background is a per-tenant
   value set inline (a CSS class cannot carry a dynamic colour); the class only
   supplies the fixed chrome, built on the existing stone token -- no new literal. */
.admin-swatch {
    display: inline-block;
    width: 0.85rem;
    height: 0.85rem;
    border-radius: 3px;
    border: 1px solid var(--stone-400);
    vertical-align: middle;
}

/* --- Admin readiness banner (CODER-020) --- */
/* The tenant hub's headline action (§2): a full-width callout above the card grid
   stating go-live readiness. No banner/callout/alert component existed to reuse
   (the only fit, `.flash`, is a small transient message), so this is an additive,
   admin-namespaced block laying out a prominent title + the Go live button (ready)
   or the unmet-predicate list (not-ready). The two state colours reuse the EXACT
   values the flash treatment uses -- ready mirrors `.flash--success`, not-ready
   mirrors `.flash--warning` -- so no new colour literal is introduced. Additive
   only; no existing selector edited. */
.admin-readiness {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-5);
    flex-wrap: wrap;
    padding: var(--space-5) var(--space-6);
    border-radius: 4px;
    border: 1px solid transparent;
    margin-bottom: var(--space-6);
}

.admin-readiness--ready {
    background: var(--ilp-sage-soft);
    border-color: var(--ilp-sage);
    color: #3D6B1E;
}

.admin-readiness--not-ready {
    background: rgba(200, 155, 60, 0.1);
    border-color: var(--accent-amber);
    color: #8A6D1B;
}

.admin-readiness__body {
    flex: 1;
    min-width: 0;
}

.admin-readiness__title {
    font-size: var(--text-lg);
    font-weight: 600;
    margin: 0 0 var(--space-1);
}

.admin-readiness__unmet {
    margin: var(--space-2) 0 0;
    padding-left: var(--space-5);
    font-size: var(--text-sm);
}


/* --- Admin Sub-navigation --- */

.admin-subnav {
    background: var(--paper);
    border-bottom: 1px solid var(--stone-200);
    padding: 0 var(--space-6);
}

.admin-subnav__inner {
    max-width: var(--container-wide);
    margin: 0 auto;
    display: flex;
    gap: var(--space-5);
    overflow-x: auto;
}

.admin-subnav__link {
    display: block;
    padding: var(--space-3) 0;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--stone-400);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
    transition: color 200ms ease-out, border-color 200ms ease-out;
}

.admin-subnav__link:hover {
    color: var(--ilp-navy);
}

.admin-subnav__link--active {
    color: var(--ilp-navy);
    border-bottom-color: var(--ilp-sage);
}


/* --- Admin Stat Cards --- */

.stat-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-4);
    margin-bottom: var(--space-8);
}

/* P265 / mobile sweep: column-count modifiers replace per-template inline
   `grid-template-columns: repeat(N,1fr)` overrides on `.stat-grid`. An inline
   style would beat the phone-width collapse rule below (inline specificity); a
   shared class lets the `@media (max-width: 640px)` block reach it. Desktop
   column count is unchanged. */
.stat-grid--cols-3 { grid-template-columns: repeat(3, 1fr); }
.stat-grid--cols-4 { grid-template-columns: repeat(4, 1fr); }

.stat-card {
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-5) var(--space-6);
}

.stat-card__value {
    font-family: var(--font-display);
    font-size: var(--text-3xl);
    font-weight: 400;
    color: var(--ilp-navy);
    line-height: 1;
    margin-bottom: var(--space-2);
}

.stat-card__label {
    font-size: var(--text-sm);
    color: var(--stone-400);
    font-weight: 500;
}

.stat-card--complete .stat-card__value { color: #3D6B1E; }
.stat-card--progress .stat-card__value { color: var(--accent-amber); }


/* --- Data Table --- */

.data-table-wrapper {
    overflow-x: auto;
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
}

.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
}

.data-table th {
    text-align: left;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--stone-400);
    padding: var(--space-3) var(--space-5);
    border-bottom: 1px solid var(--stone-200);
    white-space: nowrap;
}

.data-table td {
    padding: var(--space-3) var(--space-5);
    border-bottom: 1px solid var(--stone-100);
    vertical-align: middle;
    color: var(--ilp-navy);
}

.data-table tbody tr:last-child td {
    border-bottom: none;
}

.data-table tbody tr:hover td {
    background: var(--stone-100);
}

.data-table a {
    text-decoration: none;
    font-weight: 500;
}

.data-table a:hover {
    text-decoration: underline;
}

.data-table .col-name { min-width: 160px; }
.data-table .col-dept { min-width: 140px; }
.data-table .col-status { width: 120px; }
.data-table .col-score { width: 80px; text-align: right; }
.data-table .col-level { width: 110px; }
.data-table .col-actions { width: 100px; text-align: right; }

/* P262 / R3: inline-edit forms inside a table cell (offboarding revocation
   checklist, phone status) wrap their controls rather than forcing a fixed-width
   row, so they stay usable when the table is scrolled/narrowed on a phone. The
   server contract (field names, action, csrf) is untouched -- this is layout
   only. */
.form-inline-edit {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

/* --- Detail List (IT Profile header tiles) ---
   coder-184: supersedes the old P262/R2 trailing-colon `dt::after` rule --
   uppercase micro-labels below take no colon. The `.vc-card__field` /
   `.vc-card__label` / `.vc-card__value` treatment, applied to the header dl. */
.detail-list {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
    margin-top: var(--space-5);
}

.detail-list__cell {
    background: var(--stone-100);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-3) var(--space-4);
}

.detail-list__cell--wide {
    grid-column: 1 / -1;
}

.detail-list dt {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--stone-400);
    margin-bottom: var(--space-1);
}

.detail-list dd {
    font-size: var(--text-base);
    color: var(--ilp-navy);
    line-height: 1.4;
    overflow-wrap: anywhere;
    margin: 0;
}


/* --- Level Tags --- */

.level-tag {
    display: inline-block;
    padding: var(--space-1) var(--space-3);
    border-radius: 2px;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: capitalize;
}

.level-tag--beginner {
    background: rgba(200, 155, 60, 0.12);
    color: #8A6D1B;
}

.level-tag--intermediate {
    background: rgba(31, 58, 95, 0.08);
    color: var(--ilp-navy);
}

.level-tag--advanced {
    background: var(--ilp-sage-soft);
    color: #3D6B1E;
}


/* --- Status Dot --- */

.status-dot {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
}

.status-dot::before {
    content: '';
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}

.status-dot--complete::before    { background: #5C8E3A; }
.status-dot--in_progress::before { background: var(--accent-amber); }
.status-dot--not_started::before { background: var(--stone-400); }

/* Process-engine task states (coder-096). The dot modifier is keyed on the
   INTERNAL enum value -- the user-facing words (To Do / In Progress / Complete)
   are the label beside it, never the class name. `in_progress` renders as the
   `.badge--in-progress` chip instead of a dot, which is what makes a started
   task visually distinct in a column of dots. */
.status-dot--pending::before        { background: var(--stone-400); }
.status-dot--completed::before      { background: #5C8E3A; }
.status-dot--not_applicable::before { background: var(--stone-400); }
.status-dot--deferred::before       { background: var(--accent-amber); }

/* Ops-health rollup modifiers. Reused by any future tile that needs
   a green/amber/red/grey severity indicator. */
.status-dot--ok::before       { background: #5C8E3A; }
.status-dot--warning::before  { background: var(--accent-amber); }
.status-dot--critical::before { background: #B23A2E; }
.status-dot--unknown::before  { background: var(--stone-400); }


/* --- Score Bar (inline progress-style bar) --- */

.score-bar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.score-bar__track {
    flex: 1;
    height: 6px;
    background: var(--stone-200);
    border-radius: 999px;
    overflow: hidden;
}

.score-bar__fill {
    height: 100%;
    background: var(--ilp-sage);
    border-radius: 999px;
    transition: width 400ms ease-out;
}

.score-bar__value {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ilp-navy);
    min-width: 32px;
    text-align: right;
}


/* --- Flag Pills --- */

.flag-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.flag-pill {
    display: inline-block;
    padding: var(--space-1) var(--space-3);
    background: rgba(181, 85, 46, 0.08);
    color: var(--accent-rust);
    border: 1px solid rgba(181, 85, 46, 0.2);
    border-radius: 999px;
    font-size: var(--text-xs);
    font-weight: 500;
}


/* --- Admin Report Section Headings --- */

.report-section {
    margin-bottom: var(--space-8);
}

.report-section__title {
    font-size: var(--text-xs);
    letter-spacing: 0.15em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--stone-400);
    margin-bottom: var(--space-4);
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--stone-200);
}


/* --- Level Distribution Bar --- */

.level-bar {
    display: flex;
    border-radius: 4px;
    overflow: hidden;
    height: 24px;
    margin-bottom: var(--space-4);
}

.level-bar__segment {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--cream);
    transition: width 400ms ease-out;
}

.level-bar__segment--beginner     { background: var(--accent-amber); }
.level-bar__segment--intermediate { background: var(--ilp-navy); }
.level-bar__segment--advanced     { background: #5C8E3A; }


/* --- Department list row --- */

.dept-row {
    display: flex;
    align-items: center;
    padding: var(--space-3) var(--space-5);
    border-bottom: 1px solid var(--stone-100);
    gap: var(--space-4);
}

.dept-row:last-child { border-bottom: none; }

.dept-row__name {
    flex: 1;
    font-weight: 500;
    color: var(--ilp-navy);
}

.dept-row__name--inactive {
    color: var(--stone-400);
    font-style: italic;
}

.dept-row__count {
    font-size: var(--text-sm);
    color: var(--stone-400);
    min-width: 80px;
    text-align: right;
}

.dept-row__actions {
    display: flex;
    gap: var(--space-3);
}


/* --- Required field marker (shared: vendor + composer forms) --- */

.form-required {
    color: var(--accent-rust);
    font-weight: 600;
    margin-left: 0.15em;
}


/* --- Composer / steps builder --- */

/* O1 -- chip multiselect (departments + sub-departments). The <input> checkbox
   stays inside the <label> chip and carries the POST value; the chip is the
   visible control. Selected state is driven by :has(input:checked) (covers the
   [[D261]] server-side pre-check with no JS) and mirrored by a .chip--selected
   class that sop_composer.js keeps in sync on toggle for older engines. */
.chip-multiselect {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-4);
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 999px;
    font-size: var(--text-sm);
    color: var(--ilp-navy);
    line-height: 1.3;
    cursor: pointer;
    transition: background 200ms ease-out, border-color 200ms ease-out;
}

.chip:hover {
    border-color: var(--ilp-sage);
}

/* Keep the underlying checkbox operable + keyboard-focusable, but out of the
   visual chip -- the chip label is the control. */
.chip input[type="checkbox"] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    margin: 0;
    pointer-events: none;
}

.chip:focus-within {
    outline: none;
    box-shadow: 0 0 0 3px var(--focus-ring);
}

.chip__label::before {
    content: '';
    display: inline-block;
    width: 1em;
    margin-right: 0.15em;
}

.chip--selected,
.chip:has(input:checked) {
    background: var(--ilp-sage-soft);
    border-color: var(--ilp-sage);
    font-weight: 500;
}

/* Check glyph on the selected state (replaces the reserved space above). */
.chip--selected .chip__label::before,
.chip:has(input:checked) .chip__label::before {
    content: '\2713';
    width: auto;
    color: var(--ilp-sage);
    font-weight: 700;
}

/* D264 -- the composer's OU department tree (parent department + nested
   sub-departments, expanded by default; mirror departments render as a single row).
   Vanilla nested lists; the cascade is JS (sop_composer.js). */
.dept-tree,
.dept-tree__children {
    list-style: none;
    margin: 0;
    padding: 0;
}
.dept-tree__dept {
    margin-bottom: var(--space-2);
}
.dept-tree__children {
    margin-left: var(--space-5);
    border-left: 2px solid var(--stone-200);
    padding-left: var(--space-3);
}
.dept-tree__row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) 0;
    cursor: pointer;
}
.dept-tree__dept > .dept-tree__row .dept-tree__label {
    font-weight: 600;
}

/* O2 -- carded steps with a number chip. */
.composer-step {
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    background: var(--paper);
    padding: var(--space-4) var(--space-5);
    margin-bottom: var(--space-4);
}

.composer-step > legend,
.composer-step__head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    font-weight: 600;
    color: var(--ilp-navy);
    padding: 0;
}

/* Retained: still consumed by import_wizard.js's step legend (import_tool/wizard.html).
   CODER-059 removed the composer's chip emit, but this class is NOT orphaned -- the
   import wizard shares it. Removing the rule would leave that chip unstyled. */
.composer-step__num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    background: var(--ilp-sage);
    color: var(--cream);
    font-size: var(--text-sm);
    font-weight: 700;
    flex: 0 0 auto;
}

.composer-step__ctrls {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: var(--space-3) 0;
}

.composer-step__body {
    margin-top: var(--space-3);
    padding-left: calc(1.75rem + var(--space-3));
}

.composer-add-step {
    margin-top: var(--space-3);
}

/* ==========================================================================
   coder-234 -- SOP composer block-card visual polish.

   sop_composer.js is not the only consumer of .composer-step / .composer-
   step__ctrls / .composer-step__body / .composer-verbiage* / .composer-menu-
   path* / .composer-dropzone* / .content-editor__* -- import_wizard.js
   (app/templates/import_tool/wizard.html, #import-steps-surface) builds its
   own step editor from the SAME class vocabulary. None of those shared base
   rules are touched here. Everything below either:
     (a) is a brand-new class (.composer-block*, .composer-step__toolbar,
         .composer-step__label, .composer-step__title, .composer-block-adder)
         that only sop_composer.js emits, or
     (b) is scoped under #sop-steps-surface -- sop_composer.js's own mount
         point (distinct from the wizard's #import-steps-surface) -- so an
         override can never reach the wizard's markup.
   The verbiage/menu-path in-treatment styling (.composer-verbiage*,
   .composer-menu-path*) is untouched by design (task scope): only its
   parent card chrome is new.
   ========================================================================== */

/* The step toolbar: "Step N", the title input, and the step-level controls
   as one row instead of three stacked, differently-weighted pieces. */
#sop-steps-surface .composer-step__toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

#sop-steps-surface .composer-step__label {
    font-weight: 600;
    color: var(--ilp-navy);
    white-space: nowrap;
    flex: 0 0 auto;
}

#sop-steps-surface .composer-step__title {
    flex: 1 1 220px;
    min-width: 160px;
}

/* Override the shared .composer-step__ctrls block-level margin -- inside the
   toolbar row it is a flex item that hugs the right edge, not a standalone
   block with vertical margin of its own. */
#sop-steps-surface .composer-step__ctrls {
    margin: 0 0 0 auto;
}

#sop-steps-surface .composer-step__body {
    /* No numeral chip has rendered here since CODER-057 -- the indent that
       used to align body text under it is dead weight. */
    padding-left: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* Each body block: a small card with a type header row (small-caps label,
   echoing .sop-read .sop-verbiage__label) and grouped controls on the right,
   instead of bare controls floating beside the input. */
#sop-steps-surface .composer-block {
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    background: var(--stone-100);
    padding: var(--space-3) var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

#sop-steps-surface .composer-block__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-2);
}

#sop-steps-surface .composer-block__type {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--stone-600);
}

#sop-steps-surface .composer-block__ctrls {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-1);
}

#sop-steps-surface .composer-block__ctrls .btn {
    padding: var(--space-1) var(--space-2);
    font-size: var(--text-xs);
}

/* Field weight: the paragraph/heading textarea matches the vendor form's
   .form-textarea idiom (reused as-is for border/background/focus) plus
   auto-grow (sop_composer.js sizes it on input and on mount). The heading
   variant reads as what it produces -- serif, larger, echoing
   .sop-read .sop-step__title. */
#sop-steps-surface .composer-block__text {
    resize: none;
    overflow: hidden;
    min-height: 4.5em;
}

#sop-steps-surface .composer-block__text--heading {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 600;
    min-height: 2.75em;
}

/* The adder row: outlined chip/buttons (.btn--secondary, the app's existing
   outlined idiom -- already used by "+ Add step") in one wrapping row,
   never bare text links. */
#sop-steps-surface .composer-block-adder {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

/* Narrow viewports (Michael authors from iOS Safari): stack rather than let
   the toolbar/head rows squeeze into unreadable fragments. Flex-wrap already
   keeps nothing overflowing above this width; below it we force a clean
   stack order instead of a partial wrap. */
@media (max-width: 480px) {
    #sop-steps-surface .composer-step__title {
        flex-basis: 100%;
    }

    #sop-steps-surface .composer-step__ctrls {
        margin-left: 0;
        width: 100%;
        justify-content: flex-end;
    }

    #sop-steps-surface .composer-block__ctrls {
        width: 100%;
        justify-content: flex-end;
    }
}

/* coder-232 -- authoring-side echo of the read view's inset-quote treatment
   (.sop-read .sop-verbiage), so the author sees speech as speech while typing. */
.composer-verbiage {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-2) 0 var(--space-2) var(--space-3);
    border-left: 1px solid var(--ilp-navy);
}

.composer-verbiage__label {
    max-width: 16rem;
}

.composer-verbiage__text {
    font-family: var(--font-display);
    font-style: italic;
}

/* coder-232 -- the menu-path block: one input, live breadcrumb preview below. */
.composer-menu-path {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.composer-menu-path__preview {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    color: var(--stone-600);
}

/* O3 -- per-step image dropzone -> thumbnail. */
.composer-dropzone {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    align-items: flex-start;
    border: 1px dashed var(--stone-400);
    border-radius: 4px;
    padding: var(--space-3);
    background: var(--stone-100);
}

.composer-thumb {
    max-width: 200px;
    max-height: 160px;
    border-radius: 4px;
    border: 1px solid var(--stone-200);
    display: block;
    cursor: zoom-in;
}

.composer-dropzone__ctrls {
    display: flex;
    gap: var(--space-2);
}

/* O4 -- escalation-vendor search popover + selected chip. */
.composer-vendor-field {
    position: relative;
}

.composer-vendor-results {
    position: absolute;
    z-index: 20;
    left: 0;
    right: 0;
    margin-top: var(--space-1);
    list-style: none;
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    box-shadow: 0 4px 16px rgba(26, 26, 26, 0.12);
    max-height: 260px;
    overflow-y: auto;
    padding: var(--space-1);
}

.composer-vendor-results li {
    padding: var(--space-2) var(--space-3);
    border-radius: 2px;
    cursor: pointer;
    font-size: var(--text-sm);
    color: var(--ilp-navy);
}

.composer-vendor-results li:hover,
.composer-vendor-results li:focus {
    background: var(--ilp-sage-soft);
    outline: none;
}

.composer-vendor-current {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-3);
    font-size: var(--text-sm);
    color: var(--stone-600);
}

.composer-vendor-current strong {
    display: inline-flex;
    align-items: center;
    padding: var(--space-1) var(--space-3);
    background: var(--ilp-sage-soft);
    border: 1px solid var(--ilp-sage);
    border-radius: 999px;
    color: var(--ilp-navy);
    font-weight: 500;
}

/* O5 -- SOP list rows. */
.composer-list {
    list-style: none;
    margin-top: var(--space-3);
}

.composer-list li {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    margin-bottom: var(--space-2);
    background: var(--paper);
}

.composer-list li a {
    flex: 1;
    color: var(--ilp-navy);
    font-weight: 500;
    text-decoration: none;
}

.composer-list li a:hover {
    text-decoration: underline;
}

.composer-list small {
    color: var(--stone-400);
    font-size: var(--text-xs);
}


/* --- Troubleshooting search bar --- */

.ts-search {
    display: flex;
    gap: var(--space-3);
    margin-bottom: var(--space-6);
}

.ts-search input[type="search"] {
    flex: 1;
    display: block;
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-bottom: 2px solid var(--stone-400);
    border-radius: 2px;
    padding: var(--space-3) var(--space-4);
    font-family: var(--font-body);
    font-size: var(--text-base);
    color: var(--ilp-navy);
    transition: border-color 200ms ease-out, box-shadow 200ms ease-out;
}

.ts-search input[type="search"]::placeholder {
    color: var(--stone-400);
}

.ts-search input[type="search"]:focus {
    outline: none;
    border-bottom-color: var(--ilp-sage);
    box-shadow: 0 0 0 3px var(--focus-ring);
}


/* --- Content block editor (folded from the retired content_editor.css so the
   JS-emitted step / block bodies render styled under the single main.css that
   base.html loads; retuned to the design tokens above) --- */

.content-editor {
    margin: var(--space-3) 0;
}

.content-editor__label {
    display: block;
    font-weight: 600;
    margin-bottom: var(--space-2);
    color: var(--ilp-navy);
}

.content-editor__source {
    width: 100%;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: var(--text-sm);
}

.content-editor__surface {
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-2);
}

.content-editor__block {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--stone-100);
}

.content-editor__block[data-block-type="vendor_contact_embed"] {
    font-style: italic;
    color: var(--stone-600);
}

.content-editor__block-text {
    flex: 1;
    width: 100%;
}

.content-editor__del {
    flex: 0 0 auto;
}

.content-editor__add {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}


/* ---------- 5. Utilities ---------- */

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.text-center { text-align: center; }
.text-muted { color: var(--stone-400); }
.mt-4 { margin-top: var(--space-4); }
.mt-6 { margin-top: var(--space-6); }
.mb-4 { margin-bottom: var(--space-4); }
.mb-6 { margin-bottom: var(--space-6); }


/* ---------- 6. Media Queries (mobile-first, scaling up) ---------- */

@media (min-width: 768px) {
    .card-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 640px) {
    .header-inner {
        padding: 0 var(--space-4);
    }

    .brand-text {
        display: none;
    }

    main {
        padding: var(--space-8) var(--space-4) var(--space-6);
    }

    .container {
        padding: 0 var(--space-4);
    }

    .flash-messages {
        padding: 0 var(--space-4);
    }

    .footer-inner {
        flex-direction: column;
        text-align: center;
        gap: var(--space-3);
    }

    /* P262 / R3 + R3b: app-wide mobile-table fix. Give every table its OWN
       horizontal-scroll context at phone width so wide tables scroll inside their
       card instead of clipping the page -- `display: block` + `overflow-x: auto`
       reaches bare `<table class="data-table">` surfaces too (most app tables are
       not hand-wrapped in `.data-table-wrapper`), so no per-template edit is
       needed. `.index-table` / `.drill-table` are the only non-`data-table`
       content tables (portfolio); they are brought into the same convention here.
       Cell padding is trimmed so more columns fit before scroll kicks in. */
    .data-table,
    .index-table,
    .drill-table {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    .data-table th,
    .data-table td {
        padding: var(--space-2) var(--space-3);
    }

    /* P265 / mobile sweep: stack stat cards in a single column on a phone. The
       2/3/4-column grids (`.stat-grid` base + `.stat-grid--cols-3/4`) otherwise
       force a too-wide min-content row that overflows the page horizontally. This
       rule wins over `.stat-grid--cols-*` here by source order (equal specificity,
       declared later) so the wide grids collapse without `!important`. */
    .stat-grid {
        grid-template-columns: 1fr;
    }

    /* P265 / mobile sweep: the assessment tool checklist is a 2-column grid; at
       phone width two columns of tool labels crowd and clip, so collapse to one. */
    .tool-checklist {
        grid-template-columns: 1fr;
    }

    /* P270 / card-layout mobile sweep -- the card counterpart to P262/P265's
       table sweep. The user-facing learning-plan page is a card/section layout
       (`.plan-*`), not a table; those rules sit AFTER this breakpoint and carry
       no phone treatment, so the section-header row and the item rows clip /
       overflow at phone width. These overrides REUSE this breakpoint (no second
       CSS system) and touch phone width (<=640px) ONLY -- the desktop `.plan-*`
       rules are untouched, so no desktop regression. Covers plan_v2.html and
       the plan.html / plan_basics_cyber.html siblings that share the classes. */

    /* The header is a fixed `space-between` row (title block + "N of M done"
       progress) that doesn't stack, so the progress collides with the title at
       narrow width. Stack the progress under the title and trim the padding. */
    .plan-section__header {
        flex-direction: column;
        align-items: flex-start;
        gap: var(--space-2);
        padding: var(--space-4);
    }

    /* `.plan-item__status-block`'s `min-width: 160px` + `.plan-item__main`'s
       `flex: 1 1 280px` forces a row wider than a phone viewport before wrap
       kicks in. Drop the min-width and let the status block take its own full-
       width line under the title; left-align it (it was `flex-end`). `.plan-item`
       already has `flex-wrap: wrap`. The "Take quiz" / "Mark as complete" button
       and the "This didn't help me" flag form stay fully tappable. */
    .plan-item__status-block {
        min-width: 0;
        width: 100%;
        align-items: flex-start;
    }

    /* Trim the item/description horizontal padding from `var(--space-6)` to
       `var(--space-4)` to match the `main` / `.container` phone reduction so the
       card rows keep their width. */
    .plan-items,
    .plan-section__description {
        padding-left: var(--space-4);
        padding-right: var(--space-4);
    }

    /* CODER-134: the /email-groups row wraps at phone width -- name and mail each
       take the full width, the type pill and the member count share a line under
       them. Without this the four-item flex row forces a min-content width wider
       than a 375px viewport. (The /vendor-contacts grid needs no counterpart:
       `auto-fill` + `minmax(280px, 1fr)` already collapses to one column.) */
    .eg-list__link {
        flex-wrap: wrap;
    }

    .eg-list__name,
    .eg-list__mail {
        flex: 1 1 100%;
    }

    .eg-list__type {
        margin-left: 0;
    }

    .eg-list__members {
        margin-left: auto;
    }
}

/* ---------------------------------------------------------------------------
 * Phase 2 Step 7: user-facing learning plan page
 * ------------------------------------------------------------------------- */

.plan-overview {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    margin-bottom: var(--space-6);
    flex-wrap: wrap;
}

.plan-overview__label {
    font-size: var(--text-sm);
    color: var(--stone-600);
    flex: 1 1 200px;
}

.plan-overview__bar {
    flex: 2 1 280px;
    height: 8px;
    background: var(--stone-200);
    border-radius: 4px;
    overflow: hidden;
    min-width: 200px;
}

.plan-overview__fill {
    height: 100%;
    background: var(--brand-accent, #93B86E);
    transition: width 200ms ease-out;
}

.plan-overview__pct {
    font-weight: 600;
    color: var(--brand-primary, #1F3A5F);
    min-width: 3em;
    text-align: right;
}

/* One Module Set per <details> block. Open state matches the rest of the
 * app's card chrome. */
.plan-section {
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    margin-bottom: var(--space-5);
    overflow: hidden;
}

.plan-section[open] {
    border-color: var(--brand-accent, #93B86E);
}

.plan-section__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-5) var(--space-6);
    cursor: pointer;
    list-style: none;
    background: var(--stone-100);
}

.plan-section__header::-webkit-details-marker { display: none; }

.plan-section__header::before {
    content: "▸";
    color: var(--stone-400);
    font-size: var(--text-base);
    margin-right: var(--space-2);
    transition: transform 200ms ease-out;
    display: inline-block;
}

.plan-section[open] .plan-section__header::before {
    transform: rotate(90deg);
}

.plan-section__title {
    font-family: var(--font-display, serif);
    font-size: var(--text-xl);
    margin: 0;
    color: var(--brand-primary, #1F3A5F);
}

.plan-section__meta {
    font-size: var(--text-xs);
    color: var(--stone-400);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-top: 2px;
}

.plan-section__progress {
    font-size: var(--text-sm);
    color: var(--stone-600);
    white-space: nowrap;
}

.plan-section__description {
    margin: 0;
    padding: var(--space-4) var(--space-6) 0;
    font-size: var(--text-sm);
    color: var(--stone-600);
    line-height: 1.55;
}

.plan-items {
    list-style: none;
    margin: 0;
    padding: var(--space-4) var(--space-6);
}

/* Suggested ("elective") group -- offered inside its set, visually set apart so
   it never reads as part of the counted work. Tinted, inset, and lower-contrast
   than the counted list above it. */
.plan-suggested {
    margin: 0 var(--space-6) var(--space-4);
    border: 1px dashed var(--stone-300);
    border-radius: 4px;
    background: var(--cream);
}

.plan-suggested__header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4) 0;
}

.plan-suggested__title {
    font-weight: 600;
    font-size: var(--text-sm);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--stone-600);
}

.plan-suggested__count {
    font-size: var(--text-xs);
    color: var(--stone-600);
    white-space: nowrap;
}

.plan-suggested__note {
    margin: var(--space-1) 0 0;
    padding: 0 var(--space-4);
    font-size: var(--text-sm);
    color: var(--stone-600);
    line-height: 1.55;
}

.plan-items--suggested {
    padding: var(--space-2) var(--space-4) var(--space-3);
}

.plan-item {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) 0;
    border-bottom: 1px solid var(--stone-200);
    flex-wrap: wrap;
}

.plan-item:last-child {
    border-bottom: none;
}

.plan-item--completed {
    opacity: 0.7;
}

.plan-item--skipped {
    opacity: 0.55;
}

.plan-item__main {
    flex: 1 1 280px;
    min-width: 0;
}

.plan-item__title {
    font-size: var(--text-base);
    font-weight: 500;
    margin: 0 0 var(--space-1);
}

.plan-item__title a {
    color: var(--brand-primary, #1F3A5F);
    text-decoration: none;
}

.plan-item__title a:hover {
    text-decoration: underline;
}

.plan-item__meta {
    font-size: var(--text-xs);
    color: var(--stone-400);
    margin: 0;
}

.plan-item__priority {
    color: var(--accent-rust);
    font-weight: 500;
}

/* "This didn't help me" flag affordance (Wave 14 .5 / P214). Small and
   unobtrusive: a plain-text disclosure that expands to an optional-comment
   form. v3-backed Tools-to-Adopt items only; hidden once flagged. */
.plan-item__flag {
    margin-top: var(--space-2);
}

.plan-item__flag-toggle {
    display: inline-block;
    font-size: var(--text-xs);
    color: var(--stone-400);
    cursor: pointer;
}

.plan-item__flag-toggle:hover {
    color: var(--stone-600);
    text-decoration: underline;
}

.plan-item__flag-form {
    margin: var(--space-2) 0 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    max-width: 420px;
}

.plan-item__flag-label {
    font-size: var(--text-xs);
    color: var(--stone-600);
}

.plan-item__flag-input {
    width: 100%;
    font: inherit;
    font-size: var(--text-sm);
    padding: var(--space-2);
    border: 1px solid var(--stone-200);
    border-radius: var(--radius-sm, 4px);
    resize: vertical;
}

.plan-item__status-block {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--space-2);
    min-width: 160px;
}

.plan-item__status {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--stone-400);
}

.plan-item--completed .plan-item__status {
    color: var(--brand-accent, #93B86E);
    font-weight: 600;
}

.plan-item--in_progress .plan-item__status {
    color: var(--accent-amber);
    font-weight: 600;
}

.plan-quiz {
    margin: 0;
    padding: var(--space-5) var(--space-6);
    background: var(--stone-100);
    border-top: 1px solid var(--stone-200);
}

.plan-quiz--locked {
    color: var(--stone-400);
}

.plan-quiz__title {
    font-size: var(--text-base);
    font-weight: 600;
    margin-bottom: var(--space-2);
}

.plan-quiz--unlocked .plan-quiz__title {
    color: var(--brand-primary, #1F3A5F);
}

.plan-quiz__hint {
    font-size: var(--text-sm);
    margin: 0;
}

/* ---------------------------------------------------------------------------
 * Phase 2 Step 10: user-facing quiz form and results
 * ------------------------------------------------------------------------- */

.quiz-form {
    margin-top: var(--space-4);
}

.quiz-question {
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-5) var(--space-6);
    margin: 0 0 var(--space-4);
    background: var(--paper);
}

.quiz-question__legend {
    padding: 0;
    margin: 0;
}

.quiz-question__number {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--stone-400);
}

.quiz-question__text {
    font-size: var(--text-base);
    font-weight: 500;
    color: var(--brand-primary, #1F3A5F);
    margin: var(--space-2) 0 var(--space-4);
}

.quiz-options {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.quiz-option {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    cursor: pointer;
    transition: background 200ms ease-out, border-color 200ms ease-out;
}

.quiz-option:hover {
    background: var(--stone-100);
    border-color: var(--stone-400);
}

.quiz-option input[type="radio"]:checked + span {
    font-weight: 500;
}

.quiz-option:has(input[type="radio"]:checked) {
    background: var(--brand-accent-soft, #EAF1DD);
    border-color: var(--brand-accent, #93B86E);
}

/* ----- Results page ----- */

.quiz-result-card {
    text-align: center;
    padding: var(--space-8) var(--space-6);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    background: var(--paper);
    margin-bottom: var(--space-8);
}

.quiz-result-card__score {
    font-family: var(--font-display, serif);
    font-size: var(--text-4xl);
    line-height: 1;
    margin-bottom: var(--space-2);
}

.quiz-result-card--pass .quiz-result-card__score {
    color: var(--brand-accent, #93B86E);
}

.quiz-result-card--fail .quiz-result-card__score {
    color: var(--accent-rust);
}

.quiz-result-card__label {
    font-size: var(--text-lg);
    font-weight: 500;
    color: var(--brand-primary, #1F3A5F);
    margin-bottom: var(--space-2);
}

.quiz-result-card__sub {
    font-size: var(--text-sm);
    color: var(--stone-600);
}

.quiz-feedback {
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-4) var(--space-5);
    margin-bottom: var(--space-3);
    background: var(--paper);
}

.quiz-feedback--correct {
    border-left: 4px solid var(--brand-accent, #93B86E);
}

.quiz-feedback--wrong {
    border-left: 4px solid var(--accent-rust);
}

.quiz-feedback__head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: var(--space-2);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.quiz-feedback__number {
    color: var(--stone-400);
}

.quiz-feedback--correct .quiz-feedback__verdict {
    color: var(--brand-accent, #93B86E);
    font-weight: 600;
}

.quiz-feedback--wrong .quiz-feedback__verdict {
    color: var(--accent-rust);
    font-weight: 600;
}

.quiz-feedback__text {
    font-size: var(--text-base);
    margin: 0 0 var(--space-3);
    color: var(--brand-primary, #1F3A5F);
}

.quiz-feedback__answers {
    font-size: var(--text-sm);
    color: var(--stone-600);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-bottom: var(--space-3);
}

.quiz-feedback__explanation {
    font-size: var(--text-sm);
    color: var(--stone-600);
    padding-top: var(--space-3);
    border-top: 1px solid var(--stone-200);
    line-height: 1.55;
}

/* ---------------------------------------------------------------------------
 * Phase 2 Step 12: landing-page learning plan card
 * ------------------------------------------------------------------------- */

.learning-card .learning-card__progress {
    height: 6px;
    background: var(--stone-200);
    border-radius: 3px;
    overflow: hidden;
    margin: var(--space-3) 0 var(--space-2);
}

.learning-card .learning-card__progress-fill {
    height: 100%;
    background: var(--brand-accent, #93B86E);
    transition: width 200ms ease-out;
}

/* ---------------------------------------------------------------------------
 * P269: in-app YouTube training player (learning.watch)
 * Responsive 16:9 embed on the existing .plan-* system -- mobile-first, the box
 * scales to phone width (padding-top reserves the aspect ratio; the iframe fills
 * it absolutely). No second CSS framework.
 * ------------------------------------------------------------------------- */

.video-embed {
    position: relative;
    width: 100%;
    padding-top: 56.25%; /* 16:9 */
    margin: var(--space-4) 0;
    background: #000;
    border-radius: 4px;
    overflow: hidden;
}

.video-embed iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.video-page__back {
    display: inline-block;
    margin-bottom: var(--space-2);
    font-size: var(--text-sm);
    color: var(--stone-600);
    text-decoration: none;
}

.video-page__back:hover {
    text-decoration: underline;
}

.video-page__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-4) 0;
}

/* ---------------------------------------------------------------------------
 * P297 — Vendor-contact detail card (the `.vc-*` body the shared
 * `app/content/render.py::render_contact_card` emits). The renderer ALREADY
 * emits structured `vc-card` / `__field` / `__label` / `__value` spans, but
 * main.css carried NO rule for any of them, so on the detail view the label and
 * value ran together inline ("Sales Phone+17786001722"). This adds the missing
 * card treatment — each populated field is its own labelled cell, a small
 * uppercase label ABOVE a prominent value — reusing the existing product tokens
 * and the `.stat-card` idiom so it matches the rest of the app. The same body
 * renders inside the `ts-embed--card` escalation embed (shared renderer), so the
 * styling lands there too — intended. CSS only; no markup/renderer change here
 * (the link-wrap was P296).
 * ------------------------------------------------------------------------- */

.vc-card {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-4);
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-5) var(--space-6);
}

/* The vendor logo + name head the card, each spanning the full width above the
   field grid. */
.vc-card__logo {
    height: 48px;
    width: auto;
}

.vc-card__name {
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-weight: 400;
    line-height: 1.2;
    letter-spacing: -0.01em;
    color: var(--ilp-navy);
    padding-bottom: var(--space-4);
    border-bottom: 1px solid var(--stone-100);
}

/* Each field is its own labelled cell: a small uppercase label stacked ABOVE a
   prominent value (the Get-Help support-card treatment). `flex-direction:
   column` makes the two inline spans stack — that is what fixes the
   run-together defect. */
.vc-card__field {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-4);
    background: var(--stone-100);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
}

.vc-card__label {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--stone-400);
}

.vc-card__value {
    font-size: var(--text-base);
    color: var(--ilp-navy);
    line-height: 1.4;
    word-break: break-word; /* long emails / URLs wrap inside the cell */
}

/* The tappable contact-method anchor (P296: tel:/mailto:/href). Navy by
   default, sage on hover — the product's existing link convention. */
.vc-card__link {
    color: var(--ilp-navy);
    font-weight: 500;
    text-decoration: none;
}

.vc-card__link:hover {
    color: var(--ilp-sage);
    text-decoration: underline;
}

/* Desktop: tile the field cells two-up; the logo and name span the full row. */
@media (min-width: 768px) {
    .vc-card {
        grid-template-columns: repeat(2, 1fr);
    }

    .vc-card__logo,
    .vc-card__name {
        grid-column: 1 / -1;
    }
}

/* ==========================================================================
   SOP import wizard + drag-image-between-steps (CODER-056)
   ========================================================================== */
.import-wizard {
    display: grid;
    grid-template-columns: minmax(240px, 1fr) minmax(320px, 1.4fr);
    gap: var(--space-4);
    align-items: start;
}
@media (max-width: 800px) {
    .import-wizard { grid-template-columns: 1fr; }
}
.import-wizard__page {
    max-width: 100%;
    border: 1px solid var(--stone-300);
    border-radius: 4px;
    display: block;
    cursor: zoom-in;
}
.import-wizard__preview { position: sticky; top: var(--space-3); }
/* Sticky only earns its keep while the preview sits BESIDE the steps. Once the
   grid collapses to one column the two cards share a horizontal band, and a
   sticky box -- being positioned, and clamped to the whole .import-wizard box
   rather than to its own grid row -- rides the scroll straight down and paints
   on top of the proposal editor (CODER-090). Must follow the rule above: same
   specificity, and a media query adds none. */
@media (max-width: 800px) {
    .import-wizard__preview { position: static; }
}
/* CODER-094: a uniform tile grid. The old flex-wrap row sized every cell to its
   own thumbnail, so a row of mixed-aspect screenshots left the attach selects on
   a ragged line at different heights -- "very strange looking". Equal columns,
   a fixed letterbox for the thumbnail, and the select pinned to the bottom of
   the cell make the controls line up whatever the images are shaped like. */
.import-wizard__images {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: var(--space-2);
    margin-top: var(--space-2);
}
.import-wizard__image-cell {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding: var(--space-1);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    background: var(--stone-100);
}
/* The letterbox. Fixed height so every tile is the same height; the thumbnail
   is centred and contained inside it rather than setting the tile's size. */
.import-wizard__thumb-box {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 140px;
    border: 1px solid var(--stone-300);
    border-radius: 3px;
    background: #fff;
    overflow: hidden;
}
/* CODER-093: 90px was unreadable for the Opera UI screenshots these documents
   are made of. 140px is the cheap half of the fix; the lightbox is the other
   half. CODER-094 keeps the 140px box and contains the image inside it. */
.import-wizard__thumb {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    cursor: zoom-in;
}
.import-wizard__nav {
    display: flex;
    justify-content: space-between;
    gap: var(--space-2);
    margin: var(--space-3) 0;
}
.import-wizard__finish { margin-top: var(--space-3); }

/* CODER-093 Phase 3: ONE picker per wizard page ("Images in this document"),
   not one per step -- a 9-step page with a 12-image pool used to paint 108
   thumbnails. The pool is shared across the whole document (LibreOffice emits a
   single resource dict), so the honest place for it is the page, once. */
.import-wizard__pool {
    margin: var(--space-3) 0;
    padding-top: var(--space-3);
    border-top: 1px solid var(--stone-200);
}
.import-wizard__pool-title {
    font-weight: 600;
    margin-bottom: var(--space-1);
}
/* The attach control: full width, BELOW the thumbnail, inside the cell, and
   pushed to the bottom (margin-top:auto) so selects align across a row. */
.import-wizard__attach {
    margin-top: auto;
}
.import-wizard__attach .form-select {
    width: 100%;
}
/* The per-step chips: an attached image shown small next to its step, with the
   detach control on the chip itself. */
.import-wizard__chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}
.import-wizard__chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px;
    border: 1px solid var(--stone-300);
    border-radius: 3px;
    background: var(--stone-100);
}
.import-wizard__chip img {
    max-width: 56px;
    max-height: 56px;
    display: block;
    cursor: zoom-in;
}

/* CODER-093 Phase 2 / CODER-094 Phase 2: the shared image lightbox (lightbox.js).
   CODER-093 sized the image to the viewport and called it zoom. For a PORTRAIT
   page raster the binding cap is max-height, which lands at ~650px wide on a
   landscape monitor -- the same size as the in-column render. Hence explicit
   scale controls, and a stage that scrolls on BOTH axes so a zoomed page pans. */
#lightbox {
    width: 96vw;
    height: 96vh;
    max-width: 96vw;
    max-height: 96vh;
    padding: 0;
    border: 0;
    background: transparent;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
#lightbox::backdrop { background: rgba(0, 0, 0, 0.7); }
/* The control bar: fixed within the dialog, above the stage that scrolls. */
.lightbox__bar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-2);
    background: #fff;
    border-bottom: 1px solid var(--stone-300);
}
.lightbox__btn {
    min-width: 34px;
    padding: 4px 10px;
    border: 1px solid var(--stone-300);
    border-radius: 4px;
    background: #fff;
    cursor: pointer;
}
.lightbox__readout {
    min-width: 52px;
    text-align: center;
    color: var(--stone-600);
}
/* Centring is done with `margin: auto` on the image rather than with
   align-items/justify-content, which clip the overflowing edge of an item bigger
   than its flex container -- and "bigger than the container" is the entire point
   of a zoomed page. */
.lightbox__stage {
    flex: 1 1 auto;
    overflow: auto;
    display: flex;
    background: var(--stone-100);
}
/* Default state and the [Fit] button: contained in the stage, which is the
   dialog (96vw / 96vh) less the control bar -- the CODER-093 96vw/90vh, minus
   the overflow that a hard vh cap inside a flex column would cause. Any other
   scale sets an explicit pixel width in JS and the stage scrolls to reach it. */
.lightbox__img {
    display: block;
    margin: auto;
    background: var(--stone-100);
}
.lightbox__img--fit {
    max-width: 100%;
    max-height: 100%;
}
.lightbox__close {
    margin-left: auto;
    padding: 4px 12px;
    border: 1px solid var(--stone-300);
    border-radius: 4px;
    background: #fff;
    cursor: pointer;
}

/* coder-276 -- the mandatory SOP step image editor (sop_image_editor.js).
   Same native-<dialog> chrome idiom as #lightbox (bar + ::backdrop, dialog
   itself unstyled/transparent), scaled to the editor's own needs: a fixed
   toolbar above a scrollable canvas stage. Tool buttons reuse
   .btn/.btn--secondary/.btn--sm -- the editor introduces no new button
   vocabulary, only the active-tool indicator and the canvas stage itself.

   coder-282 -- the stage (.sop-image-editor__wrap) is now a fixed-size flex
   viewport (not a shrink-to-content box) so JS can read its clientWidth/
   clientHeight to compute a fit-to-screen display scale independent of the
   canvas's internal pixel resolution. The canvas elements' CSS width/height
   are set inline by JS per the current zoom level; their width/height
   *attributes* (native resolution) are untouched by any of this. When the
   scaled canvas exceeds the stage, native overflow scrolling (no custom pan
   tool) makes the rest reachable. */
#sop-image-editor {
    width: 96vw;
    max-width: 96vw;
    height: 92vh;
    max-height: 92vh;
    padding: 0;
    border: 0;
    border-radius: 4px;
    background: var(--paper);
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
#sop-image-editor::backdrop { background: rgba(0, 0, 0, 0.7); }
/* coder-377: an unconditional `display: flex` on an ID selector beats the UA
   `dialog:not([open]) { display: none }`, so a closed dialog stayed painted at
   the top of the page. Gate the flex layout on [open]. */
#sop-image-editor:not([open]),
#lightbox:not([open]) { display: none; }
.sop-image-editor__bar {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    background: #fff;
    border-bottom: 1px solid var(--stone-300);
}
.sop-image-editor__spacer { flex: 1 1 auto; }
.sop-image-editor__tool--active {
    border-color: var(--ilp-navy);
    background: var(--ilp-navy);
    color: #fff;
}
.sop-image-editor__wrap {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
    overflow: auto;
    background: var(--stone-100);
}
.sop-image-editor__canvas { display: block; }
.sop-image-editor__canvas--overlay {
    position: absolute;
    top: 0;
    left: 0;
    cursor: crosshair;
}
.sop-image-editor__text-input {
    position: absolute;
    z-index: 1;
    font-family: Inter, sans-serif;
    font-weight: bold;
    padding: 1px 4px;
    border: 1px solid var(--ilp-navy);
    border-radius: 2px;
    background: #fff;
    color: #111;
}
/* coder-287 -- Font Size label+select pair (XS/S/M/L/XL), shown only while
   the Text tool is active (JS toggles display via
   refreshSizeControlVisibility). Replaces coder-284's five toggle buttons;
   the select reuses .form-select/.form-select--sm (coder-237) -- no new
   form-control vocabulary, just width:auto so it doesn't fill the toolbar. */
.sop-image-editor__sizes {
    display: none;
    align-items: center;
    gap: var(--space-2);
}
.sop-image-editor__sizes-label {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--ilp-navy);
    white-space: nowrap;
}
.sop-image-editor__sizes .form-select {
    width: auto;
    min-width: 4.5em;
}

/* Phase 5 (F8) drag-image-between-steps affordances. */
.composer-dropzone--dragging { opacity: 0.5; }
.composer-step--drop {
    outline: 2px dashed var(--ilp-sage, #6a8f7a);
    outline-offset: 2px;
}
.composer-move-block {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.85em;
}
/* coder-237 -- token-based compact size modifier for .form-select, mirroring
   .form-input--sm (selects and inputs share the same base rule at
   .form-input, .form-select { ... } above). */
.form-select--sm {
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-sm);
}


/* ==========================================================================
   CODER-095 -- the published SOP read view.

   Michael, off the live parking SOP (/troubleshooting/sop/property/4): "the
   semantics are right ... now we just need to work on formatting -- we need it
   to be clean and clear. Think elegant."

   The diagnosis was that `.sop-step`, `.sop-step__title` and `.ts-sop-*` had
   been EMITTED by the renderer since D257 but never styled, so a twelve-step SOP
   arrived as one undifferentiated column of 16px Inter: step label, title, body
   prose, guest-facing script and Opera menu path all at identical visual weight.
   Nothing here changes what an SOP says. It changes only what the reader's eye
   is told to do with it.
   ========================================================================== */

.sop-read {
    /* Reading measure. ~70ch of Inter lands near 660px -- long enough for an
       Opera instruction to stay on one line, short enough that the eye finds the
       next line's start without hunting. The .container--medium 960px stays the
       PAGE width so the stale banner and version footer keep their full bleed. */
    --sop-measure: 70ch;
    /* Rail geometry, shared by the disc, the connector and the body indent so the
       three can never drift apart. */
    --sop-disc-size: 2rem;
    --sop-rail-gap: var(--space-5);
}

.sop-read .page-intro {
    max-width: var(--sop-measure);
}

.sop-read .ts-sop-body {
    max-width: var(--sop-measure);
    margin-top: var(--space-8);
}


/* ---------- The step rail ---------- */

/* Each step is a row on a single hairline that runs the length of the SOP, with
   the number carried by a disc sitting ON the line -- the app's existing
   circled-numeral idiom (.composer-step__num), dialled down from the composer's
   sage-on-cream to a quiet stone disc, because on a read view the number is
   orientation, not a call to action. */
.sop-read .sop-step {
    position: relative;
    padding-left: calc(var(--sop-disc-size) + var(--sop-rail-gap));
    padding-bottom: var(--space-8);
}

/* The connector. Runs the full height of the step, so consecutive steps join
   seamlessly; the disc is opaque and painted over its top end. */
.sop-read .sop-step::before {
    content: "";
    position: absolute;
    left: calc(var(--sop-disc-size) / 2);
    top: 0;
    bottom: 0;
    width: 1px;
    margin-left: -0.5px;
    background: var(--stone-200);
}

/* Nothing below the last step to connect to -- a rule trailing into whitespace
   reads as a truncation bug. */
.sop-read .sop-step:last-child::before {
    display: none;
}

.sop-read .sop-step:last-child {
    padding-bottom: var(--space-4);
}

.sop-read .sop-step__disc {
    position: absolute;
    left: 0;
    top: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--sop-disc-size);
    height: var(--sop-disc-size);
    border-radius: 50%;
    border: 1px solid var(--stone-300);
    background: var(--paper);
    color: var(--ilp-navy);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

/* Serif, and a clear size step above the body -- the single change that makes
   the step/title/body hierarchy register at a glance. Optically centred against
   the disc rather than sitting on the same baseline. */
.sop-read .sop-step__title {
    margin: 0 0 var(--space-4);
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 600;
    line-height: 1.3;
    color: var(--ilp-navy);
    padding-top: 0.1em;
}


/* ---------- Body prose ---------- */

.sop-read .sop-prose {
    margin: 0 0 var(--space-4);
    line-height: 1.7;
    color: var(--wgit-black);
}

.sop-read .sop-step__main > *:last-child {
    margin-bottom: 0;
}


/* ---------- Guest-facing verbiage ---------- */

/* A line a human reads ALOUD to a guest is a different kind of sentence from an
   instruction about Opera, and it was rendering as the same grey paragraph. The
   inset rule plus italic serif says "this is speech" before a word is read. */
.sop-read .sop-verbiage {
    margin: var(--space-5) 0;
    padding: var(--space-1) 0 var(--space-1) var(--space-5);
    border-left: 1px solid var(--ilp-navy);
}

.sop-read .sop-verbiage p {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-style: italic;
    line-height: 1.6;
    color: var(--ilp-navy);
}

/* The "Suggested Verbiage:" lead-in is a LABEL, not speech -- so it stays in the
   sans face, small and quiet, and does not get the italic treatment. */
.sop-read .sop-verbiage .sop-verbiage__label {
    margin: 0 0 var(--space-2);
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-style: normal;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--stone-600);
}


/* ---------- Opera menu paths ---------- */

/* `Options>Fixed Charge> Trans Code 2200` is a thing you CLICK, not a thing you
   read. Setting it as a chip lets the eye pick it out of the sentence and stops
   the `>` chain from reading as punctuation. */
.sop-read .sop-path {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.85em;
    padding: 0.1em 0.4em;
    border: 1px solid var(--stone-300);
    border-radius: 3px;
    background: var(--stone-100);
    color: var(--stone-600);
    white-space: nowrap;
}


/* ---------- Figures ---------- */

.sop-read .sop-figure {
    margin: var(--space-5) 0;
    text-align: center;
}

.sop-read .sop-figure__img {
    max-width: 100%;
    height: auto;
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    background: var(--paper);
    cursor: zoom-in;
}


/* ---------- Page furniture (emitted since D250/D251, never styled) ---------- */

.sop-read .ts-sop-stale {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2) var(--space-3);
    margin-top: var(--space-5);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--accent-amber);
    border-left-width: 3px;
    border-radius: 4px;
    background: var(--stone-100);
}

.sop-read .ts-sop-stale__label {
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    color: var(--accent-rust);
}

.sop-read .ts-sop-stale__detail {
    font-size: var(--text-sm);
    color: var(--stone-600);
}

.sop-read .ts-sop-versioning {
    max-width: var(--sop-measure);
    margin-top: var(--space-6);
    padding-top: var(--space-4);
    border-top: 1px solid var(--stone-200);
}

.sop-read .ts-sop-history__stamp {
    cursor: pointer;
    font-size: var(--text-sm);
    color: var(--stone-600);
}

.sop-read .ts-sop-history__list {
    margin: var(--space-3) 0 0;
    padding: 0;
    list-style: none;
}

.sop-read .ts-sop-history__item {
    display: flex;
    gap: var(--space-3);
    padding: var(--space-1) 0;
    font-size: var(--text-sm);
    color: var(--stone-600);
}

.sop-read .ts-sop-history__version {
    font-variant-numeric: tabular-nums;
    color: var(--ilp-navy);
    font-weight: 600;
}


/* ---------- Narrow viewports ---------- */

/* Below ~600px the rail gutter costs more than it earns, so the disc goes inline
   above the title and the body reclaims the full width. The connector stays --
   it is what makes twelve steps read as a sequence rather than twelve headings. */
@media (max-width: 600px) {
    .sop-read {
        --sop-disc-size: 1.75rem;
        --sop-rail-gap: var(--space-3);
    }

    .sop-read .sop-step__title {
        font-size: var(--text-lg);
    }

    .sop-read .sop-verbiage {
        padding-left: var(--space-4);
    }

    .sop-read .sop-verbiage p {
        font-size: var(--text-base);
    }

    .sop-read .sop-path {
        white-space: normal;
    }
}


/* ==========================================================================
   coder-276 -- print/PDF stylesheet for the published SOP read view.

   Browser print-to-PDF is the export path (no server-side PDF renderer for
   SOPs). One rule: the same read-view DOM as screen, styled for print --
   never a forked print-only template (a later docx exporter mirrors this
   same block->visual mapping, so it must stay centralized here). The print
   header (.sop-print-header, markup in troubleshooting/sop.html) exists in
   the DOM at all times; it is what toggles, screen vs print, not the markup.
   ========================================================================== */

.sop-print-header { display: none; }

@media print {
    /* App chrome: nav, header/footer, buttons, edit affordances, the agent
       widget, flash messages -- none of it belongs on a laminated desk copy. */
    .site-header,
    .site-footer,
    .flash-messages,
    #agent-widget,
    .sop-read .page-actions,
    .sop-read .pin-form,
    .sop-read .ts-sop-versioning {
        display: none !important;
    }

    .sop-print-header {
        display: block;
        margin-bottom: var(--space-6);
        padding-bottom: var(--space-4);
        border-bottom: 1px solid var(--stone-300);
    }
    .sop-print-header__property {
        font-size: var(--text-sm);
        font-weight: 600;
        letter-spacing: 0.04em;
        text-transform: uppercase;
        color: var(--stone-600);
    }
    .sop-print-header__title {
        margin: var(--space-1) 0 var(--space-3);
        font-family: var(--font-display);
        font-size: var(--text-2xl);
        color: var(--ilp-navy);
    }
    .sop-print-header__meta {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-1) var(--space-6);
        margin: 0;
        font-size: var(--text-sm);
    }
    .sop-print-header__field { display: flex; gap: var(--space-1); }
    .sop-print-header__field dt {
        font-weight: 600;
        color: var(--stone-600);
    }
    .sop-print-header__field dd { margin: 0; }

    /* The page-title h1 in .page-intro duplicates .sop-print-header__title --
       .page-intro itself is hidden above via .sop-read .page-actions... no,
       page-intro carries no chrome of its own besides the actions button, so
       only the redundant title needs suppressing; the breadcrumb link is
       inert ink on paper and costs nothing to leave, but the duplicate h1
       would read as a doubled heading directly under the print header. */
    .sop-read .page-intro .page-title { display: none; }

    /* Step containers: avoid an orphaned title at a page bottom, and prefer
       not to split a step body across pages when it reasonably fits on one. */
    .sop-read .sop-step {
        break-inside: avoid;
        page-break-inside: avoid;
    }
    .sop-read .sop-step__title {
        break-after: avoid;
        page-break-after: avoid;
    }

    /* Full-width images; the lightbox affordance is inert in print (no click
       handler runs on a printed page, but the zoom cursor/hover cue is
       screen-only chrome). */
    .sop-read .sop-figure__img {
        max-width: 100%;
        cursor: default;
    }
    #lightbox { display: none !important; }
}


/* ==========================================================================
   CODER-100 -- the onsite-calendar surface (List / Week / Month).

   The page was a bare <ul> of raw UTC ISO timestamps against no CSS at all: the
   `.oc-*` classes the P121 card emitted had never been given a rule. This block is
   the whole surface, written in the SOP READ VIEW's idiom rather than a parallel
   style system:

     * a reading measure on the intro (`--oc-measure`), as `.sop-read` does;
     * hairline `--stone-200` rules doing the dividing, not boxes and shadows;
     * `--font-display` for the headings that ORIENT you (the day, the month), the
       body face for everything you read at speed;
     * `--stone-600` for anything supporting -- locations, empty lines, day numbers.

   The pill toggle borrows the `.freq-option label` vocabulary (999px radius, stone
   hairline, navy-on-cream when active) so the toggle is a shape the product already
   uses. No JS: the pills are links.
   ========================================================================== */

.oc-read {
    /* Same measure as the SOP read view -- the list view is prose-shaped and wants
       the same ~70ch column. The grids opt out below, since a five- or seven-column
       week needs the full .container--medium width. */
    --oc-measure: 70ch;
}

.oc-read .page-intro {
    max-width: var(--oc-measure);
}


/* ---------- View toggle ---------- */

.oc-views {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-6);
}

.oc-views__pill {
    display: block;
    padding: var(--space-2) var(--space-4);
    border: 1px solid var(--stone-200);
    border-radius: 999px;
    font-size: var(--text-sm);
    color: var(--stone-600);
    text-decoration: none;
    white-space: nowrap;
    transition: color 200ms ease-out, border-color 200ms ease-out,
                background-color 200ms ease-out;
}

.oc-views__pill:hover {
    border-color: var(--ilp-sage);
    color: var(--ilp-navy);
}

.oc-views__pill--active,
.oc-views__pill--active:hover {
    background: var(--ilp-navy);
    border-color: var(--ilp-navy);
    color: var(--cream);
}


/* ---------- Period line + prev/next ---------- */

.oc-period {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    margin-top: var(--space-6);
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--stone-200);
}

.oc-period__label {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 600;
    color: var(--ilp-navy);
}

.oc-period__nav {
    display: flex;
    gap: var(--space-4);
}

.oc-period__step {
    font-size: var(--text-sm);
    color: var(--stone-600);
    text-decoration: none;
    white-space: nowrap;
}

.oc-period__step:hover {
    color: var(--ilp-navy);
}


/* ---------- Graceful states ---------- */

/* Not-configured and temporarily-unavailable. Deliberately NOT a card with a
   border and a shadow: the honest states read better as a quiet paragraph than as
   an object demanding attention. */
.oc-notice {
    max-width: var(--oc-measure);
    margin-top: var(--space-6);
    padding: var(--space-5) 0 var(--space-5) var(--space-5);
    border-left: 1px solid var(--ilp-navy);
}

.oc-notice--unavailable {
    border-left-color: var(--accent-amber);
}

.oc-notice__title {
    margin: 0 0 var(--space-2);
    font-family: var(--font-display);
    font-size: var(--text-lg);
    color: var(--ilp-navy);
}

.oc-notice__body {
    margin: 0;
    font-size: var(--text-sm);
    line-height: 1.7;
    color: var(--stone-600);
}


/* ---------- List view ---------- */

.oc-days {
    max-width: var(--oc-measure);
    margin-top: var(--space-6);
}

/* One hairline per day, the SOP rail's logic flattened: the rule is what tells you
   five separate days were checked, which is the whole point of rendering the empty
   ones. */
.oc-day {
    padding: var(--space-5) 0;
    border-bottom: 1px solid var(--stone-200);
}

.oc-day:last-child {
    border-bottom: none;
}

.oc-day__label {
    margin: 0 0 var(--space-3);
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--ilp-navy);
}

.oc-day--today .oc-day__label::after {
    content: "Today";
    margin-left: var(--space-3);
    padding: 0.1em 0.5em;
    border-radius: 999px;
    background: var(--ilp-sage-soft);
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ilp-navy);
    vertical-align: middle;
}

.oc-day__events {
    margin: 0;
    padding: 0;
    list-style: none;
}

.oc-day__empty {
    margin: 0;
    font-size: var(--text-sm);
    font-style: italic;
    color: var(--stone-400);
}


/* ---------- One event ---------- */

/* The time leads, in tabular numerals so a column of them aligns; the subject is
   what you read; the location is supporting detail and is set as such. */
.oc-event {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2) var(--space-4);
    padding: var(--space-2) 0;
}

.oc-event__when {
    flex: 0 0 auto;
    min-width: 11ch;
    font-size: var(--text-sm);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--ilp-navy);
}

.oc-event__subject {
    flex: 1 1 12ch;
    color: var(--wgit-black);
}

.oc-event__where {
    flex: 0 1 auto;
    font-size: var(--text-sm);
    color: var(--stone-600);
}

/* In a week column there is no room for a row; the three parts stack. */
.oc-event--stacked {
    flex-direction: column;
    gap: 0;
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--stone-100);
}

.oc-event--stacked:last-child {
    border-bottom: none;
}

.oc-event--stacked .oc-event__when {
    min-width: 0;
    font-size: var(--text-xs);
}


/* ---------- Week view ---------- */

.oc-week {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--space-4);
    margin-top: var(--space-6);
}

.oc-week__col {
    padding-top: var(--space-3);
    border-top: 2px solid var(--stone-200);
}

/* Today gets the sage rule rather than a filled cell -- the same restraint the
   admin subnav uses to mark its active tab. */
.oc-week__col--today {
    border-top-color: var(--ilp-sage);
}

.oc-week__head {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    margin: 0 0 var(--space-3);
}

.oc-week__weekday {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--stone-600);
}

.oc-week__date {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--ilp-navy);
}

.oc-week__events {
    margin: 0;
    padding: 0;
    list-style: none;
}


/* ---------- Month view ---------- */

.oc-month {
    margin-top: var(--space-6);
}

.oc-month__weekdays,
.oc-month__week {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
}

.oc-month__weekday {
    padding: var(--space-2) var(--space-2);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--stone-600);
}

.oc-month__cell {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-height: 6.5rem;
    padding: var(--space-2);
    border-top: 1px solid var(--stone-200);
    border-left: 1px solid var(--stone-200);
    background: var(--paper);
}

.oc-month__week:last-child .oc-month__cell {
    border-bottom: 1px solid var(--stone-200);
}

.oc-month__cell:last-child {
    border-right: 1px solid var(--stone-200);
}

/* Weekends stay in the grid (a month with five columns is not a month) but recede,
   and days belonging to the neighbouring months recede further still. */
.oc-month__cell--weekend {
    background: var(--stone-100);
}

.oc-month__cell--outside {
    background: var(--cream);
}

.oc-month__cell--today {
    box-shadow: inset 0 2px 0 0 var(--ilp-sage);
}

.oc-month__daynum {
    font-size: var(--text-sm);
    font-variant-numeric: tabular-nums;
    color: var(--stone-600);
}

.oc-month__cell--today .oc-month__daynum {
    font-weight: 700;
    color: var(--ilp-navy);
}

/* A chip has to survive a 13-character column, so it truncates rather than wraps --
   the full text stays reachable in the title attribute. */
.oc-chip {
    display: block;
    overflow: hidden;
    padding: 0.1em 0.35em;
    border-radius: 3px;
    background: var(--ilp-sage-soft);
    font-size: var(--text-xs);
    line-height: 1.5;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: var(--ilp-navy);
}

.oc-chip__time {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

.oc-chip--more {
    background: none;
    color: var(--stone-600);
}


/* ---------- Narrow viewports ---------- */

/* Below ~700px a five-column week and a seven-column month are both unreadable, so
   the week collapses to stacked day sections (the list view's shape, which already
   works there) and the month cells shed their chips' minimum height. */
@media (max-width: 700px) {
    .oc-week {
        grid-template-columns: 1fr;
        gap: 0;
    }

    .oc-week__col {
        padding-bottom: var(--space-4);
        border-top: 1px solid var(--stone-200);
    }

    .oc-month__cell {
        min-height: 4.5rem;
        padding: var(--space-1);
    }

    .oc-month__weekday {
        padding: var(--space-1);
    }

    .oc-chip__subject {
        display: none;
    }
}


/* ==========================================================================
   CODER-102 -- add-to-calendar link + the "Today" period step.

   Two small additions inside the CODER-100 `.oc-*` vocabulary; no new tokens, no
   script. The add link is deliberately the quietest thing in an event row: it is an
   escape hatch a reader uses once, not the reason they came to the page, so it sits
   below the location in weight and only reaches navy on hover.
   ========================================================================== */

.oc-event__add {
    flex: 0 0 auto;
    font-size: var(--text-xs);
    color: var(--stone-400);
    text-decoration: none;
    white-space: nowrap;
    transition: color 200ms ease-out;
}

.oc-event__add:hover,
.oc-event__add:focus-visible {
    color: var(--ilp-navy);
    text-decoration: underline;
}

/* In a week column the row stacks, so the link needs its own line of air rather
   than the baseline gap the flex row gives it. */
.oc-event--stacked .oc-event__add {
    align-self: flex-start;
    margin-top: var(--space-1);
}

/* `.oc-period__step--today` intentionally carries NO rule of its own: Today is the
   same kind of control as Previous/Next -- one of three ways to move the period --
   so it takes `.oc-period__step` wholesale. The modifier stays on the element as a
   hook for the day it needs to differ. */


/* ==========================================================================
   CODER-134 -- the two directory INDEXES: /email-groups (`.eg-*`) and
   /vendor-contacts (`.vc-list*` / `.vc-facet*` / `.vc-empty`).

   Defect class P297 (`.vc-card`) / CODER-095 (the SOP read view) a third time:
   both templates emit a full, structured class vocabulary that main.css carried
   NO rule for, so every span collapsed into one underlined inline anchor and both
   pages read as a wall of links. Additive only -- no existing selector is edited,
   no new token, no new colour literal.
   ========================================================================== */

/* ---------- /email-groups: rows on hairlines, not boxed cards ----------
   A directory is scanned top-to-bottom, so each group takes the quiet
   `.dept-row` / `.oc-day` rule rather than a card border of its own. */

.eg-department {
    margin-bottom: var(--space-8);
}

/* Keeps the serif h2 from the base heading rules; the hairline is the
   `.report-section__title` spirit, anchoring each department block. */
.eg-department__name {
    margin: 0 0 var(--space-2);
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--stone-200);
}

.eg-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The whole row is the link (the `.admin-card-list__row` contract), so the
   hover tint and the focus ring live on the anchor, not on the <li>. */
.eg-list__link {
    display: flex;
    align-items: center;
    gap: var(--space-3) var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--stone-100);
    text-decoration: none;
    color: inherit;
    transition: background-color 200ms ease-out;
}

.eg-list__item:last-child .eg-list__link {
    border-bottom: none;
}

.eg-list__link:hover {
    background: var(--ilp-sage-soft);
}

.eg-list__link:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--focus-ring);
}

/* The thing the eye scans: no underline until hover. */
.eg-list__name {
    font-weight: 500;
    color: var(--ilp-navy);
    min-width: 0;
    overflow-wrap: anywhere;
}

.eg-list__link:hover .eg-list__name {
    text-decoration: underline;
}

.eg-list__mail {
    font-size: var(--text-sm);
    color: var(--stone-600);
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Pill shape and colour come from `.badge badge--not-started` on the element
   itself (see the template comment); this rule is layout only -- it is what
   pushes the type + count pair to the right of the row, with or without a mail
   address present. */
.eg-list__type {
    margin-left: auto;
    flex-shrink: 0;
}

/* Right-aligned tabular counts so the numbers form a scannable column. */
.eg-list__members {
    flex-shrink: 0;
    min-width: 6.5em;
    text-align: right;
    font-size: var(--text-sm);
    color: var(--stone-600);
    font-variant-numeric: tabular-nums;
}

.eg-empty {
    color: var(--stone-600);
    font-size: var(--text-sm);
}


/* ---------- /vendor-contacts: short blocks in a card grid ----------
   Michael 2026-07-31: each vendor is a short block carrying its support phone
   and/or email, and the scope badge is gone entirely (it was noise -- the
   `.vc-badge*` classes died with the markup, so no rule is left behind for
   them). The grid is the `.admin-card-list--grid` auto-fill idiom. */

.vc-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--space-4);
    margin: 0 0 var(--space-8);
    padding: 0;
    list-style: none;
}

.vc-list__item {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
    background: var(--paper);
    border: 1px solid var(--stone-200);
    border-radius: 4px;
    padding: var(--space-4) var(--space-5);
}

/* The name is the ONLY link into the detail card -- the block is deliberately
   not one big anchor, because the phone and the email are their own links. */
.vc-list__name {
    font-weight: 500;
    color: var(--ilp-navy);
    text-decoration: none;
    overflow-wrap: anywhere;
}

.vc-list__name:hover {
    text-decoration: underline;
}

/* The `.card-eyebrow` label scale without the sage: the category is an
   orienting tag, not the thing being read. */
.vc-list__category {
    font-size: var(--text-xs);
    letter-spacing: 0.15em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--stone-400);
}

/* The `.vc-card__link` convention (navy, sage on hover), in the index
   namespace: the detail card's rule is P297's and is not widened here. */
.vc-list__contact {
    font-size: var(--text-sm);
    color: var(--ilp-navy);
    text-decoration: none;
    overflow-wrap: anywhere;
}

.vc-list__contact:hover {
    color: var(--ilp-sage);
    text-decoration: underline;
}

/* Tag facets in the product's pill vocabulary (`.oc-views__pill` /
   `.freq-option label`). `.vc-search` is gone from the template -- the form
   reuses `.ts-search`, the one search-bar implementation. */
.vc-facets {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
    margin-bottom: var(--space-6);
}

.vc-facets__label {
    font-size: var(--text-sm);
    color: var(--stone-600);
}

.vc-facets ul {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.vc-facet {
    display: block;
    padding: var(--space-2) var(--space-4);
    border: 1px solid var(--stone-200);
    border-radius: 999px;
    font-size: var(--text-sm);
    color: var(--stone-600);
    text-decoration: none;
    white-space: nowrap;
    transition: color 200ms ease-out, border-color 200ms ease-out,
                background-color 200ms ease-out;
}

.vc-facet:hover {
    border-color: var(--ilp-sage);
    color: var(--ilp-navy);
}

.vc-facet--active,
.vc-facet--active:hover {
    background: var(--ilp-navy);
    border-color: var(--ilp-navy);
    color: var(--cream);
}

.vc-empty {
    color: var(--stone-600);
    font-size: var(--text-sm);
}

/* coder-209 -- recipient chip multiselect (offboarding start form's three
   forward-emails / mailbox-access / files-access fields). Search-driven, unlike
   the fixed-list .chip-multiselect above: a pick appends a removable chip here. */
.recipient-chip-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.recipient-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3);
    background: var(--ilp-sage-soft);
    border: 1px solid var(--ilp-sage);
    border-radius: 999px;
    font-size: var(--text-sm);
    color: var(--ilp-navy);
    line-height: 1.3;
}

.recipient-chip__remove {
    border: none;
    background: none;
    cursor: pointer;
    color: var(--ilp-navy);
    font-size: var(--text-sm);
    line-height: 1;
    padding: 0;
}

/* System Map (coder-294): repeatable vendor/link rows on the system form, the
   filter bar on the systems list, and the map's SVG layout + side panel. */
.repeatable-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    flex-wrap: wrap;
}

.repeatable-row select,
.repeatable-row input {
    flex: 1 1 160px;
}

.filter-bar {
    display: flex;
    align-items: flex-end;
    gap: var(--space-4);
    margin-bottom: var(--space-4);
}

.filter-bar .form-label {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    font-size: var(--text-sm);
}

.system-map__svg {
    width: 100%;
    height: auto;
    border: 1px solid var(--ilp-sage-soft);
    border-radius: 8px;
    background: #fff;
}

.system-map__node circle {
    fill: var(--ilp-sage-soft);
    stroke: var(--ilp-sage);
    stroke-width: 2;
    cursor: pointer;
}

.system-map__node text {
    font-size: 11px;
    fill: var(--ilp-navy);
    pointer-events: none;
}

.system-map__legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin: var(--space-3) 0;
    font-size: var(--text-sm);
}

.system-map__legend-item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}

.system-map__legend-swatch {
    display: inline-block;
    width: 24px;
    height: 0;
    border-top-width: 3px;
    border-top-style: solid;
}

.system-map__panel {
    display: none;
    margin-top: var(--space-4);
}

.system-map__panel.is-active {
    display: block;
}
