/*
 * kb-toc.css — knowledge base article section rail + Mermaid surface [19P-210]
 *
 * Visual parity with the in-report section nav
 * (modules/addons/vantage_reports/assets/vantage-report.css, the
 * "IN-REPORT SECTION NAV (PART 1, 2026-08-09)" block) without loading that
 * stylesheet on KB pages: vantage-report.css restyles an entire report
 * document and carries forced-dark tokens, so pulling it into the twenty-one
 * theme's KB page would restyle far more than the rail.
 *
 * Instead the same rules are re-declared here and the --vr-* tokens are
 * scoped to .kb-toc-shell, so nothing leaks into the rest of the theme.
 * Token values are copied verbatim from vantage-report.css's dark set,
 * keeping the audited WCAG 2.2 AA contrast pairings intact. See the palette
 * note below for why the dark set is pinned rather than media-gated.
 *
 * Revert: delete this file, templates/twenty-one/js/kb-toc.js, and the
 * 19P-210 block in templates/twenty-one/knowledgebasearticle.tpl.
 */

/* ==== Palette: ONE DARK SYSTEM, unconditionally ====
   Deliberately NOT gated on @media (prefers-color-scheme: dark). The WHMCS
   client-area shell is a single dark system regardless of OS preference
   (approved architecture 2026-08-05; see the "OPEN-DESIGN-PORT A" block in
   modules/addons/vantage_reports/assets/vantage-report.css, which pins the
   same values for the report surface for exactly this reason).

   Verified on the live portal 2026-08-10: <html data-theme="strategic">,
   body background rgb(10,10,15), while
   matchMedia('(prefers-color-scheme: dark)') was FALSE. An OS-preference
   media query therefore renders a white rail on a black page — which is
   what the first cut of this file did. Pinning the dark set is what makes
   the rail match its surroundings and match the report rail it mirrors.

   Values are the audited dark set from vantage-report.css (WCAG 2.2 AA
   contrast table at the top of that file). No new colours introduced. */
.kb-toc-shell {
    --vr-bg: #0a0a0f;
    --vr-bg-secondary: #12121a;
    --vr-bg-elevated: #1a1a25;
    --vr-text: #f0f0f0;
    --vr-text-secondary: #b7b7c2;
    --vr-border: #2a2a3a;
    --vr-accent: #f5c518;
    --vr-focus: #f5c518;
}

/* ---- shell: two-column at desktop, stacked below 901px (same breakpoint) ---- */
.kb-toc-shell {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
    align-items: start;
}
.kb-toc-content { min-width: 0; }

@media (min-width: 901px) {
    .kb-toc-shell {
        grid-template-columns: 260px minmax(0, 1fr);
    }

    /* ---- STICKY RAIL FIX (2026-08-10, follow-up to 19P-210) ----
       The rail already declared position:sticky when the TOC shipped, but it
       never actually pinned. Measured on the live portal via CDP:

         document.documentElement.scrollHeight === clientHeight  (1247 === 1247)

       The twenty-one client area does NOT scroll the document. The only real
       scroller is div.col-lg-8.col-xl-9.primary-content (overflow-y:auto,
       overflowing by 1489px on the test article).

       position:sticky resolves against the element's NEAREST scrollport
       ancestor. For the KB rail that was div.card-body, which the theme gives
       overflow-y:auto -- so it is a scrollport, but one that never scrolls
       (scrollHeight === clientHeight === 2243). Sticky therefore anchored to a
       box that never moves and the rail scrolled away with the article.
       Baseline measurement: scrolling .primary-content by 600px moved the rail
       by exactly 600px.

       Fix = stop .card-body creating that dead scrollport, but ONLY on pages
       that actually carry the KB TOC, so no other card in the portal changes.
       :has() scopes this precisely; where :has() is unsupported the rule is
       simply dropped and behaviour is exactly what it is today (no regression,
       progressive enhancement). With .card-body transparent, the rail's
       nearest scrollport becomes .primary-content -- the real scroller -- and
       the rail pins at (scrollport top + 16px).

       Verified after the fix: rail top held at y=99 across scrollTop 600 and
       1200, clearing the sticky breadcrumb (which ends at y=83) by 16px and
       never reaching the scroller's bottom edge.

       NOTE the report rail (.vr-detail-shell in vantage-report.css) does NOT
       need this: it sits directly in .primary-content with no .card-body
       between, so its anchor was already correct. */
    .card-body:has(.kb-toc-shell) {
        overflow: visible;
    }

    /* Selector carries .kb-toc as well as .vr-section-nav-rail purely to win
       on specificity (0,3,0) against `.kb-toc-shell .vr-lifecycle` below
       (0,2,0), which sets the `overflow` SHORTHAND to hidden for the rounded
       corners. Being later in the file, that shorthand was resetting this
       block's overflow-y back to hidden -- computed overflow-y measured as
       "hidden" on the live page despite the `auto` declared here. Harmless
       with 6 headings (rail 304px), but it would have clipped a long TOC with
       no way to reach the rest of it. overflow-x stays hidden so the corner
       clipping is preserved.

       max-height is measured against the scrollport, not the document: the
       scroller starts ~83px down and the footer takes the rest, so the usable
       column is roughly 100vh - 220px (1027px at the 1247px test viewport,
       inside the scroller's 1104px). The test article's 6 headings render a
       304px rail, so this only engages on unusually long articles. */
    .kb-toc-shell .vr-section-nav-rail.kb-toc {
        position: sticky;
        top: 16px;
        margin: 0;
        align-self: start;
        max-height: calc(100vh - 220px);
        overflow-y: auto;
        overflow-x: hidden;
    }
}

/* ---- rail container: .vr-lifecycle treatment ---- */
.kb-toc-shell .vr-lifecycle {
    margin: 0 0 28px;
    border: 1px solid var(--vr-border);
    border-radius: 10px;
    background: var(--vr-bg-elevated);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.16);
    overflow: hidden;
}
.kb-toc-shell .vr-section-nav-rail { margin: 0 0 28px; }

.kb-toc-shell .vr-lifecycle-top {
    display: flex;
    align-items: flex-start;
    flex-direction: column;
    gap: 4px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--vr-border);
    font-size: 12px;
    color: var(--vr-text-secondary);
}
.kb-toc-shell .vr-lifecycle-top strong { color: var(--vr-text); }
.kb-toc-shell .vr-lifecycle-progress {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .04em;
    color: var(--vr-accent);
}

/* ---- items: .vr-section-nav-item treatment ---- */
.kb-toc-shell .vr-section-nav {
    display: flex;
    flex-direction: column;
    overflow-x: visible;
}
.kb-toc-shell .vr-section-nav-item {
    position: relative;
    display: grid;
    grid-template-columns: 24px minmax(0, 1fr);
    align-items: center;
    gap: 8px;
    min-height: 40px;
    padding: 8px 10px 8px 12px;
    border-left: 3px solid transparent;
    color: var(--vr-text-secondary);
    text-decoration: none;
}
.kb-toc-shell .vr-section-nav-item:hover {
    padding-left: 14px;
    color: var(--vr-text);
    background: var(--vr-bg-secondary);
    text-decoration: none;
}
.kb-toc-shell .vr-section-nav-item.is-active-fragment,
.kb-toc-shell .vr-section-nav-item[aria-current="true"] {
    color: var(--vr-text);
    background: linear-gradient(90deg, color-mix(in srgb, var(--vr-accent) 15%, transparent), transparent);
    border-left-color: var(--vr-accent);
}
.kb-toc-shell .vr-section-nav-item:focus-visible {
    outline: 2px solid var(--vr-focus);
    outline-offset: -2px;
}

.kb-toc-shell .vr-lifecycle-step-num {
    width: 24px;
    height: 24px;
    display: grid;
    place-items: center;
    border: 1px solid var(--vr-border);
    border-radius: 999px;
    background: var(--vr-bg);
    color: var(--vr-text-secondary);
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 10px;
    font-weight: 700;
}
.kb-toc-shell .vr-section-nav-item[aria-current="true"] .vr-lifecycle-step-num {
    border-color: var(--vr-accent);
    color: var(--vr-accent);
}
.kb-toc-shell .vr-lifecycle-step-label {
    display: block;
    white-space: normal;
    font-size: 12px;
    font-weight: 650;
    letter-spacing: -.01em;
}

/* Heading depth: h2/h3 indent under h1, matching the report rail's
   group-label / item hierarchy without needing real groups. */
.kb-toc-shell .kb-toc-level-2 .vr-lifecycle-step-label { font-weight: 600; }
.kb-toc-shell .kb-toc-level-3 {
    padding-left: 26px;
}
.kb-toc-shell .kb-toc-level-3:hover { padding-left: 28px; }
.kb-toc-shell .kb-toc-level-3 .vr-lifecycle-step-label {
    font-weight: 500;
    font-size: 11.5px;
}

/* Anchor targets should not hide under any sticky header when jumped to. */
.card-body article :is(h1, h2, h3)[id] { scroll-margin-top: 80px; }

/* ---- Mermaid ----
   Pre-render (and on failure) the diagram stays a readable monospace source
   block. Once Mermaid has replaced the contents with an <svg>, the <pre>
   chrome (monospace font, background, border, scrollbars) is dropped so the
   diagram sits on the page cleanly. Keyed off Mermaid's own data-processed
   attribute so the two states can never disagree. */
.card-body article pre.mermaid {
    white-space: pre;
    overflow-x: auto;
}
.card-body article pre.mermaid[data-processed="true"] {
    background: none;
    border: none;
    padding: 0;
    margin: 1.25rem 0;
    overflow-x: auto;
    text-align: center;
    white-space: normal;
}
.card-body article pre.mermaid[data-processed="true"] svg {
    max-width: 100%;
    height: auto;
}
/* Failed parse: explicitly keep the source-text presentation. */
.card-body article pre.mermaid[data-vr-mermaid-error] {
    white-space: pre;
}
