:root {
    --ink: #151f1a;
    --muted: #6d7a73;
    --line: #dde6df;
    --panel: rgba(255, 255, 250, 0.9);
    --call: #1b9347;
    --call-soft: rgba(27, 147, 71, 0.14);
    --put: #d33b34;
    --put-soft: rgba(211, 59, 52, 0.14);
    --blue: #3976c9;
    --gold: #fff0bd;
    --orange: #f08a24;
    /* Pace "most active strike" accent (design/PACE-ENHANCEMENT-DESIGN.md §3.1). Electric violet —
       the one high-energy hue with no existing meaning here (green/red=direction, gold=volume,
       blue=VWAP, orange=warning). Applied to the pace sub-cell only, never the whole cell. */
    --pace: #8a6dff;
    --pace-rank1-text: #cabbff;
    --pace-rank1-glow: rgba(138, 109, 255, 0.55);
    --pace-rank2-bg: rgba(138, 109, 255, 0.16);
    --pace-rank3-line: rgba(138, 109, 255, 0.60);
    --pace-unconf: rgba(138, 109, 255, 0.60);
    --pace-converge-ring: var(--gold);
    --pace-ignite: var(--orange);
    --shadow: 0 24px 70px rgba(32, 44, 37, 0.14);
    /* Strike-intelligence action badge — COLOR = direction (green bullish / red bearish / amber pin),
       MOTION = verb (pulse = BUY, spin = SELL). */
    --action-buy-color: #00c853;
    --action-sell-color: #ff3b30;
    --action-bull: #00c853;
    --action-bull-glow: rgba(0, 200, 83, 0.55);
    --action-bear: #ff3b30;
    --action-bear-glow: rgba(255, 59, 48, 0.55);
    --action-premium: #ffbf47;
    --action-premium-glow: rgba(255, 191, 71, 0.55);
    --action-avoid: #8b949e;
    /* Strike-invasion badge — GREEN do-not-short (real break), RED short-call candidate (actionable),
       AMBER pending, BLUE forecast. Reuses the action bull/bear/premium hues so the board stays coherent;
       adds one blue for the Stage-1 forecast state. */
    --invasion-forecast: #58a6ff;
    --invasion-forecast-glow: rgba(88, 166, 255, 0.5);
}

* { box-sizing: border-box; }

body {
    margin: 0;
    color: var(--ink);
    font-family: Avenir Next, Gill Sans, Trebuchet MS, sans-serif;
    background:
        linear-gradient(rgba(28, 45, 35, 0.045) 1px, transparent 1px),
        linear-gradient(90deg, rgba(28, 45, 35, 0.045) 1px, transparent 1px),
        radial-gradient(circle at 12% 5%, rgba(255, 204, 111, 0.42), transparent 30rem),
        radial-gradient(circle at 84% 12%, rgba(82, 155, 105, 0.24), transparent 28rem),
        linear-gradient(135deg, #f4f7ed, #e8f1f4);
    background-size: 28px 28px, 28px 28px, auto, auto, auto;
    min-height: 100vh;
}

.chain-shell {
    width: min(2400px, calc(100% - 16px));
    margin: 0 auto;
    padding: 4px 0 8px;
}


.chain-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-start;
    gap: 10px;
    padding: 2px 4px 5px;
    min-height: 28px;
}

.back-link {
    color: var(--blue);
    font-weight: 900;
    text-decoration: none;
    font-size: 12px;
}

.subtitle {
    margin: 0;
    color: #425047;
    font-size: 12px;
    font-weight: 800;
    min-width: 0;
}

.selected-expiry-date,
.gex-status {
    flex: 0 0 auto;
    border-radius: 999px;
    padding: 4px 8px;
    border: 1px solid var(--line);
    background: rgba(255, 255, 255, 0.78);
    color: #243026;
    font-size: 10px;
    font-weight: 950;
    text-transform: uppercase;
}

.gex-status.ready {
    border-color: rgba(117, 190, 255, 0.72);
    background: #dff0ff;
    color: #0f4c91;
}

.gex-status.stale {
    border-color: rgba(255, 204, 102, 0.72);
    background: #fff0bd;
    color: #5d3b00;
}

.gex-status.disabled {
    border-color: rgba(92, 107, 99, 0.28);
    background: rgba(229, 234, 231, 0.76);
    color: #5c6b63;
}

.status-pill {
    border-radius: 999px;
    padding: 4px 8px;
    background: rgba(255, 255, 255, 0.78);
    border: 1px solid var(--line);
    color: var(--ink);
    font-size: 10px;
    font-weight: 950;
    text-transform: uppercase;
}

.status-pill.live { background: #dff5df; border-color: #acd6ad; }
.status-pill.error { background: #ffe2dd; border-color: #e4aaa1; }

.freshness-strip {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    min-height: 30px;
    margin: 0 4px 6px;
    padding: 5px 8px;
    border: 1px solid rgba(92, 107, 99, 0.24);
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.78);
    color: #314038;
    font-size: 11px;
    font-weight: 850;
}

.freshness-strip span {
    min-width: 0;
}

.freshness-state {
    flex: 0 0 auto;
    border-radius: 999px;
    padding: 3px 7px;
    color: #fff;
    background: #5c6b63;
    font-size: 10px;
    font-weight: 950;
    letter-spacing: 0.04em;
}

.freshness-strip.live {
    border-color: rgba(27, 147, 71, 0.42);
    background: rgba(223, 245, 223, 0.82);
}

.freshness-strip.live .freshness-state {
    background: #1b9347;
}

.freshness-strip.lagging {
    border-color: rgba(240, 138, 36, 0.48);
    background: rgba(255, 240, 189, 0.86);
    color: #5d3b00;
}

.freshness-strip.lagging .freshness-state {
    background: #b76413;
}

.freshness-strip.stale {
    border-color: rgba(211, 59, 52, 0.44);
    background: rgba(255, 226, 221, 0.86);
    color: #54231d;
}

.freshness-strip.stale .freshness-state {
    background: #d33b34;
}

.freshness-strip.closed {
    border-color: rgba(92, 107, 99, 0.4);
    background: rgba(236, 239, 237, 0.92);
    color: #3c4a42;
}

.freshness-strip.closed .freshness-state {
    background: #5c6b63;
}

.feed-notice {
    margin-top: 5px;
    padding: 8px 10px;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.82);
    color: #425047;
    font-size: 12px;
    font-weight: 900;
}

.feed-notice.unavailable {
    border-color: #e4aaa1;
    background: #ffe2dd;
    color: #54231d;
}

.controls, .summary-card, .chain-card {
    border: 1px solid rgba(255, 255, 255, 0.78);
    border-radius: 14px;
    background: var(--panel);
    box-shadow: 0 10px 28px rgba(32, 44, 37, 0.10);
    /* backdrop-filter blur removed: it forced a full-region GPU re-composite on every live tick,
       which read as the whole screen flickering. Flat translucent panel paints once and stays static. */
}

.controls {
    display: grid;
    grid-template-columns: repeat(8, minmax(90px, 1fr));
    gap: 5px;
    align-items: end;
    padding: 5px;
}

.mode-toggle {
    margin-left: 8px;
    border-radius: 999px;
    padding: 3px 12px;
    font-weight: 900;
    font-size: 10px;
    letter-spacing: 0.05em;
    cursor: pointer;
    border: 1px solid rgba(255, 255, 255, 0.5);
}
.mode-toggle.live { background: linear-gradient(135deg, #2f8f5b, #1f6b41); color: #fff; }
.mode-toggle.replay { background: linear-gradient(135deg, #c9863a, #a4631f); color: #fff; }

.replay-banner {
    margin: 6px 0;
    padding: 6px 12px;
    border-radius: 10px;
    background: repeating-linear-gradient(45deg, #4a2f12, #4a2f12 10px, #5c3a16 10px, #5c3a16 20px);
    color: #ffd9a8;
    font-weight: 900;
    letter-spacing: 0.06em;
    text-align: center;
    border: 1px solid #a4631f;
}

.replay-controls {
    border: 1px solid rgba(255, 255, 255, 0.78);
    border-radius: 14px;
    background: var(--panel);
    box-shadow: 0 10px 28px rgba(32, 44, 37, 0.10);
    /* backdrop-filter blur removed: it forced a full-region GPU re-composite on every live tick,
       which read as the whole screen flickering. Flat translucent panel paints once and stays static. */
    margin-top: 5px;
    padding: 8px;
    display: grid;
    gap: 8px;
}

.replay-launcher {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
    gap: 6px;
    align-items: end;
}

.replay-button { background: linear-gradient(135deg, #c9863a, #a4631f); }

.replay-status {
    display: grid;
    gap: 4px;
    padding: 6px 8px;
    border-radius: 10px;
    background: rgba(0, 0, 0, 0.04);
}
.replay-status-line, .replay-counts, .replay-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.replay-state {
    border-radius: 999px;
    padding: 1px 8px;
    font-size: 10px;
    font-weight: 900;
    background: #2456a4; color: #fff;
}
.replay-state.completed { background: #1f6b41; }
.replay-state.failed { background: #a32020; }
.replay-state.recovery_required { background: #a32020; }
.replay-state.paused { background: #8a6d1f; }
.replay-state.stopped { background: #555; }
.replay-stop { background: linear-gradient(135deg, #c14040, #8a2020) !important; }
.replay-step { background: linear-gradient(135deg, #3a7bd5, #2554a8) !important; }
.session-note { display: block; margin-top: 4px; font-size: 11px; color: #9aa4af; }
.session-note.early-close { color: #f0b429; }
.session-note.non-trading { color: #f08a24; }
.replay-stale { color: #f0b429; font-size: 12px; margin-bottom: 6px; font-weight: 600; }
.replay-status.stale { outline: 1px solid rgba(240, 180, 41, 0.5); }
.replay-error { color: #a32020; font-weight: 700; font-size: 11px; }
.replay-evidence-link { font-weight: 800; color: #2456a4; }
.replay-run-list { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.replay-run-list-title { font-size: 10px; font-weight: 900; color: var(--muted); text-transform: uppercase; }
.replay-run-item {
    font-size: 10px;
    padding: 2px 8px;
    border-radius: 8px;
    border: 1px solid rgba(0, 0, 0, 0.15);
    background: transparent;
    cursor: pointer;
}
.replay-run-item.active { background: #2456a4; color: #fff; }

label {
    display: grid;
    gap: 2px;
    color: var(--muted);
    font-size: 10px;
    font-weight: 900;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

input, select, button {
    height: 28px;
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 0 7px;
    background: rgba(255, 255, 255, 0.85);
    color: var(--ink);
    font: inherit;
    font-size: 12px;
}

.check {
    grid-template-columns: 18px auto;
    align-items: center;
    gap: 5px;
    height: 28px;
    padding-top: 10px;
}

.check input { width: 14px; height: 14px; }

button {
    cursor: pointer;
    border: 0;
    color: #fff;
    background: linear-gradient(135deg, #1b9347, #127738);
    font-weight: 950;
    letter-spacing: 0.03em;
}

button:disabled { opacity: 0.58; cursor: wait; }

.summary-grid {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 5px;
    margin-top: 5px;
}

.summary-card {
    min-height: 48px;
    padding: 6px 10px;
    display: grid;
    gap: 1px;
    align-content: center;
}

.summary-card span {
    color: var(--muted);
    font-weight: 850;
    font-size: 11px;
}

.summary-card strong {
    font-size: clamp(18px, 1.8vw, 24px);
    letter-spacing: -0.04em;
}

.spot-card strong {
    display: inline-block;
    width: max-content;
    border-bottom: 5px solid var(--blue);
    line-height: 0.95;
    padding-bottom: 4px;
}

.call-text { color: var(--call); }
.put-text { color: var(--put); }
.ratio-text { color: var(--orange); }

.option-behavior-panel {
    margin-top: 5px;
    padding: 8px 10px;
    border-top: 1px solid rgba(128, 177, 232, 0.16);
    border-bottom: 1px solid rgba(128, 177, 232, 0.16);
    background: linear-gradient(180deg, rgba(9, 13, 22, 0.96), rgba(13, 18, 30, 0.92));
    display: grid;
    grid-template-rows: 22px 42px 74px;
    gap: 7px;
    height: 160px;
    min-height: 160px;
    overflow: hidden;
}
.option-behavior-panel.positive { border-color: rgba(27, 147, 71, 0.52); }
.option-behavior-panel.negative { border-color: rgba(222, 74, 74, 0.52); }
.option-behavior-board-header {
    align-items: center;
    display: grid;
    grid-template-columns: 210px minmax(240px, 1fr) minmax(520px, 760px);
    gap: 12px;
    min-width: 0;
    overflow: hidden;
}
.option-behavior-board-header strong {
    color: #ffffff;
    font-size: 13px;
    font-weight: 950;
    letter-spacing: 0;
    overflow: hidden;
    text-transform: uppercase;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.option-behavior-board-signal {
    color: #f8fafc;
    display: block;
    font-size: 12px;
    font-weight: 950;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    text-transform: uppercase;
    white-space: nowrap;
}
.option-behavior-panel.positive .option-behavior-board-signal { color: #34d399; }
.option-behavior-panel.negative .option-behavior-board-signal { color: #fb7185; }
.option-behavior-meta span,
.option-behavior-list span,
.option-behavior-metric em {
    color: var(--muted);
    font-size: 10px;
    font-style: normal;
    font-weight: 900;
}
.option-behavior-session-score {
    color: #e5efff !important;
}
.option-behavior-meta {
    display: grid;
    grid-template-columns: 92px 78px 170px 110px 86px;
    gap: 4px;
    min-height: 0;
    overflow: hidden;
}
.option-behavior-meta span {
    padding: 2px 6px;
    border: 1px solid rgba(108, 123, 151, 0.26);
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.03);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.option-behavior-score-row {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 5px;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}
.option-behavior-metric {
    min-width: 0;
    padding: 5px 6px;
    border: 1px solid rgba(108, 123, 151, 0.22);
    background: rgba(255, 255, 255, 0.035);
    display: grid;
    grid-template-rows: 16px 1fr;
    gap: 2px;
    overflow: hidden;
}
.option-behavior-metric b {
    color: #e5efff;
    font-size: 14px;
    line-height: 1;
    align-self: center;
    font-variant-numeric: tabular-nums;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.option-behavior-metric.positive b { color: #34d399; }
.option-behavior-metric.negative b { color: #fb7185; }
.option-behavior-lists {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 6px;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}
.option-behavior-list {
    min-width: 0;
    border: 1px solid rgba(108, 123, 151, 0.2);
    background: rgba(255, 255, 255, 0.025);
    display: grid;
    grid-template-rows: 22px 1fr;
    min-height: 0;
    overflow: hidden;
}
.option-behavior-list.call { border-color: rgba(27, 147, 71, 0.32); }
.option-behavior-list.put { border-color: rgba(86, 101, 220, 0.34); }
.option-behavior-list.warn { border-color: rgba(222, 74, 74, 0.28); }
.option-behavior-list > span {
    background: rgba(255, 255, 255, 0.03);
    border-bottom: 1px solid rgba(108, 123, 151, 0.18);
    line-height: 22px;
    overflow: hidden;
    padding: 0 8px;
    text-overflow: ellipsis;
    text-transform: uppercase;
    white-space: nowrap;
}
.option-behavior-list ol {
    display: grid;
    gap: 3px;
    grid-auto-rows: 17px;
    list-style: none;
    margin: 0;
    min-height: 0;
    overflow: hidden;
    padding: 5px;
}
.option-behavior-list li,
.option-behavior-list small {
    background: rgba(255, 255, 255, 0.03);
    border-radius: 5px;
    color: #e5efff;
    font-size: 11px;
    font-weight: 850;
    line-height: 17px;
    overflow: hidden;
    padding: 0 6px;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.vix-card {
    border-color: rgba(86, 101, 220, 0.28);
}

.vix-card strong {
    color: #303c9d;
}

.vix-card.live strong {
    color: #1b9347;
}

.vix-card.delayed strong {
    color: #8a5a00;
}

.vix-price-meta {
    color: #536778;
    font-size: 10px;
    font-weight: 900;
    line-height: 1.1;
}

.put-call-ratio-label,
.pace-total-label {
    color: #5d675f;
    font-size: 10px;
    font-weight: 900;
    line-height: 1.1;
}

.pace-total-label {
    color: #536778;
}

.pressure-card {
    position: relative;
    overflow: visible;
    border-color: rgba(17, 20, 16, 0.18);
}

.pressure-card-title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.pressure-window-control {
    height: 24px;
    padding: 0 6px;
    font-size: 9px;
}

.pressure-window-select {
    width: 58px;
    height: 20px;
    font-size: 10px;
}

.pressure-signal {
    color: #111410;
    font-size: clamp(15px, 1.35vw, 20px) !important;
}

.pressure-strong-bullish .pressure-signal,
.pressure-bullish .pressure-signal {
    color: var(--call);
}

.pressure-strong-bearish .pressure-signal,
.pressure-bearish .pressure-signal {
    color: var(--put);
}

.pressure-choppy .pressure-signal {
    color: var(--orange);
}

.pressure-metrics {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

.pressure-metrics span {
    color: #35443b;
    font-size: 10px;
    font-weight: 950;
}

/* Liquidity-wall pressure: a second reading beside the volume-weighted one, never merged with it.
   The colour carries the DIRECTION and the muted grey carries "nothing was measured" -- four of the
   six states are net 0.0 and must not all look alike. */
.pressure-wall {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin-top: 3px;
    padding-top: 3px;
    border-top: 1px solid rgba(53, 68, 59, 0.18);
    font-size: 10px;
    font-weight: 950;
    line-height: 1.2;
}

.pressure-wall-label {
    color: #6b7a71;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    flex: 0 0 auto;
}

.pressure-wall-value {
    color: #35443b;
}

/* Measured direction. */
.pressure-wall.wall-bullish .pressure-wall-value { color: #0f7a3d; }
.pressure-wall.wall-bearish .pressure-wall-value { color: #b3261e; }
.pressure-wall.wall-neutral .pressure-wall-value { color: #35443b; }

/* Absence, in its three distinguishable forms -- deliberately muted so it never reads as a call. */
.pressure-wall.wall-none .pressure-wall-value {
    color: #8a978f;
    font-weight: 800;
    font-style: italic;
}

/* Stale is a WARNING, not an absence: data arrived and cannot be trusted for this moment. */
.pressure-wall.wall-stale .pressure-wall-value {
    color: #9a6b00;
    font-weight: 900;
    font-style: italic;
}

.pressure-popover {
    position: absolute;
    right: 0;
    top: calc(100% + 8px);
    z-index: 30;
    width: min(520px, calc(100vw - 32px));
    padding: 12px;
    border: 1px solid rgba(55, 86, 126, 0.34);
    border-radius: 14px;
    background: #090b11;
    box-shadow: 0 18px 48px rgba(8, 10, 16, 0.34);
    color: #ffffff;
    opacity: 0;
    pointer-events: none;
    transform: translateY(-4px);
    transition: opacity 120ms ease, transform 120ms ease;
}

.pressure-card:hover .pressure-popover,
.pressure-card:focus-within .pressure-popover {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

.pressure-popover strong {
    color: #dcecff;
    font-size: 12px;
    letter-spacing: 0.03em;
}

.pressure-columns {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    margin-top: 8px;
}

.pressure-list-title {
    display: block;
    margin-bottom: 5px;
    color: #96ccff !important;
    font-size: 11px !important;
    font-weight: 950;
}

.pressure-list ol {
    display: grid;
    gap: 5px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.pressure-list li {
    display: grid;
    grid-template-columns: 48px 58px 70px 48px 56px;
    gap: 5px;
    align-items: center;
    padding: 5px 6px;
    border: 1px solid rgba(128, 177, 232, 0.18);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.045);
}

.pressure-list li span {
    color: #dcecff;
    font-size: 10px;
    font-weight: 900;
}

.pressure-strike {
    color: #ffffff !important;
    font-size: 11px !important;
    font-weight: 950 !important;
}

.strike-flow-leaderboard {
    margin-top: 5px;
    padding: 8px 10px;
    border-top: 1px solid rgba(128, 177, 232, 0.16);
    border-bottom: 1px solid rgba(128, 177, 232, 0.16);
    background: linear-gradient(180deg, rgba(9, 13, 22, 0.96), rgba(13, 18, 30, 0.92));
}

.strike-flow-leaderboard-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 7px;
}

.strike-flow-leaderboard-header strong {
    color: #ffffff;
    font-size: 13px;
    font-weight: 950;
    letter-spacing: 0;
    text-transform: uppercase;
}

.strike-flow-leaderboard-header span {
    color: #91a7bd;
    font-size: 11px;
    font-weight: 850;
}

/* Cheap-flow filter control (Filtered/Raw toggle + k strictness slider). */
.strike-flow-filter-control {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-left: auto;
}
.sff-toggle {
    cursor: pointer;
    border: 1px solid var(--line, rgba(108, 123, 151, 0.4));
    border-radius: 999px;
    padding: 3px 11px;
    font-size: 10.5px;
    font-weight: 900;
    letter-spacing: 0.04em;
    color: #8b99ab;
    background: rgba(255, 255, 255, 0.03);
    user-select: none;
}
.sff-toggle.on {
    color: #fff;
    background: #1f6feb;
    border-color: #1f6feb;
}
.sff-k {
    display: flex;
    align-items: center;
    gap: 6px;
    color: #91a7bd;
    font-size: 10px;
    font-weight: 850;
}
.sff-k input[type="range"] { width: 96px; accent-color: #1f6feb; }

/* Rolling-window control: lookback buttons (All/5m/10m/15m/30m/4h) + $/# measure toggle. */
.sff-window {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.sff-win-btn {
    appearance: none;
    border: 0;
    background: rgba(255, 255, 255, 0.05);
    color: #91a7bd;
    font: inherit;
    font-size: 10px;
    font-weight: 850;
    line-height: 1;
    padding: 4px 7px;
    border-radius: 4px;
    cursor: pointer;
    transition: background 0.12s ease, color 0.12s ease;
}
.sff-win-btn:hover { color: #d7e2ef; }
.sff-win-btn.on { background: #1f6feb; color: #fff; }
.sff-measure {
    display: inline-flex;
    gap: 2px;
    padding-left: 6px;
    border-left: 1px solid rgba(255, 255, 255, 0.12);
}

.strike-flow-leaderboard-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
}

/* Strike Flow Board — four independent tracks (call-buy / call-sell / put-sell / put-buy). */
.flow-track {
    border: 1px solid rgba(108, 123, 151, 0.22);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.025);
    overflow: hidden;
}

.flow-track.flow-bull { box-shadow: inset 3px 0 0 rgba(68, 241, 154, 0.7); }
.flow-track.flow-bear { box-shadow: inset 3px 0 0 rgba(255, 106, 118, 0.7); }

.flow-thead {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    padding: 5px 9px;
    border-bottom: 1px solid rgba(108, 123, 151, 0.18);
    background: rgba(255, 255, 255, 0.03);
}

.flow-name { font-weight: 900; font-size: 11.5px; letter-spacing: 0.04em; }
.flow-bull .flow-name { color: #44f19a; }
.flow-bear .flow-name { color: #ff6a76; }
.flow-tag { color: #8b99ab; font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.06em; }
.flow-total { font-weight: 900; font-size: 11.5px; font-variant-numeric: tabular-nums; }
.flow-bull .flow-total { color: #44f19a; }
.flow-bear .flow-total { color: #ff6a76; }

.flow-track ol {
    display: grid;
    gap: 3px;
    margin: 0;
    padding: 5px;
    list-style: none;
}

.flow-track li {
    display: grid;
    grid-template-columns: 26px 52px 1fr 72px;
    align-items: center;
    gap: 7px;
    padding: 4px 7px;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.03);
}

.flow-rank { color: #8b99ab; font-weight: 900; font-size: 10px; }
.flow-strike { color: #ffffff; font-weight: 900; font-size: 11.5px; }
.flow-strike.flow-atm { color: #ffd54f; }
.flow-bar { height: 7px; border-radius: 3px; }
.flow-bull .flow-bar { background: linear-gradient(90deg, rgba(68, 241, 154, 0.45), #44f19a); }
.flow-bear .flow-bar { background: linear-gradient(90deg, rgba(255, 106, 118, 0.45), #ff6a76); }
.flow-amt { text-align: right; font-weight: 900; font-size: 11px; font-variant-numeric: tabular-nums; }
.flow-bull .flow-amt { color: #44f19a; }
.flow-bear .flow-amt { color: #ff6a76; }

.flow-blink { animation: strikeFlowSoftBlink 2.6s ease-in-out infinite; }
@keyframes strikeFlowSoftBlink {
    0%, 100% { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05); }
    50% { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.35), 0 0 12px rgba(255, 255, 255, 0.1); }
}

/* Level-based cluster wall: soft-blink the call-flow AND put-flow cells of the member strikes, tinted by
   side (bought = green, sold = red). Persistent while the wall holds; the rank-1 wall pulses a touch
   stronger. Backend-detected (strike-intelligence) — the UI only paints. */
.flow-cell.cluster-blink { animation: strikeClusterSoftBlink 2.4s ease-in-out infinite; border-radius: 4px; }
.flow-cell.cluster-bought { --cluster-glow: 105, 211, 154; }  /* green — bought/positive delta wall */
.flow-cell.cluster-sold   { --cluster-glow: 238, 119, 112; }  /* red   — sold/negative delta wall */
.flow-cell.cluster-rank1  { animation-duration: 1.8s; }        /* strongest wall reads a touch stronger */
@keyframes strikeClusterSoftBlink {
    0%, 100% { box-shadow: inset 0 0 0 1px rgba(var(--cluster-glow), 0.20); }
    50% { box-shadow: inset 0 0 0 1px rgba(var(--cluster-glow), 0.75), 0 0 12px rgba(var(--cluster-glow), 0.30); }
}
@media (prefers-reduced-motion: reduce) {
    .flow-cell.cluster-blink { animation: none; box-shadow: inset 0 0 0 1px rgba(var(--cluster-glow), 0.55); }
}

.strike-flow-empty {
    margin: 0;
    color: #74869a;
    font-size: 11px;
    font-weight: 850;
}

/* ES seller-activity session chart: same multi-strike line treatment as the analysis view. */
.seller-activity-page {
  width: min(1500px, calc(100% - 32px));
  margin: 0 auto;
  padding: 24px 0 40px;
  box-sizing: border-box;
}
.seller-activity-page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  margin: 0 0 16px;
}
.seller-activity-page-header h1 { margin: 0; color: #e6edf3; font-size: 22px; line-height: 1.25; }
.seller-activity-page-header p { margin: 6px 0 0; color: #8b98aa; font-size: 13px; }
.seller-activity-page-status { display: flex; align-items: center; gap: 10px; color: #8b98aa; font-size: 12px; }
.seller-activity-panel {
  margin: 12px 0;
  padding: 14px 16px 10px;
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 12px;
  background: rgba(12, 18, 28, 0.78);
}

.seller-activity-header,
.seller-activity-controls,
.seller-follow-control,
.seller-sample-control,
.seller-strike-selector {
  display: flex;
  align-items: center;
  gap: 8px;
}

.seller-activity-header {
  justify-content: space-between;
  flex-wrap: wrap;
  color: #e8edf4;
}

.seller-activity-controls { flex-wrap: wrap; }

.seller-activity-header strong { font-size: 14px; }
.seller-activity-header span,
.seller-follow-control span,
.seller-sample-control span,
.seller-activity-detail { color: #94a0b2; font-size: 12px; }

.seller-sample-control select {
  color: #e8edf4;
  background: #151d29;
  border: 1px solid #344055;
  border-radius: 6px;
  padding: 4px 7px;
}

/* The side dropdown rotates on its own every 15s; this is the badge that says so, next to the
   control it describes rather than in a legend somewhere else. Dim and small: it is an
   explanation, not a reading. */
.seller-mode-auto {
  color: #7f8da3;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1px solid #2b3648;
  border-radius: 999px;
  padding: 2px 7px;
  white-space: nowrap;
}

.seller-strike-selector {
  flex-wrap: wrap;
  margin: 10px 0 4px;
}

.seller-strike-selector button {
  color: var(--seller-series-color, #aab4c2);
  background: transparent;
  border: 1px solid #354156;
  border-radius: 6px;
  padding: 3px 7px;
  cursor: pointer;
}

.seller-strike-selector button.selected {
  color: var(--seller-series-color, #63d7ff);
  background: rgba(255, 255, 255, 0.08);
  border-color: var(--seller-series-color, #63d7ff);
  box-shadow: inset 0 0 0 1px var(--seller-series-color, #63d7ff);
}

.seller-activity-chart { display: block; width: 100%; height: auto; min-height: 230px; }
.seller-grid { stroke: rgba(255, 255, 255, 0.09); stroke-width: 1; }
.seller-axis-label, .seller-axis-title { fill: #8f9bad; font-size: 11px; }
/* Unselected trajectories are context, and context is said with WEIGHT and dash — not by fading
   every line to 0.58, which is the same fault as .tvol-line.is-ctx had. Each of these is a real
   seller series; a half-transparent line on a busy chart cannot be followed. */
.seller-activity-line { fill: none; stroke: var(--seller-series-color, #738096); stroke-width: 1.4; stroke-dasharray: 4 3; stroke-linejoin: round; cursor: pointer; pointer-events: stroke; }
.seller-activity-line:focus { outline: none; stroke-width: 4; stroke-dasharray: none; }
.seller-activity-line.selected { stroke: var(--seller-series-color, #63d7ff); stroke-width: 3.5; stroke-dasharray: none; }
.seller-hover-guide { stroke: #e8edf4; stroke-width: 1; opacity: 0.35; }
.seller-selected-label { fill: var(--seller-series-color, #e8edf4); font-size: 12px; font-weight: 600; }
.seller-activity-detail { min-height: 18px; text-align: center; }
.seller-activity-empty { padding: 28px 0; color: #7f8b9c; text-align: center; }

@media (max-width: 680px) {
  .seller-activity-page { width: min(100% - 20px, 1500px); padding-top: 16px; }
  .seller-activity-page-header { flex-direction: column; }
  .seller-activity-panel { padding-left: 10px; padding-right: 10px; }
  .seller-activity-chart { min-height: 190px; }
}

.chain-card {
    margin-top: 5px;
    overflow: hidden;
}

/* 0DTE binary direction — one chain-wide background, never per-row voting.
   NORMAL uses broad-view light yellow/pink; backend-qualified UNUSUAL uses dark yellow/pink.
   The class disappears on stale/degraded/expired data, returning every existing table color unchanged. */
.zero-dte-direction-state {
    display: inline-flex;
    align-items: center;
    margin-left: 10px;
    padding: 3px 8px;
    border-radius: 999px;
    font-size: 10px !important;
    font-weight: 950 !important;
    letter-spacing: 0.04em;
}
.zero-dte-direction-state.up.normal { background: #fff3b8; color: #55420a; }
.zero-dte-direction-state.down.normal { background: #f8dce8; color: #5b1835; }
.zero-dte-direction-state.up.unusual { background: #806000; color: #fff8d6; }
.zero-dte-direction-state.down.unusual { background: #7d2451; color: #fff0f7; }

.chain-card.chain-direction-up-normal .table-wrap,
.chain-card.chain-direction-up-normal .chain-table { background: #fff3b8; }
.chain-card.chain-direction-down-normal .table-wrap,
.chain-card.chain-direction-down-normal .chain-table { background: #f8dce8; }
.chain-card.chain-direction-up-unusual .table-wrap,
.chain-card.chain-direction-up-unusual .chain-table { background: #806000; }
.chain-card.chain-direction-down-unusual .table-wrap,
.chain-card.chain-direction-down-unusual .chain-table { background: #7d2451; }

.chain-card.chain-direction-up-normal tbody tr {
    --cell-text-mask-bg: #fff8cf;
    background: linear-gradient(90deg, rgba(110, 84, 10, 0.055) 1px, transparent 1px), #fff8cf;
    color: #332805;
}
.chain-card.chain-direction-up-normal tbody tr:nth-child(even) {
    --cell-text-mask-bg: #fff2bd;
    background: linear-gradient(90deg, rgba(110, 84, 10, 0.065) 1px, transparent 1px), #fff2bd;
}
.chain-card.chain-direction-up-normal tbody tr.current-strike {
    --cell-text-mask-bg: #f7e69d;
    background: linear-gradient(90deg, rgba(110, 84, 10, 0.085) 1px, transparent 1px), #f7e69d;
}

.chain-card.chain-direction-down-normal tbody tr {
    --cell-text-mask-bg: #fce8f0;
    background: linear-gradient(90deg, rgba(120, 28, 70, 0.055) 1px, transparent 1px), #fce8f0;
    color: #3f1025;
}
.chain-card.chain-direction-down-normal tbody tr:nth-child(even) {
    --cell-text-mask-bg: #f7dce7;
    background: linear-gradient(90deg, rgba(120, 28, 70, 0.065) 1px, transparent 1px), #f7dce7;
}
.chain-card.chain-direction-down-normal tbody tr.current-strike {
    --cell-text-mask-bg: #efc8d8;
    background: linear-gradient(90deg, rgba(120, 28, 70, 0.085) 1px, transparent 1px), #efc8d8;
}

.chain-card.chain-direction-up-unusual tbody tr {
    --cell-text-mask-bg: #8f6b00;
    background: linear-gradient(90deg, rgba(255, 255, 255, 0.055) 1px, transparent 1px), #8f6b00;
    color: #fff8d6;
}
.chain-card.chain-direction-up-unusual tbody tr:nth-child(even) {
    --cell-text-mask-bg: #765800;
    background: linear-gradient(90deg, rgba(255, 255, 255, 0.065) 1px, transparent 1px), #765800;
}
.chain-card.chain-direction-up-unusual tbody tr.current-strike {
    --cell-text-mask-bg: #a57c00;
    background: linear-gradient(90deg, rgba(255, 255, 255, 0.09) 1px, transparent 1px), #a57c00;
}

.chain-card.chain-direction-down-unusual tbody tr {
    --cell-text-mask-bg: #8d2b5d;
    background: linear-gradient(90deg, rgba(255, 255, 255, 0.055) 1px, transparent 1px), #8d2b5d;
    color: #fff0f7;
}
.chain-card.chain-direction-down-unusual tbody tr:nth-child(even) {
    --cell-text-mask-bg: #742047;
    background: linear-gradient(90deg, rgba(255, 255, 255, 0.065) 1px, transparent 1px), #742047;
}
.chain-card.chain-direction-down-unusual tbody tr.current-strike {
    --cell-text-mask-bg: #a3366d;
    background: linear-gradient(90deg, rgba(255, 255, 255, 0.09) 1px, transparent 1px), #a3366d;
}

.chain-card.chain-direction-up-unusual tbody td,
.chain-card.chain-direction-down-unusual tbody td {
    color: inherit;
}

.chain-toolbar {
    min-height: 34px;
    padding: 5px 9px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 18px;
    border-bottom: 1px solid var(--line);
}

.chain-toolbar strong {
    margin-right: 10px;
    font-size: 13px;
}

.chain-toolbar .spot-inline {
    color: var(--blue);
}

.chain-toolbar span {
    color: var(--muted);
    font-weight: 750;
    font-size: 12px;
}

.legend {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.center-spot {
    width: auto;
    height: 28px;
    padding: 0 12px;
    white-space: nowrap;
    background: linear-gradient(135deg, #3976c9, #285aa2);
}

.center-spot.floating {
    position: fixed;
    right: 18px;
    bottom: 18px;
    z-index: 50;
    height: 40px;
    padding: 0 16px;
    box-shadow: 0 14px 34px rgba(35, 76, 132, 0.28);
}

.pace-window-control {
    display: inline-flex;
    grid-template-columns: none;
    align-items: center;
    gap: 6px;
    height: 28px;
    padding: 0 8px;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.72);
    color: #35443b;
    font-size: 10px;
    font-weight: 950;
}

.pace-window-select {
    width: 64px;
    height: 22px;
    padding: 0 5px;
    border-radius: 7px;
    background: #111410;
    color: #fff;
    font-size: 11px;
    font-weight: 950;
}

/* Keep the Option Truth timeframe beside the thermometers it controls. The former
   right-toolbar placement could be pushed outside the viewport by the order ticket. */
.strike-header-cell {
    min-width: 104px;
}

.strike-header-label {
    display: block;
    margin-bottom: 3px;
}

.option-truth-window-control.compact {
    height: 24px;
    padding: 0 4px;
    gap: 3px;
    font-size: 9px;
    white-space: nowrap;
}

.option-truth-window-control.compact .option-truth-window-select {
    width: 50px;
    height: 20px;
    padding: 0 3px;
    font-size: 10px;
}

.option-truth-premium-control {
    white-space: nowrap;
}

.option-truth-premium-select {
    width: 62px;
}

.chain-table-shell {
    width: 100%;
}

.option-control-summary {
    min-height: 38px;
    padding: 5px 10px 4px;
    display: grid;
    grid-template-columns: minmax(290px, auto) minmax(220px, 1fr);
    align-items: center;
    gap: 14px;
    border-bottom: 1px solid var(--line);
    border: 1px solid rgba(119, 138, 168, 0.34);
    border-bottom: 0;
    border-radius: 4px 4px 0 0;
    background: rgba(9, 12, 18, 0.94);
}

.option-control-copy {
    display: flex;
    align-items: baseline;
    gap: 9px;
    white-space: nowrap;
}

.option-control-copy strong {
    color: rgba(255, 255, 255, 0.62);
    font-size: 10px;
    letter-spacing: 0.08em;
}

.option-control-copy b {
    color: #ffffff;
    font-size: 13px;
}

.option-control-up .option-control-copy b { color: var(--call); }
.option-control-down .option-control-copy b { color: var(--put); }

.option-control-copy span {
    color: var(--muted);
    font-size: 10px;
    font-weight: 750;
}

.option-control-track {
    position: relative;
    height: 16px;
    min-width: 180px;
}

.option-control-track-axis {
    position: absolute;
    left: 30px;
    right: 34px;
    top: 8px;
    height: 2px;
    border-radius: 2px;
    background: rgba(255, 255, 255, 0.18);
}

.option-control-track-center {
    position: absolute;
    z-index: 2;
    left: 50%;
    top: 4px;
    width: 2px;
    height: 10px;
    background: rgba(255, 255, 255, 0.68);
}

.option-control-track-fill {
    position: absolute;
    z-index: 1;
    top: 6px;
    height: 6px;
    border-radius: 5px;
    transition: width 900ms ease;
}

.option-control-up .option-control-track-fill {
    left: 50%;
    background: var(--call);
}

.option-control-down .option-control-track-fill {
    right: 50%;
    background: var(--put);
}

.option-control-track small {
    position: absolute;
    top: 1px;
    color: rgba(255, 255, 255, 0.48);
    font-size: 8px;
    font-weight: 850;
}

.option-control-put-label { left: 0; }
.option-control-call-label { right: 0; }

@media (max-width: 860px) {
    .option-control-summary {
        grid-template-columns: 1fr;
        gap: 2px;
    }
    .option-control-copy {
        overflow: hidden;
    }
    .option-control-copy span {
        overflow: hidden;
        text-overflow: ellipsis;
    }
}

.legend i {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    margin-right: 6px;
}

.legend-call { background: var(--call); }
.legend-put { background: var(--put); }

.table-wrap {
    position: relative;
    overflow: auto;
    height: calc(100vh - var(--oc-topnav-h, 0px) - 193px);
    min-height: 420px;
    overscroll-behavior: contain;
    scroll-behavior: auto;
    /* Live data updates per-row content height every tick (pace/EWMA bars, net-$ superscripts, blink,
       rolling-window values). With default scroll anchoring the browser shifts scrollTop to "keep" an
       anchor element, which reads as the whole table drifting/scrolling on its own. Disable anchoring so
       the table stays exactly where the user (or the one-shot initial center) left it. */
    overflow-anchor: none;
    border: 1px solid rgba(119, 138, 168, 0.34);
    border-radius: 0 0 4px 4px;
    background:
        linear-gradient(90deg, rgba(255, 255, 255, 0.035) 1px, transparent 1px),
        linear-gradient(180deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px),
        #080a10;
    background-size: 86px 100%, 100% 34px, auto;
}

/* The board's horizontal floor, declared ONCE and consumed by both boxes below.
   .table-stage is the positioning context for the absolutely inset (left:0/right:0) spot line and
   spot band, so its width IS the coordinate system those overlays span. If it and .chain-table
   carry different floors, then at any viewport between them the table scrolls out to its own floor
   while the overlays stop at the stage's — the spot line ends mid-board and the gradient stop that
   centres it on the Strike column lands on the wrong column. They drifted apart exactly once, when
   the table's floor was raised for the flow columns and the stage's was left behind; one
   declaration with two consumers removes the way that happened — it does not make the drift
   impossible — a later selector can still override either consumer. OptionChainAssetsTest checks
   that both read the property rather than restating it. */
.chain-card,
.table-wrap {
    --oc-board-min-w: 1722px;
}
.table-stage {
    position: relative;
    width: 100%;
    min-width: var(--oc-board-min-w, 1722px);
}

.chain-table {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
    /* Sum of the columns that state an explicit width (84 Call Volume + 96 Call OI + 272 Call
       Flow + 200 Δ-Flow + 2×104 Band + 170 Strike + 272 Put Flow + 96 Put OI + 96 Put Volume =
       1494), plus 114px for each of the two auto-width Mid columns. Under table-layout:fixed a
       table narrower than its stated columns gives the auto ones ZERO width and their content
       spills, so this floor is what keeps Call/Put Mid readable; below it .table-wrap scrolls
       horizontally, which it is already set up to do (overflow:auto). The old 1370px predates the
       flow columns getting a real width and left the Mid columns at 0 once they did.
       Read from --oc-board-min-w, the same declaration .table-stage reads, so the two are not
       restated independently. OptionChainAssetsTest asserts that both READ it rather than each
       stating a number, which is the part a source check can see; that the rendered widths then
       agree follows from there being one declaration, and is not separately asserted. */
    min-width: var(--oc-board-min-w, 1722px);
    background: #080a10;
}

thead {
    position: sticky;
    /* Pin below the sticky Liquidity menu (.lh-controls) when the heatmap is active; the heatmap
       JS keeps --lh-controls-h in sync with that menu's height and leaves it 0 when the heatmap is
       off — so this is a no-op (top:0) in that case. */
    top: var(--lh-controls-h, 0px);
    z-index: 30;
}

th, td {
    border-right: 1px solid rgba(108, 123, 151, 0.22);
    border-bottom: 1px solid rgba(108, 123, 151, 0.22);
    /* Compact: tighter vertical padding (keeps all per-cell data, just denser). */
    padding: 2px 8px;
    text-align: center;
    vertical-align: middle;
}

tbody td {
    position: relative;
}

tbody td > * {
    position: relative;
    z-index: 5;
}

tbody tr {
    --cell-text-mask-bg: #090b11;
}

tbody tr:nth-child(even) {
    --cell-text-mask-bg: #101119;
}

tbody tr.current-strike {
    --cell-text-mask-bg: #151823;
}

/* Text-first mask: keep cell labels readable while the liquidity heatmap remains a background
   context layer. Decorative GEX/S/R elements stay open; flow cells are reopened below so the
   heatmap ribbon can show through. */
tbody td > *:not(.gex-strength-fill):not(.gex-strength-axis):not(.gex-strength-arrow):not(.strike-gex-content):not(.uw-gex-popover):not(.gamma-stale-marker):not(.strike-sr-corner):not(.strike-sr-gamma):not(.vanna-strength-fill):not(.vanna-strength-axis):not(.vanna-strength-arrow):not(.strike-vanna-line):not(.charm-strength-fill):not(.charm-strength-axis):not(.charm-strength-arrow):not(.sides-strength-axis):not(.sides-put-fill):not(.sides-call-fill):not(.es-strength-fill):not(.es-strength-axis):not(.es-strength-arrow):not(.es-band-tag):not(.move-auth-track):not(.oi-sr-pill):not(.wall-lane) {
    background: var(--cell-text-mask-bg);
    box-shadow: 0 0 0 6px var(--cell-text-mask-bg);
    border-radius: 6px;
}

tbody td > .flow-inner {
    background: transparent !important;
    box-shadow: none !important;
}

th {
    position: sticky;
    top: var(--lh-controls-h, 0px);
    z-index: 31;
    height: 38px;
    color: #d8e7ff;
    background:
        linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(18, 19, 29, 0.98)),
        #12131d;
    font-size: 12px;
    font-weight: 950;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    text-shadow: 0 1px 0 #000;
    background-clip: padding-box;
    box-shadow: 0 2px 0 rgba(108, 123, 151, 0.48), 0 12px 16px rgba(0, 0, 0, 0.55);
}

tbody tr {
    background:
        linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px),
        #090b11;
    background-size: 72px 100%, auto;
    /* FIXED uniform row height: every row is the same height regardless of whether a cell shows the big
       top-volume font or the EWMA mini, so rows below never shift -- the table stays static (only the
       numbers change in place, like the leaderboard). Sized to fit the 21px top-volume font + EWMA. */
    height: 44px;
}

tbody tr:nth-child(even) {
    background:
        linear-gradient(90deg, rgba(255, 255, 255, 0.055) 1px, transparent 1px),
        #101119;
    background-size: 72px 100%, auto;
}

		                tbody tr.current-strike {
		                    background:
		                        linear-gradient(90deg, rgba(255, 255, 255, 0.065) 1px, transparent 1px),
		                        #151823;
		                }

td.sandwich-cell {
    position: relative;
    --cell-text-mask-bg: rgba(255, 244, 214, 0.88);
    background: var(--sandwich-bg) !important;
    box-shadow: inset 0 0 0 999px var(--sandwich-wash), inset 0 0 0 2px var(--sandwich-edge);
    color: #23130f;
}

.sandwich-rank-badge {
    position: absolute;
    top: 2px;
    right: 4px;
    min-width: 14px;
    height: 14px;
    padding: 0 3px;
    border: 1px solid #b45309;
    border-radius: 999px;
    background: #fff4d6;
    color: #3a1c08;
    font-size: 10px;
    font-weight: 950;
    line-height: 13px;
    text-align: center;
    box-shadow: 0 1px 3px rgba(58, 28, 8, 0.24);
}

td.sandwich-rank-1 {
    --sandwich-wash: rgba(255, 255, 255, 0.08);
    --sandwich-edge: rgba(35, 19, 15, 0.44);
}

td.sandwich-rank-2 {
    --sandwich-wash: rgba(255, 255, 255, 0.28);
    --sandwich-edge: rgba(35, 19, 15, 0.24);
}

td.sandwich-role-top {
    --sandwich-bg: linear-gradient(90deg, rgba(222, 35, 35, 0.9), rgba(255, 99, 93, 0.68));
}

td.sandwich-role-middle {
    --sandwich-bg: linear-gradient(90deg, rgba(255, 126, 178, 0.9), rgba(255, 195, 218, 0.72));
}

td.sandwich-role-outer {
    --sandwich-bg: linear-gradient(90deg, rgba(244, 132, 33, 0.88), rgba(255, 183, 91, 0.66));
}

/* Mission sandwich walls (databento-mission-sandwich-service). Deliberately light-touch: a thin inset
   side-stripe drawn as a pseudo-element with NO background override, so it layers over the GEX heatmap,
   pace highlight, net-sell glow and spread selection instead of masking them (z-index sits above the GEX
   fill but below the cell text). Color encodes tilt (call lower-heavy -> green, upper-heavy -> red; put
   reversed); shade depth + stripe width encode the heavier wall (hi = heavier). */
td.mission-wall, td.mission-pin {
    position: relative;
}
td.mission-wall {
    /* Fill the wall cell with the tilt color so the sandwich is visible at a glance, not just via the
       thin edge stripe (which was too subtle to notice). inset box-shadow tints the cell BELOW its text,
       so the price/volume stays readable; --mission-fill is translucent and deeper for the heavier wall. */
    box-shadow: inset 0 0 0 999px var(--mission-fill, transparent);
}
td.mission-wall::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    width: var(--mission-w, 3px);
    background: var(--mission-edge, transparent);
    pointer-events: none;
    z-index: 2;
}
td.mission-wall.mission-call::after { left: 0; }
td.mission-wall.mission-put::after { right: 0; }
td.mission-red.mission-hi { --mission-edge: rgba(226, 75, 74, 1); --mission-w: 4px; --mission-fill: rgba(226, 75, 74, 0.34); }
td.mission-red.mission-lo { --mission-edge: rgba(226, 75, 74, 0.8); --mission-w: 3px; --mission-fill: rgba(226, 75, 74, 0.20); }
td.mission-green.mission-hi { --mission-edge: rgba(99, 153, 34, 1); --mission-w: 4px; --mission-fill: rgba(99, 153, 34, 0.38); }
td.mission-green.mission-lo { --mission-edge: rgba(99, 153, 34, 0.8); --mission-w: 3px; --mission-fill: rgba(99, 153, 34, 0.22); }
td.mission-neutral { --mission-edge: rgba(150, 150, 150, 0.7); --mission-w: 3px; --mission-fill: rgba(150, 150, 150, 0.18); }
td.mission-pin::after {
    content: '';
    position: absolute;
    inset: 2px;
    border: 1px dashed rgba(200, 200, 200, 0.75);
    border-radius: 2px;
    pointer-events: none;
    z-index: 2;
}

.spot-line {
    position: absolute;
    left: 0;
    right: 0;
    z-index: 3;
    height: 2px;
    border-top: 0;
    background: linear-gradient(90deg,
        #f08a24 0%,
        #f08a24 42.8571%,
        transparent 42.8571%,
        transparent 57.1429%,
        #f08a24 57.1429%,
        #f08a24 100%);
    box-shadow: none;
    filter: drop-shadow(0 0 1px rgba(255, 255, 255, 0.82)) drop-shadow(0 0 9px rgba(240, 138, 36, 0.58));
    pointer-events: none;
    transform: translateY(-1px);
    transition: none;
}

.spot-line::before {
    content: none;
}

/* Background band (USER 2026-07-29, Option A): a translucent amber strip centered on the
   spot line. It replaces the old opaque label pill (98% white + border + shadow, z-index 29)
   that sat over the Strike column and hid the ATM strike. z-index 2 keeps the band under the
   2px spot line (z-index 3); everything is pointer-events none so rows stay interactive. */
.spot-band {
    position: absolute;
    left: 0;
    right: 0;
    z-index: 2;
    height: 22px;
    pointer-events: none;
    transform: translateY(-50%);
    background: rgba(240, 138, 36, 0.13);
}

/* Faded price · source · time watermark inside the band. Semi-transparent by design: the
   strike-row data must remain the dominant layer; the spot detail is a glance-read only. */
.spot-watermark {
    position: absolute;
    top: 50%;
    z-index: 1;
    transform: translate(-50%, -50%);
    display: inline-flex;
    flex-direction: row;
    align-items: baseline;
    gap: 8px;
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
    white-space: nowrap;
}

/* Single label centered over the Strike column. The table is asymmetric: the call side carries an
   extra 200px Δ-Flow column (delta-windows-col) with no put-side mirror, so the Strike cell's center
   sits 100px (half that column) to the right of the table's geometric mid-line. */
.spot-label-center {
    left: calc(50% + 100px);
}

.spot-time-label, .spot-price-label {
    display: block;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    transform: none;
    white-space: nowrap;
}

/* Spot provenance label — which cascade tier produced the displayed spot
   (LIVE = live SPX cash index, ES-BASIS, ES, SYN, DELAYED, STATIC). Tier colors stay,
   at watermark opacity, so a degraded source still reads amber at a glance. */
.spot-source-label {
    display: block;
    font-size: 8px;
    font-weight: 900;
    letter-spacing: 0.08em;
    line-height: 1.1;
    color: #9aa6b8;
    text-shadow:
        1px 0 0 rgba(28, 14, 2, 0.95), -1px 0 0 rgba(28, 14, 2, 0.95),
        0 1px 0 rgba(28, 14, 2, 0.95), 0 -1px 0 rgba(28, 14, 2, 0.95),
        1px 1px 0 rgba(28, 14, 2, 0.95), 1px -1px 0 rgba(28, 14, 2, 0.95),
        -1px 1px 0 rgba(28, 14, 2, 0.95), -1px -1px 0 rgba(28, 14, 2, 0.95);
    white-space: nowrap;
}

.spot-source-live {
    color: rgba(96, 220, 145, 0.55);
}

.spot-source-syn, .spot-source-delayed, .spot-source-static {
    color: rgba(255, 165, 60, 0.6);
}

.spot-time-label {
    font-size: 10px;
    font-weight: 850;
    letter-spacing: 0.03em;
    color: #ffb454;
    text-shadow:
        1px 0 0 rgba(28, 14, 2, 0.95), -1px 0 0 rgba(28, 14, 2, 0.95),
        0 1px 0 rgba(28, 14, 2, 0.95), 0 -1px 0 rgba(28, 14, 2, 0.95),
        1px 1px 0 rgba(28, 14, 2, 0.95), 1px -1px 0 rgba(28, 14, 2, 0.95),
        -1px 1px 0 rgba(28, 14, 2, 0.95), -1px -1px 0 rgba(28, 14, 2, 0.95);
}

.spot-price-label {
    color: #ffb454;
    text-shadow:
        1px 0 0 rgba(28, 14, 2, 0.95), -1px 0 0 rgba(28, 14, 2, 0.95),
        0 1px 0 rgba(28, 14, 2, 0.95), 0 -1px 0 rgba(28, 14, 2, 0.95),
        1px 1px 0 rgba(28, 14, 2, 0.95), 1px -1px 0 rgba(28, 14, 2, 0.95),
        -1px 1px 0 rgba(28, 14, 2, 0.95), -1px -1px 0 rgba(28, 14, 2, 0.95);
    font-size: 13px;
    font-weight: 950;
    letter-spacing: 0.02em;
}

.mid-call, .mid-put {
    color: #2e9cff;
    font-weight: 950;
    text-shadow: 0 0 10px rgba(46, 156, 255, 0.34);
}

.price-with-credit {
    display: inline-flex;
    align-items: flex-start;
    justify-content: center;
    gap: 4px;
    min-width: 72px;
}

.spread-credit {
    color: #96ccff;
    font-size: 10px;
    font-weight: 950;
    line-height: 1;
    transform: translateY(-0.28em);
}

/* ES chain: per-strike SPX-equivalent superscript (strike − carry-decayed ES-SPX basis) */
.spx-equiv {
    color: #7ce7d0;
    font-size: 9px;
    font-weight: 800;
    line-height: 1;
    margin-left: 2px;
    transform: translateY(-0.3em);
}

/* ES price card: the ES→SPX mapping line under the ESM6 price */
.es-spx-mapping {
    color: #7ce7d0;
    display: block;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.spread-selectable {
    cursor: pointer;
    user-select: none;
}

.spread-selectable .price-with-credit {
    border-bottom: 1px dotted currentColor;
}

.spread-selectable:hover {
    background: rgba(46, 156, 255, 0.16);
}

.spread-selected {
    background: rgba(46, 156, 255, 0.22);
    box-shadow: inset 0 0 0 2px rgba(46, 156, 255, 0.58);
}

.order-ticket {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    flex-wrap: wrap;
    min-width: min(100%, 520px);
}

.order-ticket strong {
    margin: 0;
    color: var(--ink);
    font-size: 12px;
}

.order-ticket input {
    width: 70px;
}

.stage-order {
    width: auto;
    min-width: 112px;
    padding: 0 12px;
    white-space: nowrap;
    background: linear-gradient(135deg, #f08a24, #cb6916);
}

.strike-cell {
    position: relative;
    isolation: isolate;
    overflow: visible;
    /* Top-anchor content so the gamma line never re-centers when the vanna band renders — constant layout. */
    vertical-align: top;
    --cell-text-mask-bg: #191a25;
    min-width: 170px;
    font-size: 16px;
    font-weight: 650;
    color: #ffffff;
    background:
        linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px),
        #191a25;
    text-shadow: none;
    text-rendering: geometricPrecision;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

.strike-gex-content {
    position: relative;
    z-index: 3;
    display: block;
    min-height: 18px;
}

.strike-gex-line {
    /* FLEX, not a 2-column grid. This line holds a variable number of children -- price, GEX
       value, delta-flow, the dealer-ledger pill, the strike-action badge -- and a grid with two
       declared columns auto-places every extra child onto a NEW ROW. That is what made the cell
       grow ~10px the moment an action badge (AVOID included) appeared: the badge was not beside
       the GEX value, it was underneath it, doubling the line and breaking the fixed 44px row
       height, so every row below shifted. A single nowrap flex row keeps them all on one line no
       matter how many appear or disappear. */
    display: flex;
    flex-wrap: nowrap;
    align-items: baseline;
    gap: 10px;
    width: 100%;
    min-width: 0;
    white-space: nowrap;
    /* Contains the line now that .uw-gex-value has a min-width floor: a crowded line clips at the
       cell edge instead of painting into the band column beside it. The GEX history popover is a
       sibling of this line, not a child, so it is not clipped. */
    overflow: hidden;
}

.strike-gex-line > * {
    flex: 0 0 auto;
}

/* Two children may give up space so the line can never overflow a narrow strike column: the GEX
   value first, then the action badge. Everything else (the price wrapper above all) keeps its
   size. table-layout: fixed stops the column from growing but does NOT contain a child that is
   wider than it, so something must be allowed to shrink. */
.strike-gex-line > .uw-gex-value,
.strike-gex-line > .strike-action-badge {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The GEX value may TRUNCATE, never vanish. It is the first child the line gives up, and min-width: 0
   above let a narrow column delete the number outright — which is exactly what happened when the band
   columns took the strike column down to 87px. This must carry the SAME specificity as that rule
   (.strike-gex-line > .uw-gex-value); a plain .uw-gex-value floor loses the cascade and computes to
   0px, measured. The action badge keeps min-width: 0 and remains the child that gives way second, and
   .strike-gex-line clips, so this floor can never push content out of the cell. */
.strike-gex-line > .uw-gex-value {
    min-width: 4ch;
}

.strike-price-value {
    display: inline-block;
    min-width: 48px;
    line-height: 1.05;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    text-align: left;
}

/* Option Control lives on the LOWER EDGE of the strike box. The price and the GEX/flow badges stay
   unobstructed above it. The horizontal track is put-control on the left and call-control on the
   right. Direction colors follow their market meaning: call-leads/upside is green and
   put-leads/downside is red; the small number is the stabilized normalized residual gap. */
.strike-price-with-truth {
    display: inline-flex;
    align-items: center;
    min-height: 30px;
    white-space: nowrap;
}

/* IV-divergence confirmation strip (rev 3.5 §10): 5px vertical band on the strike cell's right
   edge, ABSOLUTELY positioned so the fixed row skeleton is untouched. Non-color cues are the
   glyph + native tooltip (title/aria-label). Colors are >=3:1 against the dark cell background
   (WCAG 2.1 AA non-text): teal #5dcaa5, amber #ef9f27, gray #8a93a3. */
.iv-confirm-strip {
    position: absolute;
    z-index: 6;
    top: 3px;
    bottom: 10px;
    right: 1px;
    width: 5px;
    border-radius: 2px;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: auto;
}
.iv-confirm-strip .iv-confirm-glyph {
    font-size: 8px;
    line-height: 1;
    font-weight: 700;
    color: #0b0e14;
}
.iv-confirm-confirms { background: #5dcaa5; }
.iv-confirm-diverges { background: #ef9f27; }
.iv-confirm-abstain { background: #8a93a3; }
.iv-confirm-abstain .iv-confirm-glyph { color: #1a1c26; }

/* IV-divergence header chip: five DISTINCT states; text color carries >=4.5:1 on its pill. */
.iv-confirm-chip {
    display: inline-flex;
    align-items: center;
    margin-left: 10px;
    padding: 1px 8px;
    border-radius: 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    background: #232633;
    color: #aeb6c4;
    border: 1px solid #3a3f52;
}
.iv-confirm-chip.iv-confirm-confirms { background: #10281f; color: #5dcaa5; border-color: #5dcaa5; }
.iv-confirm-chip.iv-confirm-diverges { background: #2a1f0a; color: #ef9f27; border-color: #ef9f27; }
.iv-confirm-chip.iv-confirm-neutral { background: #232633; color: #aeb6c4; border-color: #3a3f52; }
.iv-confirm-chip.iv-confirm-abstain { background: #232633; color: #8a93a3; border-color: #3a3f52; }
.iv-confirm-chip.iv-confirm-stale { background: #232633; color: #8a93a3; border-style: dashed; }

.option-truth-readout {
    position: absolute;
    z-index: 6;
    left: 8px;
    right: 7px;
    bottom: 1px;
    display: flex;
    align-items: center;
    gap: 4px;
    height: 7px;
    pointer-events: auto;
}

.option-truth-control-line {
    position: relative;
    display: block;
    flex: 1 1 auto;
    min-width: 40px;
    height: 5px;
}

.option-truth-axis {
    position: absolute;
    z-index: 1;
    left: 0;
    right: 0;
    bottom: 2px;
    height: 1px;
    background: rgba(255, 255, 255, 0.28);
}

.option-truth-center-mark {
    position: absolute;
    z-index: 3;
    left: 50%;
    bottom: 0;
    width: 1px;
    height: 5px;
    background: rgba(255, 255, 255, 0.68);
}

.option-truth-fill {
    position: absolute;
    z-index: 2;
    bottom: 1px;
    height: 3px;
    border-radius: 3px;
    transition: width 700ms ease;
}

.option-truth-call-leads .option-truth-fill {
    left: 50%;
    background: var(--call);
    box-shadow: 0 0 5px color-mix(in srgb, var(--call) 60%, transparent);
}

.option-truth-put-leads .option-truth-fill {
    right: 50%;
    background: var(--put);
    box-shadow: 0 0 5px color-mix(in srgb, var(--put) 60%, transparent);
}

.option-truth-filtered .option-truth-axis {
    background: rgba(255, 255, 255, 0.10);
    border-top: 1px dashed rgba(255, 255, 255, 0.16);
}

.option-truth-strength {
    flex: 0 0 24px;
    color: rgba(255, 255, 255, 0.72);
    font-size: 8px;
    font-weight: 650;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.strike-price-value,
.uw-gex-value {
    background: var(--cell-text-mask-bg);
    box-shadow: 0 0 0 5px var(--cell-text-mask-bg);
    border-radius: 6px;
}

/* Turn-alert "blink": pulses the strike GLYPH only (never the cell/row) while a StrikeTurnAlert is
   active for that strike. Direction sets the colour; the glow uses currentColor so it matches. */
.strike-price-value.strike-turn-blink {
    animation: strikeTurnBlink 1.1s ease-in-out infinite;
}
.strike-price-value.strike-turn-blink.turn-bearish { color: #ff5d6b; }
.strike-price-value.strike-turn-blink.turn-bullish { color: #2fd39a; }
@keyframes strikeTurnBlink {
    0%, 100% { opacity: 1; text-shadow: none; }
    50% { opacity: 0.4; text-shadow: 0 0 9px currentColor; }
}
@media (prefers-reduced-motion: reduce) {
    .strike-price-value.strike-turn-blink {
        animation: none;
        text-shadow: 0 0 9px currentColor;
    }
}

.uw-gex-value {
    display: inline-block;
    margin-top: 0;
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    color: rgba(255, 255, 255, 0.96);
    font-size: 12px;
    font-weight: 500;
    line-height: 1.05;
    letter-spacing: 0.005em;
    text-shadow: none;
    font-variant-numeric: tabular-nums;
    text-overflow: ellipsis;
    text-align: right;
    justify-self: end;
}

/* Compact per-strike Δ-Flow (sessionNetDeltaFlow), signed + colored by sign. */
.delta-flow-value {
    /* Δ-flow now lives at the far-LEFT of the in-flow vanna line (line 2) — a fixed bottom-left slot
       that never changes side with gamma sign or with which way the strength bars fill (Δ sits on top
       of the bars at a higher z-index). display:block/justify-self:end were the old line-1 grid-era
       styles; inline-block + left is the flex-child home. */
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
    text-overflow: ellipsis;
    text-align: left;
    white-space: nowrap;
}

.delta-flow-value.delta-flow-positive {
    color: #2ecc71;
}

.delta-flow-value.delta-flow-negative {
    color: #e74c3c;
}

.delta-flow-value.delta-flow-zero {
    color: rgba(255, 255, 255, 0.7);
}

/* Driver "mechanic" colouring (session window): bullish drivers green, a hedge is AMBER (a lean,
   not supply), real resistance is red. Amber deliberately breaks the "negative = down" reflex. */
.delta-flow-value.delta-flow-chase,
.delta-flow-value.delta-flow-support {
    color: #2ecc71;
}

.delta-flow-value.delta-flow-hedge {
    color: #f2bd63;
}

.delta-flow-value.delta-flow-resist {
    color: #e74c3c;
}

.delta-flow-driver-ic {
    margin-right: 1px;
    font-size: 0.95em;
}

/* Flip-risk: a contested strike (thin net on heavy two-sided flow) whose driver is fragile — likely to
   flip if the underlying pushes through. Amber warning bolt + a subtle dashed underline on the value. */
.delta-flow-flip {
    color: #f2bd63;
    font-size: 0.9em;
    margin-left: 1px;
}
.delta-flow-value.delta-flow-fragile {
    text-decoration: underline dotted rgba(242, 189, 99, 0.7);
    text-underline-offset: 3px;
}

/* Support / Resistance render a custom inline SVG mark (green-floor + red falling knife / red-ceiling +
   green rising knife) instead of an emoji. Sized ~1.4em so it reads next to the value without breaking the row. */
.delta-flow-driver-svg {
    width: 1.4em;
    height: 1.4em;
    vertical-align: -0.28em;
    margin-right: 1px;
}

.gex-strength-fill {
    position: absolute;
    top: 0;
    bottom: 0;
    z-index: 0;
    display: block;
    width: var(--gex-fill-width, 0%);
    opacity: 0.92;
    pointer-events: none;
    transition: width 220ms ease, left 220ms ease, right 220ms ease;
}

.strike-cell.gamma-positive .gex-strength-fill {
    left: 50%;
    background:
        repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.16) 0 8px, transparent 8px 11px),
        linear-gradient(90deg, rgba(46, 156, 255, 0.34), rgba(46, 156, 255, 0.96));
    box-shadow: 0 0 20px rgba(46, 156, 255, 0.28);
}

.strike-cell.gamma-negative .gex-strength-fill {
    right: 50%;
    background:
        repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.15) 0 8px, transparent 8px 11px),
        linear-gradient(270deg, rgba(255, 90, 104, 0.34), rgba(255, 90, 104, 0.96));
    box-shadow: 0 0 20px rgba(255, 90, 104, 0.28);
}

.strike-cell.gamma-neutral .gex-strength-fill {
    left: 50%;
    transform: translateX(-50%);
    background: rgba(160, 172, 184, 0.42);
}

.strike-cell.gamma-stale .gex-strength-fill {
    left: 0;
    width: 100%;
    background: rgba(88, 96, 108, 0.34);
}

.gex-strength-axis {
    position: absolute;
    top: 4px;
    bottom: 4px;
    left: 50%;
    z-index: 1;
    width: 1px;
    background: rgba(255, 255, 255, 0.42);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.22);
    pointer-events: none;
}

.gex-strength-arrow {
    position: absolute;
    top: 2px;
    left: var(--gex-arrow-left, 50%);
    z-index: 4;
    width: 18px;
    transform: translateX(-50%);
    border-radius: 999px;
    background: rgba(4, 8, 16, 0.72);
    font-size: 13px;
    font-weight: 950;
    line-height: 16px;
    text-align: center;
    text-shadow: none;
    pointer-events: none;
    transition: left 220ms ease;
}

.gex-arrow-right { color: #75beff; }
.gex-arrow-left { color: #ff7b7b; }
.gex-arrow-flat { color: #d8e4ef; }

/* ── Move-authenticity track (greek-move-auth / MoveAuthenticityVerdict §17.6) ─────────────────
   A thin horizontal bar pinned below the strike box on the ATM row, mirroring the .gex-strength-fill
   absolute-fill approach. Segments (green=REAL / red=FAKE / grey=NEUTRAL) span a spot-domain %-axis;
   the start / turned-fake / turned-real / now tick markers ride on top. Dark-launched behind
   greekMoveAuthVisible, so it only ever appears once the backend enables it. */
.move-auth-track {
    position: absolute;
    left: 6px;
    right: 6px;
    bottom: 2px;
    height: 4px;
    z-index: 3;
    border-radius: 999px;
    background: rgba(120, 132, 148, 0.22);
    pointer-events: none;
    overflow: visible;
}

.move-auth-seg {
    position: absolute;
    top: 0;
    bottom: 0;
    min-width: 1px;
    border-radius: 999px;
    transition: left 220ms ease, width 220ms ease;
}

.move-auth-seg-real {
    background: linear-gradient(90deg, rgba(46, 200, 120, 0.72), rgba(46, 200, 120, 0.98));
    box-shadow: 0 0 8px rgba(46, 200, 120, 0.4);
}

.move-auth-seg-fake {
    background: linear-gradient(90deg, rgba(255, 90, 104, 0.72), rgba(255, 90, 104, 0.98));
    box-shadow: 0 0 8px rgba(255, 90, 104, 0.4);
}

.move-auth-seg-neutral {
    background: rgba(160, 172, 184, 0.5);
}

.move-auth-mark {
    position: absolute;
    top: 50%;
    width: 5px;
    height: 5px;
    z-index: 4;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35);
    transition: left 220ms ease;
}

.move-auth-mark-start { background: #d8e4ef; }
.move-auth-mark-fake { background: #ff5a68; }
.move-auth-mark-real { background: #2ec878; }
.move-auth-mark-now {
    width: 6px;
    height: 6px;
    background: #ffffff;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45), 0 0 6px rgba(255, 255, 255, 0.7);
}

/* ── LEGACY half-cell exposure geometry (compatibility-only) ────────────────
   Superseded 2026-07-24 by the checkbox lane layout: every StrikeCell now carries
   .xb, whose var-driven lane rules (appended at the END of this file) override the
   half-cell geometry below at equal specificity. Precisely: .gv-split is STILL
   emitted on .xb cells (it drives the in-flow vanna text line) but its geometry
   here is overridden by the .xb lanes; .gv-has-es is no longer emitted anywhere
   (dead fallback kept for a cell that ever renders without lane vars); the
   .gv-es-only ES-only overnight rows have their OWN rules further down and do
   not use these. Do not extend them — extend the .xb lanes. */
.strike-cell.gv-split .gex-strength-fill { bottom: 50%; }
.strike-cell.gv-split .gex-strength-axis { bottom: calc(50% + 3px); }
/* LEGACY (compatibility-only, see the header above): .gv-has-es is no longer emitted by StrikeCell —
   the ES lane rides the .xb vars now. Kept solely as a fallback for a cell without lane vars. */
.strike-cell.gv-has-es .gex-strength-fill { bottom: 50%; }
.strike-cell.gv-has-es .gex-strength-axis { bottom: calc(50% + 3px); }

.vanna-strength-fill {
    position: absolute;
    top: 0;
    bottom: 0;
    z-index: 0;
    display: block;
    width: var(--vanna-fill-width, 0%);
    opacity: 0.9;
    pointer-events: none;
    transition: width 220ms ease, left 220ms ease, right 220ms ease;
}

.strike-cell.gv-split .vanna-strength-fill { top: 50%; }

.strike-cell.vanna-positive .vanna-strength-fill {
    left: 50%;
    background:
        repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.14) 0 8px, transparent 8px 11px),
        linear-gradient(90deg, rgba(179, 140, 255, 0.30), rgba(179, 140, 255, 0.90));
    box-shadow: 0 0 18px rgba(179, 140, 255, 0.24);
}

.strike-cell.vanna-negative .vanna-strength-fill {
    right: 50%;
    background:
        repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.14) 0 8px, transparent 8px 11px),
        linear-gradient(270deg, rgba(245, 178, 74, 0.30), rgba(245, 178, 74, 0.92));
    box-shadow: 0 0 18px rgba(245, 178, 74, 0.24);
}

.strike-cell.vanna-neutral .vanna-strength-fill {
    left: 50%;
    transform: translateX(-50%);
    background: rgba(160, 172, 184, 0.36);
}

.vanna-strength-axis {
    position: absolute;
    top: 4px;
    bottom: 4px;
    left: 50%;
    z-index: 1;
    width: 1px;
    background: rgba(255, 255, 255, 0.34);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.22);
    pointer-events: none;
}

.strike-cell.gv-split .vanna-strength-axis { top: calc(50% + 3px); }

.vanna-strength-arrow {
    position: absolute;
    top: 2px;
    left: var(--vanna-arrow-left, 50%);
    z-index: 4;
    width: 16px;
    transform: translateX(-50%);
    border-radius: 999px;
    background: rgba(4, 8, 16, 0.72);
    font-size: 12px;
    font-weight: 950;
    line-height: 15px;
    text-align: center;
    text-shadow: none;
    pointer-events: none;
    transition: left 220ms ease;
}

.strike-cell.gv-split .vanna-strength-arrow { top: auto; bottom: 2px; }

.strike-cell.vanna-positive .vanna-strength-arrow { color: #cbb4ff; }
.strike-cell.vanna-negative .vanna-strength-arrow { color: #f6c065; }
.strike-cell.vanna-neutral .vanna-strength-arrow { color: #d8e4ef; }

/* Vanna value row: bottom band, a hairline below the gamma line, its own masked chips. */
.strike-vanna-line {
    position: relative;
    z-index: 3;
    display: flex;
    /* center (not baseline): Δ's driver badge — the 🚀 chase / 🛡 hedge glyphs and the support/resist
       SVG marks — is taller than the text, and baseline alignment shoved it (and the Δ value) out of
       the fixed 15px band where overflow:hidden clipped it. Centering keeps badge + Δ + V + C fully
       visible in the band. */
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: 3px;
    padding-top: 2px;
    /* Fixed height so the band occupies the SAME space whether the vanna value is present or not —
       the cell never reflows/flickers as vanna arrives/updates. */
    height: 15px;
    box-sizing: border-box;
    overflow: hidden;
    white-space: nowrap;
}

/* Δ-flow is the FIXED bottom-left of line 2: margin-right:auto pins it hard-left (vanna/charm pack to
   the right, unchanged); under crowding it shrinks + ellipsizes rather than pushing V/C off the band;
   and it stays visible even when the line is .vanna-idle (which sets visibility:hidden on the band) —
   Δ must always show, vanna/charm may not. */
.strike-vanna-line .delta-flow-value {
    margin-right: auto;
    /* shrink + ellipsize under crowding so a long Δ never pushes V/C off the band (Codex) */
    flex: 0 1 auto;
    min-width: 0;
    visibility: visible;
    line-height: 1;
}

/* Δ's driver badge must fit the fixed 15px band: the default 1.4em SVG (~15.4px) overran it and was
   clipped. Pin the support/resist marks to 12px and center them; the 🚀/🛡 emoji ride the same line. */
.strike-vanna-line .delta-flow-driver-svg {
    width: 12px;
    height: 12px;
    vertical-align: middle;
    margin-right: 2px;
}
.strike-vanna-line .delta-flow-driver-ic {
    font-size: 11px;
    line-height: 1;
    vertical-align: middle;
}

/* Reserved-but-empty vanna text line (gamma+vanna checked, no vanna value for this strike):
   occupies its fixed height so the cell never reflows, but renders nothing — no "V", no divider —
   so strikes without vanna stay quiet and the real vanna values (near spot) stand out. */
.strike-vanna-line.vanna-idle {
    visibility: hidden;
}

/* The hairline divider only on cells that actually show a vanna value. */
.strike-cell.gv-split.gv-has-vanna .strike-gex-content {
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    padding-bottom: 2px;
}

.vanna-tag {
    display: inline-block;
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 0.08em;
    color: rgba(255, 255, 255, 0.62);
    background: var(--cell-text-mask-bg);
    box-shadow: 0 0 0 4px var(--cell-text-mask-bg);
    border-radius: 5px;
}

.uw-vanna-value {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.05;
    letter-spacing: 0.005em;
    text-shadow: none;
    font-variant-numeric: tabular-nums;
    text-overflow: ellipsis;
    text-align: right;
    background: var(--cell-text-mask-bg);
    box-shadow: 0 0 0 5px var(--cell-text-mask-bg);
    border-radius: 6px;
}

.strike-cell.vanna-positive .uw-vanna-value { color: #c9b3ff; }
.strike-cell.vanna-negative .uw-vanna-value { color: #f4b24a; }
.strike-cell.vanna-neutral .uw-vanna-value { color: rgba(255, 255, 255, 0.7); }

/* The header exposure control is now the gamma/vanna/charm checkbox picker —
   see .exposure-band-picker at the end of this file. */
/* ES-on-SPX gamma overlay: independent toggle + status chip + the independent ES exposure lane. */
.es-gamma-toggle-wrap { display: inline-flex; align-items: center; gap: 4px; }
.es-gamma-toggle {
    display: inline-flex; align-items: center; height: 28px; padding: 0 10px;
    border: 1px solid var(--line); border-radius: 10px;
    background: rgba(255, 255, 255, 0.72); color: #35443b; font-size: 10px; cursor: pointer;
}
.es-gamma-toggle-on { background: #2a3f6b; color: #eaf1ff; border-color: #2a3f6b; }
/* Strike Flow Board switch. Shaped like the ES gamma toggle beside it because it does the same
   KIND of job — it decides whether a whole surface is drawn, not what that surface shows — and
   carries its own checkbox so its state is readable without hovering for the title. */
.flow-board-toggle {
    display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 10px;
    border: 1px solid var(--line); border-radius: 10px;
    background: rgba(255, 255, 255, 0.72); color: #35443b; font-size: 10px; cursor: pointer;
    white-space: nowrap;
}
.flow-board-toggle input { margin: 0; width: 13px; height: 13px; cursor: pointer; }
.flow-board-toggle-on { background: #2a3f6b; color: #eaf1ff; border-color: #2a3f6b; }
.es-gamma-status { font-size: 9px; padding: 1px 5px; border-radius: 8px; background: rgba(42,63,107,0.12); color: #2a3f6b; }
.es-gamma-status-stale, .es-gamma-status-mirror-unavailable, .es-gamma-status-invalid-basis { background: rgba(180,60,60,0.14); color: #b43c3c; }
.es-gamma-status-projected { background: rgba(200,150,40,0.16); color: #8a6a10; }
/* ── ES gamma band ──────────────────────────────────────────────────────────
   ES gamma renders as a GAUGE, not a number chip (USER 2026-07-21: the old
   `ES 1.2M` text read as clutter). Markup mirrors the vanna band exactly; the
   .xb lane vars assign it its own selected lane on loaded SPX rows;
   .gv-es-only (ES-only overnight rows, no SPX gamma to share
   with) leaves it at full cell height. Green = long gamma, red = short gamma —
   the ES chip's original colours, kept so the sign reads the same as before.
   Scale is the single ES max-abs, INDEPENDENT of SPX gamma (see tooltip). */
.es-strength-fill {
    position: absolute;
    top: 0;
    bottom: 0;
    z-index: 0;
    display: block;
    width: var(--es-fill-width, 0%);
    opacity: 0.9;
    pointer-events: none;
    transition: width 220ms ease, left 220ms ease, right 220ms ease;
}

.strike-cell.gv-has-es .es-strength-fill { top: 50%; }

.strike-cell.es-gex-positive .es-strength-fill {
    left: 50%;
    background:
        repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.14) 0 8px, transparent 8px 11px),
        linear-gradient(90deg, rgba(46, 200, 120, 0.30), rgba(46, 200, 120, 0.88));
    box-shadow: 0 0 18px rgba(46, 200, 120, 0.22);
}

.strike-cell.es-gex-negative .es-strength-fill {
    right: 50%;
    background:
        repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.14) 0 8px, transparent 8px 11px),
        linear-gradient(270deg, rgba(255, 90, 104, 0.30), rgba(255, 90, 104, 0.90));
    box-shadow: 0 0 18px rgba(255, 90, 104, 0.22);
}

.strike-cell.es-gex-neutral .es-strength-fill {
    left: 50%;
    transform: translateX(-50%);
    background: rgba(160, 172, 184, 0.36);
}

.es-strength-axis {
    position: absolute;
    top: 4px;
    bottom: 4px;
    left: 50%;
    z-index: 1;
    width: 1px;
    background: rgba(255, 255, 255, 0.34);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.22);
    pointer-events: none;
}

.strike-cell.gv-has-es .es-strength-axis { top: calc(50% + 3px); }

.es-strength-arrow {
    position: absolute;
    top: 2px;
    left: var(--es-arrow-left, 50%);
    z-index: 4;
    width: 16px;
    transform: translateX(-50%);
    border-radius: 999px;
    background: rgba(4, 8, 16, 0.72);
    font-size: 12px;
    font-weight: 950;
    line-height: 15px;
    text-align: center;
    text-shadow: none;
    pointer-events: none;
    transition: left 220ms ease;
}

.strike-cell.gv-has-es .es-strength-arrow { top: auto; bottom: 2px; }

.strike-cell.es-gex-positive .es-strength-arrow { color: #7ff0b4; }
.strike-cell.es-gex-negative .es-strength-arrow { color: #ff9aa4; }
.strike-cell.es-gex-neutral  .es-strength-arrow { color: #d8e4ef; }

/* "ES" marker — several look-alike gauge lanes can coexist, so the ES lane says whose gamma this is. */
.es-band-tag {
    position: absolute;
    left: 3px;
    z-index: 4;
    font-size: 7px;
    font-weight: 800;
    letter-spacing: 0.06em;
    line-height: 1;
    color: rgba(216, 228, 239, 0.72);
    text-shadow: 0 0 3px rgba(4, 8, 16, 0.9);
    pointer-events: none;
}

.strike-cell.gv-has-es .es-band-tag { bottom: 3px; }
.strike-cell.gv-es-only .es-band-tag { top: 3px; }

/* Projected basis = the ES→SPX mapping is extrapolated, not measured. Dashed axis flags it. */
.strike-cell.es-gex-projected .es-strength-axis {
    background: repeating-linear-gradient(180deg, rgba(255,255,255,0.5) 0 3px, transparent 3px 6px);
}

/* ES-ONLY overlay row (Part B): an ES-mapped strike with no SPX chain row yet (overnight, pre-open).
   Faint tint + dashed left rule so it reads as a provisional overlay, not a real SPX row. */
.es-only-row { background: rgba(42,63,107,0.05); }
.es-only-row .es-only-blank { color: var(--muted, #9aa4b2); text-align: center; }
.es-only-row .es-only-price { font-weight: 700; }
.es-only-strike { border-left: 2px dashed rgba(42,63,107,0.45); }
.es-gex-only { outline: 1px dotted rgba(42,63,107,0.55); }


.uw-gex-popover {
    position: absolute;
    z-index: 40;
    left: 50%;
    bottom: calc(100% + 8px);
    display: none;
    width: 260px;
    transform: translateX(-50%);
    padding: 11px 12px;
    border: 1px solid rgba(180, 224, 255, 0.45);
    border-radius: 12px;
    background: rgba(12, 16, 26, 0.98);
    box-shadow: 0 18px 42px rgba(0, 0, 0, 0.35);
    color: #f8fbff;
    text-align: left;
    text-shadow: none;
    pointer-events: none;
}

.strike-cell:hover .uw-gex-popover,
.strike-cell:focus-within .uw-gex-popover {
    display: block;
}

.uw-gex-popover::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: -7px;
    width: 12px;
    height: 12px;
    transform: translateX(-50%) rotate(45deg);
    border-right: 1px solid rgba(180, 224, 255, 0.45);
    border-bottom: 1px solid rgba(180, 224, 255, 0.45);
    background: rgba(12, 16, 26, 0.98);
}

.uw-gex-popover strong,
.uw-gex-popover-strike,
.uw-gex-popover-meta,
.uw-gex-popover-updated {
    display: block;
}

.uw-gex-popover strong {
    margin-bottom: 4px;
    font-size: 12px;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

.uw-gex-popover-strike {
    margin: 2px 0 4px;
    color: #ffffff;
    font-size: 13px;
    font-weight: 850;
    letter-spacing: 0.02em;
}

.uw-gex-popover-meta,
.uw-gex-popover-updated {
    color: #b8c8db;
    font-size: 11px;
    font-weight: 800;
}

.uw-gex-popover ul {
    margin: 9px 0 0;
    padding-left: 0;
    list-style: none;
}

.uw-gex-popover li {
    display: grid;
    grid-template-columns: 42px minmax(64px, 1fr) auto;
    gap: 7px;
    align-items: baseline;
    margin-top: 5px;
    font-size: 11px;
}

.uw-gex-popover b {
    font-size: 11px;
}

.uw-gex-popover small {
    grid-column: span 2;
    color: #8fa0b3;
    font-size: 11px;
    font-weight: 800;
}

.gex-delta {
    font-style: normal;
    font-size: 11px;
    font-weight: 950;
}

.gex-delta-up { color: #75beff; }
.gex-delta-down { color: #ff7b7b; }
.gex-delta-flat { color: #b8c8db; }

.strike-cell.gamma-positive {
    background:
        linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px),
        #111a2a;
    box-shadow: inset 0 0 0 1px rgba(180, 224, 255, 0.72);
}

.strike-cell.gamma-negative {
    background:
        linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px),
        #23131a;
    box-shadow: inset 0 0 0 1px rgba(255, 186, 194, 0.68);
}

.strike-cell.gamma-neutral {
    background:
        linear-gradient(135deg, rgba(160, 172, 184, 0.4), rgba(39, 48, 60, 0.96)),
        #27303c;
}

.strike-cell.gamma-stale {
    background:
        linear-gradient(135deg, rgba(88, 96, 108, 0.58), rgba(25, 26, 37, 0.96)),
        #191a25;
    box-shadow: inset 0 0 0 1px rgba(255, 204, 102, 0.5);
}

/* Page-level fail-closed alarm: today's OI baseline has not arrived — visible pre-open, row-independent. */
.oi-missing-banner {
    margin: 8px 0;
    padding: 10px 16px;
    border-radius: 8px;
    background: linear-gradient(135deg, rgba(150, 40, 40, 0.92), rgba(96, 22, 22, 0.96));
    box-shadow: inset 0 0 0 1px rgba(255, 92, 92, 0.8);
    color: #ffd7d7;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-align: center;
}

/* Per-strike fail-closed marker: OI baseline missing, GEX deliberately absent for this strike. */
.strike-cell.gamma-oi-missing {
    background:
        linear-gradient(135deg, rgba(120, 52, 52, 0.55), rgba(25, 26, 37, 0.96)),
        #191a25;
    box-shadow: inset 0 0 0 1px rgba(255, 92, 92, 0.65);
}

.strike-cell.gamma-oi-missing .uw-gex-value {
    color: #ff8a8a;
    font-weight: 600;
}

.gamma-stale-marker {
    position: absolute;
    top: 4px;
    right: 7px;
    color: #ffcc66;
    font-size: 10px;
    font-weight: 950;
    line-height: 1;
    text-shadow: 0 1px 0 #000;
}

/* The chain table is table-layout:fixed, so COLUMN width comes from the HEADER cell — the td width
   alone was ignored and the volume columns ballooned to an equal share of the table. The th width is
   the real control. Sizing: fmtVolume caps at "999.9k" (then flips to M), and that 6-char string at the
   21px/950 gold font measures ~80px — 96px minus the 4+6px cell padding leaves 86px, so even the largest
   gold top-volume figure fits without spilling into the next cell. */
.chain-table th.volume-col {
    width: 96px;
}
.volume-cell {
    /* Volume shows the number + the pace chip (rate/10s-delta, relocated from FLOW per user request);
       net-$/sweep signals stay in FLOW. Right-aligned; width kept in sync with th.volume-col. */
    width: 96px;
    min-width: 96px;
}
.call-volume { text-align: right; padding-left: 4px; padding-right: 6px; }
.put-volume { text-align: right; padding-left: 4px; padding-right: 6px; }

.volume-value {
    font-weight: 950;
    font-size: 14px;
    line-height: 1;
    color: #ffffff;
    text-shadow: 0 1px 0 #000;
    /* Tabular figures: the number changes in place without jitter. */
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* Intentional top-volume emphasis: bigger font + gold glow. The font size is bounded so it fits the FIXED
   compact row height below -- a cell crossing the top-volume threshold changes the DIGITS, not the row
   height, so the table stays static (like the leaderboard) instead of ballooning/shifting. */
.volume-cell.large-volume .volume-value {
    color: #fff7c2;
    text-shadow: 0 0 8px rgba(255, 224, 92, 0.85), 0 1px 0 #000;
}

/* Rank-tiered size for the top-3 volume strikes: #1 biggest, #2 smaller, #3 smallest — all gold.
   The multi-line FLOW cell drives row height, so the #1 tier can run a touch above the old 21px. */
.volume-cell.large-volume-1 .volume-value { font-size: 24px; }
.volume-cell.large-volume-2 .volume-value { font-size: 18px; }
.volume-cell.large-volume-3 .volume-value { font-size: 13px; }

.call-volume .volume-value,
.put-volume .volume-value { color: #ffffff; }

tr.strike-flow-row-buy td {
    background-color: rgba(68, 241, 154, 0.035);
}

tr.strike-flow-row-sell td {
    background-color: rgba(255, 106, 118, 0.04);
}

tr.strike-flow-row-mixed td {
    background-color: rgba(183, 197, 212, 0.025);
}

.pace-change-up {
    color: #3cff9a;
}

.pace-change-down {
    color: #ff5a68;
}

.pace-change-flat {
    color: #91a7bd;
}

@keyframes strikeFlowSlowPulse {
    0%, 100% {
        box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08), 0 0 0 rgba(255, 255, 255, 0);
    }
    50% {
        box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.28), 0 0 22px rgba(255, 255, 255, 0.12);
    }
}

.strike-flow-pulse {
    border-radius: 16px;
    animation: strikeFlowSlowPulse 4s ease-in-out infinite;
}

/* Continuous soft "breathing" blink for the board's top-N |net aggressor $| volume cells.
   Always-on (data-tick independent); migrates as flow changes. Amber so it does not collide with
   the green/red net superscript or the blue large-volume blink. */
@keyframes strikeFlowNetBlink {
    0%, 100% {
        box-shadow: inset 0 0 0 1px rgba(255, 196, 84, 0.18), 0 0 0 rgba(255, 196, 84, 0);
    }
    50% {
        box-shadow: inset 0 0 0 2px rgba(255, 196, 84, 0.55), 0 0 18px rgba(255, 196, 84, 0.30);
    }
}

.strike-flow-net-blink {
    border-radius: 16px;
    animation: strikeFlowNetBlink 2s ease-in-out infinite;
}

/* Accessibility: no motion — show a static amber ring instead of the pulsing animation. */
@media (prefers-reduced-motion: reduce) {
    .strike-flow-net-blink {
        animation: none;
        box-shadow: inset 0 0 0 2px rgba(255, 196, 84, 0.55);
    }
}

.chain-empty {
    padding: 28px;
    color: var(--muted);
    font-size: 14px;
    font-weight: 850;
    text-align: center;
}

.react-error {
    margin: 24px auto;
    max-width: 760px;
    padding: 18px;
    border: 1px solid #e4aaa1;
    border-radius: 18px;
    background: #ffe2dd;
    color: #54231d;
    font-family: Avenir Next, Gill Sans, Trebuchet MS, sans-serif;
    font-weight: 850;
}

@media (max-width: 980px) {
    .chain-header { align-items: flex-start; flex-direction: column; }
    .controls { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .summary-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .option-behavior-panel {
        grid-template-rows: auto auto auto;
        height: auto;
        min-height: 0;
        overflow: visible;
    }
    .option-behavior-board-header {
        grid-template-columns: 1fr;
        gap: 6px;
    }
    .option-behavior-meta {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .option-behavior-score-row,
    .option-behavior-lists {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .strike-flow-leaderboard-grid {
        grid-template-columns: 1fr;
    }
    .strike-flow-leader-column li {
        grid-template-columns: 56px 52px 78px;
    }
    .strike-flow-context {
        grid-column: 1 / -1;
    }
    .chain-toolbar { align-items: flex-start; flex-direction: column; }
    .table-wrap {
        height: calc(100vh - var(--oc-topnav-h, 0px) - 230px);
        min-height: 360px;
    }
}

@media (max-width: 640px) {
    .option-behavior-meta,
    .option-behavior-score-row,
    .option-behavior-lists {
        grid-template-columns: 1fr;
    }
}

/* ===== Phase H: strike-flow quality banner + sweep badge + EWMA momentum mini (append-only at EOF) ===== */
.strike-flow-quality-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 11px;
    font-weight: 700;
    background: rgba(255, 255, 255, 0.06);
    color: #cfd8e3;
}
.strike-flow-quality-badge .strike-flow-quality-dot { font-size: 12px; }
.strike-flow-quality-badge.quality-full { color: #6cf096; background: rgba(108, 240, 150, 0.10); }
.strike-flow-quality-badge.quality-best-effort { color: #f3c14a; background: rgba(243, 193, 74, 0.12); }
.strike-flow-quality-badge.quality-frozen { color: #ff7878; background: rgba(255, 120, 120, 0.14); }
.strike-flow-quality-badge.quality-unknown { color: #8d99a7; background: rgba(255, 255, 255, 0.05); }
/* FROZEN is railed, not dimmed (2026-08-13, USER: "remove this blur layer"). The red FROZEN
   quality badge above already names the state; opacity 0.55 only made the frozen numbers — which
   are still the last true reading — harder to read. */
.strike-flow-leaderboard.strike-flow-frozen .strike-flow-leaderboard-grid {
    box-shadow: inset 4px 0 0 #ff7878;
    outline: 1px dashed rgba(255, 120, 120, 0.65);
    outline-offset: 2px;
}

.strike-flow-sweep-badge {
    display: inline-flex;
    align-items: center;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 8px;
    font-size: 10px;
    font-weight: 800;
    color: #1a1f2a;
    background: linear-gradient(90deg, #ffd24c, #ff8e2a);
    box-shadow: 0 0 6px rgba(255, 142, 42, 0.55);
}

.strike-flow-ewma-mini {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 3px;
    margin-top: 4px;
    padding: 2px 4px;
    border-radius: 6px;
    background: rgba(255, 255, 255, 0.03);
}
.strike-flow-ewma-cell {
    text-align: center;
    font-size: 9px;
    font-weight: 700;
    padding: 2px 0;
    border-radius: 3px;
    color: #98a3b1;
}
.strike-flow-ewma-cell.ewma-pos { color: #6cf096; }
.strike-flow-ewma-cell.ewma-neg { color: #ff7878; }
.strike-flow-ewma-cell.ewma-zero { color: #6a7382; }
.strike-flow-ewma-cell.ewma-best { background: rgba(255, 255, 255, 0.08); }

/* ----- Max Pain card + 0DTE stale-OI banner ------------------------------- */
.maxpain-card {
    border-color: rgba(192, 132, 252, 0.40);
}
.maxpain-card-title {
    display: flex;
    align-items: center;
    gap: 6px;
}
.maxpain-chip {
    background: rgba(192, 132, 252, 0.18);
    color: #6f3fc7;
    padding: 1px 6px;
    border-radius: 4px;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.04em;
    /* Preserve the approved exact-text "Max Pain" — NEVER uppercase it. */
    text-transform: none;
}
.maxpain-strike {
    color: #6f3fc7;
}
.maxpain-tie {
    color: var(--muted);
    font-size: 10px;
    font-weight: 600;
    margin-left: 4px;
}
.maxpain-meta {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: 4px 8px;
    font-size: 11px;
    color: var(--muted);
    align-items: baseline;
}
.maxpain-oi-note {
    color: var(--muted);
    font-size: 9px;
    text-transform: uppercase;
}
.maxpain-warn {
    color: var(--orange);
    font-weight: 700;
}
/* v2 payout-surface signals */
.maxpain-tier {
    font-size: 9px;
    font-weight: 700;
    text-transform: uppercase;
    padding: 1px 5px;
    border-radius: 6px;
    letter-spacing: 0.03em;
}
.maxpain-tier-high { color: #16a34a; background: rgba(22, 163, 74, 0.16); }
.maxpain-tier-medium { color: #ca8a04; background: rgba(202, 138, 4, 0.16); }
.maxpain-tier-low { color: var(--muted); background: rgba(148, 163, 184, 0.16); }
.maxpain-dir { color: #6f3fc7; font-weight: 600; }
.maxpain-no-data .maxpain-strike { color: var(--muted); }

/* Continuous ES futures aggressor pressure — placed directly beside Magnet in the summary grid. */
.es-aggressor-flow-card { border-color: rgba(100, 116, 139, 0.5); }
.es-aggressor-flow-card.flow-bullish { border-color: rgba(34, 197, 94, 0.65); }
.es-aggressor-flow-card.flow-bearish { border-color: rgba(239, 68, 68, 0.65); }
/* Insufficient sample/unknown-side coverage — distinct dashed border so it never reads as a
   confident neutral read (flow-neutral is a real, reliable "balanced" measurement). */
.es-aggressor-flow-card.flow-insufficient { border-color: rgba(148, 163, 184, 0.5); border-style: dashed; }
.es-flow-title { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.es-flow-title select {
    background: var(--panel); color: var(--text); border: 1px solid var(--line);
    border-radius: 5px; padding: 2px 4px; font-size: 10px;
}
.es-aggressor-flow-card.flow-bullish > strong { color: #16a34a; }
.es-aggressor-flow-card.flow-bearish > strong { color: #dc2626; }
.es-aggressor-flow-card.flow-neutral > strong { color: var(--muted); }
.es-aggressor-flow-card.flow-insufficient > strong { color: var(--muted); font-style: italic; }
.es-flow-analysis { color: var(--muted); font-size: 10px; }
.es-flow-counts { display: flex; justify-content: space-between; gap: 8px; font-size: 10px; font-weight: 700; }
.es-flow-buy { color: #16a34a; }
.es-flow-sell { color: #dc2626; }
.es-flow-unknown { color: var(--muted); font-weight: 600; }
.es-flow-score { color: var(--muted); font-size: 9px; text-transform: uppercase; }
.es-flow-window-markers {
    display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 4px;
    margin-top: 3px; padding-top: 5px; border-top: 1px solid var(--line);
}
.es-flow-window-marker {
    min-width: 0; border-radius: 4px; padding: 3px 2px; text-align: center;
    font-size: 8px; font-weight: 800; line-height: 1.1; white-space: nowrap;
    color: var(--muted); background: rgba(100, 116, 139, 0.14);
}
.es-flow-window-marker.signal-green { color: #dcfce7; background: #16803d; }
.es-flow-window-marker.signal-red { color: #fee2e2; background: #b91c1c; }
.es-flow-window-marker.signal-na { color: var(--muted); font-style: italic; }
.es-flow-window-marker.is-selected { outline: 2px solid currentColor; outline-offset: 1px; }

/* Magnet (pin) card — sits next to Max Pain; amber accent to distinguish from Max Pain's purple. */
.magnet-card {
    border-color: rgba(217, 164, 65, 0.45);
}
.magnet-card-title {
    display: flex;
    align-items: center;
    gap: 6px;
}
.magnet-chip {
    background: rgba(217, 164, 65, 0.18);
    color: #b57e12;
    padding: 1px 6px;
    border-radius: 4px;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.04em;
    text-transform: none;
}
.magnet-strike {
    color: #b57e12;
}
.magnet-meta {
    display: grid;
    grid-template-columns: 1fr;
    gap: 4px 8px;
    font-size: 11px;
    color: var(--muted);
    align-items: baseline;
}
.magnet-no-data .magnet-strike { color: var(--muted); }

/* Gamma-flip / breakdown-risk / gamma-collapse rows under the pin number (data already in the magnet payload). */
.magnet-risk-row,
.magnet-flip-row,
.magnet-collapse-row {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    margin-top: 3px;
    /* Reserve height even when empty so toggling content never resizes the card (constant height = no reflow). */
    min-height: 15px;
    white-space: nowrap;
    overflow: hidden;
}
.magnet-risk-badge {
    padding: 1px 6px;
    border-radius: 4px;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.03em;
}
.magnet-risk-badge.risk-low { background: rgba(34, 197, 94, 0.18); color: #16a34a; }
.magnet-risk-badge.risk-elevated { background: rgba(245, 158, 11, 0.20); color: #d97706; }
.magnet-risk-badge.risk-high { background: rgba(239, 68, 68, 0.20); color: #ef4444; }
.magnet-risk-label { color: var(--muted); font-size: 10px; }
.magnet-flip-row { color: var(--muted); }
.magnet-below-flip { color: #ef4444; font-weight: 700; }
.magnet-above-flip { color: #16a34a; font-weight: 700; }
/* MFL-R3: "no flip, and here is why" fills the row that used to render blank. Muted and italic so it
   reads as an absence rather than as a value. The row is nowrap + overflow:hidden, so this copy must
   stay short — MFL-V2b asserts scrollWidth <= clientWidth at the narrowest supported layout. */
.magnet-no-flip { color: var(--muted); font-style: italic; }
.magnet-collapse-row { color: #ef4444; font-weight: 700; font-size: 10px; letter-spacing: 0.02em; }

/* MFL-R5/R6/R7: regime consequence. An OVERLAY, deliberately — the card documents a constant-height
   invariant (rows reserve height so toggling content never reflows the summary grid), and an in-flow
   sentence would break it. position:absolute takes the tip out of flow entirely. */
.magnet-regime-hint-wrap { position: relative; display: inline-block; }
.magnet-regime-hint { cursor: help; border-bottom: 1px dotted var(--muted); }
.magnet-regime-hint:focus-visible { outline: 2px solid var(--accent, #3b82f6); outline-offset: 2px; }
.magnet-regime-tip {
    position: absolute;
    left: 0;
    top: calc(100% + 6px);
    z-index: 60;
    width: max-content;
    max-width: 260px;
    /* The tip is the one place copy may wrap — it is outside the nowrap row. */
    white-space: normal;
    font-size: 11px;
    font-weight: 400;
    line-height: 1.4;
    color: var(--text, #e5e7eb);
    background: var(--panel, #111827);
    border: 1px solid var(--border, #374151);
    border-radius: 4px;
    padding: 7px 9px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
}

/* Magnet pin on the option chain: BOLD + a soft blink on the strike PRICE glyph ONLY (never the cell/row),
   matching the flow-value soft-blink cadence (2.6s, gentle text glow). Mirrors .strike-turn-blink's
   glyph-only approach but softer, per spec. */
.strike-price-value.hot-strike-gold,
.strike-price-value.hot-strike-gold.skew-strike-cheap,
.strike-price-value.hot-strike-gold.skew-strike-rich,
.strike-price-value.hot-strike-gold.magnet-pin {
    color: #d4a017 !important;
    font-weight: 700;
    text-shadow: 0 0 8px rgba(212, 160, 23, 0.55);
}
.strike-price-value.hot-strike-gold sup.spx-equiv { color: #d4a017; opacity: 0.85; }

/* TOP PRESSURE STRIKE mark.
   The Options Pressure card already ranks these; the mark only makes them visible ON the strike
   instead of only inside a hover popover.

   Three constraints shape it, all learned the hard way:

   1. NO LAYOUT COST. This board holds a constant-geometry contract (SBX-147) -- data must never
      resize a row. So: no border, no padding, and no font-weight change either (weight alters
      glyph width, and .strike-price-value has only a min-width).
   2. THE TEXT MASK MUST SURVIVE. .strike-price-value carries
      `background: var(--cell-text-mask-bg)` and `box-shadow: 0 0 0 5px var(--cell-text-mask-bg)`
      to stay readable over the row tint. A bare `box-shadow:`/`background:` here REPLACES both and
      silently destroys that mask, so the mask is re-declared first in every rule below and the
      pressure tint is layered OVER it.
   3. NOT COLOUR ALONE. Call and put pressure differ by the SIDE the rule sits on (left vs right),
      not only by hue, so the two remain distinguishable without colour vision. */
.strike-price-value.pressure-top-call {
    box-shadow: 0 0 0 5px var(--cell-text-mask-bg), inset 2px 0 0 0 #0f7a3d;
    background:
        linear-gradient(90deg, rgba(15, 122, 61, 0.16), rgba(15, 122, 61, 0) 70%),
        var(--cell-text-mask-bg);
}

.strike-price-value.pressure-top-put {
    box-shadow: 0 0 0 5px var(--cell-text-mask-bg), inset -2px 0 0 0 #b3261e;
    background:
        linear-gradient(270deg, rgba(179, 38, 30, 0.16), rgba(179, 38, 30, 0) 70%),
        var(--cell-text-mask-bg);
}

/* When another reading already owns the glyph's colour — the magnet pin, hot-strike gold, the SVR
   band, the skew marks — the pressure mark keeps only its edge rule and drops its tint. Two fills
   in one glyph is not a legend anyone can read, and a red band over a green tint is worse than
   either alone. The DECISION is made in JS (see pressureColourTaken): the strike-band contract
   forbids ANY line naming that band's class from painting the cell — prose included, since the
   check is line-based — so a CSS yield could not be written here at all. */
.strike-price-value.pressure-no-fill {
    background: var(--cell-text-mask-bg);
}

.strike-price-value.magnet-pin {
    font-weight: 800;
    animation: strikeMagnetSoftBlink 2.6s ease-in-out infinite;
}
@keyframes strikeMagnetSoftBlink {
    0%, 100% { opacity: 1; text-shadow: none; }
    50% { opacity: 0.55; text-shadow: 0 0 9px currentColor; }
}
@media (prefers-reduced-motion: reduce) {
    .strike-price-value.magnet-pin { animation: none; text-shadow: 0 0 9px currentColor; }
}

.maxpain-stale-banner {
    background: rgba(245, 158, 11, 0.18);
    border: 1px solid rgba(245, 158, 11, 0.55);
    color: #9a3412;
    padding: 6px 12px;
    border-radius: 6px;
    margin: 6px 0;
    font-weight: 700;
    font-size: 12px;
}

/* Per-strike sweep-count tally + window dropdown
 * BUY (green) / SELL (red). Hidden when both counts are 0. The dropdown sits inline in the column
 * header next to "Call Volume" / "Put Volume" and drives that column's tally for every strike.
 */
.volume-th {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
/* FLOW column header label + the sweep-window dropdown (moved here from the volume header). */
.flow-th {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

/* ===== FLOW column: per-strike directional signals, lifted out of the volume cell =====
   Both flow columns are the same width, and it is stated on the HEADER as well as here, because
   the chain table is table-layout:fixed — a td width is ignored and only the th counts (the same
   lesson already written up on th.volume-col above).

   The header rule used to select the 3rd header cell positionally, and the 3rd header cell is the
   CALL OI header, not Call Flow. So the 260px meant for the flow column was sizing OI, both flow
   columns fell back to the auto share, and the td widths here did nothing. Measured at a 1837px
   board that left each flow column 163px, against a 117px invasion badge (“⛊ DO NOT SHORT†”,
   the widest of the seven badge texts invasionStrikeState can emit) sharing its line with a
   right-hugging NET value: a 96px overlap, i.e. the NET was completely covered — the reported bug.

   272px is the measured requirement, not a guess. The two things that share the cell's line are
   capped as SHARES of it rather than in px (see .strike-invasion-badge and .flow-net-val), so the
   50% + 42% + 8% gap below always sums to the content box whatever the column or the font: 248px
   of content gives a 124px badge slot against a measured 117.05px need, a 104px value slot against
   a measured 100.17px need, and 19.8px of gap against an 11px requirement. The width is taken back
   from the two OI columns (th.oi-col), which were 260px and 163px for no reason anyone chose, so
   the board's total is unchanged. */
.chain-table th.flow-col,
.flow-cell {
    width: 272px;
}
.flow-cell {
    min-width: 272px;
    padding: 3px 12px;
    vertical-align: middle;
}
.flow-inner {
    display: grid;
    gap: 2px;
    /* Explicit positioning context: the strike-invasion badge is an absolutely positioned child
       (see .flow-cell .strike-invasion-badge) and must anchor to this box, not the page. */
    position: relative;
}
/* NET — the headline: signed aggressor $ (green bought / red sold / gray flat). */
.flow-net {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
}
/* Each NET value hugs the STRIKE side of its flow cell so heatmap bubbles fill the cell
   outward from it and never sit under it: the call flow cell is LEFT of the strike, so its
   value pins right; the put flow cell is right of the strike, so its value stays left. */
.call-flow .flow-net { justify-content: flex-end; }
.put-flow .flow-net { justify-content: flex-start; }
.flow-net-lab {
    font-size: 8.5px;
    letter-spacing: 0.08em;
    font-weight: 800;
    color: #8b99ab;
}
.flow-net-val {
    font-size: 14px;
    font-weight: 950;
    text-shadow: 0 1px 0 #000;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    /* FIXED-WIDTH slot (covers the widest formatter output, e.g. "−$999.9K"): the heatmap
       anchors its bubbles at this value's edge, so a fixed slot keeps that edge identical on
       every row and stable as the value changes — no ribbon shift, no per-row drift. */
    /* min(), not a bare 8ch: when min-width and max-width conflict, CSS resolves it by raising the
       effective MAXIMUM to the minimum -- so a bare `min-width: 8ch` would silently defeat the 42%
       cap below wherever 8ch exceeds it (a wide fallback face, or a large accessibility font, makes
       `ch` bigger), and the value slot would walk into the badge's. Clamping the floor to the cap
       keeps the two from ever disagreeing: the slot is 8ch wide when there is room and 42% when
       there is not. */
    min-width: min(8ch, 42%);
    /* CEILING on the same slot, and the reason the invasion badge can never be reached.
       fmtStrikeFlowUsd's M branch has no magnitude cap, so "the widest formatter output" is not a
       real bound — a large enough number simply makes a longer string. Sizing the flow column to
       a sampled worst case would therefore be a guess that holds until it doesn't. This makes the
       clearance structural instead — and expressed as a SHARE of the cell, not in px, so the
       guarantee does not depend on the font. The board asks for Avenir Next, Gill Sans, Trebuchet
       MS, sans-serif, and which of those a machine actually has changes every measurement here:
       measured, the widest legitimate value ("+$9999.9M", ≈$10bn of net flow at ONE strike) needs
       100.17px in Gill Sans, 90.19px in Verdana and 66.70px in the generic fallback. A px cap
       calibrated on one of those clips on another. 42% of the 248px content box is 104.2px, which
       clears the widest measured need with room, and 42 + 50 (badge) + 8 (gap) = 100% by
       construction, so the two can never meet however wide the glyphs get.
       That arithmetic is over BORDER boxes, which is what max-width bounds. Painted pixels are not
       quite the same: this element carries a 3px box-shadow mask halo outside its border box, so
       the 19.84px of border-box gap is ~16.84px of painted gap. Still clear, but the 8% is not a
       promise about ink. The prerequisites the arithmetic rests on — global border-box sizing,
       this cell's 12px side padding and that 3px halo — are pinned in OptionChainAssetsTest,
       because changing any of them silently changes what 50% and 42% mean.
       It is NOT "every value the formatter can produce", which is not a finite set:
       fmtStrikeFlowUsd's M branch is unbounded. Past that the figure is ellipsised, and the only
       place it stays readable in full is the enclosing td's title (set from strikeFlow.netTitle in
       FlowCell), not this element. overflow:hidden here does not touch the 3px box-shadow mask
       below: a box-shadow is painted outside the border box and is not clipped by the element's
       own overflow. */
    max-width: 42%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Call value hugs the strike (right) side of its slot; put value hugs the left (strike) side. */
.call-flow .flow-net-val { text-align: right; }
.put-flow .flow-net-val { text-align: left; }
.flow-net-lab,
.flow-net-val,
.flow-pace-rate,
.flow-pace-chg,
.sweep-count-tally {
    background: rgba(9, 11, 17, 0.76);
    box-shadow: 0 0 0 3px rgba(9, 11, 17, 0.76);
    border-radius: 4px;
}
.flow-net-val.strike-flow-net-buy  { color: #44f19a; }
.flow-net-val.strike-flow-net-sell { color: #ff6a76; }
.flow-net-val.strike-flow-net-flat { color: #8a99ab; }
/* Top-2 net-SELL per side (calls/puts ranked independently): the NET number itself pulses red -> bright yellow
   with a glow. Only color/text-shadow animate -> the number never changes size, so the row never shifts. */
@keyframes net-sell-glow {
    0%, 100% { color: #ff6a76; text-shadow: none; }
    50%      { color: #ffd21e; text-shadow: 0 0 8px rgba(245, 197, 24, 0.85); }
}
.flow-net-val.net-sell-box {
    animation: net-sell-glow 1.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .flow-net-val.net-sell-box { animation: none; color: #ffd21e; text-shadow: 0 0 6px rgba(245, 197, 24, 0.7); }
}
/* Second line: pace rate + change on the left, the sweep BUY/SELL tally on the right. */
.flow-row2 {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.flow-pace {
    display: flex;
    align-items: baseline;
    gap: 4px;
    font-size: 11px;
}
.flow-pace-rate {
    font-weight: 900;
    color: #dce8f7;
    font-variant-numeric: tabular-nums;
}
.flow-pace-chg {
    font-size: 10px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}
/* ── Pace explainer popover (design §3.2) ────────────────────────────────────────────────────────
   Click a ranked pace chip → plain-English explanation of its state, built from the cell's own data.
   Fixed-positioned (coords from the chip's rect) so a table-cell overflow can't clip it. */
.flow-pace-clickable { cursor: pointer; }
.flow-pace-clickable:focus-visible { outline: 2px solid var(--pace-rank1-text); outline-offset: 2px; border-radius: 4px; }
.pace-explainer-pop {
    z-index: 60;
    width: 320px;
    max-width: calc(100vw - 16px);
    background: #12151d;
    border: 1px solid rgba(138, 109, 255, 0.35);
    border-radius: 12px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
    padding: 12px 14px;
    text-align: left;
    cursor: default;
    font-weight: 400;
}
.pace-pop-head {
    font-size: 13px;
    font-weight: 700;
    color: var(--pace-rank1-text);
    margin-bottom: 8px;
}
.pace-pop-rows { display: flex; flex-direction: column; gap: 2px; margin-bottom: 8px; }
.pace-pop-row { display: flex; justify-content: space-between; gap: 12px; font-size: 12px; color: #9aa6b8; }
.pace-pop-row b { color: #e6edf6; font-weight: 600; font-variant-numeric: tabular-nums; text-align: right; }
.pace-pop-row b.pace-change-up { color: #44f19a; }
.pace-pop-row b.pace-change-down { color: #ff6a76; }
.pace-pop-badge {
    font-size: 11.5px;
    line-height: 1.42;
    padding: 6px 9px;
    border-radius: 8px;
    margin-top: 7px;
    color: #d7def0;
}
.pace-pop-badge.conf { background: rgba(138, 109, 255, 0.16); }
.pace-pop-badge.unc { background: rgba(148, 163, 184, 0.14); border: 1px dashed rgba(148, 163, 184, 0.4); }
.pace-pop-badge.conv { background: rgba(255, 210, 30, 0.14); color: #ffe9a3; }
.pace-pop-badge.ig { background: rgba(240, 138, 36, 0.16); color: #ffcf9e; }
.pace-pop-sum {
    font-size: 12px;
    line-height: 1.45;
    color: #9aa6b8;
    margin-top: 10px;
    padding-top: 8px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}
/* ── Pace "most active strike" emphasis (design §3.1) ─────────────────────────────────────────────
   Applied to the .flow-pace sub-cell only. Intensity = rank; CONFIRMED = solid glow, UNCONFIRMED/
   WAIVED = hollow dashed (same hue), convergence = violet + gold ring, ignite = orange spark. The
   pace text recolors to violet so the directional green/red NET above it is never suppressed. */
.flow-pace.pace-rank-1,
.flow-pace.pace-rank-2,
.flow-pace.pace-rank-3 {
    border-radius: 4px;
    padding: 0 3px;
}
.flow-pace.pace-rank-1 .flow-pace-rate { color: var(--pace-rank1-text); }
.flow-pace.pace-rank-2 .flow-pace-rate,
.flow-pace.pace-rank-3 .flow-pace-rate { color: var(--pace); }
/* CONFIRMED: solid violet glow; rank-1 also blinks (reuse the existing soft-blink keyframes). */
.flow-pace.pace-confirmed.pace-rank-1 {
    background: var(--pace-rank2-bg);
    box-shadow: 0 0 10px var(--pace-rank1-glow);
    animation: strikeFlowSoftBlink 2.6s ease-in-out infinite;
}
.flow-pace.pace-confirmed.pace-rank-2 { background: var(--pace-rank2-bg); }
.flow-pace.pace-confirmed.pace-rank-3 {
    border-bottom: 2px solid var(--pace-rank3-line);
    border-radius: 0;
}
/* UNCONFIRMED / WAIVED: hollow dashed outline, no fill — "active, but not confirmed across windows". */
.flow-pace.pace-unconfirmed {
    border: 1px dashed var(--pace-unconf);
    background: transparent;
    box-shadow: none;
    animation: none;
}
/* Convergence (pace ∩ volume): the loudest cell — violet glow plus a gold ring. */
.flow-pace.pace-converge {
    box-shadow: 0 0 0 1.5px var(--pace-converge-ring), 0 0 10px var(--pace-rank1-glow);
}
.pace-ignite-mark {
    color: var(--pace-ignite);
    font-size: 10px;
    margin-right: 2px;
    line-height: 1;
}
/* §9a lagging-strikes warning banner: pinned atop the chain, flashing in the warning hue. */
.pace-lagging-banner {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    margin: 4px 0;
    border-radius: var(--border-radius-md, 6px);
    font-size: 12px;
    font-weight: 600;
    color: #ff9800;
    background: rgba(240, 138, 36, 0.12);
    border: 1px solid rgba(240, 138, 36, 0.5);
    animation: strikeFlowSoftBlink 2.0s ease-in-out infinite;
}
/* Thin pace-intensity bar, colored by net side. */
.flow-bar {
    display: block;
    height: 3px;
    border-radius: 2px;
    background: rgba(255, 255, 255, 0.06);
    overflow: hidden;
    margin-top: 1px;
}
.flow-bar > i {
    display: block;
    height: 100%;
    border-radius: 2px;
}
.flow-bar-buy  > i { background: linear-gradient(90deg, rgba(68, 241, 154, 0.4), #44f19a); }
.flow-bar-sell > i { background: linear-gradient(90deg, rgba(255, 106, 118, 0.4), #ff6a76); }
.flow-bar-flat > i { background: rgba(140, 153, 171, 0.30); }

.sweep-window-dd {
    appearance: none;
    -webkit-appearance: none;
    background: #0f1620;
    color: #d7e2ef;
    border: 1px solid #1f2730;
    border-radius: 3px;
    padding: 2px 16px 2px 6px;
    font: inherit;
    font-size: 10px;
    font-weight: 800;
    text-transform: none;
    letter-spacing: 0;
    line-height: 1.1;
    cursor: pointer;
    background-image: linear-gradient(45deg, transparent 50%, #6e7d92 50%), linear-gradient(135deg, #6e7d92 50%, transparent 50%);
    background-position: calc(100% - 8px) 50%, calc(100% - 4px) 50%;
    background-size: 4px 4px;
    background-repeat: no-repeat;
}
.sweep-window-dd:hover { border-color: #1f6feb; }
.sweep-window-dd:focus { outline: 1px solid #1f6feb; outline-offset: -1px; }

.sweep-count-tally {
    display: inline-flex;
    align-items: baseline;
    gap: 3px;
    margin-top: 2px;
    padding: 1px 5px;
    border-radius: 3px;
    background: rgba(255, 255, 255, 0.03);
    font-size: 10px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
}
.sweep-count-tally .sw-win {
    font-size: 8px;
    font-weight: 700;
    color: #6e7d92;
    letter-spacing: 0.05em;
    margin-right: 2px;
}
.sweep-count-tally .sw-buy { color: #2ecc71; }
.sweep-count-tally .sw-sell { color: #ff5d5d; }
.sweep-count-tally .sw-slash { color: #6e7d92; font-weight: 400; }
.sweep-count-tally .sw-zero { color: #8593a8; font-weight: 700; }

/* Backend-decided "most aggressive" markers — 🔥 = most-aggressively-SOLD strike, 🚀 = most-aggressively-
   BOUGHT strike for this side. The marker sits ON TOP of the sweep numbers; we RESERVE space with extra top
   padding (not a negative offset) so it never lifts into / overlaps the NET row above. A faint ring
   reinforces it (red for sold, green for bought) without another animation. */
.sweep-count-tally.top-sell-sweep,
.sweep-count-tally.top-buy-sweep {
    position: relative;
    padding-top: 12px;            /* reserves room for the marker inside the tally box */
}
.sweep-count-tally.top-sell-sweep {
    background: rgba(255, 93, 93, 0.12);
    box-shadow: inset 0 0 0 1px rgba(255, 93, 93, 0.55);
}
.sweep-count-tally.top-buy-sweep {
    background: rgba(46, 204, 113, 0.12);
    box-shadow: inset 0 0 0 1px rgba(46, 204, 113, 0.55);
}
/* both rings when a strike is the top BOTH bought and sold (rare) */
.sweep-count-tally.top-sell-sweep.top-buy-sweep {
    box-shadow: inset 0 0 0 1px rgba(245, 180, 0, 0.7);
}
.sweep-count-tally .sweep-marker {
    position: absolute;
    left: 50%;
    top: 0;                       /* inside the reserved padding, above the numbers, not over NET */
    transform: translateX(-50%);
    display: inline-flex;
    gap: 2px;
    font-size: 11px;
    line-height: 1;
    pointer-events: none;
}

/* Unified support/resistance overlay on the center strike cell.
   Score = wall PRESENCE; the border (colour+thickness+opacity) is set inline by StrikeCell.
   Corner labels: top-right = resistance (red), bottom-right = support (green).
   Gamma marker: filled dot = CONFIRMS (likely holds), hollow = CONTRADICTS (breakout-prone). */
td.strike-cell.strike-sr { position: relative; }
/* Score CHIP (was a bare 9px digit users missed): solid colour block, white numeral. Still an
   absolutely positioned overlay in the cell corner — never in the 46px grid flow. */
.strike-sr-corner {
  position: absolute;
  right: 1px;
  font-size: 10px;
  font-weight: 800;
  line-height: 1;
  padding: 1px 3px;
  border-radius: 3px;
  color: #fff;
  pointer-events: none;
  z-index: 3;
}
.strike-sr-corner-res { top: 1px; background: rgba(220, 53, 69, 0.92); }
.strike-sr-corner-sup { bottom: 1px; background: rgba(40, 167, 69, 0.92); }
/* LOW-confidence levels stay visibly provisional: dashed outline + damped chip. */
td[data-sr-confidence="LOW"] .strike-sr-corner { outline: 1px dashed rgba(255, 255, 255, 0.55); outline-offset: -1px; opacity: 0.85; }

/* Whole-row level line: resistance paints the row's TOP edge red, support the BOTTOM edge green.
   Its OWN pseudo-element layer, deliberately NOT box-shadow: box-shadow on the cell is already
   owned by the cluster-blink / flow-blink animations, the short-premium frames and the sandwich
   treatments — a second declaration would replace theirs (or be replaced), fragmenting the line
   and eating pre-existing emphasis. `tbody td` is already position:relative, so ::before adds no
   containing block and no geometry: an absolutely positioned 2px strip, painted above the cell
   background and below the content layer (which sits at z-index 5). Alpha is the wall-presence
   score, stamped per-row as --sr-line-alpha by strikeSrRowLineState. */
tbody tr.sr-row-resistance > td::before,
tbody tr.sr-row-support > td::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    height: 2px;
    z-index: 4;
    pointer-events: none;
}
tbody tr.sr-row-resistance > td::before { top: 0; background: rgba(220, 53, 69, var(--sr-line-alpha, 0.8)); }
tbody tr.sr-row-support > td::before { bottom: 0; background: rgba(40, 167, 69, var(--sr-line-alpha, 0.8)); }

/* Proximity banner: a FIXED-HEIGHT slot above the chain (sibling of the chain summary, outside
   the scrolling wrap). Idle keeps the height and hides the content, so appearing/disappearing
   never shifts the table — the no-geometry-change rule, applied to the banner itself. */
.sr-proximity-banner {
  height: 38px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 14px;
  margin: 4px 0;
  border-radius: 6px;
  border: 1px solid transparent;
  overflow: hidden;
  white-space: nowrap;
}
.sr-proximity-banner.sr-banner-idle { visibility: hidden; }
.sr-proximity-banner.sr-banner-resistance {
  background: linear-gradient(90deg, rgba(220, 53, 69, 0.22), rgba(220, 53, 69, 0.05));
  border-color: rgba(220, 53, 69, 0.55);
  border-left: 4px solid #dc3545;
}
.sr-proximity-banner.sr-banner-support {
  background: linear-gradient(90deg, rgba(40, 167, 69, 0.22), rgba(40, 167, 69, 0.05));
  border-color: rgba(40, 167, 69, 0.55);
  border-left: 4px solid #28a745;
}
.sr-banner-lead { font-size: 13px; letter-spacing: 0.3px; }
.sr-banner-resistance .sr-banner-lead { color: #ff97a1; }
.sr-banner-support .sr-banner-lead { color: #7fd89a; }
.sr-banner-why { font-size: 12px; color: #8a93a6; overflow: hidden; text-overflow: ellipsis; }
/* Which engine's claim the banner is carrying — pinned to the far end of the row. */
.sr-banner-src { margin-left: auto; font-size: 11px; color: #6f7889; white-space: nowrap; }

/* Call-wall toast: fixed overlay top-right (out of every layout), auto-dismissed by the page. */
.call-wall-toast {
  position: fixed;
  top: calc(var(--oc-topnav-h, 42px) + 10px);
  right: 14px;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 34px 10px 14px;
  border-radius: 8px;
  background: #2a1216;
  border: 1px solid rgba(220, 53, 69, 0.8);
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.5);
  color: #ff97a1;
}
.call-wall-toast strong { font-size: 13px; letter-spacing: 0.4px; }
/* Attribution line: which engine made this claim, and how strong it rates it. */
.call-wall-toast-src { font-size: 11px; color: #ffb3bb; font-weight: 700; }
.call-wall-toast-sub { font-size: 11px; color: #b58e93; }
.call-wall-toast-close {
  position: absolute;
  top: 4px;
  right: 6px;
  background: none;
  border: none;
  color: #b58e93;
  font-size: 15px;
  cursor: pointer;
  line-height: 1;
}
.strike-sr-gamma {
  position: absolute;
  top: 1px;
  left: 2px;
  font-size: 9px;
  line-height: 1;
  pointer-events: none;
}
.strike-sr-gamma-confirms { color: #28a745; }
.strike-sr-gamma-contradicts { color: #e0a800; }

/* Sold-flow ratio card (next to spot). Backend-authoritative; UI only displays the selected top-N entry. */
.sold-flow-card { align-items: stretch; }
.sold-flow-bar { display: flex; height: 8px; border-radius: 5px; overflow: hidden; margin: 6px 0 4px; background: rgba(255, 255, 255, 0.06); }
.sold-flow-bar-call { background: #ff6a76; }
.sold-flow-bar-put { background: #44f19a; }
.sold-flow-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.sold-flow-lean { font-size: 10px; text-transform: uppercase; letter-spacing: 0.4px; color: rgba(255, 255, 255, 0.55); }
.sold-flow-topn { font-size: 11px; padding: 1px 4px; }
.sold-flow-bearish .ratio-text { color: #ff6a76; }
.sold-flow-bullish .ratio-text { color: #44f19a; }
.sold-flow-balanced .ratio-text { color: #ffcc66; }
.sold-flow-nodata .ratio-text { color: rgba(255, 255, 255, 0.45); }

.chain-nav-link {
    flex: 0 0 auto;
    min-height: 24px;
    display: inline-flex;
    align-items: center;
    border-radius: 999px;
    padding: 4px 10px;
    border: 1px solid rgba(57, 118, 201, 0.28);
    background: rgba(255, 255, 255, 0.74);
    color: #185fa8;
    font-size: 11px;
    font-weight: 950;
    line-height: 1;
    text-decoration: none;
    text-transform: uppercase;
    white-space: nowrap;
}

.chain-nav-link:hover,
.chain-nav-link:focus-visible {
    border-color: rgba(57, 118, 201, 0.56);
    background: #e6f1ff;
    color: #0f4c91;
}

/* =====================================================================   Dealer-ledger strike signal (ARMED / DEFENDED / ARMING) + detail drawer.
   Gated behind config.dealerLedgerVisible; renders inside the existing strike
   cell (gold = call/ARMED, teal = put/DEFENDED, dim amber = ARMING) so it never
   collides with the red/blue GEX bar. Kept dark to match .strike-cell (#191a25).
   ============================================================================ */
:root {
    --dl-armed: #f5b544;              /* gold — call-side / ARMED */
    --dl-armed-soft: rgba(245, 181, 68, 0.16);
    --dl-defended: #2fd8b6;           /* teal — put-side / DEFENDED */
    --dl-defended-soft: rgba(47, 216, 182, 0.16);
    --dl-arming: #cdb06a;             /* dim amber — ARMING (building) */
    --dl-arming-soft: rgba(205, 176, 106, 0.12);
}

/* In-cell signal pill: sits on its own full-width line below the strike price. */
.dl-signal-pill {
    grid-column: 1 / -1;
    justify-self: start;
    margin-top: 3px;
    padding: 1px 7px;
    border: 1px solid transparent;
    border-radius: 999px;
    background: var(--dl-arming-soft);
    color: #f4efe2;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.04em;
    line-height: 1.35;
    text-transform: uppercase;
    white-space: nowrap;
    cursor: pointer;
    transition: filter 0.12s ease, box-shadow 0.12s ease;
}
.dl-signal-pill:hover { filter: brightness(1.12); }
.dl-signal-pill:focus-visible { outline: 2px solid #ffffff; outline-offset: 1px; }

.dl-signal-armed { background: var(--dl-armed-soft); border-color: var(--dl-armed); color: var(--dl-armed); }
.dl-signal-defended { background: var(--dl-defended-soft); border-color: var(--dl-defended); color: var(--dl-defended); }
.dl-signal-arming { background: var(--dl-arming-soft); border-color: var(--dl-arming); color: var(--dl-arming); }
/* Stale = DASHED, at full strength. The dashed border is the signal; the old opacity 0.55 on top
   of it just made an already-subtle pill hard to read. The width stays 1px on purpose — the pill
   sits inside a strike cell and any extra border shifts the row (the table-shake regression). */
.dl-signal-stale { border-style: dashed; }

/* Whole-cell accent ring so an actionable strike reads at a glance. */
.strike-cell.strike-dl-armed { box-shadow: inset 0 0 0 1.5px var(--dl-armed); }
.strike-cell.strike-dl-defended { box-shadow: inset 0 0 0 1.5px var(--dl-defended); }
.strike-cell.strike-dl-arming { box-shadow: inset 0 0 0 1px var(--dl-arming); }

/* --- Detail drawer ------------------------------------------------------- */
.dl-detail-backdrop {
    position: fixed;
    inset: 0;
    z-index: 1200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    /* Scrim only — no backdrop-filter. Blurring the live board behind the drawer made the chain
       unreadable while the drawer was open (and forced a full-region GPU re-composite on every
       tick, the same reason blur was removed twice above). A slightly deeper scrim separates the
       drawer just as well. */
    background: rgba(10, 12, 18, 0.72);
}
.dl-detail-panel {
    width: min(560px, 100%);
    max-height: 88vh;
    overflow-y: auto;
    padding: 20px 22px 18px;
    border-radius: 14px;
    border: 1px solid rgba(255, 255, 255, 0.10);
    background: #191a25;
    color: #eef0f6;
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
}
.dl-detail-armed { border-top: 3px solid var(--dl-armed); }
.dl-detail-defended { border-top: 3px solid var(--dl-defended); }
.dl-detail-arming { border-top: 3px solid var(--dl-arming); }

.dl-detail-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.dl-detail-title { display: flex; flex-direction: column; gap: 6px; }
.dl-detail-title .dl-signal {
    align-self: flex-start;
    padding: 2px 9px;
    border: 1px solid transparent;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}
.dl-detail-strike { font-size: 18px; font-weight: 650; color: #ffffff; font-variant-numeric: tabular-nums; }
.dl-detail-close {
    flex: none;
    width: 28px;
    height: 28px;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 8px;
    background: transparent;
    color: #c7cbd6;
    font-size: 13px;
    cursor: pointer;
}
.dl-detail-close:hover { background: rgba(255, 255, 255, 0.08); color: #ffffff; }
.dl-detail-reason { margin: 12px 0 4px; color: #b9c0cf; font-size: 12.5px; line-height: 1.4; }

.dl-detail-section-label {
    margin-top: 16px;
    margin-bottom: 8px;
    color: #8b93a6;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
}
.dl-detail-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.dl-field {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 9px 11px;
    border-radius: 9px;
    background: rgba(255, 255, 255, 0.035);
    cursor: help;
}
.dl-field-wide { grid-column: 1 / -1; }
.dl-field-label { color: #8b93a6; font-size: 10.5px; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase; }
.dl-field-value { color: #ffffff; font-size: 15px; font-weight: 650; font-variant-numeric: tabular-nums; }

.dl-detail-trace { width: 100%; border-collapse: collapse; font-size: 12px; }
.dl-detail-trace th {
    padding: 5px 8px;
    color: #8b93a6;
    font-weight: 600;
    text-align: left;
    text-transform: uppercase;
    font-size: 10px;
    letter-spacing: 0.05em;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.dl-detail-trace td { padding: 5px 8px; border-bottom: 1px solid rgba(255, 255, 255, 0.045); font-variant-numeric: tabular-nums; }
.dl-detail-trace td:first-child { cursor: help; }
.dl-trace-pass td:last-child { color: var(--dl-defended); font-weight: 700; }
.dl-trace-fail td:last-child { color: #ff6b78; font-weight: 700; }

.dl-detail-quality {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 16px;
    padding-top: 12px;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.dl-detail-quality span {
    padding: 3px 9px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.05);
    color: #b9c0cf;
    font-size: 11px;
    font-weight: 600;
    cursor: help;
}
.dl-detail-disclaimer { margin: 14px 0 0; color: #6f7789; font-size: 10.5px; line-height: 1.45; }

/* Lightweight hover tooltip for the drawer fields (in addition to native title). */
[data-tip] { position: relative; }
[data-tip]:hover::after {
    content: attr(data-tip);
    position: absolute;
    left: 0;
    bottom: calc(100% + 6px);
    z-index: 1300;
    width: max-content;
    max-width: 260px;
    padding: 7px 10px;
    border-radius: 8px;
    background: #0c0e15;
    border: 1px solid rgba(255, 255, 255, 0.12);
    color: #e7eaf2;
    font-size: 11px;
    font-weight: 500;
    line-height: 1.4;
    letter-spacing: 0.005em;
    text-transform: none;
    white-space: normal;
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .dl-signal-pill { transition: none; }
}

/* Zone-permission chips (ActionState) in the drawer — decision-support states, not orders. */
.dl-detail-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.dl-action {
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.14);
    background: rgba(255, 255, 255, 0.05);
    color: #d6dae4;
    font-size: 11px;
    font-weight: 650;
    letter-spacing: 0.02em;
    cursor: help;
}
.dl-action-active { border-color: var(--dl-defended); color: var(--dl-defended); background: var(--dl-defended-soft); }
.dl-action-staged { border-color: var(--dl-armed); color: var(--dl-armed); background: var(--dl-armed-soft); }
.dl-action-waiting, .dl-action-caution { border-color: var(--dl-arming); color: var(--dl-arming); background: var(--dl-arming-soft); }
.dl-action-blocked, .dl-action-forbidden, .dl-action-closed { border-color: rgba(255, 107, 120, 0.55); color: #ff8a94; }

/* ---- Δ-Flow Windows column: all six windows (10s/30s/1m/5m/15m/session) per strike ---- */
.chain-table th.delta-windows-col { width: 200px; padding: 4px 6px; vertical-align: bottom; }
.delta-windows-th { display: block; font-size: 11px; font-weight: 600; color: rgba(255, 255, 255, 0.85); text-align: center; letter-spacing: 0.02em; }
.delta-windows-sub { display: grid; grid-template-columns: repeat(6, 1fr); font-size: 9px; color: rgba(255, 255, 255, 0.4); text-align: right; margin-top: 2px; }
.delta-windows-cell { width: 200px; min-width: 200px; padding: 0 6px; vertical-align: middle; }
/* Grid lives on an inner div, not the <td>, so table layout/alignment is unaffected (review #8). */
.delta-windows-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 3px; align-items: center; }
.dw-val { font-size: 10.5px; line-height: 1.15; text-align: right; font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; }
.dw-pos { color: #2ecc71; }
.dw-neg { color: #e74c3c; }
.dw-zero { color: rgba(255, 255, 255, 0.45); }
.dw-missing { color: rgba(255, 255, 255, 0.28); }
.dw-strong { font-weight: 650; }
/* Partial-session indicator: when the Δ-flow session started well after the open (mid-day cold start). */
.delta-flow-session-from { margin-left: 8px; font-size: 11px; color: #e0a458; opacity: 0.9; cursor: help; }

/* Reclaim width for the new column: shrink Strike + Call Volume a bit. */
.strike-cell { min-width: 140px; }
.chain-table th.call-volume-col { width: 84px; }
.volume-cell.call-volume { width: 84px; min-width: 84px; }

/* =====================================================================   STRIKE-INTELLIGENCE ACTION SIGNALS (append-only)
   Encoding: MOTION = verb, COLOR = direction.
     - BUY  (buy_call / buy_put)  -> pulsing box-shadow glow  (@keyframes strikeActionPulse)
     - SELL (sell_call / sell_put / sell_premium) -> rotating conic-gradient edge (@keyframes strikeActionSpin)
     - green = bullish (BUY_CALL, SELL_PUT); red = bearish (BUY_PUT, SELL_CALL);
       amber = SELL_PREMIUM (pin); AVOID / NONE = dim + static (no motion).
   Only clean directional signals animate — a bounded overlay, never a light show.
   Accessibility: pulse capped at ~1Hz; prefers-reduced-motion swaps to a static ring/glow.
   ============================================================================ */

.strike-cell.has-strike-action {
    position: relative;
}

/* ---- ES-origin projected signal overlay (source=ES_ON_SPX) -------------------------
   A SEPARATE layer from the native strike action above. Rendered as a small "ES" corner
   tag via a pseudo-element so it adds NO row height (the 46px row is already full) and
   stays visually distinct from the native SPX action badge. Tinted bull/bear by the ES
   actionBias; the translated ES strike + role ride on data-es-action-* attributes. */
.strike-cell.has-es-action {
    position: relative;
}
.strike-cell.has-es-action::after {
    content: "ES";
    position: absolute;
    top: 1px;
    right: 1px;
    z-index: 3;
    pointer-events: none;
    font-size: 7px;
    font-weight: 850;
    line-height: 1;
    letter-spacing: 0.3px;
    padding: 1px 2px;
    border-radius: 3px;
    color: #0b0d0f;
    background: rgba(255, 255, 255, 0.82);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.18);
}
.strike-cell.has-es-action.es-action-buy_call::after,
.strike-cell.has-es-action.es-action-sell_put::after {
    color: var(--action-bull);
    box-shadow: inset 0 0 0 1px var(--action-bull-glow);
}
.strike-cell.has-es-action.es-action-buy_put::after,
.strike-cell.has-es-action.es-action-sell_call::after {
    color: var(--action-bear);
    box-shadow: inset 0 0 0 1px var(--action-bear-glow);
}
@media (prefers-reduced-motion: reduce) {
    .strike-cell.has-es-action::after { background: rgba(255, 255, 255, 0.9); }
}

.strike-action-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 3px;
    /* Secondary stabiliser only -- the row-height jump is fixed on .strike-gex-line above (the
       grid was placing this badge on its own row). The pinned height is what matters here: it
       keeps the badge inside the line box so it can never add height.
       Deliberately NOT given a reserved min-width. An earlier revision reserved 74px so the badge
       would not resize as the label changed (AVOID vs SELL PREM) or the ×N counter ticked -- but
       74px plus a 6px margin plus the price and the gaps needs ~148px, while .strike-cell only
       guarantees 140px, so a narrow column would have overflowed. table-layout: fixed stops the
       COLUMN expanding; it does not stop a child spilling out of it. The badge is the LAST child,
       so its own width changing moves nothing to its left -- the jitter that reservation bought
       was not worth an overflow. It shrinks and clips instead. The 6px left margin is gone for
       the same reason: the line's 10px gap already spaces it. */
    box-sizing: border-box;
    height: 14px;
    line-height: 14px;
    padding: 0 6px;
    align-self: center;
    min-width: 0;
    overflow: hidden;
    border-radius: 9px;
    font-size: 9px;
    font-weight: 850;
    letter-spacing: 0.4px;
    white-space: nowrap;
    vertical-align: middle;
    color: #0b0d0f;
    background: rgba(255, 255, 255, 0.86);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
    position: relative;
    z-index: 2;
}

/* ---- Direction colors ------------------------------------------------------ */
.strike-action-badge.action-buy_call,
.strike-action-badge.action-sell_put {
    color: var(--action-bull);
    box-shadow: inset 0 0 0 1px var(--action-bull-glow);
}

.strike-action-badge.action-buy_put,
.strike-action-badge.action-sell_call {
    color: var(--action-bear);
    box-shadow: inset 0 0 0 1px var(--action-bear-glow);
}

.strike-action-badge.action-sell_premium {
    color: #7a5a00;
    box-shadow: inset 0 0 0 1px var(--action-premium-glow);
}

.strike-action-badge.action-avoid {
    color: var(--action-avoid);
    box-shadow: inset 0 0 0 1px rgba(139, 148, 158, 0.5);
}

/* ---- BUY: pulsing glow (motion = commit) ----------------------------------
   Capped at ~1Hz (strong ~1s, lean ~1.6s) so it reads as a heartbeat, not a strobe. */
@keyframes strikeActionPulse {
    0%, 100% {
        box-shadow: inset 0 0 0 1px currentColor, 0 0 0 rgba(0, 0, 0, 0);
    }
    50% {
        box-shadow: inset 0 0 0 1px currentColor, 0 0 12px 1px var(--action-pulse-glow, rgba(0, 200, 83, 0.55));
    }
}

.strike-action-badge.action-buy_call { --action-pulse-glow: var(--action-bull-glow); }
.strike-action-badge.action-buy_put  { --action-pulse-glow: var(--action-bear-glow); }

/* Per-strike gamma-lifecycle badge (emerging / sticky / fading) — inline, next to the GEX value. */
.strike-lifecycle-badge {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-left: 6px;
    padding: 1px 5px;
    border-radius: 8px;
    font-size: 9px;
    font-weight: 850;
    letter-spacing: 0.3px;
    line-height: 1.4;
    white-space: nowrap;
    vertical-align: middle;
    position: relative;
    z-index: 2;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.14);
}
.strike-lifecycle-badge.lifecycle-new  { color: #0d3b12; background: rgba(99, 153, 34, 0.30); }
.strike-lifecycle-badge.lifecycle-pin  { color: #082b4d; background: rgba(55, 138, 221, 0.32); }
.strike-lifecycle-badge.lifecycle-fade { color: #4a1010; background: rgba(226, 75, 74, 0.28); }

.strike-action-badge.action-buy_call.action-strength-strong,
.strike-action-badge.action-buy_put.action-strength-strong {
    animation: strikeActionPulse 1s ease-in-out infinite;
}

.strike-action-badge.action-buy_call.action-strength-lean,
.strike-action-badge.action-buy_put.action-strength-lean {
    animation: strikeActionPulse 1.6s ease-in-out infinite;
}

/* ---- SELL: rotating conic-gradient edge (motion = fade/distribute) ----------
   A ::before ring spins around the badge; direction color drives the sweep. */
@property --strike-action-angle {
    syntax: '<angle>';
    inherits: false;
    initial-value: 0deg;
}

@keyframes strikeActionSpin {
    to { --strike-action-angle: 360deg; }
}

.strike-action-badge.action-sell_call,
.strike-action-badge.action-sell_put,
.strike-action-badge.action-sell_premium {
    isolation: isolate;
}

.strike-action-badge.action-sell_call::before,
.strike-action-badge.action-sell_put::before,
.strike-action-badge.action-sell_premium::before {
    content: '';
    position: absolute;
    inset: -2px;
    border-radius: 11px;
    padding: 2px;
    z-index: -1;
    background: conic-gradient(from var(--strike-action-angle),
        transparent 0deg,
        var(--action-spin-color, rgba(255, 59, 48, 0.85)) 90deg,
        transparent 180deg,
        var(--action-spin-color, rgba(255, 59, 48, 0.85)) 270deg,
        transparent 360deg);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask-composite: exclude;
    animation: strikeActionSpin 2.4s linear infinite;
}

.strike-action-badge.action-sell_put    { --action-spin-color: var(--action-bull-glow); }
.strike-action-badge.action-sell_call   { --action-spin-color: var(--action-bear-glow); }
.strike-action-badge.action-sell_premium { --action-spin-color: var(--action-premium-glow); }

/* STRONG sells spin a touch faster / brighter than LEAN. */
.strike-action-badge.action-strength-strong.action-sell_call::before,
.strike-action-badge.action-strength-strong.action-sell_put::before,
.strike-action-badge.action-strength-strong.action-sell_premium::before {
    animation-duration: 1.6s;
    opacity: 1;
}

.strike-action-badge.action-strength-lean.action-sell_call::before,
.strike-action-badge.action-strength-lean.action-sell_put::before,
.strike-action-badge.action-strength-lean.action-sell_premium::before {
    animation-duration: 2.8s;
    opacity: 0.75;
}

/* AVOID / NONE never animate — dim + static by construction. */
.strike-action-badge.action-avoid {
    animation: none;
}

/* Accessibility: no motion — static glow for BUY, static ring for SELL. */
@media (prefers-reduced-motion: reduce) {
    .strike-action-badge.action-buy_call,
    .strike-action-badge.action-buy_put {
        animation: none;
        box-shadow: inset 0 0 0 1px currentColor, 0 0 8px 1px var(--action-pulse-glow, rgba(0, 200, 83, 0.45));
    }

    .strike-action-badge.action-sell_call::before,
    .strike-action-badge.action-sell_put::before,
    .strike-action-badge.action-sell_premium::before {
        animation: none;
        background: none;
        border: 1px solid var(--action-spin-color, rgba(255, 59, 48, 0.7));
        -webkit-mask: none;
        mask: none;
    }
}


/* ---- Strike-invasion badge (direction-routed into the flow cells) ----
   Compact pill rendered inside the Call Flow cell (direction UP — spot rising into resistance) or
   the Put Flow cell (direction DOWN — spot falling into support). COLOR encodes the invasion outcome:
   red = SHORT_CALL_CANDIDATE / SHORT_PUT_CANDIDATE (actionable fake break), green = DO NOT SHORT
   (real break), amber = PENDING, blue = Stage-1 forecast. No motion — a static state marker.
   It moved out of the strike cell: strike-intelligence action badge + invasion badge together
   overflowed the rigid strike-cell grid past the fixed 46px row. */
.strike-invasion-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 9px;
    font-size: 9px;
    font-weight: 850;
    letter-spacing: 0.4px;
    line-height: 1.4;
    white-space: nowrap;
    vertical-align: middle;
    color: #0b0d0f;
    background: rgba(255, 255, 255, 0.86);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
    position: relative;
    z-index: 2;
}

/* Red — the actionable short-call candidate (never suppressed). */
.strike-invasion-badge.invasion-short-call {
    color: var(--action-bear);
    box-shadow: inset 0 0 0 1px var(--action-bear-glow);
}

/* Green — the level really broke; do not short. */
.strike-invasion-badge.invasion-do-not-short {
    color: var(--action-bull);
    box-shadow: inset 0 0 0 1px var(--action-bull-glow);
}

/* Amber — invasion pending resolution. */
.strike-invasion-badge.invasion-pending {
    color: var(--action-premium);
    box-shadow: inset 0 0 0 1px var(--action-premium-glow);
}

/* Red — the actionable short-put candidate (down-direction fake break; same red as short-call:
   both are the actionable fake-break verdicts). */
.strike-invasion-badge.invasion-short-put {
    color: var(--action-bear);
    box-shadow: inset 0 0 0 1px var(--action-bear-glow);
}

/* UNCALIBRATED — the fence. Every badge carries this today; the measurement behind it is recorded
   in STRIKE-INVASION-CALIBRATION-GATE1.md and deliberately not restated in this file, which is
   served as a public static asset. The tone colour is deliberately LEFT ALONE — an
   actionable short candidate must stay as visible as it was; the point is not to hide the signal,
   it is to stop the signal reading as a measured probability. So the marking is textural: a dashed
   rim instead of a solid one, plus the '†' the badge text already carries. Same intent as
   .tz-uncalibrated on the Tape Zones card.

   No opacity fade here, on purpose: the Tape Zones card learned that dimming the thing you are
   warning about just makes it unreadable during the hours it is most looked at. */
.strike-invasion-badge.invasion-uncalibrated {
    box-shadow: none;
    outline: 1px dashed currentColor;
    outline-offset: -1px;
    text-decoration: none;
}

/* Blue — Stage-1 forecast while approaching. */
.strike-invasion-badge.invasion-forecast {
    color: var(--invasion-forecast);
    box-shadow: inset 0 0 0 1px var(--invasion-forecast-glow);
}

/* Placement inside the flow cell: an absolutely positioned chip pinned to the corner AWAY from the
   strike column — the call cell's NET value hugs the right (strike) edge and the put cell's hugs the
   left, so the opposite top corner is provably empty. Out of the grid flow, the badge can never grow
   the fixed 46px row or push the flow-net/flow-row2/flow-bar lines. Nested inside .flow-inner, it is
   exempt from the `tbody td > *` text-mask (which styles direct td children only) and keeps its own
   white pill background; z-index lifts it above the flow bar and heatmap ribbon. */
.flow-cell .strike-invasion-badge {
    position: absolute;
    top: 1px;
    margin-left: 0;
    z-index: 6;
    /* CEILING, for the same reason .flow-net-val has one. The flow column is sized for the widest
       badge, so an unbounded badge means no column width is ever sufficient -- and the badge text
       IS unbounded: the forecast branch appends Math.round(record.ips) with no range constraint,
       so an unbounded IPS widens the pill until it reaches the NET value. This cap is what stops
       that: the text ellipsises inside the pill instead of growing across the cell. 118px
       fits the widest legitimate text ("⛊ DO NOT SHORT†", measured), so nothing the producer is
       supposed to emit is truncated; anything wider is ellipsised rather than allowed to take the
       board's layout with it. The text is never rewritten to fit -- that would quietly report a
       wrong value as a right one -- and the full string stays in the badge's
       title and aria-label, which already carry the whole record.

       A SHARE, not px, for the same reason as .flow-net-val: the widest badge measures 117.05px in
       Gill Sans, 114.81px in Verdana and 99.94px in the generic fallback, so any px number is
       calibrated to whichever font the measuring machine had. 50% of the 248px content box is
       124px, clearing the widest measured need by ~7px, and 50 + 42 + 8 = 100% by construction.
       The full text always stays in the badge's title and aria-label, which carry the whole
       record either way.

       The cap is here but the TRUNCATION is on .strike-invasion-badge-text below, because this box
       is inline-flex: a bare string child becomes an anonymous flex item, and text-overflow on a
       flex CONTAINER does not reliably ellipsise that child -- it clips, which on a live board
       means a partial number with no sign it was cut. So the text gets a real element that can
       carry min-width:0 and do it properly. */
    max-width: 50%;
    overflow: hidden;
}
/* Where the badge's truncation actually happens. min-width:0 is the load-bearing part: a flex item
   refuses to shrink below its content size without it, so the ellipsis would never trigger. */
.strike-invasion-badge-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Call side: flush to the left padding edge, the mirror of the put side's `right: 0`.
   It used to be `left: 24px`, to clear a rank-1 gold volume figure said to spill out of the
   neighbouring Call Volume cell. Call Volume is not a neighbour of this cell — Call OI sits
   between them — and the spill does not exist anyway: measured, the widest gold figure
   ("999.9k" at the 24px rank-1 font) renders 73px wide inside its own 84px column and its rect
   intersects neither the OI cell nor this one. The 24px was buying nothing and costing 24px of
   the clearance the badge actually needs against the right-hugging NET value. */
.flow-cell.call-flow .strike-invasion-badge { left: 0; }
.flow-cell.put-flow .strike-invasion-badge { right: 0; }

/* Unified-S/R pill (Option A): a side + score + wall-type chip.
   It lives in the OI cell — see .oi-sr-pill below. It USED to ride the flow cell in the invasion
   badge's absolute top-corner slot, and that is the bug this replaced: an overlay has no layout of
   its own, so with several strikes carrying a level at once the chips covered the flow values
   beneath them. Resistance still routes to the call side and support to the put side. */

/* LOW confidence stays visibly provisional: dashed ring instead of the solid one. */
.oi-sr-pill.sr-pill-low.sr-pill-res { box-shadow: none; outline: 1px dashed rgba(220, 53, 69, 0.8); outline-offset: -1px; }
.oi-sr-pill.sr-pill-low.sr-pill-sup { box-shadow: none; outline: 1px dashed rgba(40, 167, 69, 0.8); outline-offset: -1px; }
.sr-pill-gamma { color: #e0a800; font-weight: 400; }


/* ---- Agent A short-premium recommendation overlay (paper/advisory) ---- */
/* Border on the centre strike cell (4th td). Resting frame (0%/100%) is fully
   visible so the marker stays clear even when re-render pauses the animation. */
.short-premium-short > td:nth-child(4) {
  border: 2px dotted #ff5d5d !important;
  border-radius: 5px;
  animation: shortPremiumShortBlink 1.5s ease-in-out infinite;
}
.short-premium-long > td:nth-child(4) {
  border: 2px dotted #2ecc71 !important;
  border-radius: 5px;
  animation: shortPremiumLongBlink 1.5s ease-in-out infinite;
}
@keyframes shortPremiumShortBlink {
  0%, 100% { box-shadow: 0 0 0 1px rgba(255, 93, 93, 0.5), 0 0 12px rgba(255, 93, 93, 0.45); }
  50%      { box-shadow: none; }
}
@keyframes shortPremiumLongBlink {
  0%, 100% { box-shadow: 0 0 0 1px rgba(46, 204, 113, 0.5), 0 0 12px rgba(46, 204, 113, 0.45); }
  50%      { box-shadow: none; }
}

/* γ sign-boundary line — drawn by the imperative effect in option-chain.js on the shared edge
   between a boundary's two bracket strikes (where ADJACENT strikes flip dealer-gamma sign). This is
   the SAME per-strike boundary the context tape draws, NOT the cumulative flip level. Violet matches
   the tape. The effect adds --below (line on the row's bottom edge) or --above (top edge) so the
   dotted line lands on the true edge facing the other bracket strike, whatever the sort direction;
   the bracket nearest spot is emphasised (--primary) and labelled "γ flip". A full-width dotted
   border reads as a line between the two strikes. !important beats the collapsed-table cell borders. */
.gamma-sign-boundary--below > td {
  border-bottom: 2px dotted rgba(143, 111, 232, 0.72) !important;
}
.gamma-sign-boundary--above > td {
  border-top: 2px dotted rgba(143, 111, 232, 0.72) !important;
}
.gamma-sign-boundary--primary.gamma-sign-boundary--below > td {
  border-bottom: 2px dotted #8f6fe8 !important;
  box-shadow: 0 2px 7px -3px rgba(143, 111, 232, 0.6);
}
.gamma-sign-boundary--primary.gamma-sign-boundary--above > td {
  border-top: 2px dotted #8f6fe8 !important;
  box-shadow: 0 -2px 7px -3px rgba(143, 111, 232, 0.6);
}
/* Exactly one row per primary bracket carries the label; its edge class puts it on the drawn side. */
.gamma-sign-boundary--label > td:first-child {
  position: relative;
}
.gamma-sign-boundary--label > td:first-child::after {
  content: 'γ flip';
  position: absolute;
  left: 4px;
  z-index: 6;
  font: 700 9px/1 ui-monospace, Menlo, monospace;
  letter-spacing: 0.06em;
  color: #cdbcff;
  background: #0b0e14;
  padding: 1px 4px;
  border-radius: 3px;
  pointer-events: none;
}
.gamma-sign-boundary--label.gamma-sign-boundary--below > td:first-child::after { bottom: -8px; }
.gamma-sign-boundary--label.gamma-sign-boundary--above > td:first-child::after { top: -8px; }

.short-premium-banner {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 6px 0; padding: 6px 12px;
  background: rgba(38, 216, 136, 0.08);
  border: 1px solid rgba(38, 216, 136, 0.4);
  border-left: 3px solid #26d888;
  border-radius: 8px; font-size: 12.5px;
}
.short-premium-banner .sp-tag {
  font-size: 9.5px; letter-spacing: 0.12em; text-transform: uppercase;
  color: #26d888; font-weight: 700;
}
.short-premium-banner .sp-legs {
  font-family: ui-monospace, Menlo, monospace; color: #d7e2f0; cursor: help;
}
@media (prefers-reduced-motion: reduce) {
  .short-premium-short > td:nth-child(4),
  .short-premium-long > td:nth-child(4) { animation: none; }
}

/* ── SPX 0DTE spread-skew (design/SPREAD-SKEW-SIGNAL-GATE1.md §5) ──────────────────────────────── */

/* §5.1 consolidated Mid (the extreme Call Mid / Put Mid columns): strict quote mid, color/blink is
   pair-state driven (class toggle, CSS animation only — no JS timer, no re-render churn). Default
   (unpaired/ATM/ITM/tie/stale) inherits the row; greyed .skew-mid-fallback = last-trade, uncolored. */
.skew-mid-value { font-variant-numeric: tabular-nums; }
/* Last-trade fallback (no two-sided quote): greyed, never skew-colored. */
.skew-mid-fallback { color: var(--muted); font-variant-numeric: tabular-nums; }
/* Strike number inherits its OTM side's pair state: green = lean direction (cheap side),
   red = rich side (market unlikely to reach). Steady only — no animation on the strike. */
.strike-price-value.skew-strike-cheap { color: var(--call); font-weight: 850; }
.strike-price-value.skew-strike-rich { color: var(--put); font-weight: 850; }
/* Cheaper side of the mirrored pair = lean direction under AWAY-from-rich: green + ~1s opacity pulse. */
.skew-mid-cheap {
  color: var(--call);
  font-weight: 850;
  animation: skewMidPulse 1s ease-in-out infinite;
}
/* Richer side: red, steady (never blinks). */
.skew-mid-rich {
  color: var(--put);
  font-weight: 850;
}
@keyframes skewMidPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
@media (prefers-reduced-motion: reduce) {
  .skew-mid-cheap { animation: none; }
}

/* §5.0 panel — dark board panel, mirroring .option-behavior-panel. */
.spread-skew-panel {
  margin-top: 5px;
  padding: 8px 10px;
  border-top: 1px solid rgba(128, 177, 232, 0.16);
  border-bottom: 1px solid rgba(128, 177, 232, 0.16);
  background: linear-gradient(180deg, rgba(9, 13, 22, 0.96), rgba(13, 18, 30, 0.92));
  display: grid;
  gap: 7px;
  overflow: hidden;
}
.spread-skew-panel.bearish { border-color: rgba(222, 74, 74, 0.52); }
.spread-skew-panel.bullish { border-color: rgba(27, 147, 71, 0.52); }
.spread-skew-header {
  align-items: center;
  display: grid;
  grid-template-columns: 230px minmax(150px, max-content) 1fr;
  gap: 12px;
  min-width: 0;
}
.spread-skew-header strong {
  color: #ffffff;
  font-size: 13px;
  font-weight: 950;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* =====================================================================   ES 09:15 Open Direction panel (es-open-direction-forecast / -outcome events).
   Compact standalone card below SummaryGrid; kept dark to match the
   option-behavior board. Purely additive — no existing selector is touched.
   ============================================================================ */
.es-open-direction-panel {
  margin-top: 5px;
  padding: 8px 10px;
  border: 1px solid rgba(128, 177, 232, 0.16);
  border-radius: 6px;
  background: linear-gradient(180deg, rgba(9, 13, 22, 0.96), rgba(13, 18, 30, 0.92));
  display: grid;
  gap: 6px;
}
.es-open-direction-panel.es-od-up { border-color: rgba(27, 147, 71, 0.52); }
.es-open-direction-panel.es-od-down { border-color: rgba(222, 74, 74, 0.52); }
.es-open-direction-panel.es-od-failed,
.es-open-direction-panel.es-od-waiting { border-style: dashed; }
.es-od-header {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.es-od-header strong {
  color: #ffffff;
  font-size: 13px;
  font-weight: 950;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The chip is NEVER blank: gray NEUTRAL/WARMING/degraded-reason, red BEARISH, green BULLISH. */
.spread-skew-chip {
  display: inline-block;
  justify-self: start;
  padding: 2px 10px;
  border-radius: 999px;
  border: 1px solid rgba(148, 163, 184, 0.5);
  color: #cbd5e1;
  background: rgba(148, 163, 184, 0.12);
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
}
.spread-skew-chip.bearish {
  color: #fb7185;
  border-color: rgba(222, 74, 74, 0.65);
  background: rgba(222, 74, 74, 0.14);
}
.spread-skew-chip.bullish {
  color: #34d399;
  border-color: rgba(27, 147, 71, 0.65);
  background: rgba(27, 147, 71, 0.14);
}
.spread-skew-meta {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
  min-width: 0;
  overflow: hidden;
}
.spread-skew-meta span {
  color: var(--muted);
  font-size: 10px;
  font-weight: 850;
  text-transform: uppercase;
  white-space: nowrap;
}
.spread-skew-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
  gap: 14px;
  align-items: stretch;
}
.spread-skew-line { min-width: 0; }
.spread-skew-line svg { display: block; width: 100%; height: 150px; }
.spread-skew-line-empty {
  align-self: center;
  color: var(--muted);
  font-size: 11px;
  padding: 8px 0;
}
.spread-skew-band { fill: rgba(77, 163, 255, 0.14); stroke: none; }
/* §5.0.2: late session (14:00 ET pin filter) is marked by COLOUR, not by fading to 0.4 — a faded
   marker on a dark chart is an invisible marker. */
.spread-skew-band.late { fill: rgba(148, 163, 184, 0.16); }
.spread-skew-marker.late { stroke: #94a3b8; stroke-width: 1.6; }
.spread-skew-stroke {
  fill: none;
  stroke: #7ecbff;
  stroke-width: 1.6;
  vector-effect: non-scaling-stroke;
}
/* §5.0.2: dashed where valid=false; late session gets its OWN dash rhythm + a cooler stroke,
   instead of the old opacity 0.4 that erased the line. */
.spread-skew-stroke.invalid { stroke-dasharray: 5 4; stroke: rgba(148, 163, 184, 0.8); }
.spread-skew-stroke.late { stroke-dasharray: 2 3; stroke: #8fb4cc; }
/* Both at once (option-chain.js emits `invalid` and `late` independently): validity is the more
   important of the two, so the long 5-4 "invalid" rhythm survives and late is said by the cooler
   stroke alone. Without this rule the late dash would overwrite it and an invalid late run would
   be indistinguishable from a valid one. */
.spread-skew-stroke.invalid.late { stroke-dasharray: 5 4; stroke: #8fb4cc; }
.spread-skew-marker { fill: #cbd5e1; stroke: #0b0e14; stroke-width: 1; }
.spread-skew-marker.fire.bearish, .spread-skew-marker.reversal.bearish { fill: #fb7185; }
.spread-skew-marker.fire.bullish, .spread-skew-marker.reversal.bullish { fill: #34d399; }
.spread-skew-marker.exit { fill: #94a3b8; }

/* §5.0.3 offset tornado: put credit grows LEFT (coral), call credit grows RIGHT (teal). */
.spread-skew-ladder { display: grid; gap: 6px; align-content: center; }
.spread-skew-ladder-row {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) 34px minmax(0, 1fr) 42px;
  align-items: center;
  gap: 6px;
}
.spread-skew-ladder-row.stale { box-shadow: inset 3px 0 0 #94a3b8; }
.spread-skew-ladder-k {
  color: #cbd5e1;
  font-size: 11px;
  font-weight: 950;
  text-align: center;
}
.spread-skew-ladder-credit {
  color: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  font-weight: 850;
}
.spread-skew-ladder-credit.put { text-align: right; }
.spread-skew-ladder-credit.call { text-align: left; }
.spread-skew-ladder-track {
  height: 9px;
  border-radius: 5px;
  background: rgba(255, 255, 255, 0.06);
  overflow: hidden;
  display: flex;
}
.spread-skew-ladder-track.put { justify-content: flex-end; }
.spread-skew-ladder-track.call { justify-content: flex-start; }
.spread-skew-ladder-track i { display: block; height: 100%; }
.spread-skew-ladder-track.put i { background: #ef6a5a; }
.spread-skew-ladder-track.call i { background: #2dd4bf; }
.es-od-badge {
  padding: 1px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
}
.es-od-badge-up { color: #34d399; background: rgba(27, 147, 71, 0.18); border: 1px solid rgba(52, 211, 153, 0.55); }
.es-od-badge-down { color: #fb7185; background: rgba(222, 74, 74, 0.16); border: 1px solid rgba(251, 113, 133, 0.55); }
.es-od-badge-none { color: var(--muted); border: 1px solid rgba(148, 163, 184, 0.4); }
.es-od-meta { color: var(--muted); font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; }
.es-od-placeholder,
.es-od-failure-text {
  color: var(--muted);
  font-size: 12px;
  font-style: italic;
}
.es-od-failure-reasons {
  margin: 4px 0 0;
  padding-left: 18px;
  color: var(--muted);
  font-size: 11px;
}
.es-od-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(230px, 300px);
  gap: 12px;
  align-items: start;
}
.es-od-headline { color: #e2e8f0; font-size: 12.5px; line-height: 1.35; }
.es-od-evidence-row { display: flex; align-items: center; gap: 8px; margin-top: 5px; }
.es-od-evidence-text { color: #f8fafc; font-size: 11.5px; font-weight: 900; white-space: nowrap; }
.es-od-evidence-bar {
  flex: 0 1 140px;
  height: 6px;
  border-radius: 999px;
  background: rgba(148, 163, 184, 0.18);
  overflow: hidden;
}
.es-od-evidence-bar i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #38bdf8, #34d399);
}
.es-open-direction-panel.es-od-down .es-od-evidence-bar i {
  background: linear-gradient(90deg, #f59e0b, #fb7185);
}
.es-od-ref { color: var(--muted); font-size: 11px; white-space: nowrap; }
.es-od-components { display: flex; flex-wrap: wrap; gap: 4px 8px; margin-top: 6px; }
.es-od-component {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  padding: 1px 6px;
  border-radius: 4px;
  background: rgba(148, 163, 184, 0.08);
}
.es-od-component em { color: var(--muted); font-size: 10px; font-style: normal; }
.es-od-component b { font-size: 10.5px; font-family: ui-monospace, Menlo, monospace; }
.es-od-component.positive b { color: #34d399; }
.es-od-component.negative b { color: #fb7185; }
.es-od-component.neutral b { color: #94a3b8; }
.es-od-outcomes { display: grid; gap: 3px; }
.es-od-outcome-row {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr) 18px minmax(64px, auto);
  align-items: center;
  gap: 6px;
  padding: 2px 6px;
  border-radius: 4px;
  background: rgba(148, 163, 184, 0.06);
  font-size: 11px;
}
.es-od-outcome-horizon { color: #cbd5e1; font-weight: 900; }
.es-od-outcome-window { color: var(--muted); white-space: nowrap; }
.es-od-headline-tag {
  margin-left: 6px;
  padding: 0 5px;
  border-radius: 999px;
  border: 1px solid rgba(56, 189, 248, 0.5);
  color: #38bdf8;
  font-size: 9px;
  font-style: normal;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.es-od-outcome-mark { text-align: center; font-size: 11px; }
.es-od-outcome-row.correct .es-od-outcome-mark { color: #34d399; font-weight: 900; }
.es-od-outcome-row.wrong .es-od-outcome-mark { color: #fb7185; font-weight: 900; }
.es-od-outcome-row.pending .es-od-outcome-mark,
.es-od-outcome-row.unresolved .es-od-outcome-mark { color: var(--muted); }
.es-od-outcome-detail { color: #cbd5e1; font-family: ui-monospace, Menlo, monospace; font-size: 10px; white-space: nowrap; }
.es-od-outcome-row.correct .es-od-outcome-detail { color: #34d399; }
.es-od-outcome-row.wrong .es-od-outcome-detail { color: #fb7185; }
.es-od-outcome-row.pending .es-od-outcome-detail,
.es-od-outcome-row.unresolved .es-od-outcome-detail { color: var(--muted); }
@media (max-width: 900px) {
  .es-od-body { grid-template-columns: minmax(0, 1fr); }
}

/* ----- ES open-direction LIVE STATUS strip (append-only) ---------------------------------
   Single compact row inside .es-open-direction-panel, above the forecast/placeholder area.
   Rendered ONLY while the 60s heartbeat is fresh (asOf within 5 min client-side); when the
   status is stale or absent the strip is simply not in the DOM — nothing here handles a
   "stale" visual state on purpose. */
.es-od-status-strip {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 12px;
  margin: 6px 0 4px;
  padding: 5px 8px;
  border: 1px solid rgba(148, 163, 184, 0.28);
  border-radius: 6px;
  background: rgba(15, 23, 42, 0.35);
  font-size: 11px;
}
.es-od-status-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #cbd5e1;
}
.es-od-status-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #64748b;
  display: inline-block;
}
/* MONITORING: pulsing live dot — same soft-blink family as the flow/turn pulses. */
.es-od-status-dot.live {
  background: #34d399;
  box-shadow: 0 0 4px rgba(52, 211, 153, 0.7);
  animation: esOdStatusPulse 1.6s ease-in-out infinite;
}
@keyframes esOdStatusPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.35; transform: scale(0.72); }
}
@media (prefers-reduced-motion: reduce) {
  .es-od-status-dot.live { animation: none; }
}
.es-od-status-monitoring { color: #34d399; }
.es-od-status-frozen { color: #7dd3fc; }
.es-od-status-forecasted { color: #f8fafc; }
.es-od-status-evaluating { color: #fbbf24; }
.es-od-status-cell {
  color: #e2e8f0;
  font-family: ui-monospace, Menlo, monospace;
  font-size: 10.5px;
  white-space: nowrap;
}
.es-od-status-timing {
  margin-left: auto;
  color: var(--muted);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* PACE-VOLUME-TRAJECTORY-DESIGN.md §R8 — white hover popup for a golden top-volume strike. Display-only;
   line colour is set inline by strike level (green highest / orange middle / red lower). */
.volume-cell.tvol-has-popup { cursor: help; }
/* pace indicator relocated into the volume cell (user request): number on top, chip beneath.
   The chip reuses the existing .flow-pace styles (violet rank emphasis, clickable explainer). */
.volume-cell { vertical-align: middle; }
.volume-cell .volume-value { display: block; }
.volume-cell .flow-pace {
    display: inline-flex; margin-top: 1px; font-size: 9.5px; gap: 3px;
    max-width: 100%; overflow: hidden; white-space: nowrap;   /* bounded: never spills into FLOW */
}
/* Fixed-positioned (top/left set inline off the cell rect) so the .table-wrap/.chain-card overflow
   ancestors can't clip it near the viewport edges. */
.tvol-popup {
    position: fixed; z-index: 60;
    width: 280px; background: #ffffff; color: #1a1f27;
    border-radius: 12px; box-shadow: 0 18px 44px rgba(0,0,0,.45), 0 0 0 1px rgba(0,0,0,.06);
    padding: 10px 12px; pointer-events: none;
}
.tvol-head { display: flex; align-items: center; gap: 7px; margin-bottom: 6px; }
.tvol-level { font-size: 9px; font-weight: 800; letter-spacing: .04em; color: #fff;
    padding: 1px 6px; border-radius: 5px; }
.tvol-title { font-size: 12px; font-weight: 700; color: #2b323c; }
.tvol-rank { margin-left: auto; font-size: 11px; font-weight: 700; color: #6b7480; }
.tvol-svg { width: 100%; height: 84px; display: block; }
/* popup axes: hairline scales + tiny labels (display-only re-renderings of plotted values) */
.tvol-axline { stroke: #dfe4ea; stroke-width: 1; }
.tvol-ax { font-size: 7px; fill: #8a93a0; font-variant-numeric: tabular-nums; }
.tvol-ax-price { font-size: 7px; fill: #9aa3ae; font-variant-numeric: tabular-nums; }
.tvol-ax-spot { font-size: 7px; font-weight: 700; fill: #1a86bd; font-variant-numeric: tabular-nums; }
.tvol-line { fill: none; stroke-width: 2.4; }
.tvol-proj { fill: none; stroke-width: 2.4; stroke-dasharray: 5 4; opacity: .8; }
.tvol-now { stroke: #c3bdec; stroke-width: 1; stroke-dasharray: 3 3; }
.tvol-foot { display: flex; align-items: center; justify-content: space-between; margin-top: 4px; }
.tvol-badge { font-size: 11px; font-weight: 800; letter-spacing: .03em; padding: 2px 8px; border-radius: 999px; display: inline-flex; align-items: center; gap: 5px; }
.tvol-badge.up { color: #12894f; background: rgba(27,147,71,.12); }
.tvol-badge.flat { color: #b26a06; background: rgba(239,125,16,.12); }
.tvol-badge.down { color: #c02a24; background: rgba(216,54,47,.12); }
.tvol-exp { font-size: 8px; font-weight: 700; color: #8a6dff; background: rgba(138,109,255,.14); border-radius: 4px; padding: 0 4px; }
.tvol-pace { font-size: 11px; color: #48515d; font-variant-numeric: tabular-nums; }
.tvol-empty { font-size: 12px; color: #6b7480; padding: 14px 4px; text-align: center; font-style: italic; }

/* §10 spot-ETA rows — the backend model's predicted reach time + probability per top-3 strike. */
.tvol-eta { margin-top: 6px; padding-top: 6px; border-top: 1px solid #eef1f5; display: flex; flex-direction: column; gap: 2px; }
.tvol-eta-row { display: flex; align-items: center; gap: 6px; font-size: 10.5px; color: #48515d; font-variant-numeric: tabular-nums; }
.tvol-eta-row i { width: 9px; height: 3px; border-radius: 2px; display: inline-block; flex: none; }
.tvol-eta-row.is-focus { font-weight: 700; color: #1a1f27; }
.tvol-eta-strike { min-width: 38px; }
.tvol-eta-text { margin-left: auto; }

/* multi-line trajectory: focused strike emphasized, others are context; grey = 4th. The split is
   carried by WEIGHT and dash, not by fading the context lines to .5 — a half-transparent line on a
   busy chart is a line you cannot follow, and each of these is a real strike's trajectory. */
.tvol-line.is-focus { stroke-width: 2.8; stroke-dasharray: none; }
.tvol-line.is-ctx { stroke-width: 1.4; stroke-dasharray: 4 3; }
.tvol-legend { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.tvol-leg { display: inline-flex; align-items: center; gap: 4px; font-size: 10px; color: #6b7480; font-variant-numeric: tabular-nums; }
.tvol-leg i { width: 9px; height: 3px; border-radius: 2px; display: inline-block; }

/* spot overlay in the trajectory popup: faint strike reference lines + the moving spot line (right price axis) */
.tvol-strikeref { stroke: #d7dde5; stroke-width: 1; stroke-dasharray: 2 4; }
.tvol-spot { fill: none; stroke: #1a86bd; stroke-width: 2.4; opacity: .95; }
.tvol-spotdot { fill: #1a86bd; }
.tvol-spotval { font-size: 11px; font-weight: 800; color: #1a86bd; }

/* §9b recent-signals trail: BUY/SELL bursts retained by the backend after the live role flips.
   Chips are newest-first; bullish = buy-call/sell-put green, bearish = buy-put/sell-call red. */
.recent-signals-panel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 8px 0;
    padding: 8px 12px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 10px;
}
.recent-signals-panel .rs-title {
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--muted);
    margin-right: 4px;
}
.rs-chip {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid var(--line);
    font-size: 12px;
    line-height: 1.5;
    white-space: nowrap;
}
.rs-chip .rs-bias { font-weight: 800; }
.rs-chip .rs-strike { font-weight: 700; }
.rs-chip .rs-strength {
    font-size: 10px;
    font-weight: 800;
    text-transform: uppercase;
}
.rs-chip .rs-meta { font-size: 11px; color: var(--muted); }

/* LIVE burst indicator: the story re-confirmed within the last 3 minutes */
.rs-chip .rs-live {
    animation: rs-live-pulse 1.2s ease-in-out infinite;
    color: #58e6a8;
    font-weight: 900;
    letter-spacing: 0.06em;
}
.rs-chip.rs-live-chip { border-color: rgba(88, 230, 168, 0.55); }
@keyframes rs-live-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

/* live burst breath-count on the chain's strike-action badge */
.strike-action-badge .badge-burst-count {
    font-size: 10px;
    font-weight: 900;
}
.rs-chip.rs-bullish {
    background: rgba(0, 200, 83, 0.16);
    border-color: #00c853;
}
.rs-chip.rs-bullish .rs-bias { color: #00c853; }
.rs-chip.rs-bearish {
    background: rgba(255, 59, 48, 0.16);
    border-color: #ff3b30;
}
.rs-chip.rs-bearish .rs-bias { color: #ff3b30; }
.rs-chip.rs-neutral { background: var(--gold, #fff0bd); }

/* =====================================================================   Flow Explorer — full-screen canvas range-selector fed by GET /api/pin-flow.
   Reached from the top-nav "Flow Explorer" button; brushes a time window on the
   session spot line. See design/FLOW-EXPLORER-OPTION-CHAIN-GATE1.md §7.
   ========================================================================= */
button.flow-explorer-nav-link {
    cursor: pointer;
    font-family: inherit;
}

.flow-explorer {
    width: min(2400px, calc(100% - 16px));
    margin: 0 auto;
    padding: 10px 0 24px;
}

.flow-explorer-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    padding: 4px 4px 12px;
}

.flow-explorer-toolbar button.flow-explorer-close {
    cursor: pointer;
    font-family: inherit;
}

.flow-explorer-title {
    font-size: 15px;
    color: var(--ink);
}

.flow-explorer-hint {
    font-size: 12px;
    color: var(--muted);
}

.flow-explorer-refresh {
    font-size: 12px;
    color: var(--muted);
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
}

.flow-explorer-refresh select {
    font-family: inherit;
    font-size: 12px;
    padding: 3px 6px;
    border-radius: 6px;
    border: 1px solid var(--line);
    background: var(--panel);
    color: var(--ink);
}

.flow-explorer-updated {
    font-size: 12px;
    color: var(--muted);
    min-width: 140px;
    text-align: right;
}

.flow-explorer-canvas-wrap {
    position: relative;
    width: 100%;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--border-radius-md, 6px);
    padding: 8px;
    margin: 8px 0;
}

.flow-explorer-out {
    margin: 12px 4px;
    font-size: 13px;
    color: var(--ink);
}

/* §9b recent-signal hover popup: full peak-observation reasoning (scores, flow, engine reason). */
.rs-chip { position: relative; cursor: default; }
.rs-pop {
    display: none;
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 60;
    min-width: 340px;
    max-width: 460px;
    padding: 10px 12px;
    background: var(--panel, #fffffa);
    border: 1px solid var(--line);
    border-radius: 10px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.14);
    white-space: normal;
    line-height: 1.45;
}
.rs-chip:hover .rs-pop { display: flex; flex-direction: column; gap: 4px; }
.rs-pop .rs-pop-title { font-size: 12px; }
.rs-pop .rs-pop-line { font-size: 11.5px; color: var(--ink); }
.rs-pop .rs-pop-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
    font-size: 11.5px;
    font-weight: 700;
}
.rs-pop .rs-pop-reason {
    font-size: 11px;
    color: var(--muted);
    border-top: 1px dashed var(--line);
    padding-top: 5px;
    margin-top: 2px;
}

/* §9c SOLID story blink: a STRONG (two-sided) burst still re-confirming after 15+ observations —
   the market is consistently repeating the same story at this strike. Soft pulse, side-colored. */
@keyframes rs-solid-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(0, 0, 0, 0); filter: brightness(1); }
    50% { box-shadow: 0 0 10px 2px var(--rs-pulse-color, rgba(0, 200, 83, 0.55)); filter: brightness(1.12); }
}
.rs-chip.rs-solid {
    animation: rs-solid-pulse 1.1s ease-in-out infinite;
    font-weight: 800;
}
.rs-chip.rs-solid.rs-bullish { --rs-pulse-color: rgba(0, 200, 83, 0.55); }
.rs-chip.rs-solid.rs-bearish { --rs-pulse-color: rgba(255, 59, 48, 0.55); }
@media (prefers-reduced-motion: reduce) {
    .rs-chip.rs-solid { animation: none; outline: 2px solid var(--rs-pulse-color, rgba(0, 200, 83, 0.55)); }
}
.rs-chip .rs-runs {
    font-size: 10px;
    font-weight: 800;
    padding: 0 5px;
    border-radius: 999px;
    background: var(--gold, #fff0bd);
    border: 1px solid var(--line);
}

/* ── Checkbox exposure lanes (.xb) ──────────────────────────────────────────
   The strike cell divides into N equal horizontal lanes — one per SELECTED band
   (gamma, vanna, charm, ES), in that fixed order — inside the SAME fixed-height
   box: no checkbox combination ever changes the cell size. Lane math for slot k
   of n: top = k/n, bottom = (n-k-1)/n. Slot/count arrive as inline CSS vars
   (--xb-n, --xb-g/--xb-v/--xb-c/--xb-e) from StrikeCell. These rules sit LAST
   in the file so, at equal specificity, they override the legacy half-cell
   geometry (.gv-split / .gv-has-es) for cells carrying the .xb class. */
.strike-cell.xb .gex-strength-fill {
    top: calc(var(--xb-g, 0) / var(--xb-n, 1) * 100%);
    bottom: calc((var(--xb-n, 1) - var(--xb-g, 0) - 1) / var(--xb-n, 1) * 100%);
}
.strike-cell.xb .gex-strength-axis {
    top: calc(var(--xb-g, 0) / var(--xb-n, 1) * 100% + 3px);
    bottom: calc((var(--xb-n, 1) - var(--xb-g, 0) - 1) / var(--xb-n, 1) * 100% + 3px);
}
.strike-cell.xb .gex-strength-arrow {
    top: calc(var(--xb-g, 0) / var(--xb-n, 1) * 100% + 1px);
    bottom: auto;
}
.strike-cell.xb .vanna-strength-fill {
    top: calc(var(--xb-v, 0) / var(--xb-n, 1) * 100%);
    bottom: calc((var(--xb-n, 1) - var(--xb-v, 0) - 1) / var(--xb-n, 1) * 100%);
}
.strike-cell.xb .vanna-strength-axis {
    top: calc(var(--xb-v, 0) / var(--xb-n, 1) * 100% + 3px);
    bottom: calc((var(--xb-n, 1) - var(--xb-v, 0) - 1) / var(--xb-n, 1) * 100% + 3px);
}
.strike-cell.xb .vanna-strength-arrow {
    top: calc(var(--xb-v, 0) / var(--xb-n, 1) * 100% + 1px);
    bottom: auto;
}
.strike-cell.xb .charm-strength-fill {
    top: calc(var(--xb-c, 0) / var(--xb-n, 1) * 100%);
    bottom: calc((var(--xb-n, 1) - var(--xb-c, 0) - 1) / var(--xb-n, 1) * 100%);
}
.strike-cell.xb .charm-strength-axis {
    top: calc(var(--xb-c, 0) / var(--xb-n, 1) * 100% + 3px);
    bottom: calc((var(--xb-n, 1) - var(--xb-c, 0) - 1) / var(--xb-n, 1) * 100% + 3px);
}
.strike-cell.xb .charm-strength-arrow {
    top: calc(var(--xb-c, 0) / var(--xb-n, 1) * 100% + 1px);
    bottom: auto;
}
/* The sides rendering lives in the GAMMA lane (--xb-g), not a lane of its own: one gamma lane
   whichever way it is drawn, so checking the box never resizes anything else in the cell. */
.strike-cell.xb .sides-strength-axis {
    top: calc(var(--xb-g, 0) / var(--xb-n, 1) * 100% + 3px);
    bottom: calc((var(--xb-n, 1) - var(--xb-g, 0) - 1) / var(--xb-n, 1) * 100% + 3px);
}
.strike-cell.xb .sides-put-fill,
.strike-cell.xb .sides-call-fill {
    top: calc(var(--xb-g, 0) / var(--xb-n, 1) * 100%);
    bottom: calc((var(--xb-n, 1) - var(--xb-g, 0) - 1) / var(--xb-n, 1) * 100%);
}
.strike-cell.xb .es-strength-fill {
    top: calc(var(--xb-e, 0) / var(--xb-n, 1) * 100%);
    bottom: calc((var(--xb-n, 1) - var(--xb-e, 0) - 1) / var(--xb-n, 1) * 100%);
}
.strike-cell.xb .es-strength-axis {
    top: calc(var(--xb-e, 0) / var(--xb-n, 1) * 100% + 3px);
    bottom: calc((var(--xb-n, 1) - var(--xb-e, 0) - 1) / var(--xb-n, 1) * 100% + 3px);
}
.strike-cell.xb .es-strength-arrow {
    top: calc(var(--xb-e, 0) / var(--xb-n, 1) * 100% + 1px);
    bottom: auto;
}
.strike-cell.xb .es-band-tag {
    top: calc(var(--xb-e, 0) / var(--xb-n, 1) * 100% + 2px);
    bottom: auto;
}
/* Arrows scale with lane height: at n=3/4 a lane is ~11-15px while the default arrow line box is
   15px, which would bleed into the neighbouring lane (Codex F2). clamp() keeps the full size for
   1-2 lanes and shrinks the glyph + line box proportionally for 3-4. */
.strike-cell.xb .gex-strength-arrow,
.strike-cell.xb .vanna-strength-arrow,
.strike-cell.xb .charm-strength-arrow,
.strike-cell.xb .es-strength-arrow {
    font-size: clamp(7px, calc(26px / var(--xb-n, 1)), 12px);
    line-height: clamp(9px, calc(34px / var(--xb-n, 1)), 15px);
}

/* Charm band (teal + / rose −) — the exact vanna gauge pattern on netCharmExposure
   ($delta per day of decay). Hues deliberately distinct from gamma (blue/red) and
   vanna (violet/amber) so a lane is identifiable at a glance. */
.charm-strength-fill {
    position: absolute;
    top: 0;
    bottom: 0;
    z-index: 0;
    display: block;
    width: var(--charm-fill-width, 0%);
    opacity: 0.9;
    pointer-events: none;
    transition: width 220ms ease, left 220ms ease, right 220ms ease;
}
.strike-cell.charm-positive .charm-strength-fill {
    left: 50%;
    background:
        repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.14) 0 8px, transparent 8px 11px),
        linear-gradient(90deg, rgba(45, 212, 191, 0.30), rgba(45, 212, 191, 0.90));
    box-shadow: 0 0 18px rgba(45, 212, 191, 0.24);
}
.strike-cell.charm-negative .charm-strength-fill {
    right: 50%;
    background:
        repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.14) 0 8px, transparent 8px 11px),
        linear-gradient(270deg, rgba(244, 114, 182, 0.30), rgba(244, 114, 182, 0.92));
    box-shadow: 0 0 18px rgba(244, 114, 182, 0.24);
}
.strike-cell.charm-neutral .charm-strength-fill {
    left: 50%;
    transform: translateX(-50%);
    background: rgba(160, 172, 184, 0.36);
}
.charm-strength-axis {
    position: absolute;
    top: 4px;
    bottom: 4px;
    left: 50%;
    z-index: 1;
    width: 1px;
    background: rgba(255, 255, 255, 0.34);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.22);
    pointer-events: none;
}
.charm-strength-arrow {
    position: absolute;
    top: 2px;
    left: var(--charm-arrow-left, 50%);
    z-index: 4;
    width: 16px;
    transform: translateX(-50%);
    border-radius: 999px;
    background: rgba(4, 8, 16, 0.72);
    font-size: 12px;
    font-weight: 950;
    line-height: 15px;
    text-align: center;
    text-shadow: none;
    pointer-events: none;
    transition: left 220ms ease;
}
.strike-cell.charm-positive .charm-strength-arrow { color: #7ff0df; }
.strike-cell.charm-negative .charm-strength-arrow { color: #f9a8d4; }
.strike-cell.charm-neutral .charm-strength-arrow { color: #d8e4ef; }
.uw-charm-value { color: #8ee8d8; }

/* Header exposure checkboxes (replaces the 3-way .gex-vanna-toggle button). */
.exposure-band-picker {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 2px 8px;
    border: 1px solid rgba(124, 196, 255, 0.28);
    border-radius: 999px;
    background: rgba(10, 18, 30, 0.55);
    white-space: nowrap;
}
.exposure-band-caption {
    font-size: 11px;
    font-weight: 700;
    color: rgba(216, 228, 239, 0.78);
}
.exposure-band-item {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    cursor: pointer;
    user-select: none;
}
.exposure-band-item input {
    margin: 0;
    width: 12px;
    height: 12px;
    cursor: pointer;
}
.exposure-band-label {
    font-size: 12px;
    font-weight: 800;
    line-height: 1;
}
.exposure-band-gamma input { accent-color: #4f9cf0; }
.exposure-band-vanna input { accent-color: #b38cff; }
.exposure-band-charm input { accent-color: #2dd4bf; }
.exposure-band-wall input { accent-color: #e0713a; }
.exposure-band-gamma .exposure-band-label { color: #7cc4ff; }
.exposure-band-vanna .exposure-band-label { color: #cbb4ff; }
.exposure-band-charm .exposure-band-label { color: #7ff0df; }

/* Close-direction card (CLOSE-DIRECTION-GATE1 §8/CD-R31): final-hour dealer-ledger forecast. */
.close-direction-card {
    border-color: rgba(120, 120, 140, 0.45);
}
.close-direction-title {
    display: flex;
    align-items: center;
    gap: 6px;
}
.cd-direction {
    font-size: 20px;
    letter-spacing: 0.02em;
}
.close-direction-card.cd-up .cd-direction { color: #1f9d55; }
.close-direction-card.cd-down .cd-direction { color: #d64545; }
.close-direction-card.cd-choppy .cd-direction { color: #b57e12; }
.close-direction-card.cd-unknown .cd-direction { color: #8a8fa3; }
.close-direction-card.cd-verdict {
    border-width: 2px;
}
.close-direction-card.cd-verdict.cd-up { border-color: rgba(31, 157, 85, 0.7); }
.close-direction-card.cd-verdict.cd-down { border-color: rgba(214, 69, 69, 0.7); }
.close-direction-card.cd-verdict.cd-choppy { border-color: rgba(181, 126, 18, 0.7); }
.cd-verdict-chip {
    background: rgba(90, 105, 220, 0.18);
    color: #4a58c8;
    padding: 1px 6px;
    border-radius: 4px;
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.04em;
}
.cd-stale-chip {
    background: rgba(140, 140, 150, 0.2);
    color: #77808f;
    padding: 1px 6px;
    border-radius: 4px;
    font-size: 10px;
    font-weight: 700;
}
/* Stale card: railed, not faded — the numbers on it are the last true reading and have to stay
   readable while the rail says they are old. */
.close-direction-card.cd-stale {
    box-shadow: inset 4px 0 0 #ff7878;
    outline: 1px dashed rgba(255, 120, 120, 0.6);
    outline-offset: 2px;
}
.close-direction-card.cd-idle .cd-direction { color: #8a8fa3; }
.cd-state-line {
    display: block;
    min-height: 14px;
}
.cd-calibration {
    display: block;
    min-height: 12px;
    color: #9aa1b3;
    font-size: 10px;
}

/* Charm number on the shared value line + charm chips in the GEX history popover (charm-only). */
.charm-tag {
    font-size: 8px;
    font-weight: 800;
    letter-spacing: 0.06em;
    color: #7ff0df;
}
.uw-charm-now,
.uw-charm-history {
    color: #8ee8d8;
    font-style: normal;
    font-weight: 700;
}

/* Value line carrying ONLY the charm number (vanna unchecked/absent): stays fully visible —
   the vanna-idle visibility trick must never swallow charm content (Codex r2). */
.strike-vanna-line.charm-line { visibility: visible; }

/* Charm history chip is the FOURTH child of the popover row's 3-column grid — without explicit
   placement auto-flow would drop it under the window label. Deliberate layout: the charm pair
   renders as a second line under the gamma pair, spanning the value+delta columns (Codex r3). */
.uw-gex-popover li .uw-charm-history {
    grid-column: 2 / -1;
    grid-row: 2;
    font-size: 10px;
}

/* Charm-only popover rows (gamma unchecked): the charm chip is the row's primary content —
   lift it onto the first grid row beside the window label (Codex r5). */
.uw-gex-popover li.charm-only .uw-charm-history {
    grid-row: 1;
    grid-column: 2 / -1;
    font-size: 11px;
}

/* ------------------------------------------------------------------------------------------
   HOT STRIKE — the strike currently gaining the most gamma, from the gamma-migration service.

   Two states, and the difference between them is the whole point. A strike's gamma depends on
   its DISTANCE from spot, so when price walks toward a strike its gamma climbs with nobody
   trading it. Pulsing on that would be announcing price movement as though it were positioning.

     .gamma-hot        spot held still, so the gain is the strike's own  -> soft pulse
     .gamma-hot-weak   spot moved, so the gain is mostly distance        -> static faint tint

   The pulse is deliberately slow and low-contrast: this sits on a dense chain the user reads for
   minutes at a time, and a hard blink would make the page unreadable rather than informative.
   ------------------------------------------------------------------------------------------ */
@keyframes gexHotPulse {
    0%, 100% { opacity: 0.62; box-shadow: 0 0 20px rgba(46, 156, 255, 0.28); }
    50%      { opacity: 1;    box-shadow: 0 0 26px rgba(96, 214, 255, 0.75); }
}

.strike-cell.gamma-hot .gex-strength-fill {
    animation: gexHotPulse 1.8s ease-in-out infinite;
}

/* A thin leading edge so the hot strike is findable by eye while scanning the ladder, without
   changing the bar's length — the length is the reading and must stay honest. */
.strike-cell.gamma-hot::after {
    content: "";
    position: absolute;
    left: 0;
    top: 2px;
    bottom: 2px;
    width: 2px;
    border-radius: 2px;
    background: rgba(96, 214, 255, 0.95);
    animation: gexHotPulse 1.8s ease-in-out infinite;
    pointer-events: none;
}

.strike-cell.gamma-hot-weak .gex-strength-fill {
    opacity: 0.88;
}

/* Respect the OS setting: replace the motion with a steady state that still marks the strike,
   rather than dropping the signal for anyone who has motion turned off. */
@media (prefers-reduced-motion: reduce) {
    .strike-cell.gamma-hot .gex-strength-fill,
    .strike-cell.gamma-hot::after {
        animation: none;
        opacity: 1;
        box-shadow: 0 0 26px rgba(96, 214, 255, 0.6);
    }
}

/* GEX carry-regime badge in the freshness strip. Mirrors the .freshness-state pill shape.
   Semantics decided 2026-08: MARKET_DERIVED is the healthy live state (green); STATIC_CONFIG is
   NEUTRAL, not a warning — a env deliberately running static carry is legitimate; a market value
   older than 2 min dims to amber; UNKNOWN/MIXED are grey. */
.carry-badge {
    flex: 0 0 auto;
    border-radius: 999px;
    padding: 3px 7px;
    font-size: 10px;
    font-weight: 950;
    letter-spacing: 0.04em;
    color: #fff;
    background: #5c6b63;
    white-space: nowrap;
}
.carry-badge.carry-market       { background: #1f8a56; }
.carry-badge.carry-market-stale { background: #b7791f; }
.carry-badge.carry-static       { background: #45566b; }   /* neutral slate, not a warning */
.carry-badge.carry-mixed        { background: #5c6b63; }   /* grey per spec, not a warning colour */
.carry-badge.carry-unknown      { background: #5c6b63; }

/* Spot-vol regime pill (header, next to the GEX status). Colors follow the two-sided
   philosophy: vol-confirmed direction = saturated green/red; DIVERGENT_UP (suspect rally)
   reads as the warning red, COMPLACENT_DOWN (decline without fear) as the watch green —
   matching the strike-color latch theory. Stale/absent regime never renders (no pill). */
.svr-pill {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: #fff;
  background: #45566b;           /* neutral slate default (NEUTRAL) */
  white-space: nowrap;
}
.svr-pill.svr-confirmed-up    { background: #1f8a56; }
.svr-pill.svr-stable-up       { background: #33796b; }
.svr-pill.svr-divergent-up    { background: #a32020; }  /* suspect rally — the interesting red */
.svr-pill.svr-confirmed-down  { background: #b91c1c; }
.svr-pill.svr-complacent-down { background: #2f9e6e; }  /* bounce watch — the interesting green */
.svr-pill.svr-neutral         { background: #45566b; }
.svr-pill.svr-unknown         { background: #5c6b63; }
/* Volatility-regime prediction strip (0DTE model). Present only when the service publishes a
   prediction block — i.e. only once a CALIBRATED model ships. Sized in a fixed-height row with
   nowrap chips so appearing/disappearing cannot reflow the strike table: the same lesson the
   avoid-signal shake taught. */
.vol-regime-strip {
    display: inline-flex; align-items: baseline; gap: 6px;
    margin-left: 10px; white-space: nowrap; line-height: 1;
}
.vol-regime-caption { font-size: 10px; letter-spacing: .08em; color: var(--muted); }
.vol-regime-chip {
    font-size: 11px; padding: 2px 6px; border-radius: 3px;
    border: 1px solid transparent; font-variant-numeric: tabular-nums;
}
.vol-regime-expansion   { background: rgba(214, 88, 60, .16);  border-color: rgba(214, 88, 60, .45); }
.vol-regime-contraction { background: rgba(60, 150, 214, .16); border-color: rgba(60, 150, 214, .45); }
.vol-regime-balanced    { background: rgba(150, 150, 150, .14); border-color: rgba(150, 150, 150, .38); }

/* ── spot-vol-regime LATCHED STRIKE BAND ───────────────────────────────────────────────────────
   The strikes the spot traversed while the regime was DIVERGENT_UP (red) or COMPLACENT_DOWN
   (green), anchor included, latched for the rest of the session.

   GLYPH ONLY. The strike CELL background already carries GEX / vanna / support-resistance meaning
   and is never touched here — only .strike-price-value recolours.

   Reuses the EXISTING turn-alert colour pair verbatim (#ff5d6b / #2fd39a, see
   .strike-price-value.strike-turn-blink.turn-bearish/.turn-bullish above); no new colour
   vocabulary is introduced. Steady, never animated: this is a record of where price has BEEN, not
   a live alert, and the two blinking glyph states (turn-alert, magnet) must stay distinguishable.

   Precedence is decided in JS (strikeBandGlyphClass), not by stylesheet source order: the class is
   only emitted when no turn-alert / hot-strike / spread-skew signal already owns the glyph colour.
   These rules sit at the tail purely so they are not accidentally outranked by a later edit. */
.strike-price-value.svr-band-bearish { color: #ff5d6b; }
.strike-price-value.svr-band-bullish { color: #2fd39a; }

/* ---- Pre-open IBKR GEX window (OVERNIGHT-IBKR-GEX rev13, R-UI/O6/D12++) ---- */
/* WCAG-AA tokens: positive gamma GREEN, negative ORANGE — dark text on light fills
   (contrast >= 4.5:1) so the IBKR-derived window is visually distinct from the RTH colours. */
/* The value/strike glyphs draw over --cell-text-mask-bg: the IBKR tokens override the mask to
   MATCH their light fills, so the effective glyph contrast is dark-on-light (>= 4.5:1):
   #0b5c2e on #d7f5e2 ~ 7.5:1, #8a4404 on #ffe8cc ~ 6.6:1. */
/* Waiting text sits over the DARK mask — use a light gray readable on #191a25 (~7:1). */
.strike-cell.gamma-preopen-waiting { background: transparent; color: #c3c7d1; font-style: italic; }
.strike-cell.gamma-preopen-waiting .uw-gex-value { color: #c3c7d1; }

/* D12++ per-strike switch alert chips — non-colour-only (text + border style differ). */
.preopen-chip {
  display: inline-block; margin-left: 6px; padding: 0 6px; border-radius: 8px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.4px; vertical-align: middle;
}
.preopen-chip-switching {
  background: #fff7e0; color: #7a5b00; border: 1px dashed #b98a00;
  animation: preopen-chip-pulse 1.2s ease-in-out infinite;
}
.preopen-chip-live { background: #e2f7e9; color: #0b5c2e; border: 1px solid #1c7c46; }
@keyframes preopen-chip-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.55; } }
@media (prefers-reduced-motion: reduce) {
  .preopen-chip-switching { animation: none; }
}

/* ---- Open interest -------------------------------------------------------
   OI is not a static reference number here. The exchange settles it once overnight and the OI
   nowcast carries it through the session, so the cell shows the current value AND how far it has
   moved since this browser first saw it -- not since the session opened, which a tab opened at
   14:00 never witnessed. A flat column is meaningful: it says the nowcast is not contributing,
   which is exactly what an operator needs to be able to see at a glance.

   Width and alignment mirror .volume-cell so the board stays symmetric either side of the strike.
   Tabular figures again, so a number changing in place cannot jitter the row. */
.oi-cell {
    width: 96px;
    min-width: 96px;
    text-align: right;
    padding-left: 4px;
    padding-right: 6px;
    white-space: nowrap;
    /* The S/R pill adds a THIRD line to this cell. tbody tr is a fixed 44px (SBX-147 constant
       geometry), so a taller stack cannot grow the row — it would spill over the neighbouring
       cells instead, which is the exact overlap this change set out to remove. The pill is given a
       deterministic 10px box below so the stack lands ON the 39px budget (measured: overflow 0).
       The clip is the structural backstop for font-metric drift in the other two lines. It is
       `clip` with a 6px margin, NOT `hidden`: .oi-value and .oi-delta are not on the mask
       cascade's exclusion list, so they carry `box-shadow: 0 0 0 6px` — a plain `hidden` would
       shear that halo off at the cell edge. 6px matches the spread exactly, so the mask renders
       untouched while spill stays bounded instead of unbounded. */
    overflow: clip;
    overflow-clip-margin: 6px;
}
/* The header carries the real column width under table-layout:fixed — the .oi-cell width above is
   a td rule and was being ignored, which is how Call OI ended up 260px (from a stale
   positional 3rd-header-cell rule meant for the flow column) and Put OI 163px (the auto share),
   while the comment
   above claimed both "mirror .volume-cell". Stating it on the th makes the claim true and hands
   the reclaimed width to the flow columns, where the invasion badge needs it. */
.chain-table th.oi-col {
    width: 96px;
}
/* S/R pill in the OI column.
   It used to ride the flow cell in an absolute top-corner slot, where it covered the flow value
   whenever several strikes carried a level at once — the reported bug.
   Here it is a BLOCK on its own line above the number, the same technique .oi-delta already uses,
   so it cannot overlap the value however wide either grows. No absolute positioning: an overlay
   is exactly what caused the collision it is being moved away from.
   The cell is a fixed 96px, so the pill is allowed to shrink its own text rather than widen the
   column — the board's constant-geometry contract (SBX-147) means data must never resize a row. */
.oi-sr-pill {
    display: block;
    max-width: 100%;
    margin-bottom: 0;
    padding: 0 4px;
    border-radius: 8px;
    font-size: 8.5px;
    font-weight: 850;
    letter-spacing: 0.2px;
    /* RESERVED box, not a computed one: 13px value + 11px delta + strut = 29px measured, against a
       39px budget (44px row - 4px padding - 1px border). A 10px pill lands exactly on it. Stated as
       height+matching line-height so the font can never renegotiate it. */
    height: 10px;
    line-height: 10px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* No per-side alignment rule: .oi-cell is already text-align:right and the pill is a block, so it
   inherits. The call/put pair that used to sit here set the same value twice and implied a pill can
   appear on both sides of a row at once — it cannot. strikeSrPillState() gates on srDominantSide and
   returns {visible:false} for the side that is not dominant, so a row carries AT MOST ONE pill. */
.oi-sr-pill.sr-pill-res {
    color: #ff97a1;
    background: rgba(66, 14, 20, 0.92);
    box-shadow: inset 0 0 0 1px rgba(220, 53, 69, 0.8);
}
.oi-sr-pill.sr-pill-sup {
    color: #7fd89a;
    background: rgba(10, 48, 26, 0.92);
    box-shadow: inset 0 0 0 1px rgba(45, 164, 78, 0.8);
}
.oi-sr-pill.sr-pill-low { opacity: 0.72; }

.oi-value {
    font-weight: 800;
    font-size: 13px;
    line-height: 1;
    color: #cfd8e3;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}
/* The change since the session's first observation, on its own line so the value stays readable
   and the row height does not move when a delta appears mid-session. */
.oi-delta {
    display: block;
    font-size: 10px;
    line-height: 1.1;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    opacity: 0.9;
}
.oi-cell.oi-up .oi-value { color: #eaf4ff; }
.oi-cell.oi-up .oi-delta { color: #4ade80; }
.oi-cell.oi-down .oi-value { color: #eaf4ff; }
.oi-cell.oi-down .oi-delta { color: #f87171; }


/* Gamma SIDES band (±Γ): call and put gamma as two bars from a shared centre axis.
   Put LEFT, call RIGHT — a fixed semantic convention, never swapped by sign, so "left is put"
   stays dependable (Codex). Colours echo the gamma palette (call blue / put red) but POSITION
   carries the meaning; the pair is legible without colour. A two-sided strike is wide on both
   sides — which is precisely what the net band cancels away. */
.sides-strength-axis {
    position: absolute;
    left: 50%;
    width: 1px;
    z-index: 0;
    display: block;
    background: rgba(226, 232, 240, 0.30);
    pointer-events: none;
}
.sides-put-fill,
.sides-call-fill {
    position: absolute;
    z-index: 0;
    display: block;
    pointer-events: none;
    border-radius: 1px;
    transition: width 220ms ease;
}
.sides-put-fill {
    right: 50%;
    width: var(--sides-put-width, 0%);
    background: linear-gradient(270deg, rgba(248, 113, 113, 0.85), rgba(248, 113, 113, 0.30));
}
.sides-call-fill {
    left: 50%;
    width: var(--sides-call-width, 0%);
    background: linear-gradient(90deg, rgba(96, 165, 250, 0.85), rgba(96, 165, 250, 0.30));
}
/* Both books material: the case the band was built for gets a visible outline so it is findable
   by scanning the ladder, not only by reading widths. */
.sides-put-fill.sides-two-sided,
.sides-call-fill.sides-two-sided {
    box-shadow: 0 0 0 1px rgba(250, 204, 21, 0.55);
}
/* One side not priced this tick: hatched, so a missing component never reads as "no exposure". */
.sides-put-fill.sides-partial,
.sides-call-fill.sides-partial {
    background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.22) 0 3px, transparent 3px 6px);
}
.exposure-band-sides .exposure-band-label {
    letter-spacing: 0.02em;
}

/* Balanced ±Γ structure: the largest gross call+put book among the balanced strikes near spot.
   STATIC by default. The property can hold for hours and its 20-session backtest was null, so it
   gets a quiet standing outline rather than the attention-demanding motion the hot strike earns
   (Codex). Motion appears only when the marked strike CHANGES, and is finite. */
.strike-cell.sides-balanced .sides-strength-axis {
    background: rgba(250, 204, 21, 0.75);
    width: 2px;
}
.strike-cell.sides-balanced .sides-put-fill,
.strike-cell.sides-balanced .sides-call-fill {
    box-shadow: 0 0 0 1px rgba(250, 204, 21, 0.65);
}
/* A transition ACKNOWLEDGEMENT, not a signal: two gentle cycles, then it stops on its own.
   Non-infinite by construction, so even a cell that never re-renders cannot keep moving. */
@keyframes sidesBalancedSettle {
    0%, 100% { box-shadow: 0 0 0 1px rgba(250, 204, 21, 0.65); }
    50%      { box-shadow: 0 0 0 2px rgba(250, 204, 21, 0.95), 0 0 12px rgba(250, 204, 21, 0.35); }
}
.strike-cell.sides-balanced-new .sides-put-fill,
.strike-cell.sides-balanced-new .sides-call-fill {
    animation: sidesBalancedSettle 1.6s ease-in-out 2;
}
/* Reduced motion gets the standing marker immediately — never the acknowledgement. */
@media (prefers-reduced-motion: reduce) {
    .strike-cell.sides-balanced-new .sides-put-fill,
    .strike-cell.sides-balanced-new .sides-call-fill {
        animation: none;
    }
}

/* ----- Drop-classifier SHADOW nowcast strip (advisory-only) ----- */
.drop-nowcast-panel { margin: 6px 0; padding: 6px 10px; border: 1px solid #2a2f3a; border-radius: 6px; background: #12151c; font-size: 12px; }
.drop-nowcast-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.drop-nowcast-title { font-weight: 600; color: #c9d4e3; }
.drop-nowcast-shadow-tag { font-size: 10px; letter-spacing: 0.08em; padding: 1px 6px; border-radius: 3px; background: #3a2f14; color: #d8b45a; cursor: help; }
.drop-nowcast-row { display: flex; align-items: center; gap: 10px; padding: 2px 0; color: #aeb8c8; }
.drop-nowcast-time { color: #7f8a9c; font-variant-numeric: tabular-nums; }
.drop-nowcast-ref { min-width: 110px; }
.drop-nowcast-cat { font-weight: 700; padding: 1px 7px; border-radius: 3px; cursor: help; }
.drop-cat-sweep { background: #12351f; color: #5fd68a; }
.drop-cat-real { background: #3a1518; color: #f07a7a; }
.drop-cat-undecided { background: #262b35; color: #98a2b3; }
.drop-nowcast-k { color: #6b7687; font-size: 10px; }
/* Idle (no rows in the 10-min window): the head stays so the sound can be armed before the
   first sweep of the day. It recedes by being SMALL and quiet-coloured, not by fading — the arm
   button on it has to stay obviously clickable. */
.drop-nowcast-idle .drop-nowcast-title { color: #7f8a9c; }
.drop-nowcast-idle .drop-nowcast-head { margin-bottom: 0; }
.drop-nowcast-sound { margin-left: auto; background: none; border: 1px solid #2a2f3a; border-radius: 4px; color: #7f8a9c; font-size: 12px; line-height: 1; padding: 2px 6px; cursor: pointer; }
.drop-nowcast-sound.on { border-color: #3a5a3f; color: #5fd68a; background: #12351f; }
.drop-nowcast-sound:hover { border-color: #3d5a8a; }
/* Entry link to the /notifications settings page, sitting beside the sound control it governs. */
.drop-nowcast-notify-link { margin-left: 6px; border: 1px solid #2a2f3a; border-radius: 4px; font-size: 12px; line-height: 1; padding: 2px 6px; text-decoration: none; }
.drop-nowcast-notify-link:hover { border-color: #3d5a8a; }

/* ---------- Money map (shared with the strike board via /strike-money-map.js) ----------
   Two markers only, both structural rather than judgemental: the strikes that bracket spot,
   and the one strike the volume actually concentrated on. They sit on the row's left edge so
   they never compete with the existing current-strike, flow or S/R colouring, and they carry
   no green/red — nothing here says which way price goes. */
tbody tr.mm-wall > td:first-child { box-shadow: inset 3px 0 0 var(--blue); }
tbody tr.mm-busiest > td:first-child { box-shadow: inset 3px 0 0 var(--orange); }
/* A strike can be both a wall and the busiest one; show both rather than letting order decide. */
tbody tr.mm-wall.mm-busiest > td:first-child {
    box-shadow: inset 3px 0 0 var(--blue), inset 6px 0 0 -3px var(--orange);
}
.money-map-card strong { font-variant-numeric: tabular-nums; white-space: nowrap; }
.money-map-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.money-map-foot small { color: var(--muted); font-variant-numeric: tabular-nums; }
.money-map-coverage { opacity: .8; }

/* ---------- SPOT BAND column: what each strike traded while spot stood in the selected range ----
   Colour = side (call / put), fill = direction (solid bought, hollow sold). Four quantities,
   because side alone cannot carry direction — a bought call and a SOLD put are both bullish. */
/* One band column per SIDE, hugging the strike — this board mirrors every measure, and a single
   band column sitting next to Put Flow read as a put column while carrying both sides' data. */
.band-col { width: 104px; }
/* overflow: hidden, not visible. `tbody td > *` gives these children z-index 5 while the strike cell
   sits at auto, so a band figure wider than its cell painted OVER the strike box next door. Clipping
   is the fix rather than a z-index lift: no band pixel can leave this column, so the order no longer
   matters — and .spot-line (absolute, full row, z-index 3) keeps crossing the strike cell, which
   lifting that cell would have cut a 170px hole in. */
.band-cell { width: 104px; white-space: nowrap; overflow: hidden; }
/* table-layout: fixed hands DECLARED widths out first. Both band columns declare 104px; the strike
   header declared nothing, so it took the remainder and landed on 87px against the 170px
   .strike-cell asks for — and .strike-gex-line then shrank the GEX value to ZERO width, exactly as
   it is built to (it gives that child up first). Declaring the width here is the whole fix: measured
   on dev it restores Strike 87px -> 170px and the GEX value 0 -> 25px, taking the 83px from the
   four undeclared columns that had surplus (87px -> 70px each). The band columns keep their size. */
th.strike-header-cell { width: 170px; }
/* calls grow toward the strike from the left, puts away from it on the right — same as the flow
   columns either side, so the eye reads outward from the strike in both directions. */
.call-band-cell { text-align: right; }
.call-band-cell .band-track { flex-direction: row-reverse; }
.call-band-cell .band-total { margin: 0 7px 0 0; }
/* 40px, not 66: measured in this font a band total needs up to 40px ($12.3M) and the cell has 16px of
   padding plus the 7px margin, so 66 left the figure nothing and it overflowed the column. */
.band-track { display: inline-flex; align-items: center; gap: 1px; width: 40px; height: 10px;
              background: color-mix(in srgb, var(--muted) 14%, transparent); border-radius: 2px;
              overflow: hidden; vertical-align: middle; }
.band-track .bd { display: block; height: 100%; border-radius: 1px; }
.band-track .bd.c { background: var(--call); color: var(--call); }
.band-track .bd.p { background: var(--put); color: var(--put); }
.band-track .bd.sold { background: transparent; border: 1.5px solid currentColor; box-sizing: border-box; }
.band-total { margin-left: 7px; font-size: 11.5px; color: var(--muted);
              font-variant-numeric: tabular-nums; }
.band-cell.band-busiest .band-total { color: var(--gold-strong, #a8790d); font-weight: 700; }
.band-card strong { font-variant-numeric: tabular-nums; white-space: nowrap; }
.band-slider { position: relative; height: 26px; margin: 2px 0 4px; }
.band-slider .rail { position: absolute; top: 11px; left: 0; right: 0; height: 4px; border-radius: 2px;
                     background: color-mix(in srgb, var(--muted) 25%, transparent); }
.band-slider .sel { position: absolute; top: 11px; height: 4px; border-radius: 2px; background: var(--orange); }
.band-slider input[type=range] { position: absolute; top: 2px; left: 0; width: 100%; margin: 0; height: 22px;
  background: none; -webkit-appearance: none; appearance: none; pointer-events: none; }
.band-slider input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; pointer-events: auto;
  width: 14px; height: 22px; border-radius: 4px; background: var(--panel); border: 2px solid var(--orange); cursor: ew-resize; }
.band-slider input[type=range]::-moz-range-thumb { pointer-events: auto;
  width: 14px; height: 22px; border-radius: 4px; background: var(--panel); border: 2px solid var(--orange); cursor: ew-resize; }
.band-unplaced { color: var(--put); }

/* Board snapshot control. Lives in the chain toolbar beside ATM/Spot, because that is where the
   reading it captures is stated — the button and the numbers it stores are read together. */
.board-snapshot-btn {
    margin-left: 12px;
    padding: 2px 10px;
    font: 600 11px -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    color: #c9d1d9;
    background: #1b2634;
    border: 1px solid #2c3442;
    border-radius: 4px;
    cursor: pointer;
}
.board-snapshot-btn:hover { background: #223044; }
.board-snapshot-status {
    margin-left: 8px;
    font: 11px -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    color: #8a94a6;
}
.board-snapshot-bad { color: #ef6f6f; }

/* ── Liquidity-wall lane (the W exposure box) ────────────────────────────────────
   Its own lane in the .xb stack (--xb-w), after charm and before ES. Put bid size grows LEFT in
   cyan, call ask size grows RIGHT in orange: the Liquidity Wall page's own support and resistance
   colours. A bar is quoted size only, never itself a wall; support or resistance is claimed only
   by the solid 3px bracket and the S / R tag, which appear only where the strike sits inside a
   live wall. A frame that is not LIVE, is DEGRADED, or is more than
   15s old draws the flat grey stale band and no sizes (the same treatment as a stale gamma lane). */
.strike-cell.xb .wall-lane {
    position: absolute;
    left: 0;
    right: 0;
    top: calc(var(--xb-w, 0) / var(--xb-n, 1) * 100%);
    bottom: calc((var(--xb-n, 1) - var(--xb-w, 0) - 1) / var(--xb-n, 1) * 100%);
    z-index: 0;
    pointer-events: none;
}
.wall-lane-bid, .wall-lane-ask {
    position: absolute;
    top: 0;
    bottom: 0;
    transition: width 220ms ease;
}
.wall-lane-bid {
    right: 50%;
    width: var(--wall-bid-width, 0%);
    background:
        repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.12) 0 6px, transparent 6px 8px),
        linear-gradient(270deg, rgba(63, 167, 214, 0.28), rgba(63, 167, 214, 0.95));
}
.wall-lane-ask {
    left: 50%;
    width: var(--wall-ask-width, 0%);
    background:
        repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.12) 0 6px, transparent 6px 8px),
        linear-gradient(90deg, rgba(224, 113, 58, 0.28), rgba(224, 113, 58, 0.95));
}
.wall-lane-axis {
    position: absolute;
    top: 2px;
    bottom: 2px;
    left: 50%;
    width: 1px;
    background: rgba(255, 255, 255, 0.34);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.22);
}
.wall-lane.wall-lane-in-r { box-shadow: inset -3px 0 0 #e0713a; }
.wall-lane.wall-lane-in-s { box-shadow: inset 3px 0 0 #3fa7d6; }
.wall-lane.wall-lane-in-r.wall-lane-in-s { box-shadow: inset -3px 0 0 #e0713a, inset 3px 0 0 #3fa7d6; }
.wall-lane-tag {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 1;
    padding: 0 3px;
    border-radius: 2px;
    font-size: 9px;
    font-weight: 800;
    line-height: 11px;
    color: #0b0f16;
}
.wall-lane-tag-r { right: 5px; background: #e0713a; }
.wall-lane-tag-s { left: 5px; background: #3fa7d6; }
.wall-lane.wall-lane-stale { background: rgba(88, 96, 108, 0.34); }
@media (prefers-reduced-motion: reduce) {
    .wall-lane-bid, .wall-lane-ask { transition: none; }
}


/* ---------- Audited pace UI (ported additively from pace-ui-hardening-v3) ---------- */
:root {
  --pace-live: #21c7a8;
  --pace-live-strong: #00a88a;
  --pace-call: #38d996;
  --pace-put: #ff7085;
  --pace-corrected: #ffc857;
  --pace-warmup: #91a4b7;
  --pace-gap: #ffb020;
  --pace-reset: #8b9cff;
  --pace-stale: #8291a3;
  --pace-invalid: #f15cda;
  --pace-legacy: #b8a4d9;
  --pace-unknown: #6d7c8d;
  --pace-panel: #090d16;
  --pace-panel-raised: #111827;
  --pace-grid: rgba(151, 176, 205, 0.17);
  --pace-text: #f7fbff;
  --pace-muted: #9eb1c5;
}

.pace-mode-badge,
.pace-status-badge,
.pace-quality-chip,
.pace-legend-item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 22px;
  padding: 3px 8px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 999px;
  color: #fff;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.055em;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
}

.pace-mode-badge {
  margin-left: auto;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.12), 0 4px 14px rgba(10, 16, 27, 0.18);
}

.pace-mode-live,
.pace-status-live,
.pace-quality-chip-live,
.pace-legend-live {
  border-color: rgba(33, 199, 168, 0.74);
  background: #0f7260;
  color: #ecfffb;
}

.pace-mode-replay,
.pace-status-replay {
  border-color: rgba(86, 180, 255, 0.78);
  background: #155b94;
  color: #f3faff;
  box-shadow: inset 0 -3px 0 rgba(134, 205, 255, 0.42);
}

.pace-mode-safe,
.pace-status-safe {
  border-color: rgba(139, 156, 255, 0.74);
  background: #4c579d;
}

.pace-mode-warmup,
.pace-status-warmup,
.pace-quality-chip-warmup,
.pace-legend-warmup {
  border-color: rgba(145, 164, 183, 0.74);
  background: #46576a;
  color: #f6f9fc;
}

.pace-mode-gap,
.pace-status-gap,
.pace-quality-chip-gap,
.pace-legend-gap {
  border-color: #ffd27a;
  background:
    repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.18) 0 4px, transparent 4px 8px),
    #875200;
  color: #fff8e6;
}

.pace-mode-reset,
.pace-status-reset,
.pace-quality-chip-reset,
.pace-legend-reset {
  border-color: rgba(139, 156, 255, 0.88);
  background: #4856a9;
  color: #f4f6ff;
}

.pace-mode-corrected,
.pace-status-corrected,
.pace-quality-chip-corrected,
.pace-legend-corrected {
  border-color: rgba(255, 200, 87, 0.88);
  background: #765300;
  color: #fff8df;
}

.pace-mode-invalid,
.pace-status-invalid,
.pace-quality-chip-invalid,
.pace-legend-invalid {
  border-color: rgba(255, 158, 238, 0.92);
  background:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.18) 0 3px, transparent 3px 7px),
    #7d176d;
  color: #fff3fd;
}

.pace-mode-legacy,
.pace-status-legacy,
.pace-quality-chip-legacy {
  border-color: rgba(184, 164, 217, 0.76);
  background: #59456f;
}

.pace-mode-unknown,
.pace-status-unknown,
.pace-quality-chip-unknown {
  border-color: rgba(130, 145, 163, 0.58);
  background: #3d4957;
  color: #eef3f7;
}

.pace-command-center {
  position: relative;
  isolation: isolate;
  display: grid;
  gap: 8px;
  margin-top: 5px;
  padding: 10px;
  overflow: hidden;
  border: 1px solid rgba(133, 171, 215, 0.3);
  border-radius: 12px;
  background:
    linear-gradient(90deg, rgba(255, 255, 255, 0.025) 1px, transparent 1px),
    linear-gradient(180deg, rgba(255, 255, 255, 0.025) 1px, transparent 1px),
    radial-gradient(circle at 16% 0%, rgba(33, 199, 168, 0.13), transparent 28rem),
    linear-gradient(160deg, #090d16, #111827);
  background-size: 32px 32px, 32px 32px, auto, auto;
  box-shadow: 0 14px 42px rgba(2, 7, 16, 0.3);
  color: var(--pace-text);
}

.pace-command-center::before {
  position: absolute;
  inset: 0 auto 0 0;
  width: 4px;
  background: var(--pace-unknown);
  content: "";
}

.pace-command-center[data-health="LIVE"]::before { background: var(--pace-live); }
.pace-command-center[data-health="PARTIAL"]::before,
.pace-command-center[data-health="WARMUP"]::before { background: var(--pace-warmup); }
.pace-command-center[data-health="DEGRADED"]::before { background: var(--pace-gap); }
.pace-command-center[data-health="RESET"]::before { background: var(--pace-reset); }
.pace-command-center[data-health="CAUTION"]::before { background: var(--pace-corrected); }
.pace-command-center[data-health="CRITICAL"]::before { background: var(--pace-invalid); }

.pace-command-header,
.pace-command-card-header,
.pace-leader-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.pace-command-heading,
.pace-command-card-title {
  display: grid;
  gap: 1px;
  min-width: 0;
}

.pace-command-eyebrow {
  color: #75ddca;
  font-size: 9px;
  font-weight: 950;
  letter-spacing: 0.14em;
}

.pace-command-title {
  overflow: hidden;
  color: #fff;
  font-size: clamp(15px, 1.5vw, 21px);
  font-weight: 950;
  letter-spacing: -0.02em;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pace-command-subtitle,
.pace-command-card-title small,
.pace-leader-heading small {
  color: var(--pace-muted);
  font-size: 10px;
  font-weight: 800;
}

.pace-command-badges,
.pace-quality-rail,
.pace-quality-legend {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.pace-command-metrics {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 6px;
}

.pace-command-metric,
.pace-command-card {
  min-width: 0;
  border: 1px solid rgba(129, 158, 194, 0.2);
  border-radius: 9px;
  background: rgba(255, 255, 255, 0.035);
}

.pace-command-metric {
  display: grid;
  gap: 2px;
  min-height: 62px;
  padding: 8px;
  align-content: center;
}

.pace-command-metric > span {
  color: var(--pace-muted);
  font-size: 9px;
  font-weight: 900;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.pace-command-metric > strong {
  overflow: hidden;
  color: #fff;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 16px;
  font-variant-numeric: tabular-nums;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pace-command-metric > small {
  overflow: hidden;
  color: #92a8be;
  font-size: 9px;
  font-weight: 750;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pace-command-visual-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(360px, 0.8fr);
  gap: 8px;
}

.pace-command-card {
  padding: 8px;
}

.pace-command-card-title strong,
.pace-leader-heading strong {
  color: #fff;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.035em;
  text-transform: uppercase;
}

.pace-filter-select {
  width: 154px;
  height: 26px;
  border: 1px solid rgba(123, 157, 194, 0.42);
  border-radius: 7px;
  background: #0a111d;
  color: #e8f3ff;
  font-size: 10px;
  font-weight: 900;
}

.pace-filter-select:focus-visible {
  outline: 2px solid #8ed8ff;
  outline-offset: 2px;
}

.pace-heatmap {
  min-height: 160px;
  margin-top: 6px;
  overflow-x: auto;
}

.pace-heatmap svg {
  display: block;
  width: 100%;
  min-width: 620px;
  height: auto;
  max-height: 590px;
}


.pace-svg-axis {
  stroke: rgba(219, 234, 254, 0.42);
  stroke-width: 1;
}

.pace-svg-grid {
  stroke: var(--pace-grid);
  stroke-width: 1;
}

.pace-svg-side,
.pace-svg-strike,
.pace-svg-value,
.pace-svg-status {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
}

.pace-svg-side {
  fill: #a9bbce;
  font-size: 10px;
  font-weight: 900;
  letter-spacing: 0.08em;
}

.pace-svg-call { fill: var(--pace-call); }
.pace-svg-put { fill: var(--pace-put); }

.pace-svg-strike {
  fill: #f8fbff;
  font-size: 10px;
  font-weight: 950;
}

.pace-svg-value {
  fill: #dcecff;
  font-size: 9px;
  font-weight: 850;
}

.pace-svg-value-call { fill: #a8f5d1; }
.pace-svg-value-put { fill: #ffc0ca; }

.pace-svg-bar {
  vector-effect: non-scaling-stroke;
  stroke-width: 1;
}

.pace-svg-call .pace-svg-bar-live {
  fill: rgba(56, 217, 150, 0.78);
  stroke: #7bf0b8;
}

.pace-svg-put .pace-svg-bar-live {
  fill: rgba(255, 112, 133, 0.8);
  stroke: #ff9aaa;
}

.pace-svg-bar-corrected {
  fill: rgba(255, 200, 87, 0.72);
  stroke: #ffe09a;
}

.pace-svg-bar-legacy {
  fill: rgba(184, 164, 217, 0.6);
  stroke: #d7c5f2;
}

.pace-svg-status {
  font-size: 9px;
  font-weight: 900;
}

.pace-svg-status-live { fill: var(--pace-live); }
.pace-svg-status-corrected { fill: var(--pace-corrected); }
.pace-svg-status-warmup { fill: var(--pace-warmup); }
.pace-svg-status-gap { fill: var(--pace-gap); }
.pace-svg-status-reset { fill: var(--pace-reset); }
.pace-svg-status-stale { fill: var(--pace-stale); }
.pace-svg-status-invalid { fill: var(--pace-invalid); }
.pace-svg-status-legacy { fill: var(--pace-legacy); }
.pace-svg-status-unknown { fill: var(--pace-unknown); }

.pace-leader-columns {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 7px;
  margin-top: 7px;
}

.pace-leader-column {
  min-width: 0;
  padding: 7px;
  border: 1px solid rgba(129, 158, 194, 0.18);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.025);
}

.pace-leader-call { box-shadow: inset 3px 0 0 rgba(56, 217, 150, 0.82); }
.pace-leader-put { box-shadow: inset 3px 0 0 rgba(255, 112, 133, 0.82); }

.pace-leader-column ol {
  display: grid;
  gap: 5px;
  margin: 7px 0 0;
  padding: 0;
  list-style: none;
}

.pace-leader-item {
  display: grid;
  grid-template-columns: 28px minmax(45px, 0.7fr) minmax(58px, 1fr) minmax(50px, 0.8fr) auto;
  gap: 5px;
  align-items: center;
  min-height: 30px;
  padding: 5px 6px;
  border: 1px solid rgba(139, 179, 219, 0.16);
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.04);
}

.pace-leader-rank,
.pace-leader-strike,
.pace-leader-value,
.pace-leader-change {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
}

.pace-leader-rank {
  color: #90a6bd;
  font-size: 9px;
  font-weight: 900;
}

.pace-leader-strike {
  color: #fff;
  font-size: 12px;
}

.pace-leader-value {
  color: #e8f5ff;
  font-size: 11px;
  font-weight: 950;
}

.pace-leader-change {
  color: #a7bad0;
  font-size: 9px;
  font-weight: 850;
}

.pace-leader-live-mark {
  padding: 2px 5px;
  border: 1px solid rgba(33, 199, 168, 0.6);
  border-radius: 999px;
  background: rgba(15, 114, 96, 0.56);
  color: #eafffa;
  font-size: 8px;
  font-weight: 950;
}

.pace-leader-empty,
.pace-leader-locked {
  padding: 10px 7px;
  border-radius: 7px;
  color: #a4b4c4;
  font-size: 10px;
  font-weight: 850;
  text-align: center;
}

.pace-leader-locked {
  border: 1px dashed rgba(241, 92, 218, 0.5);
  background: rgba(125, 23, 109, 0.18);
  color: #ffd8f7;
}

.pace-quality-rail {
  padding-top: 2px;
}

.pace-quality-chip i,
.pace-legend-symbol {
  width: 11px;
  font-style: normal;
  text-align: center;
}

.pace-quality-chip-stale {
  border-color: rgba(130, 145, 163, 0.68);
  background:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.1) 0 2px, transparent 2px 5px),
    #485462;
}

.pace-issue-rail {
  display: flex;
  align-items: center;
  gap: 5px;
  min-height: 24px;
  padding: 5px 7px;
  overflow-x: auto;
  border-top: 1px solid rgba(137, 167, 202, 0.16);
  color: #b7c7d8;
  font-size: 9px;
  font-weight: 850;
  white-space: nowrap;
}

.pace-issue-rail > strong {
  color: #ffd2f7;
  letter-spacing: 0.07em;
}

.pace-issue-chip {
  padding: 3px 6px;
  border: 1px solid rgba(241, 92, 218, 0.32);
  border-radius: 999px;
  background: rgba(125, 23, 109, 0.17);
  color: #ffdff9;
}

.pace-no-issues {
  color: #8de7cf;
}

.pace-empty-state {
  margin: 26px 0;
  color: #879bb0;
  font-size: 11px;
  font-weight: 850;
  text-align: center;
}

td.pace-quality-live {
  box-shadow: inset 0 0 0 1px rgba(33, 199, 168, 0.18);
}

td.pace-quality-corrected {
  background:
    repeating-linear-gradient(135deg, rgba(255, 200, 87, 0.09) 0 5px, transparent 5px 10px),
    var(--cell-text-mask-bg) !important;
  box-shadow: inset 3px 0 0 var(--pace-corrected);
}

td.pace-quality-warmup,
td.pace-quality-unknown {
  background:
    radial-gradient(circle at 8px 8px, rgba(145, 164, 183, 0.18) 0 2px, transparent 2px),
    var(--cell-text-mask-bg) !important;
  background-size: 16px 16px, auto !important;
  box-shadow: inset 3px 0 0 var(--pace-warmup);
}

td.pace-quality-gap {
  background:
    repeating-linear-gradient(135deg, rgba(255, 176, 32, 0.13) 0 5px, transparent 5px 10px),
    var(--cell-text-mask-bg) !important;
  box-shadow: inset 3px 0 0 var(--pace-gap);
}

td.pace-quality-reset {
  background:
    repeating-linear-gradient(90deg, rgba(139, 156, 255, 0.11) 0 4px, transparent 4px 9px),
    var(--cell-text-mask-bg) !important;
  box-shadow: inset 3px 0 0 var(--pace-reset);
}

td.pace-quality-stale {
  /* The rail IS the stale signal. filter: saturate(0.5) drained the colour out of the number as
     well, which is the same fault as an opacity fade wearing a different name (2026-08-13). */
  box-shadow: inset 3px 0 0 var(--pace-stale);
}

td.pace-quality-invalid {
  background:
    repeating-linear-gradient(45deg, rgba(241, 92, 218, 0.14) 0 4px, transparent 4px 8px),
    var(--cell-text-mask-bg) !important;
  box-shadow: inset 3px 0 0 var(--pace-invalid);
}

td.pace-quality-legacy {
  box-shadow: inset 3px 0 0 var(--pace-legacy);
}

td.pace-command-untrusted .pace-track {
  /* Was opacity 0.18 — invisible. Hatched instead: the track is still there and still says the
     value under it is untrusted (2026-08-13, USER: "remove this blur layer"). */
  background-image: repeating-linear-gradient(135deg,
    rgba(255, 255, 255, 0.16) 0 3px, transparent 3px 7px);
}

td.pace-command-untrusted .pace-value {
  color: #d8e2ec;
  letter-spacing: 0.02em;
}

td.pace-command-leader {
  outline: 2px solid rgba(33, 199, 168, 0.62);
  outline-offset: -3px;
}

td.pace-command-leader .pace-value {
  color: #b8ffeb;
  font-weight: 950;
}

.pace-flow-filter-note {
  margin: 6px 0 0;
  padding: 7px;
  border: 1px dashed rgba(145, 164, 183, 0.38);
  border-radius: 7px;
  color: #98aabd;
  font-size: 10px;
  font-weight: 850;
  text-align: center;
}

.pace-flow-filtered-out {
  display: none !important;
}

@media (max-width: 1160px) {
  .pace-command-metrics {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .pace-command-visual-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 760px) {
  .pace-command-center {
    padding: 8px;
  }

  .pace-command-header {
    align-items: flex-start;
    flex-direction: column;
  }

  .pace-command-badges {
    width: 100%;
  }

  .pace-command-metrics {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .pace-leader-columns {
    grid-template-columns: 1fr;
  }

  .pace-mode-badge {
    margin-left: 0;
  }
}

@media (max-width: 480px) {
  .pace-command-metrics {
    grid-template-columns: 1fr;
  }

  .pace-filter-select {
    width: 132px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pace-command-center *,
  .pace-mode-badge,
  .pace-status-badge {
    animation: none !important;
    scroll-behavior: auto !important;
    transition: none !important;
  }
}

@media (forced-colors: active) {
  .pace-command-center,
  .pace-command-card,
  .pace-command-metric,
  .pace-status-badge,
  .pace-mode-badge,
  .pace-quality-chip,
  .pace-legend-item,
  td[class*="pace-quality-"] {
    border: 1px solid CanvasText;
    background: Canvas;
    color: CanvasText;
    forced-color-adjust: auto;
  }

  td.pace-command-leader {
    outline: 3px solid Highlight;
  }
}

/* End marker used by asset-integrity tests. */
.pace-command-center-complete { display: none; }


/* Final audited pace states that are injected into the legacy React table. */
.strike-flow-locked {
  margin: 4px 0;
  padding: 10px 12px;
  border: 1px dashed rgba(241, 92, 218, 0.58);
  border-radius: 8px;
  background:
    repeating-linear-gradient(135deg, rgba(241, 92, 218, 0.08) 0 5px, transparent 5px 10px),
    rgba(31, 17, 39, 0.82);
  color: #ffd9f7;
  font-size: 11px;
  font-weight: 900;
  text-align: center;
}

.pace-quality-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 16px;
  margin-left: 3px;
  padding: 0 3px;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-size: 8px;
  font-weight: 950;
  line-height: 1;
  letter-spacing: 0.02em;
  vertical-align: 1px;
}

.pace-quality-mark-live { color: var(--pace-live); }
.pace-quality-mark-corrected { color: var(--pace-corrected); }
.pace-quality-mark-warmup { color: var(--pace-warmup); }
.pace-quality-mark-gap { color: var(--pace-gap); }
.pace-quality-mark-reset { color: var(--pace-reset); }
.pace-quality-mark-stale { color: var(--pace-stale); }
.pace-quality-mark-invalid { color: var(--pace-invalid); }
.pace-quality-mark-legacy { color: var(--pace-legacy); }
.pace-quality-mark-unknown { color: var(--pace-unknown); }

.pace-state-warmup .pace-track,
.pace-state-gap .pace-track,
.pace-state-reset .pace-track,
.pace-state-stale .pace-track,
.pace-state-invalid .pace-track,
.pace-state-legacy .pace-track,
.pace-state-unknown .pace-track {
  /* Was opacity 0.2 — a track that faint is indistinguishable from an empty one. The track keeps
     its shape and is hatched instead, so "no trustworthy value here" stays visible (2026-08-13). */
  background-image: repeating-linear-gradient(135deg,
    rgba(255, 255, 255, 0.16) 0 3px, transparent 3px 7px);
}

.pace-state-invalid .pace-value,
.pace-state-gap .pace-value {
  font-weight: 950;
}

.pace-plotly-heatmap {
  width: 100%;
  min-width: 0;
  min-height: 220px;
  margin-top: 4px;
  border-radius: 7px;
  outline: none;
}

.pace-plotly-heatmap .plot-container,
.pace-plotly-heatmap .svg-container,
.pace-plotly-heatmap .main-svg {
  border-radius: 7px;
}

.pace-plotly-heatmap .modebar {
  top: 4px !important;
  right: 4px !important;
  border: 1px solid rgba(145, 164, 183, 0.24);
  border-radius: 6px;
  background: rgba(9, 13, 22, 0.9) !important;
}

.pace-plotly-heatmap .modebar-btn path {
  fill: #c9d8e8 !important;
}

.pace-plotly-heatmap .modebar-btn:hover path,
.pace-plotly-heatmap .modebar-btn.active path {
  fill: #75ddca !important;
}

.pace-plotly-unavailable {
  display: grid;
  gap: 6px;
  min-height: 180px;
  margin-top: 6px;
  padding: 12px;
  border: 1px dashed rgba(255, 176, 32, 0.55);
  border-radius: 8px;
  background:
    repeating-linear-gradient(135deg, rgba(255, 176, 32, 0.06) 0 5px, transparent 5px 10px),
    rgba(32, 25, 13, 0.5);
  color: #fff4d8;
}

.pace-plotly-unavailable > strong {
  font-size: 12px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.pace-plotly-unavailable > p {
  margin: 0;
  color: #d8c8a3;
  font-size: 10px;
  line-height: 1.45;
}

.pace-plotly-audit-wrap {
  max-height: 320px;
  overflow: auto;
  border: 1px solid rgba(145, 164, 183, 0.2);
  border-radius: 7px;
}

.pace-plotly-audit-table {
  width: 100%;
  border-collapse: collapse;
  color: #e8f3ff;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 10px;
  font-variant-numeric: tabular-nums;
}

.pace-plotly-audit-table caption {
  padding: 7px;
  color: #a8bacd;
  font-weight: 900;
  text-align: left;
  text-transform: uppercase;
}

.pace-plotly-audit-table th,
.pace-plotly-audit-table td {
  padding: 6px 8px;
  border-top: 1px solid rgba(145, 164, 183, 0.15);
  text-align: right;
}

.pace-plotly-audit-table th:first-child {
  text-align: left;
}

@media (max-width: 760px) {
  .pace-plotly-heatmap {
    min-height: 260px;
  }
}

@media (forced-colors: active) {
  .strike-flow-locked,
  .pace-quality-mark,
  .pace-plotly-unavailable,
  .pace-plotly-audit-wrap {
    border: 1px solid CanvasText;
    background: Canvas;
    color: CanvasText;
    forced-color-adjust: auto;
  }
}

/* Accessible pace data table kept available even when the Plotly chart renders.
   Collapsed by default to avoid clutter; keyboard- and screen-reader-reachable. */
.pace-plotly-heatmap-wrap { display: flex; flex-direction: column; gap: 6px; }
.pace-plotly-audit-details > summary {
  cursor: pointer;
  font-size: 11px;
  color: #91a4b7;
  padding: 2px 0;
  user-select: none;
}
.pace-plotly-audit-details[open] > summary { color: #dcecff; }
.pace-plotly-audit-details .pace-plotly-audit-wrap { margin-top: 4px; }


/* Phase-1 completion states: comparative visualizations are locked unless coverage is complete. */
.pace-heatmap-card.pace-audit-only {
  border-color: rgba(255, 176, 32, 0.58);
  background:
    repeating-linear-gradient(135deg, rgba(255, 176, 32, 0.035) 0 6px, transparent 6px 12px),
    rgba(255, 255, 255, 0.025);
}

.pace-audit-watermark {
  margin-top: 7px;
  padding: 6px 9px;
  border: 1px dashed rgba(255, 176, 32, 0.64);
  border-radius: 7px;
  background: rgba(88, 54, 0, 0.38);
  color: #ffe1a6;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.055em;
  text-align: center;
  text-transform: uppercase;
}

.pace-plotly-heatmap.pace-plotly-audit-only {
  border: 1px dashed rgba(255, 176, 32, 0.48);
  background:
    repeating-linear-gradient(135deg, rgba(255, 176, 32, 0.025) 0 8px, transparent 8px 16px),
    rgba(9, 13, 22, 0.34);
}

.pace-filter-select:disabled {
  cursor: not-allowed;
  opacity: 0.72;
}

@media (forced-colors: active) {
  .pace-heatmap-card.pace-audit-only,
  .pace-audit-watermark,
  .pace-plotly-heatmap.pace-plotly-audit-only {
    border: 1px solid CanvasText;
    background: Canvas;
    color: CanvasText;
    forced-color-adjust: auto;
  }
}


/* Strike Liquidity Heatmap — integrated option-chain layer (dark theme, subtle, text-first). */

.lh-canvas {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;              /* behind the table text; the canvas paints low-alpha fills */
  pointer-events: none;    /* the table stays fully interactive; hover is handled on the host */
}

.lh-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font: 11px system-ui, sans-serif;
  color: #9fb2c8;
  /* Stay visible while scrolling the (tall) option chain — pin to the top like the table
     header, instead of scrolling off as soon as strike rows fill the viewport. The chain's
     sticky thead is offset just below this by --lh-controls-h (kept in sync from the JS, and
     0 when the heatmap is off) so the column headers are never hidden behind the pinned menu.
     Flush at top:0 (no top margin) + opaque background so rows don't bleed through underneath. */
  position: sticky;
  top: 0;
  z-index: 40;                 /* above the chain's sticky thead (z-index 30/31) */
  background: #080a10;         /* matches the chain-table background */
  /* No bottom MARGIN: offsetHeight (→ --lh-controls-h) excludes margin, so any bottom margin would
     open a sliver gap between the pinned menu and the pinned thead. Fold the spacing into padding. */
  margin: 0;
  padding: 5px 0 6px;
}

.lh-title { color: #cfe0f4; font-weight: 600; cursor: help; }

.lh-group { display: inline-flex; gap: 2px; border: 1px solid #243042; border-radius: 6px; padding: 1px; }

.lh-controls button {
  background: rgba(11, 14, 20, 0.88);
  color: #9fb2c8;
  border: 0;
  border-radius: 5px;
  font: 11px system-ui, sans-serif;
  padding: 3px 8px;
  cursor: pointer;
}

.lh-controls button.lh-on { background: #22364f; color: #cfe6ff; }

/* Fixed slot (UI-stability): LIVE/GAP/STALE/DEGRADED all fit without reflowing the row. */
.lh-badge { font-weight: 700; padding: 2px 6px; border-radius: 5px; display: inline-block; min-width: 9ch; text-align: center; }
.lh-badge-live { color: #35c48c; }
.lh-badge-gap { color: #e8c752; }
.lh-badge-stale { color: #ff8a2a; }
.lh-badge-degraded { color: #ff6e50; }

/* Wall-cluster signal: a loud, compact banner. Hidden (via [hidden]) until a confirmed directional
   wall fires; colour encodes side. The one-shot flash is keyed to a NEW cluster identity only. */
.lh-wall[hidden] { display: none; }
.lh-wall { font-weight: 700; font-size: 11px; letter-spacing: 0.3px; padding: 2px 8px;
  border-radius: 5px; display: inline-block; cursor: help; }
.lh-wall-res { color: #2a0f06; background: #d85a30; }
.lh-wall-sup { color: #04241b; background: #1d9e75; }
.lh-wall-flash { animation: lh-wall-pulse 900ms ease-out 1; }
@keyframes lh-wall-pulse {
  0% { box-shadow: 0 0 0 0 rgba(216,90,48,0.8); }
  100% { box-shadow: 0 0 0 10px rgba(216,90,48,0); }
}
/* The support slot pulses in ITS OWN colour: the shared orange pulse read as a resistance alert
   flashing on the green banner. Sides are independent everywhere, including the announcement. */
.lh-wall-sup.lh-wall-flash { animation: lh-wall-pulse-sup 900ms ease-out 1; }
@keyframes lh-wall-pulse-sup {
  0% { box-shadow: 0 0 0 0 rgba(29,158,117,0.8); }
  100% { box-shadow: 0 0 0 10px rgba(29,158,117,0); }
}
/* Two slots sit side by side; keep them from colliding when both fire. */
.lh-wall + .lh-wall { margin-left: 6px; }

/* Fixed slot (UI-stability): sized for the longest state ('session history loading…') so
   backfill state changes never reflow the controls row. */
.lh-history { color: #7d90a8; display: inline-block; min-width: 24ch; }

.lh-legend { color: #7d90a8; }
.lh-legend .lh-dot-buy, .lh-legend .lh-dot-sell {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
}
.lh-legend .lh-dot-buy { background: rgba(53, 196, 140, 0.9); }
.lh-legend .lh-dot-sell { background: rgba(255, 110, 80, 0.9); }

.lh-tooltip {
  position: fixed;
  z-index: 99999;
  max-width: 330px;
  background: rgba(11, 14, 20, 0.96);
  border: 1px solid #243042;
  border-radius: 8px;
  padding: 8px 10px;
  font: 11px/1.5 system-ui, sans-serif;
  color: #cfe0f4;
  pointer-events: none;
}

.lh-copy { color: #e8c752; font-weight: 600; }
.lh-copy-detail { color: #9fb2c8; }

.lh-panel {
  flex-basis: 100%;
  font: 11px/1.5 system-ui, sans-serif;
  color: #9fb2c8;
  border-top: 1px dashed #243042;
  padding-top: 4px;
  /* Fixed height (UI-stability): hover interpretation must NEVER resize the panel and
     shove the chain table up/down. Reserves three lines; longer copy clips. */
  height: 54px;
  overflow: hidden;
}

/* Fixed widths (UI-stability): Hide<->Show / Expanded<->Compact label swaps must not
   shift the neighboring controls. */
.lh-controls button[data-lh="off"] { min-width: 5ch; }
.lh-controls button[data-lh="expand"] { min-width: 9ch; }

tr.lh-spot-row td { box-shadow: inset 0 0 0 1px rgba(120, 220, 255, 0.35); }

/* Overlay toggles: hide the chain's existing badge layers without touching their code. */
body.lh-hide-sr .strike-sr-corner,
body.lh-hide-sr .strike-sr-gamma { display: none !important; }
body.lh-hide-gex .gex-strength-fill,
body.lh-hide-gex .gex-strength-axis,
body.lh-hide-gex .strike-gex-content { display: none !important; }
body.lh-hide-si .lh-si-badge { display: none !important; }

/* Modes that need scores the session projection doesn't carry (session windows). Marked, not
   faded: at opacity 0.35 the button's own label — the thing that says WHICH mode is unavailable —
   was the first casualty. Dashed border + muted ink + not-allowed says it without hiding it. */
.lh-controls button.lh-unavailable {
    border-style: dashed;
    color: #7d90a8;
    cursor: not-allowed;
}

/* States key: compact always-visible note; native title tooltip explains the wall states. */
.lh-states-key { color: #7d90a8; cursor: help; margin-left: 6px; white-space: nowrap; }

/* Cell zoom: clicking a ribbon cell opens BOTH sides of that strike (user requirement:
   "put and call both have to be selected at the same time"). One span, one scale, one +/-
   control for the pair; the span is derived from the selected window (see zoomSpanMs). */
.lh-zoom {
  margin-top: 8px;
  padding: 8px 10px 10px;
  border: 1px solid #2a3446;
  border-radius: 6px;
  background: #0e1420;
}
.lh-zoom-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 8px; }
.lh-zoom-title { font-size: 13px; color: #e6edf8; font-weight: 600; }
.lh-zoom-span { font-size: 11px; color: #7f8ea6; }
.lh-zoom-ctl { margin-left: auto; display: flex; gap: 4px; }
.lh-zoom-btn {
  background: #18202e;
  border: 1px solid #2a3446;
  border-radius: 4px;
  color: #c4d2e6;
  font-size: 13px;
  line-height: 1;
  padding: 3px 8px;
  cursor: pointer;
}
.lh-zoom-btn:hover { background: #223047; color: #fff; }
.lh-zoom-note { font-size: 11px; color: #c8a24a; margin-bottom: 6px; }
.lh-zoom-empty { font-size: 11px; color: #7f8ea6; }
.lh-zoom-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
@media (max-width: 900px) { .lh-zoom-grid2 { grid-template-columns: 1fr; } }
.lh-zoom-side { border: 1px solid #1d2634; border-radius: 5px; padding: 6px; }
.lh-zoom-side-picked { border-color: #3d5a80; }
.lh-zoom-sidehead { font-size: 11px; color: #9fb0c8; margin-bottom: 4px; }
.lh-zoom-side-sum { font-size: 10.5px; color: #8fa0b8; margin-top: 4px; line-height: 1.45; }
.lh-zoom-svg { width: 100%; height: auto; display: block; }
.lh-zoom-gl { stroke: #1d2634; stroke-width: 1; }
.lh-zoom-ax { fill: #6d7b90; font-size: 9px; }
.lh-zoom-under { stroke: #000; stroke-width: 3.5; fill: none; opacity: 0.55; }
.lh-zoom-line { stroke: #e8eef8; stroke-width: 1.6; fill: none; }
/* Bars in the Liquidity Wall idiom: quoted size above the axis (colour comes from the same
   ramp the ribbon stripes use, set inline), traded contracts hanging below it, and a flat
   baseline tick where the side was never quoted. */
.lh-zoom-bar { fill: #3d5a80; }
.lh-zoom-nodata { fill: #3a4353; }
.lh-zoom-axis { stroke: #2a3446; stroke-width: 1; }
.lh-zoom-take-call { fill: #2f9e5e; opacity: 0.9; }
.lh-zoom-take-put { fill: #c0453f; opacity: 0.9; }
.lh-zoom-sum { font-size: 11px; color: #c4d2e6; margin-top: 8px; }
/* Measured break rate: stated where the study measured it, muted so it reads as context
   rather than a prediction. */
.lh-zoom-break, .lh-break { font-size: 10.5px; color: #d0a85c; margin-top: 3px; display: block; }
/* Risk band: colour is reinforcement, the WORD is the carrier. A deliberately separate
   palette from the flow dots so "weak wall" never reads as "sellers here". */
.lh-risk {
  display: inline-block;
  margin-top: 5px;
  padding: 2px 7px;
  border-radius: 3px;
  font-size: 10.5px;
  letter-spacing: 0.02em;
}
.lh-risk-tag { font-size: 10px; letter-spacing: 0.04em; margin-right: 4px; }


/* Gamma Trajectory — integrated option-chain background layer (additive .gt-* selectors only). */

.gt-canvas {
  position: absolute;
  top: 0;
  left: 0;
  /* Stacking contract: z-index 0 keeps this canvas BEHIND the masked strike-cell text, exactly
     like .lh-canvas (also z-index 0). Among the two equal-z overlays, Gamma Trajectory is appended
     to the shared host AFTER the liquidity heatmap (its dispatch runs after LiquidityHeatmap in
     applyUiBatch/the single-event branch), so by DOM paint order the trajectory lines sit ABOVE the
     heatmap ribbons yet still below the cell text. Keep this at 0; do not raise it above the text. */
  z-index: 0;
  pointer-events: none;    /* the table stays fully interactive */
}
