body {
    background-color: rgb(244, 242, 240);
}

.bg-light-gray {
    background-color: #d5d6da;
}

.slide-in-left {
    /* Make sure the element is initially off-screen to the left */
    transform: translateX(-100%);
    opacity: 0;
    animation: slideInFromLeft 0.8s ease-out forwards;
    /* Adjust speed and easing as desired */
}
/* Define the keyframes for sliding in from the left */
@keyframes slideInFromLeft {
    0% {
        transform: translateX(-100%);
        opacity: 0;
    }

    100% {
        transform: translateX(0);
        opacity: 1;
    }
}

.set-up-container {
    max-width: 696px;
}
.set-up-container-lg {
    max-width: 864px;
}
.feature-standout {
    background: linear-gradient(180deg, #f0f5fb 0%, #e4ecf5 100%);
    border: 1px solid #e2edff;
    border-radius: 2em;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
    max-width: 720px;
    margin: 0 auto;
}

.btn-ai {
    background: linear-gradient(135deg, #12306b 0%, #1e4ba0 50%, #2768e0 100%);
    color: #fff;
    font-weight: 500;
    border: none;
    border-radius: 0.5rem;
    box-shadow:
        inset 0 1px 1px rgba(255, 255, 255, 0.12),
        0 2px 6px rgba(20, 40, 100, 0.35);
}
.btn-ai:hover {
    background: linear-gradient(135deg, #16408a 0%, #2560cc 50%, #2e7aff 100%);
    box-shadow:
        0 3px 8px rgba(30, 60, 150, 0.45),
        inset 0 0 3px rgba(255, 255, 255, 0.2);
    color: #fff; /* ensure readability */
}

.btn-ai:active {
    background: linear-gradient(135deg, #0f2970 0%, #1c4fab 60%, #2560cc 100%);
    box-shadow: 0 2px 4px rgba(20, 40, 90, 0.3);
    color: #fff;
}

.btn-ai:focus-visible {
    outline: 2px solid #2e7aff;
    outline-offset: 2px;
}


/* Drag & drop area styling */
.drop-area {
    /* The zone is a <label for=its-file-input> (keyboard operability):
       labels default to inline, so pin the block box the padding assumes. */
    display: block;
    transition: all 0.3s ease;
    background-color: #fff;
    border: 2px dashed #6c757d;
    cursor: pointer;
}
.drop-area.dragover {
    border-color: #0d6efd;
    background-color: #f8f9fa;
}
/* Keyboard focus ring: the zone's visually-hidden file input is its
   IMMEDIATE next sibling (a template invariant, test-locked) -- ring the
   zone when the input has keyboard focus. */
.drop-area:has(+ input:focus-visible) {
    outline: 2px solid #0d6efd;
    outline-offset: 2px;
}
/* The same law on a button-shaped zone (the "Replace file" buttons): the
   file input lives INSIDE its label, so this matches a CHILD (`>`) where
   the zone rule above matches a SIBLING (`+`). Both depend on the input
   being visually-hidden rather than hidden/d-none -- only a focusable
   input can carry the keyboard focus this ring draws. */
label.btn:has(> input:focus-visible) {
    outline: 2px solid #0d6efd;
    outline-offset: 2px;
}


.table-scroll {
    min-height: 24rem;
    max-height: 40rem;
    overflow-y: auto;
}

.table-scroll thead th {
    position: sticky;
    top: 0;
    z-index: 1;      /* stay above body cells */
    background: #212529;  /* match .table-dark background */
    color: #fff;          /* match .table-dark text */
}


/* === Section Status Spinner Animation === */
@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

.spin {
    display: inline-block;
    animation: spin 1s linear infinite;
}

/* Status icon colors for section processing indicators */
.section-status-fin { color: #198754; }  /* Bootstrap success green */
.section-status-err { color: #dc3545; }  /* Bootstrap danger red */
.section-status-pro { color: #0d6efd; }  /* Bootstrap primary blue */

/* Accessibility: respect reduced motion */
@media (prefers-reduced-motion: reduce) {
    .spin {
        animation: none;
    }
}


/* ===================================================================
   Landing Page — "Dark Stage"
   Monochrome, neutral palette: charcoal, slate, white, black.
   =================================================================== */

.landing-page {
    min-height: 100vh;
    background:
        /* subtle radial spotlight behind content */
        radial-gradient(ellipse 60% 50% at 50% 45%, rgba(255,255,255,0.04) 0%, transparent 70%),
        /* main gradient */
        linear-gradient(160deg, #111 0%, #1a1a1a 40%, #0e0e0e 100%);
    /* override default body bg for this full-bleed section */
    margin-top: -1px;
}

/* Brand name */
.landing-brand {
    font-size: clamp(3rem, 8vw, 5.5rem);
    font-weight: 300;
    letter-spacing: 0.1em;
    color: #fff;
    background: linear-gradient(180deg, #ffffff 20%, #b0b0b0 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    opacity: 0;
    animation: landingFadeUp 0.9s cubic-bezier(0.23, 1, 0.32, 1) forwards;
}

/* Horizontal accent rule */
.landing-accent {
    width: 0;
    height: 2px;
    margin: 1.5rem auto 1.8rem;
    background: linear-gradient(90deg, transparent, #999, transparent);
    border-radius: 1px;
    animation: landingLineExpand 0.7s 0.5s cubic-bezier(0.23, 1, 0.32, 1) forwards;
}

/* Tagline */
.landing-tagline {
    font-size: clamp(1.4rem, 2.75vw, 1.6rem);
    font-weight: 400;
    letter-spacing: 0.02em;
    color: rgba(255,255,255,0.5);
    max-width: 600px;
    margin: 0 auto 2.5rem;
    opacity: 0;
    animation: landingFadeUp 0.7s 0.8s cubic-bezier(0.23, 1, 0.32, 1) forwards;
}

/* CTA button */
.landing-cta {
    opacity: 0;
    animation: landingFadeUp 0.7s 1.1s cubic-bezier(0.23, 1, 0.32, 1) forwards;
    border-width: 2px;
    padding: 0.7rem 2.5rem;
    letter-spacing: 0.03em;
    transition: background-color 0.25s, color 0.25s, transform 0.2s;
}

.landing-cta:hover {
    background-color: #fff;
    color: #111;
    transform: translateY(-1px);
}

.landing-cta:active {
    transform: translateY(0);
}

/* Keyframes */
@keyframes landingFadeUp {
    from {
        opacity: 0;
        transform: translateY(24px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes landingLineExpand {
    from {
        width: 0;
        opacity: 0;
    }
    to {
        width: 80px;
        opacity: 1;
    }
}

/* Reduced motion: show everything immediately, no animation */
@media (prefers-reduced-motion: reduce) {
    .landing-brand,
    .landing-tagline,
    .landing-cta {
        opacity: 1;
        animation: none;
        transform: none;
    }
    .landing-accent {
        width: 80px;
        opacity: 1;
        animation: none;
    }
}


/* ===================================================================
   Login page — dark background matching landing page
   =================================================================== */
.login-page {
    min-height: 100vh;
    background:
        radial-gradient(ellipse 60% 50% at 50% 45%, rgba(255,255,255,0.04) 0%, transparent 70%),
        linear-gradient(160deg, #111 0%, #1a1a1a 40%, #0e0e0e 100%);
    margin-top: -1px;
}

/* Auth pages fill the viewport WITHOUT overflowing it. The bare 100vh above
   overflows by the header's height on authenticated pages (change password,
   etc.) -- the body becomes a column and the dark section takes the
   REMAINING height instead: exact on the header-less login page, exact under
   the header when logged in. Non-:has browsers fall back to the 100vh rule
   (today's minor scroll), never anything worse. */
body:has(> .login-page) {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

body:has(> .login-page) .login-page {
    flex: 1 1 auto;
    min-height: 0;  /* replaces the 100vh that overflowed under the header */
}

/* Card refinement */
.login-page .card {
    background-color: #faf9f8;
    border: none;
    box-shadow: 0 8px 32px rgba(0,0,0,0.25);
    padding: 2rem 2.2rem;
}

.login-page .card h1 {
    font-weight: 300;
    letter-spacing: 0.04em;
    color: #2a2a2a;
    margin-bottom: 0.6rem;
}

.login-page .login-divider {
    border: none;
    height: 1px;
    background: #a19e9e;
    margin: 0 0 1.8rem;
    opacity: 0.75;
}

.login-page .card .form-label {
    font-size: 0.9rem;
    font-weight: 500;
    color: #555;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    margin-bottom: 0.4rem;
}

.login-page .card .mb-3 {
    margin-bottom: 1.25rem !important;
}

.login-page .card .form-control {
    background-color: #fff;
    border: 1px solid #ddd;
    border-radius: 0.4rem;
    padding: 0.6rem 0.8rem;
    transition: border-color 0.2s, box-shadow 0.2s;
}

.login-page .card .form-control:focus {
    border-color: #999;
    box-shadow: 0 0 0 3px rgba(0,0,0,0.05);
}

.login-page .card .btn-primary {
    background-color: #222;
    border-color: #222;
    font-weight: 500;
    letter-spacing: 0.03em;
    padding: 0.6rem;
    border-radius: 0.4rem;
    transition: background-color 0.2s, transform 0.15s;
}

.login-page .card .btn-primary:hover {
    background-color: #333;
    border-color: #333;
    transform: translateY(-1px);
}

.login-page .card .btn-primary:active {
    transform: translateY(0);
}

/* ---------------------------------------------------------------
   Press-down phase choice (used on deal_create form)
   Native <input type="radio"> visually hidden; the adjacent
   <label class="phase-card"> becomes the big pressable button.
   Uses a softer charcoal (--phase-card-pressed) to distinguish from
   the harder bs-dark used for page headers and primary buttons.
   --------------------------------------------------------------- */
.phase-choice {
    --phase-card-pressed: #465568;
    --phase-card-muted-pressed: #899bb1;
}

.phase-choice input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.phase-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0.4rem;
    padding: 1.5rem 1rem;
    border: 2px solid var(--bs-border-color);
    border-radius: 0.75rem;
    cursor: pointer;
    transition: all 0.12s ease-in-out;
}

.phase-card i {
    font-size: 2rem;
}

.phase-card:hover {
    border-color: var(--phase-card-pressed);
}

.phase-choice input[type="radio"]:checked + .phase-card {
    border-color: var(--phase-card-pressed);
    background-color: var(--phase-card-pressed);
    color: #fff;
    transform: translateY(2px);
    box-shadow: inset 0 0.25rem 0.5rem rgba(0, 0, 0, 0.25);
}

.phase-choice input[type="radio"]:checked + .phase-card small {
    color: rgba(255, 255, 255, 0.8) !important;
}

.phase-choice input[type="radio"]:focus-visible + .phase-card {
    outline: 2px solid var(--bs-primary);
    outline-offset: 2px;
}

/* Secondary / "unknown" variant — a slim horizontal card used beneath the
   primary two-option row to allow an explicit blank/unknown choice. */
.phase-card-muted {
    flex-direction: row;
    justify-content: center;
    padding: 0.75rem 1rem;
    border-style: dashed;
    color: var(--phase-card-muted-pressed);
    font-size: 0.95rem;
}
.phase-card-muted i {
    font-size: 1.1rem;
}

/* Override the default dark press-down state for the muted variant: when
   "Unknown" is checked, keep it grey rather than black-filled. */
.phase-choice input[type="radio"]:checked + .phase-card-muted {
    border-color: var(--bs-secondary);
    background-color: var(--bs-secondary);
    color: #fff;
}
.phase-card-muted i {
    font-size: 1.1rem;
}

/* =========================================================
   Deal-list page (PHASE_PLAN Step 6)
   Typographic, de-chromed, lines-not-boxes design language —
   matches the workflow nav reference.
   ========================================================= */

/* The rule under the site header spans the full window, matching the shell
   headers and the Guide. */
body.deal-list-page > header {
    border-bottom: 1px solid var(--bs-border-color);
}

/* Search input with leading icon, no input-group container. */
.deal-list-search {
    position: relative;
}
/* Leading magnifying glass — a real <button type="submit"> so clicking
   the icon submits the form. Visually identical to the previous decorative
   <i>, but discoverable + keyboard-accessible. */
.deal-list-search > .deal-list-search-icon {
    position: absolute;
    top: 50%;
    left: 0.5rem;
    transform: translateY(-50%);
    background: transparent;
    border: 0;
    padding: 0.25rem 0.5rem;
    color: var(--bs-secondary);
    line-height: 1;
    cursor: pointer;
    border-radius: 0.25rem;
    transition: color 0.15s ease, background-color 0.15s ease;
}
.deal-list-search > .deal-list-search-icon:hover,
.deal-list-search > .deal-list-search-icon:focus-visible {
    color: var(--bs-dark);
    background-color: rgba(0, 0, 0, 0.04);
}

.deal-list-search > input {
    padding-left: 2.25rem;
    padding-right: 2.25rem;
    background-color: #fff;
}
.deal-list-search > input:focus {
    border-color: var(--bs-dark);
    box-shadow: 0 0 0 0.15rem rgba(33, 37, 41, 0.1);
}
/* Hide the browser's native X clear button — we render our own that
   stays visible whenever the field has content (vs. only on focus/hover). */
.deal-list-search > input::-webkit-search-cancel-button,
.deal-list-search > input::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance: none;
}
/* Custom X clear button: hidden when the input is empty (placeholder
   visible), shown the moment the user types anything. CSS-only — the
   <button> always exists in the DOM; we just toggle its display. */
.deal-list-search > .deal-list-search-clear {
    position: absolute;
    top: 50%;
    right: 0.5rem;
    transform: translateY(-50%);
    background: transparent;
    border: 0;
    padding: 0.25rem 0.5rem;
    color: var(--bs-secondary);
    line-height: 1;
    cursor: pointer;
    border-radius: 0.25rem;
    transition: color 0.15s ease, background-color 0.15s ease;
}
.deal-list-search > .deal-list-search-clear:hover,
.deal-list-search > .deal-list-search-clear:focus-visible {
    color: var(--bs-dark);
    background-color: rgba(0, 0, 0, 0.04);
}
.deal-list-search > input:placeholder-shown ~ .deal-list-search-clear {
    display: none;
}


/* Sort select: bare, with leading icon. */
.deal-list-sort {
    position: relative;
}
.deal-list-sort > .bi {
    position: absolute;
    top: 50%;
    left: 0.625rem;
    transform: translateY(-50%);
    color: var(--bs-secondary);
    pointer-events: none;
    font-size: 0.875rem;
}
.deal-list-sort > select {
    padding-left: 2rem;
    background-color: #fff;
}

/* Scope toggle: text-style, mirrors workflow-nav pattern.
   Two adjacent submit-buttons rendered as plain text — the active one
   gets the same underline-on-active treatment as the workflow nav. */
.deal-list-scope {
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    font-size: 0.9375rem;
}
.deal-list-scope > .scope-label {
    color: var(--bs-secondary);
    font-size: 0.8125rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.deal-list-scope button {
    background: transparent;
    border: 0;
    padding: 0.25rem 0;
    color: var(--bs-secondary);
    line-height: 1.25;
    transition: color 0.15s ease, box-shadow 0.15s ease;
}
.deal-list-scope button:hover,
.deal-list-scope button:focus-visible {
    color: var(--bs-dark);
}
.deal-list-scope button.active {
    color: var(--bs-dark);
    font-weight: 600;
    box-shadow: inset 0 -2px 0 0 var(--bs-dark);
}
.deal-list-scope .scope-divider {
    color: var(--bs-secondary);
    opacity: 0.35;
    font-size: 0.75rem;
}

/* Panel heading: small uppercase typographic label, no box. */
.deal-list-panel-heading {
    font-size: 0.875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--bs-secondary);
    margin: 0;
}
.deal-list-panel-count {
    font-size: 0.8125rem;
    color: var(--bs-secondary);
    opacity: 0.7;
}

/* Subtle hover lift on deal cards — keep the only "boxes" on the page
   feeling alive without adding visual weight. */
.deal-card {
    border: 1px solid rgba(0, 0, 0, 0.075);
    transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.deal-card:hover {
    border-color: rgba(0, 0, 0, 0.2);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
}


/* =========================================================
   Deal/Policy sidebar shell (full-width, phase-agnostic).
   Bounded app-style layout: the deal page fills the viewport
   (body becomes a flex column), the global navbar + shell header
   stay put, and the sidebar + main pane each scroll independently
   — the window itself does not scroll. Calm, lines-not-boxes
   active state (dark left border).
   ========================================================= */
:root {
    --deal-sidebar-w: 248px;
    --deal-header-h: 56px;
}

/* Deal pages opt into a full-height flex column so the MAIN PANE (not the
   window) owns the vertical scroll. Scoped via the body class so every other
   page keeps normal document flow. The global navbar is flex:none above it. */
body.deal-shell-page,
body.settings-shell-page {
    height: 100vh;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
body.deal-shell-page > .deal-shell,
body.settings-shell-page > .settings-shell {
    flex: 1 1 auto;
    min-height: 0;
}

.deal-shell,
.settings-shell {
    display: flex;
    flex-direction: column;
}

.deal-shell__header,
.settings-shell__header {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.5rem 1rem;
    min-height: var(--deal-header-h);
    background: #fff;
    border-top: 1px solid var(--bs-border-color);
    border-bottom: 1px solid var(--bs-border-color);
}

.deal-shell__title,
.settings-shell__title {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    font-size: 1.25rem;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.deal-shell__body,
.settings-shell__body {
    flex: 1 1 auto;
    min-height: 0;
    display: grid;
    grid-template-columns: 1fr;
}

/* The main pane owns the vertical scroll; min-width:0 keeps wide children
   (e.g. the NBI pricing matrix) scrolling inside the column instead of
   blowing the page out sideways. */
.deal-shell__main,
.settings-shell__main {
    overflow-y: auto;
    min-height: 0;
    min-width: 0;
    padding: 1rem 1.25rem 2rem;
    background-color: #faf9f7;
}

@media (min-width: 992px) {
    .deal-shell__body,
    .settings-shell__body {
        grid-template-columns: var(--deal-sidebar-w) 1fr;
    }
    /* Sidebar scrolls independently of the main pane. */
    .deal-shell__sidebar,
    .settings-shell__sidebar {
        overflow-y: auto;
        min-height: 0;
        background: #fff;
        border-right: 1px solid var(--bs-border-color);
    }
}

.deal-nav,
.settings-nav {
    padding: 0.5rem 0 2rem;
}
.deal-nav__group,
.settings-nav__group {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: 600;
    color: var(--bs-secondary);
    padding: 0.85rem 0.9rem 0.3rem;
}
.deal-nav__link,
.settings-nav__link {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.4rem 0.9rem;
    color: var(--bs-body-color);
    text-decoration: none;
    border-left: 3px solid transparent;
    font-size: 0.9rem;
}
.deal-nav__link:hover,
.settings-nav__link:hover {
    background: var(--bs-light);
}
.deal-nav__link.active,
.settings-nav__link.active {
    background: var(--bs-light);
    border-left-color: var(--bs-dark);
    color: var(--bs-dark);
    font-weight: 600;
}
.deal-nav__link.disabled {
    color: var(--bs-secondary);
    opacity: 0.55;
    cursor: default;
    pointer-events: none;
}

/* ---- Collapsible nav rail (PLAN_D shell follow-up, owner-ruled) ----------
   The shell nav collapses to an icons-only 56px rail — normally driven
   RECIPROCALLY by the editor's Placeholders panel (open panel = railed nav),
   with the chevron as a manual page-view override (shell_nav.js).
   ⚠️ Desktop-only BY CONSTRUCTION: below lg the sidebar is a Bootstrap
   offcanvas drawer (burger-opened) that must keep its full-label layout, so
   EVERY rail rule lives inside this media query — never move one out. */
@media (min-width: 992px) {
    .deal-shell__body.nav-railed,
    .settings-shell__body.nav-railed {
        grid-template-columns: 64px 1fr;
    }
    /* The nav scrolls, and an unmanaged scrollbar eats the column's right
       side — the centred icons then visually hug the LEFT edge. A thin
       scrollbar + symmetric reserved gutters keeps the icons truly centred
       with equal air on both sides (degrades harmlessly where
       scrollbar-gutter is unsupported). */
    .nav-railed .deal-shell__sidebar,
    .nav-railed .settings-shell__sidebar {
        scrollbar-width: thin;
        scrollbar-gutter: stable both-edges;
    }
    /* Labels are bare text nodes beside the icon, so font-size:0 hides them
       and the icon restores its own size. position:relative anchors the AI
       cue overlay below. */
    .nav-railed .deal-nav__link,
    .nav-railed .settings-nav__link {
        font-size: 0;
        justify-content: center;
        padding: 0.5rem 0;
        position: relative;
        /* NO edge indicator in the rail — the 3px active border is an
           expanded-nav affordance; jammed beside a centred icon it reads as
           a stray bar. Active state = the background tint alone here. */
        border-left: 0;
    }
    .nav-railed .deal-nav__link > .bi,
    .nav-railed .settings-nav__link > .bi {
        font-size: 1.05rem;
    }
    .nav-railed .deal-nav__group,
    .nav-railed .settings-nav__group {
        font-size: 0;
        padding: 0;
        margin: 0.5rem 0.7rem 0;
        border-top: 1px solid var(--bs-border-color);
    }
    /* AI cues survive the rail as the item ICON's colour: the state dot is
       hidden and the link's own icon takes the dot's colour (error red,
       review amber -- the same classes the dot wears), while the running
       spinner and the AI Hub count keep the icon's top-right corner (a colour
       can show neither motion nor a number). The cue span is stretched over
       the whole link, so a hover anywhere on the icon reads the cue's hint
       ("Warranties - Needs your decision"); a cue-less span has no title and
       the link's own name shows. The count badge needs an explicit font-size
       (Bootstrap's .badge is em-based and the railed link is font-size 0). */
    .nav-railed .nav-cue {
        position: absolute;
        inset: 0;
        margin-left: 0;
        padding: 0.1rem 0.4rem 0 0;
        justify-content: flex-end;
        align-items: flex-start;
    }
    .nav-railed .nav-cue .nav-badge {
        font-size: 0.6rem;
    }
    .nav-railed .nav-cue .nav-dot:not(.nav-dot--spin) {
        display: none;
    }
    .nav-railed .deal-nav__link:has(.section-status-err) > .bi {
        color: var(--bs-danger);
    }
    .nav-railed .deal-nav__link:has(.text-attention) > .bi {
        color: #9a6700;
    }
}

/* Insurer Settings: comfortable reading width for single-column form / upload /
   review surfaces inside the full-width shell (tab-list tables stay full width). */
.settings-pane { max-width: 52rem; }


/* =========================================================
   Component schedules. A calm, scannable table: each row IS one
   schedule line. Rows are click-to-edit; the row's own buttons
   (Ignore, delete, the Auto-matched tick) are the only interactive
   islands. Styling is deliberately understated —
   no loud fills, custom pills rather than stock Bootstrap buttons.
   ========================================================= */
.comp-actions .btn { font-weight: 500; }

.comp-table thead th {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--bs-secondary);
    border-bottom-width: 2px;
}
.comp-offer { max-width: 34rem; }

/* Click-to-edit rows. */
.comp-row { cursor: pointer; }
.comp-row:hover { background: var(--bs-tertiary-bg, #f6f8fa); }
.comp-row .comp-interactive { cursor: default; }

/* Toggle pills: outline = off (empty circle + label), filled = on (check
   circle + SAME label). Consistent both ways. */
.comp-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 1;
    padding: 0.32rem 0.72rem;
    border-radius: 2rem;
    border: 1.5px solid;
    background: transparent;
    transition: background-color 0.12s, color 0.12s, border-color 0.12s;
}

/* Industry auto-apply pills (Insurer Settings template modals): every
   industry is a real checkbox (.btn-check, hidden by Bootstrap) whose label
   wears the toggle-pill idiom above, in neutral dark -- outline + empty
   circle off, filled + check circle on. :checked drives it, no JS. The
   standard switch locks the group by disabling the inputs (modal_shell.js). */
.apply-block { border: 1px solid var(--bs-border-color); border-radius: 0.6rem; padding: 0.9rem 1rem; }
.apply-block__legend {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--bs-secondary);
    margin-bottom: 0.4rem;
}
.industry-pills { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.comp-toggle--industry { color: #495057; border-color: #cfd4da; cursor: pointer; margin: 0; }
.comp-toggle--industry:hover { border-color: #212529; color: #212529; }
.btn-check:checked + .comp-toggle--industry { background: #212529; border-color: #212529; color: #fff; }
.comp-toggle--industry .bi-check-circle-fill { display: none; }
.btn-check:checked + .comp-toggle--industry .bi-circle { display: none; }
.btn-check:checked + .comp-toggle--industry .bi-check-circle-fill { display: inline; }
.btn-check:focus-visible + .comp-toggle--industry { outline: 2px solid #86b7fe; outline-offset: 1px; }
.btn-check:disabled + .comp-toggle--industry { pointer-events: none; }

/* The app modal refusing to dismiss a dirty form (modal_shell.js): the
   footer buttons pulse once, the way a static backdrop shakes, beside the
   footer hint that says why. */
@keyframes guard-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
.guard-pulse { animation: guard-pulse 0.35s ease; }

/* Row tags: matched (resolved) vs needs-attention (broker ask, no wording). */
.comp-tag {
    display: inline-flex;
    align-items: center;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 0.1rem 0.5rem;
    border-radius: 0.35rem;
    margin-top: 0.2rem;
}
.comp-tag--matched { color: #1d7a4d; background: #e7f4ec; }
.comp-tag--attention { color: #9a6700; background: #fdf3d7; }

/* AI Hub: amber attention icon (matches comp-tag--attention text). */
.text-attention { color: #9a6700; }

/* AI status cues in the deal nav (Job 4). Right-aligned so the labels stay
   flush left. Colour never carries the meaning alone: the error state has its
   own glyph, and every cue has a visually-hidden label for screen readers.
   Kept deliberately small and quiet -- the AI Hub is where the detail lives. */
/* Cue wrapper: one stable-id target per nav item, right-aligned. It carries
   the auto margin (not the dot/badge inside) so the OOB re-swap can replace its
   contents -- or leave it empty on a quiet item -- without shifting layout. */
.nav-cue {
    margin-left: auto;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
}
.nav-dot {
    font-size: 0.5rem;
}
.nav-dot--spin {
    width: 0.6rem;
    height: 0.6rem;
    border-width: 0.12em;
}

/* AI Hub review surfaces (Job 4): calm accept/reject pills (comp-toggle
   family) + dynamic Back. Rejected rows dim their content cells. */
.review-surface { max-width: 62rem; }
.rev-back { display: inline-flex; align-items: center; font-size: 0.85rem; text-decoration: none; color: var(--bs-secondary); }
.rev-back:hover { color: var(--bs-dark); }
.comp-toggle--acc { color: #1d7a4d; border-color: #bfe2cd; }
.comp-toggle--acc.is-on { background: #1d7a4d; border-color: #1d7a4d; color: #fff; }
.comp-toggle--rej { color: #b02a37; border-color: #f0c2c7; }
.comp-toggle--rej.is-on { background: #b02a37; border-color: #b02a37; color: #fff; }
.rev-row.rejected .rev-content { opacity: 0.45; }

/* Deal-details review only. Two things that surface nowhere else: the field
   table groups its rows under headings (Buyer / Seller / Target ...) as
   colgroup rows, and every row carries a source-document chip whose text is
   arbitrary. The chip is BOUNDED and ellipsised -- an unbounded chip is what
   used to widen the table past its card. */
.rev-group-row th {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
    color: var(--bs-secondary);
    background: var(--bs-tertiary-bg, #f6f8fa);
    padding-top: 0.4rem;
    padding-bottom: 0.4rem;
}
.rev-source__doc {
    display: inline-block;
    max-width: 7.5rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: middle;
    font-weight: 500;
}

/* AI Hub Needs-you list: like dash-list but WITHOUT forcing anchor colour,
   so the primary "Review" action button keeps its white btn text. */
.hub-list { list-style: none; margin: 0; padding: 0; }
.hub-list li { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; padding: 0.5rem 0; font-size: 0.9rem; }
.hub-list li + li { border-top: 1px solid var(--bs-border-color); }

/* Calm inline-edit fields on the review surfaces: read as text, reveal an
   editable border on hover/focus. Replaces the boxy form-control grid so the
   review reads like the schedules, not a spreadsheet. */
.rev-field { width: 100%; border: 1px solid transparent; background: transparent; border-radius: 0.35rem; padding: 0.3rem 0.45rem; font-size: 0.88rem; line-height: 1.4; color: var(--bs-body-color); transition: border-color 0.12s, background-color 0.12s; }
.rev-field:hover { border-color: var(--bs-border-color); background: #fff; }
.rev-field:focus { border-color: var(--bs-primary); background: #fff; outline: none; box-shadow: 0 0 0 0.15rem rgba(50, 87, 176, 0.12); }
textarea.rev-field { resize: none; }

/* Long-text fields (PLAN_C C3): prose fields ARE textareas, auto-growing to
   their content via CSS field-sizing — zero JS, no expand/collapse state.
   Non-supporting browsers keep a fixed rows=3 textarea (still better than a
   one-line box). */
.long-text-field {
    field-sizing: content;
    min-height: calc(1.5em + 0.75rem + 2px);   /* one input-row */
    max-height: 14rem;
    overflow-y: auto;
    resize: vertical;
}

/* Action chips. (The bulk bar + its NBI/POL chips were EXCISED —
   GROUP_B_PLAN_UPDATED U4; the chip base + --dark survive for the
   cover-period quick-resolve buttons and the NBI pull-notice styling.) */
.comp-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 1;
    padding: 0.32rem 0.72rem;
    border-radius: 2rem;
    border: 1.5px solid;
    background: transparent;
}
.comp-chip--dark { color: #fff; background: #212529; border-color: #212529; }
.comp-chip--dark:hover { background: #000; border-color: #000; color: #fff; }

/* Matching wait-gate (GROUP_B_MATCHING S2): amber strip while a match run is
   live; the schedule goes read-only (every .gate-dim affordance dims + dies
   under .is-gated; content stays readable). */
.wait-gate {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    background: #fdf3d7;
    border: 1px solid #f0dfae;
    color: #9a6700;
    border-radius: 0.5rem;
    padding: 0.65rem 1rem;
    margin-bottom: 1rem;
    font-size: 0.9rem;
    animation: gateIn 0.3s ease;
}
@keyframes gateIn {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: none; }
}
.wait-gate .spinner-border {
    width: 1rem;
    height: 1rem;
    border-width: 0.14em;
    flex-shrink: 0;
}
.is-gated .gate-dim { pointer-events: none; opacity: 0.55; transition: opacity 0.2s; }
.is-gated .comp-row { cursor: default; }

/* Matched-just-now flag (S5): soft purple pill + tiny acknowledge button. */
.auto-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.72rem;
    font-weight: 600;
    padding: 0.18rem 0.3rem 0.18rem 0.55rem;
    border-radius: 2rem;
    border: 1.5px solid #ddd0f0;
    background: #f3eefc;
    color: #6f42c1;
    margin-top: 0.2rem;
    margin-left: 0.25rem;
}
.auto-pill__ack {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.2rem;
    height: 1.2rem;
    border-radius: 50%;
    border: none;
    background: #e4d9f5;
    color: #6f42c1;
    font-size: 0.62rem;
    line-height: 1;
    padding: 0;
}
.auto-pill__ack:hover { background: #6f42c1; color: #fff; }

/* Auto-match summary line (derived live from the flagged rows). */
.match-summary {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.88rem;
    color: #6f42c1;
    background: #f8f5fd;
    border: 1px solid #e7ddf6;
    border-radius: 0.5rem;
    padding: 0.5rem 0.85rem;
    margin-bottom: 1rem;
    animation: gateIn 0.3s ease;
}

/* Modal match strip: a quiet bar under the header for individual matching. */
.comp-match-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem 1rem;
    background: var(--bs-tertiary-bg, #f6f8fa);
    border-bottom: 1px solid var(--bs-border-color);
}
.comp-match-bar select { max-width: 18rem; }
.comp-match-bar__hint { margin: 0; }

/* The enhancement modal has two sibling forms (match bar + edit form), so
   Bootstrap's .modal-dialog-scrollable flex chain can't drive the body scroll.
   Cap the edit body directly instead — header, match bar and footer stay put. */
#enhancementModal .modal-body {
    max-height: 60vh;
    overflow-y: auto;
}

/* Match sub-page: review table reads top-aligned (multi-line cells). */
.comp-match-table td { vertical-align: top; }
.comp-match-table .comp-preview { color: var(--bs-secondary); }

/* Modal layer sections: a tinted left-border per layer (NBI / bound). */
.comp-layer {
    border-left: 3px solid var(--bs-border-color);
    padding: 0.6rem 0 0.6rem 0.85rem;
}
.comp-layer__hdr {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
    color: var(--bs-secondary);
    margin-bottom: 0.4rem;
}
.comp-layer--nbi { border-left-color: var(--bs-primary); }
.comp-layer--pol { border-left-color: var(--bs-success); }

/* Dual-wording modals (Exclusion / Enhancement / Cover Period): the NBI layer's
   coloured bar + numbered header are a TWO-block distinguisher, so they appear
   only once the Policy block is revealed (the "differ" toggle is on). Until then
   the NBI wording is a plain field — no lone colour/number. Keyed off the POL
   block's [hidden] attr, which the toggle flips, so no extra JS. */
.comp-layer--gated.comp-layer--nbi { border-left: 0; padding: 0; }
.comp-layer--gated > .comp-layer__hdr { display: none; }
.modal-body:has(.comp-layer--pol:not([hidden])) .comp-layer--gated.comp-layer--nbi {
    border-left: 3px solid var(--bs-primary);
    padding: 0.6rem 0 0.6rem 0.85rem;
}
.modal-body:has(.comp-layer--pol:not([hidden])) .comp-layer--gated > .comp-layer__hdr {
    display: block;
}

/* Dynamic wording label (template dual-wording modals; built generically so the
   same markup can drive the deal modals on a later reverse-normalisation):
   "Default Wording" until the policy wording is decoupled (POL block revealed),
   then "Default NBI Wording". Same :has() condition as the gated bar above. */
.tpl-wording-label-nbi { display: none; }
.modal-body:has(.comp-layer--pol:not([hidden])) .tpl-wording-label-single { display: none; }
.modal-body:has(.comp-layer--pol:not([hidden])) .tpl-wording-label-nbi { display: inline; }


/* =========================================================
   Flash toasts (site-wide). Traditional Bootstrap colour
   toasts (text-bg-*) with a slightly elevated shadow as the
   only modern touch. Success/info auto-dismiss bottom-right;
   warning/error persist top-right.
   ========================================================= */
.wb-toast-top {
    top: 3.5rem;   /* clear the global navbar */
}

/* Empty corners never swallow clicks; the toast cards stay interactive. */
#wb-toasts-top,
#wb-toasts-bottom {
    pointer-events: none;
}
.wb-toast {
    pointer-events: auto;
    box-shadow: 0 0.5rem 1.25rem rgba(0, 0, 0, 0.18);
}

/* The one create-flow-exit landing toast: bigger, top-right (via the top
   container), a longer dwell than the standard success/info toast (which is
   unchanged). Autohide is per-toast, so it self-dismisses on its own timer
   while any warning/error neighbours persist. */
.wb-toast-landing {
    --bs-toast-max-width: 30rem;
}
.wb-toast-landing .toast-body {
    font-size: 1rem;
    padding: 1rem 1.1rem;
}

/* Django field errors (<ul class="errorlist">) — red text site-wide. Layout
   left as-is for now (may revisit). */
.errorlist {
    color: var(--bs-danger);
}


/* =========================================================
   Deal sub-navigation pills — calm, flat black/outline-black
   pills for intra-tab navigation (Details sub-tabs, Diligence
   DD selector, Warranties section selector). Active = filled
   dark; inactive = outline. No shadows, transforms or lift.
   ========================================================= */
.deal-subnav {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1.5rem;
    padding-left: 0;
    list-style: none;
}
.deal-subnav__link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0.9rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 2rem;
    color: var(--bs-secondary);
    background-color: transparent;
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 500;
}
.deal-subnav__link:hover {
    background-color: var(--bs-tertiary-bg, #f6f8fa);
    color: var(--bs-body-color);
}
.deal-subnav__link.active {
    background-color: var(--bs-dark);
    border-color: var(--bs-dark);
    color: #fff;
}
/* Badges inside an active (dark-filled) pill switch to an OUTLINE — transparent
   fill, keeping their own colour as the border + text (border follows the text
   colour via currentColor). Inactive pills keep them filled. */
.deal-subnav__link.active .badge {
    background-color: transparent !important;
    border: 1px solid currentColor;
}
.deal-subnav__link.active .badge.text-bg-primary { color: var(--bs-primary) !important; }
.deal-subnav__link.active .badge.text-bg-success { color: var(--bs-success) !important; }
.deal-subnav__link.active .badge.text-bg-danger { color: var(--bs-danger) !important; }
.deal-subnav__link.active .badge.text-bg-info { color: var(--bs-info) !important; }
.deal-subnav__link.active .badge.text-bg-warning { color: var(--bs-warning) !important; }
.deal-subnav__link.active .badge.text-bg-secondary { color: var(--bs-secondary) !important; }


/* =========================================================
   Deal Dashboard — calm, scannable at-a-glance status cards.
   Reuses the in-house palette (NBI #3257b0 / POL #1d7a4d / attention
   amber via .comp-tag--attention). Presence is success-check / blank
   only — never red for mere absence.
   ========================================================= */
/* Top status cards: 1 col (md and below) → 2 cols (lg) → 3 cols (xl+).
   ``align-items: stretch`` makes every card in a row share the tallest one's
   height; card content stays top-aligned via the card's own padding. */
.dash-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
    align-items: stretch;
}
@media (min-width: 992px) {
    .dash-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1200px) {
    .dash-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.dash-card {
    background: #fff;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.5rem;
    padding: 0.9rem 1.05rem 1rem;
}
/* The two lazy panels (AI tasks · Recent activity): side-by-side on lg+,
   stacked on md and below. */
.dash-panels {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
    align-items: start;
    margin-top: 1rem;
}
@media (min-width: 992px) {
    .dash-panels { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* The panels are top-aligned (a long activity feed must not stretch a one-line
   AI-tasks card), so give both a floor height to keep the row balanced. */
.dash-panels .dash-card { min-height: 10rem; }
.dash-seemore { justify-content: center !important; }
.dash-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.7rem;
}
.dash-card__title {
    font-size: 0.95rem;
    font-weight: 700;
    color: var(--bs-dark);
    text-decoration: none;
}
a.dash-card__title:hover { text-decoration: underline; }
.dash-count { font-size: 0.8rem; font-weight: 600; color: var(--bs-secondary); }
.dash-check { color: var(--bs-success); }
.dash-blank { color: var(--bs-secondary); opacity: 0.4; }
.dash-muted { opacity: 0.5; }

.dash-checklist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.45rem; }
.dash-checklist li { display: flex; align-items: center; gap: 0.5rem; }

.dash-list { list-style: none; margin: 0; padding: 0; }
.dash-list li {
    display: flex; align-items: center; justify-content: space-between;
    gap: 0.5rem; padding: 0.3rem 0; font-size: 0.85rem;
}
.dash-list li + li { border-top: 1px solid var(--bs-border-color); }
.dash-list a { text-decoration: none; color: var(--bs-body-color); }
.dash-list a:hover { text-decoration: underline; }
/* Per-document rows under a comparison line (one per DD report). */
.dash-list li.dash-list__sub { padding-left: 1.1rem; font-size: 0.8rem; }

.dash-progress { height: 0.4rem; background: var(--bs-light); border-radius: 1rem; overflow: hidden; margin-bottom: 0.7rem; }
.dash-progress__bar { height: 100%; background: var(--bs-dark); }

.dash-tabs { display: grid; grid-template-columns: 1fr 1fr; column-gap: 1rem; }
.dash-tab-row { display: flex; align-items: baseline; justify-content: space-between; gap: 0.4rem; font-size: 0.8rem; padding: 0.12rem 0; }
.dash-tab-row a { text-decoration: none; color: var(--bs-body-color); }
.dash-tab-row a:hover { text-decoration: underline; }
.dash-tab-count { color: var(--bs-secondary); }

.dash-pill { font-size: 0.72rem; font-weight: 600; padding: 0.05rem 0.45rem; border-radius: 1rem; margin-left: 0.25rem; }
.dash-pill--nbi { color: #3257b0; background: #eaf0fb; }
.dash-pill--pol { color: #1d7a4d; background: #e7f4ec; }

.dash-table { width: 100%; font-size: 0.85rem; }
.dash-table thead th {
    font-size: 0.66rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
    color: var(--bs-secondary);
    padding: 0 0.25rem 0.35rem;
    border: 0;
}
.dash-table td { padding: 0.32rem 0.25rem; border-top: 1px solid var(--bs-border-color); vertical-align: middle; }
.dash-table tr:first-child td { border-top: 0; }
.dash-table a { text-decoration: none; color: var(--bs-body-color); font-weight: 500; }
.dash-table a:hover { text-decoration: underline; }



/* =====================================================================
   UWQ surface (PLAN_I Slice 1 / I0) - tranche tabs + answer-state cells
   ===================================================================== */
/* Neutral category tag - metadata, never an action colour. */
.comp-tag--cat { color: #5a6472; background: #eef0f3; }
/* Tranche tabs - clean underline idiom, client-toggled. */
.uwq-tabs { border-bottom: 1px solid var(--bs-border-color); margin-bottom: 1rem; }
.uwq-tabs .nav-link { color: var(--bs-secondary); font-weight: 600; font-size: 0.9rem; border: 0; border-bottom: 3px solid transparent; border-radius: 0; padding: 0.5rem 0.25rem; margin-right: 1.5rem; background: transparent; }
.uwq-tabs .nav-link:hover { color: var(--bs-dark); }
.uwq-tabs .nav-link.active { color: var(--bs-dark); border-bottom-color: var(--bs-dark); background: transparent; }
.uwq-tabs .uwq-tabs__count { font-weight: 500; color: var(--bs-secondary); font-size: 0.8rem; margin-left: 0.3rem; }
/* The question column is the content - full text, readable measure. */
.uwq-question { max-width: 38rem; }
.uwq-response { max-width: 26rem; }

/* UWQ template picker: the list scrolls, header/footer stay put (PLAN_I I0 fix). */
.uwq-picker-list { max-height: 55vh; overflow-y: auto; }

/* Send-to-Client modal busy overlay (PLAN_I I2). The email dispatch is 0.5-5s;
   this covers the form with a spinner while it submits. Driven purely by the
   htmx-request class htmx adds to the form during the request - no JS. */
.uwq-send-busy {
  position: absolute; inset: 0; z-index: 5;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, 0.7);
  opacity: 0; visibility: hidden; transition: opacity 0.15s ease;
}
form.htmx-request .uwq-send-busy { opacity: 1; visibility: visible; }


/* =====================================================================
   Warranty tree row actions (PLAN_E2) - quiet icon buttons.
   Always visible, no chrome: icon-only in a muted colour, gaining a
   subtle tinted background on hover/focus as ordinary press feedback.
   The --light variant serves the dark section rows.
   ===================================================================== */
.wb-row-action {
    --bs-btn-color: var(--bs-secondary);
    --bs-btn-bg: transparent;
    --bs-btn-border-color: transparent;
    --bs-btn-hover-color: var(--bs-body-color);
    --bs-btn-hover-bg: rgba(var(--bs-dark-rgb), 0.08);
    --bs-btn-hover-border-color: transparent;
    --bs-btn-active-color: var(--bs-body-color);
    --bs-btn-active-bg: rgba(var(--bs-dark-rgb), 0.12);
    --bs-btn-active-border-color: transparent;
    --bs-btn-disabled-color: var(--bs-secondary);
    --bs-btn-disabled-bg: transparent;
    --bs-btn-disabled-border-color: transparent;
    line-height: 1;
}
.wb-row-action--light {
    --bs-btn-color: rgba(255, 255, 255, 0.75);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: rgba(255, 255, 255, 0.15);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: rgba(255, 255, 255, 0.2);
    --bs-btn-disabled-color: rgba(255, 255, 255, 0.55);
}
/* Utility borders (border-start/border-end) inside VARIANT rows blend into
   the variant background - the utilities draw in --bs-border-color, which is
   near-identical to .table-secondary's fill and stark white on the dark
   section row. Repoint them at the row's own table border colour, which
   Bootstrap derives per variant to contrast with that variant's background. */
.comp-table tr.table-secondary > .border-start,
.comp-table tr.table-secondary > .border-end,
.comp-table tr.table-dark > .border-start,
.comp-table tr.table-dark > .border-end {
    border-color: var(--bs-table-border-color) !important;
}
/* The tree indent guide. Depth comes from WarrantyBlock.visual_depth
   (headings are transparent - their immediate children render level with a
   section's own clauses); each FURTHER nesting level steps the line inward
   via --wb-indent, mirroring the text indent. */
.wb-indent {
    margin-left: var(--wb-indent, 0rem);
    padding-left: 1rem;
    border-left: 3px solid #dee2e6;
}
