/* ============================================================
   patchleaks-compat.css
   Bridges legacy class names used by the v1 codebase to the new
   v2 design tokens. Loaded AFTER patchleaks.css so it can win
   over base styles when needed. Keep small — every rule here
   represents a v1 -> v2 migration debt that should be removed
   once the corresponding template is fully migrated.

   Phase 0 baseline: passthrough only. Bridges will be added in
   later phases as concrete needs surface (analysis page diff
   classes, zeroday-results sidebar, etc.).
   ============================================================ */

/* --- v1 alert -> v2 flash (used until _flash_messages.html migrates) --- */
.alert.flash-v2-bridge {
    background: var(--panel);
    border: 1px solid var(--line);
    color: var(--ink);
    font-family: var(--mono);
    font-size: 12px;
    padding: 12px 14px;
}

/* --- highlight.js code blocks (used by analysis page) --- */
/* Keep highlight.js' github-dark theme intact, just frame it. */
pre code.hljs {
    background: var(--panel-2);
    border: 1px solid var(--line);
    border-radius: var(--r);
    font-family: var(--mono);
    font-size: 12px;
    line-height: 1.6;
}

/* --- diff classes used by static/js/analysis/analysis.js --- */
.diff-add { background: var(--ok-soft); }
.diff-remove { background: var(--sig-soft); }
.context-line { color: var(--dim); }
.ellipsis { color: var(--dim-2); font-style: italic; }

/* ============================================================
   v2 components NOT in the source styles.css that we still need
   for Phase 0 deliverables. Keep in compat (not patchleaks.css)
   so it stays a pristine port of src/styles.css.
   ============================================================ */

/* --- Flash messages (consumed by _flash_v2.html + flash.js) --- */
.flash-stack {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding-top: 16px;
    padding-bottom: 4px;
}
.flash-msg {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    border: 1px solid var(--line);
    background: var(--panel);
    color: var(--ink);
    font-family: var(--mono);
    font-size: 12px;
    padding: 10px 14px;
    border-left-width: 3px;
    transition: opacity 0.4s ease;
}
.flash-msg-text { flex: 1; line-height: 1.5; }
.flash-msg-close {
    background: transparent;
    border: 0;
    color: var(--dim);
    font-family: var(--mono);
    font-size: 16px;
    cursor: pointer;
    padding: 0 4px;
    line-height: 1;
}
.flash-msg-close:hover { color: var(--ink); }
.flash-msg.leaving { opacity: 0; }
.flash-info    { border-left-color: var(--ink-2); }
.flash-success { border-left-color: var(--ok); }
.flash-warning { border-left-color: var(--warn); }
.flash-danger,
.flash-error   { border-left-color: var(--sig); background: var(--sig-soft); }

/* --- Modal (consumed by modal.js) --- */
.modal-v2 {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}
.modal-v2[hidden] { display: none; }
.modal-v2-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}
.modal-v2-card {
    position: relative;
    z-index: 1;
    background: var(--panel);
    border: 1px solid var(--line);
    box-shadow: 0 24px 48px rgba(0, 0, 0, 0.5);
    max-width: min(720px, 100%);
    max-height: calc(100vh - 48px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.modal-v2-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 18px;
    border-bottom: 1px solid var(--line);
    font-family: var(--mono);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--dim);
}
.modal-v2-body {
    padding: 18px;
    overflow: auto;
}
.modal-v2-foot {
    padding: 12px 18px;
    border-top: 1px solid var(--line);
    display: flex;
    gap: 8px;
    justify-content: flex-end;
}

/* --- Tab panels (consumed by tabs.js) --- */
.tab-panel[hidden] { display: none; }

/* --- Force HTML5 [hidden] to win over flex/grid display rules ---
   The dropdown menus (.nav-menu) and scroll-story act frames /
   rail cards rely on the [hidden] attribute being honored even
   when the matching class sets display:flex or display:grid.   */
.nav-menu[hidden],
[data-pl-act-frame][hidden],
[data-pl-rail-chapter][hidden] { display: none !important; }

/* ============================================================
   Scroll-story landing page — Phase 1 layout fixes.
   The original src/styles.css used React + state-driven mounts;
   the vanilla port needs panels visible from chapter zero so the
   sticky stage is never empty. We override the act-frame grid to
   absolute-positioned overlays so all panels coexist.
   ============================================================ */

/* Canvas becomes an absolute-positioning context. */
.xs-canvas { position: relative; padding: 16px; }

/* Each act-frame fills the canvas (subtract the 16px padding). */
.xs-frame {
    position: absolute;
    inset: 16px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    height: auto;
    overflow: hidden;
}
.xs-frame > * { min-height: 0; }

/* Act I: code panel is the always-visible base. Commit/CVE/article
   overlay it as ribbons. We keep the code panel as flex:1 so it
   absorbs available space; commit pinned top, cve+article pinned
   bottom (dock-style) and only animate opacity in.            */
[data-pl-act-frame="I"] .xs-codewrap {
    flex: 1 1 auto;
    min-height: 200px;
    opacity: 1; /* always visible */
}
[data-pl-act-frame="I"] .xs-code {
    overflow: auto;
    max-height: none;
}
[data-pl-act-frame="I"] .xs-commit {
    flex: 0 0 auto;
}
/* Article and CVE are dockable rails that share bottom space with
   the code pane. They start opacity:0 transform:translateY but the
   layout slot is always reserved when they have .on so the code
   pane shrinks gracefully — when off, max-height collapses.   */
[data-pl-act-frame="I"] .xs-cve,
[data-pl-act-frame="I"] .xs-article {
    flex: 0 0 auto;
    max-height: 0;
    padding-top: 0;
    padding-bottom: 0;
    border-width: 0;
    transition: max-height .35s ease, opacity .35s ease,
                padding .35s ease, border-width .35s ease;
}
[data-pl-act-frame="I"] .xs-cve.on {
    max-height: 240px;
    padding: 12px 16px;
    border-width: 1px;
    opacity: 1;
    transform: none;
}
[data-pl-act-frame="I"] .xs-article.on {
    max-height: 320px;
    padding: 0;
    border-width: 1px;
    opacity: 1;
    transform: none;
}

/* Act II: 3-row grid so codebase tree, sink rules and tracer all
   coexist in the canvas. Iterations + candidates overlay below as
   they activate (max-height collapse like Act I dockables).   */
[data-pl-act-frame="II"] {
    display: grid;
    grid-template-rows: 1fr 1fr 1fr auto auto;
    gap: 8px;
    overflow: hidden;
}
[data-pl-act-frame="II"] .xs-tree,
[data-pl-act-frame="II"] .xs-sinks,
[data-pl-act-frame="II"] .xs-tracer {
    opacity: 1;     /* visible from chapter 6 onwards */
    transform: none;
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}
[data-pl-act-frame="II"] .xs-tree-body,
[data-pl-act-frame="II"] .xs-sinks-body,
[data-pl-act-frame="II"] .xs-tracer-body {
    overflow-y: auto;
    flex: 1 1 auto;
    min-height: 0;
    font-size: 10px;
}
[data-pl-act-frame="II"] .xs-tree-row,
[data-pl-act-frame="II"] .xs-sink,
[data-pl-act-frame="II"] .xs-trace-row {
    padding: 2px 12px;
}
[data-pl-act-frame="II"] .xs-tree-path { font-size: 10px; }
[data-pl-act-frame="II"] .xs-iters,
[data-pl-act-frame="II"] .xs-candboard {
    max-height: 0;
    overflow: hidden;
    padding-top: 0;
    padding-bottom: 0;
    border-width: 0;
    transition: max-height .35s ease, opacity .35s ease,
                padding .35s ease, border-width .35s ease;
}
[data-pl-act-frame="II"] .xs-iters.on {
    max-height: 320px;
    border-width: 1px;
    opacity: 1;
    transform: none;
}
[data-pl-act-frame="II"] .xs-candboard.on {
    max-height: 220px;
    border-width: 1px;
    opacity: 1;
    transform: none;
}
[data-pl-act-frame="II"] .xs-iter { padding: 6px 12px; }
[data-pl-act-frame="II"] .xs-iter-body { font-size: 10px; }
[data-pl-act-frame="II"] .xs-react-row {
    grid-template-columns: 130px 1fr 40px 80px;
    padding: 2px 10px;
    font-size: 9px;
}
[data-pl-act-frame="II"] .xs-react-body { font-size: 9.5px; }

/* Act III: lanes always populate the canvas; shipstrip + billboard
   dock at the bottom and animate in.                           */
[data-pl-act-frame="III"] {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
[data-pl-act-frame="III"] .xs-lanes { flex: 1 1 auto; }
[data-pl-act-frame="III"] .xs-shipstrip,
[data-pl-act-frame="III"] .xs-billboard {
    max-height: 0;
    overflow: hidden;
    border-width: 0;
    padding-top: 0;
    padding-bottom: 0;
    opacity: 0;
    transition: max-height .35s ease, opacity .35s ease,
                padding .35s ease, border-width .35s ease;
}
[data-pl-act-frame="III"] .xs-shipstrip.on {
    max-height: 80px;
    border-width: 1px;
    opacity: 1;
    transform: none;
}
[data-pl-act-frame="III"] .xs-billboard.on {
    max-height: 200px;
    border-width: 0;
    opacity: 1;
    padding: 12px 16px 0;
}

/* Article body — pre block sometimes adds whitespace from
   leading/trailing newlines. Reset margin so the typewriter
   text fills the panel edge-to-edge.                       */
.xs-article-body {
    margin: 0;
    padding: 10px 14px;
    height: 100%;
    overflow: auto;
}
.xs-article-body div { white-space: pre-wrap; }
.xs-article-body div[data-pl-article-line]:empty,
.xs-article-body div[data-pl-article-line][data-full=""] { min-height: 4px; }

/* Verdict-card confidence badge — large mono number, color tied to
   verdict (sig for TP exploitable, dim for FP defended).        */
.conf-badge {
    font-size: 13px;
    font-weight: 600;
    padding: 2px 8px;
    border: 1px solid currentColor;
    border-radius: 2px;
    transition: opacity .35s ease;
    opacity: 0;
}
.conf-badge.sig { color: var(--sig); background: var(--sig-soft); }
.conf-badge.dim { color: var(--dim); background: transparent; }
.xs-vcard.tp .conf-badge { color: var(--sig); }
.xs-vcard.fp .conf-badge { color: var(--dim); }
.xs-vcard {
    /* Ensure cards never translate horizontally (in-place reveal) */
    transform: none !important;
    opacity: 1;
}
.xs-vcard:not(.on) > .xs-vcard-foot,
.xs-vcard:not(.on) > .xs-vcard-reason { opacity: 0.15; }

/* Tablet / mobile fixes for the story canvas.
   Below 1100px the right rail is hidden by patchleaks-story.css —
   reduce code+article font sizes and tighten panel padding.    */
@media (max-width: 1100px) {
    .xs-canvas { padding: 10px; }
    .xs-frame  { inset: 10px; gap: 6px; }
    [data-pl-act-frame="II"] .xs-tree-body,
    [data-pl-act-frame="II"] .xs-sinks-body,
    [data-pl-act-frame="II"] .xs-tracer-body { font-size: 9.5px; }
}

/* ============================================================
   PatchLeaks logo system
   Mirrors /tmp/logo-extract/patchleaks/project/logo/canvas.jsx
   variant 02.d (on-dark) for the dark theme, with a parallel
   on-light treatment that shares shape language and identity
   colors. Block colors carry the diff signal (the patches
   themselves are the signal, not the glyphs):
     - back patch  = RED   (--logo-back)   carries MINUS  -> removed
     - front patch = GREEN (--logo-front)  carries PLUS   -> added
   Glyphs (+ and -) and the decorative dashed stitch border are
   neutral and theme-flip via --logo-fg (cream on dark, ink on
   light) to stay legible against either patch color.
   ============================================================ */

:root,
[data-theme="dark"] {
    --logo-back:   #c8372d;
    --logo-front:  #2e5244;
    --logo-fg:     #f1ede4;
    --logo-emph:   #7aa996;
    --logo-strike: #c8372d;
}
[data-theme="light"] {
    --logo-back:   #c8372d;
    --logo-front:  #2e5244;
    --logo-fg:     #1a1f1c;
    --logo-emph:   #2e5244;
    --logo-strike: #c8372d;
}

/* Lockup container — overrides .brand grid styles when used
   inside the topbar. Uses inline-flex so it sits naturally in
   any horizontal context (topbar grid cell, footer column,
   hero cell). */
.pl-logo {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    text-decoration: none;
    color: inherit;
    line-height: 1;
}
.pl-logo .pl-mark {
    display: block;
    flex-shrink: 0;
}

/* Wordmark — Fraunces serif with italic accent on "leaks".
   The "patch" half inherits --ink which already flips between
   themes (patchleaks.css line 7 dark / line 32 light), so the
   wordmark theme-flips automatically. The italic "leaks" stays
   red in both themes for brand recognition. */
.pl-wordmark {
    font-family: "Fraunces", Georgia, serif;
    font-weight: 500;
    letter-spacing: -0.025em;
    line-height: 1;
    color: var(--ink);
    white-space: nowrap;
    font-size: 17px;
    font-style: normal;
}
.pl-wordmark .leaks {
    color: #c8372d;
    font-style: italic;
    font-weight: 500;
}
.pl-wordmark--hero {
    font-size: clamp(48px, 7.5vw, 98px);
    letter-spacing: -0.03em;
}

/* Topbar version label — replaces the legacy .brand-sub. */
.pl-version {
    color: var(--dim);
    font-size: 10px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    margin-left: 4px;
    font-family: var(--mono);
}

/* The topbar grid (.topbar-inner) sets the brand cell to 220px
   with a right border and 56px height. The legacy .brand class
   provided that border + padding + border-right separator. We
   reproduce just enough so the lockup occupies the same cell
   without re-introducing the border/padding inside the lockup
   itself when used elsewhere. */
.topbar-inner > .pl-logo {
    padding: 0 20px;
    border-right: 1px solid var(--line);
    height: 100%;
    align-self: stretch;
}

/* Hero scaling — bigger mark + wordmark, stacked above tagline.
   The hero-cell already provides padding; .hero-brand stacks
   the lockup and tagline with breathing room above the §00
   marker that follows. */
.pl-logo--hero {
    align-items: flex-end;
    gap: 28px;
}
.pl-logo--hero .pl-mark {
    width: clamp(96px, 14vw, 180px);
    height: clamp(96px, 14vw, 180px);
}

.hero-brand {
    margin-bottom: 36px;
}
.hero-brand + div .mono {
    margin-top: 4px;
}

/* Footer brand wraps the lockup so we can adjust its baseline
   alignment in the footer column without leaking changes
   elsewhere. */
.footer-brand {
    margin-bottom: 14px;
    display: block;
}
.footer-brand .pl-logo {
    color: var(--ink);
}

/* Tagline — Fraunces, with the hand-drawn red strike SVG
   sitting absolutely over "story". The struck word is dim,
   the replacement "vulnerability" is italic + emph color. */
.pl-tagline {
    font-family: "Fraunces", Georgia, serif;
    font-weight: 500;
    font-size: clamp(16px, 1.6vw, 22px);
    line-height: 1.3;
    color: var(--ink);
    margin: 18px 0 0;
    display: flex;
    align-items: baseline;
    gap: 0.32em;
    flex-wrap: wrap;
    letter-spacing: -0.005em;
}
.pl-tagline .strike-wrap {
    position: relative;
    display: inline-block;
    padding: 0 0.12em;
    color: var(--dim);
}
.pl-tagline .strike-wrap .pl-strike {
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    width: 100%;
    height: 0.9em;
    transform: translateY(-40%);
    pointer-events: none;
    mix-blend-mode: multiply;
    overflow: visible;
}
.pl-tagline .vuln {
    color: var(--logo-emph);
    font-style: italic;
}

/* Mobile — shrink topbar lockup to fit the 48px topbar height,
   hide the version chip (matches legacy .brand-sub behavior). */
@media (max-width: 820px) {
    .topbar-inner > .pl-logo {
        padding: 0 14px;
        gap: 8px;
    }
    .topbar-inner > .pl-logo .pl-mark {
        width: 24px;
        height: 24px;
    }
    .pl-wordmark { font-size: 15px; }
    .pl-version { display: none; }

    .pl-logo--hero {
        gap: 18px;
        align-items: center;
    }
    .pl-logo--hero .pl-mark {
        width: 72px;
        height: 72px;
    }
    .pl-wordmark--hero {
        font-size: clamp(40px, 12vw, 64px);
    }
    .hero-brand { margin-bottom: 24px; }
    .pl-tagline {
        font-size: 15px;
        gap: 0.28em;
    }
}
