/* ============================================================================
 * python.css — styles for the "Python for DSA" workspace.
 * Consumes the existing design tokens (main.css) so it inherits dark/light,
 * radii, shadows and motion. Loaded after components.css.
 * ==========================================================================*/

/* ---- topbar workspace switch (mirrors the sidebar set-toggle) ---- */
.ws-switch { display: inline-flex; gap: 4px; margin-left: 14px; background: var(--bg-2); border: 1px solid var(--border); border-radius: 999px; padding: 3px; }
.ws-btn { background: transparent; border: none; color: var(--muted); font-size: 12.5px; font-weight: 700; padding: 5px 13px; border-radius: 999px; cursor: pointer; white-space: nowrap; }
.ws-btn:hover { color: var(--text); }
.ws-btn.active { background: var(--brand); color: #06111f; box-shadow: 0 0 12px var(--brand-glow); }
@media (max-width: 720px) { .ws-btn { padding: 5px 9px; font-size: 11.5px; } .brand-text { display: none; } }

/* When in the Python workspace, hide DSA-only sidebar widgets + topbar buttons.
   The filter gear (#filterToggle) and chip panel (#filterPanel) are deliberately
   NOT hidden here: they drive Practice filtering in every lab (SQL / PySpark /
   NumPy / Pandas) through the shared LABFILTERS model, and updateFilterContext()
   in app.js already shows the gear only in Practice mode (Learn hides it via the
   `hidden` attribute + a collapsed panel). The rest are genuinely DSA-only. */
body[data-ws="python"] .progress-box,
body[data-ws="python"] #gridBtn,
body[data-ws="python"] #dashBtn { display: none !important; }
/* The shared "Categories" tools bar (expand/collapse-all) is used by the SQL,
   PySpark, NumPy and Pandas workspaces too. Hide it only for Python-Learn,
   which renders its own .py-tools bar with an equivalent toggle. */
body[data-ws="python"][data-stack="python"] .nav-tools { display: none !important; }
body:not([data-ws="python"]) #pyProgress { display: none !important; }

/* ---- python sidebar progress + nav ---- */
.py-progress { padding: 12px 16px; border-bottom: 1px solid var(--border-soft); }
.py-progress .progress-head { display: flex; justify-content: space-between; font-size: 12.5px; font-weight: 700; color: var(--text-2); margin-bottom: 7px; }
.py-progress .progress-foot { margin-top: 6px; font-size: 11.5px; }
.py-home { width: calc(100% - 20px); margin: 10px; text-align: left; background: var(--bg-2); border: 1px solid var(--border); color: var(--text-2); font-weight: 700; font-size: 13px; padding: 9px 12px; border-radius: var(--radius-sm); cursor: pointer; }
.py-home:hover { border-color: var(--brand); color: var(--text); }
.py-home.active { background: var(--brand-glow); border-color: var(--brand); color: var(--text); }
.py-nav-head { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .7px; color: var(--muted); padding: 12px 10px 5px; }
.py-tools { display: flex; align-items: center; gap: 4px; padding: 6px 14px 4px; }
.py-tools .nav-tools-label { flex: 1; font-size: 10.5px; text-transform: uppercase; letter-spacing: .7px; color: var(--muted); font-weight: 700; }
.py-tools .nav-tool-icon:disabled { opacity: .4; cursor: default; }

/* status glyph colors (shared with cards) */
.st-not-started { color: var(--muted); }
.st-learning { color: var(--amber); }
.st-learned { color: var(--green); }
.st-mastered { color: var(--brand-2); }

/* ---- landing ---- */
.py-hero { padding: 30px 34px 6px; }
.py-hero-title { font-size: 30px; font-weight: 800; letter-spacing: -.5px; margin: 0; }
.py-hero-sub { color: var(--text-2); font-size: 15px; max-width: 720px; margin: 8px 0 0; line-height: 1.5; }

.py-readiness { margin: 20px 34px 0; background: var(--bg-1); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px 18px; box-shadow: inset 3px 0 0 var(--stripe-srs); }
.pyr-head { display: flex; justify-content: space-between; align-items: baseline; font-weight: 700; margin-bottom: 9px; }
.pyr-pct { font-size: 22px; font-weight: 800; color: var(--success-2); }
.pyr-foot { margin-top: 8px; font-size: 12.5px; }

.py-continue { margin: 16px 34px 0; background: color-mix(in srgb, var(--success) 10%, var(--bg-1)); border: 1px solid color-mix(in srgb, var(--success) 35%, var(--border)); border-radius: var(--radius); padding: 16px 18px; display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 6px 14px; }
.pc-label { font-size: 11.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .6px; color: var(--success-2); grid-column: 1 / -1; }
.pc-title { font-size: 17px; font-weight: 750; }
.pc-meta { font-size: 12.5px; }
.py-continue .cta-next { grid-row: 2 / 4; grid-column: 2; }

.py-h2 { font-size: 15px; font-weight: 800; text-transform: uppercase; letter-spacing: .6px; color: var(--text-2); margin: 0 0 12px; }
.py-learn { margin: 28px 34px 0; }
.py-group { margin-bottom: 18px; }
.py-group-head { font-size: 13px; font-weight: 800; color: var(--text); margin-bottom: 8px; }
.py-topic-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 8px; }
.py-topic-card { display: flex; align-items: center; gap: 9px; text-align: left; background: var(--bg-1); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 11px 13px; font-size: 13.5px; font-weight: 650; color: var(--text); cursor: pointer; }
.py-topic-card.live:hover { border-color: var(--brand); transform: translateY(-1px); box-shadow: var(--lift); }
.py-topic-card.soon { opacity: .55; cursor: default; justify-content: space-between; }
.ptc-glyph { font-size: 15px; }
.ptc-title { flex: 1; }
.ptc-min { font-size: 11.5px; }
.ptc-soon { font-size: 10.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .5px; color: var(--muted); border: 1px solid var(--border); border-radius: 999px; padding: 1px 7px; }

/* ---- toolkit ---- */
.py-toolkit { margin: 30px 34px 40px; background: var(--bg-1); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px 18px; box-shadow: inset 3px 0 0 var(--stripe-complexity); }
.tk-tabs { display: flex; gap: 6px; margin-bottom: 12px; flex-wrap: wrap; }
.tk-tab { background: var(--bg-2); border: 1px solid var(--border); color: var(--text-2); font-size: 12.5px; font-weight: 700; padding: 6px 13px; border-radius: 999px; cursor: pointer; }
.tk-tab:hover { color: var(--text); }
.tk-tab.on { background: var(--brand); border-color: var(--brand); color: #06111f; }
.tk-pick { display: grid; grid-template-columns: 1fr auto 1.2fr auto; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px dashed var(--border-soft); font-size: 13px; }
.tk-pick:last-child { border-bottom: none; }
.tk-need { color: var(--text); }
.tk-arrow { color: var(--brand-2); font-weight: 800; }
.tk-tool { color: var(--text-2); }
.tk-link { background: none; border: 1px solid var(--border); border-radius: 7px; color: var(--brand-2); font-size: 11.5px; font-weight: 700; padding: 3px 9px; cursor: pointer; }
.tk-link:hover { border-color: var(--brand); }
.tk-cheat { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 8px; }
.tk-cheat-row { display: flex; align-items: center; gap: 8px; background: var(--bg-2); border: 1px solid var(--border-soft); border-radius: var(--radius-sm); padding: 8px 12px; font-size: 13px; }
.tk-cheat-row span:first-child { flex: 1; color: var(--text-2); }
.tk-cheat-arrow { color: var(--muted); }
.tk-cheat-row code { color: var(--brand-2); font-family: var(--mono); font-size: 12.5px; }

/* ---- topic page bits ---- */
.py-tagline { font-size: 15px; color: var(--text-2); font-style: italic; margin: 10px 0 0; line-height: 1.5; }
.py-para { font-size: 14.5px; line-height: 1.65; color: var(--text); margin: 0 0 10px; }
.py-para:last-child { margin-bottom: 0; }
.py-para.muted { color: var(--muted); font-size: 13px; }
.py-rich { font-size: 14.5px; line-height: 1.65; color: var(--text); }
.py-rich p { margin: 0 0 10px; }
.py-rich p:last-child { margin-bottom: 0; }
.why-pre, .py-rich .why-pre { background: var(--bg-2); border: 1px solid var(--border-soft); border-radius: var(--radius-sm); padding: 12px 14px; font-family: var(--mono); font-size: 12.5px; line-height: 1.6; color: var(--text-2); overflow-x: auto; white-space: pre; margin: 8px 0; }
.dsa-dot { color: var(--border); font-size: 9px; }
.dsa-dot.on { color: var(--brand-2); }
.status-btn.py-st-not-started.on { background: var(--bg-3); }
.status-btn.py-st-learning.on { background: color-mix(in srgb, var(--amber) 22%, var(--bg-2)); border-color: var(--amber); color: var(--text); }
.status-btn.py-st-learned.on { background: color-mix(in srgb, var(--green) 20%, var(--bg-2)); border-color: var(--green); color: var(--text); }
.status-btn.py-st-mastered.on { background: color-mix(in srgb, var(--brand-2) 20%, var(--bg-2)); border-color: var(--brand-2); color: var(--text); }

/* recognize */
.recognize-list { display: grid; gap: 10px; }
.recognize-row { background: var(--bg-2); border: 1px solid var(--border-soft); border-radius: var(--radius-sm); padding: 11px 14px; }
.rec-q { font-weight: 700; color: var(--text); font-size: 14px; }
.rec-arrow { color: var(--stripe-recognize); font-size: 11.5px; font-weight: 700; margin: 3px 0; }
.rec-think { color: var(--brand-2); font-weight: 650; font-size: 13.5px; }

/* dsa connection chips */
.prob-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.prob-chip { font-weight: 650; }

/* traps */
.trap { margin-bottom: 18px; }
.trap:last-child { margin-bottom: 0; }
.trap-bad, .trap-good { margin-bottom: 8px; }
.trap-tag { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .5px; margin-bottom: 5px; }
.trap-tag-bad { color: var(--red); }
.trap-tag-good { color: var(--green); }
.trap-why { font-size: 13.5px; line-height: 1.6; color: var(--text-2); margin: 6px 0 0; }

/* complexity table — operation + complexity size to content; the explanation
   column absorbs the remaining width so notes can be full sentences. */
.cx-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.cx-table th { text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .5px; color: var(--muted); padding: 7px 12px; border-bottom: 1px solid var(--border); }
.cx-table td { padding: 9px 12px; border-bottom: 1px solid var(--border-soft); vertical-align: top; }
.cx-table th:nth-child(1), .cx-table td:nth-child(1) { white-space: nowrap; }
.cx-table th:nth-child(2), .cx-table td:nth-child(2) { white-space: nowrap; }
.cx-table th:last-child, .cx-table td:last-child { width: 100%; }
.cx-table tr:last-child td { border-bottom: none; }
.cx-table tbody tr:hover { background: var(--bg-2); }
.cx-table code { font-family: var(--mono); font-size: 12.5px; color: var(--text); background: var(--bg-2); border-radius: 5px; padding: 2px 6px; }
.cx-table td.cx-note { color: var(--text-2); line-height: 1.5; font-size: 13px; }
.cx-o { font-family: var(--mono); font-weight: 700; color: var(--amber); white-space: nowrap; }

/* challenge */
.challenge-actions { display: flex; gap: 8px; margin-top: 10px; }
.challenge-sol { margin-top: 10px; }

/* ---- visualizations ---- */
.viz { margin: 14px 0 4px; background: var(--bg-2); border: 1px solid var(--border-soft); border-radius: var(--radius-sm); padding: 16px; }
.viz-name { font-family: var(--mono); font-size: 13px; color: var(--text-2); margin-bottom: 10px; }
.viz-hint { font-size: 12px; color: var(--muted); margin-top: 10px; }
.viz-caption { font-size: 13px; color: var(--text-2); line-height: 1.55; margin: 10px 0 0; }
.viz-controls { display: flex; gap: 8px; margin-top: 12px; }
.viz-btn { background: var(--brand); border: 1px solid var(--brand); color: #06111f; font-weight: 700; font-size: 12.5px; padding: 6px 14px; border-radius: 8px; cursor: pointer; }
.viz-btn.ghost { background: var(--bg-3); border-color: var(--border); color: var(--text-2); }
.viz-btn:hover { filter: brightness(1.08); }

/* execution-order diagram: written order vs run order (SQL vs PySpark) */
.viz-eo .eo-svg { display: block; width: 100%; height: auto; }
.viz-eo .eo-svg + .eo-svg { margin-top: 6px; padding-top: 10px; border-top: 1px dashed var(--border-soft); }
.eo-sql   { --eo: #0ca678; }   /* SQL teal   */
.eo-spark { --eo: #f76707; }   /* PySpark orange */
.eo-col-h { fill: var(--muted); font-family: inherit; font-size: 12px; font-weight: 800; letter-spacing: .3px; }
.eo-wire { fill: none; stroke: var(--border); stroke-width: 2; transition: stroke .15s ease, stroke-width .15s ease, opacity .15s ease; }
.eo-wire.on { stroke: var(--eo); stroke-width: 3.4; }
.eo-wire.dim { opacity: .16; }
.eo-chip-g { cursor: pointer; transition: opacity .15s ease; }
.eo-chip-g:focus { outline: none; }
.eo-chip-g.dim { opacity: .38; }
.eo-chip { fill: var(--bg-1); stroke: var(--border); stroke-width: 1.2; transition: fill .15s ease, stroke .15s ease; }
.eo-chip-g.on .eo-chip, .eo-chip-g:focus-visible .eo-chip { stroke: var(--eo); stroke-width: 2; fill: color-mix(in srgb, var(--eo) 15%, var(--bg-1)); }
.eo-chip-label { fill: var(--text-2); font-family: var(--mono); font-size: 11px; }
.eo-chip-g.on .eo-chip-label { fill: var(--text); }
.eo-badge { fill: var(--bg-3); stroke: var(--border); stroke-width: 1; transition: fill .15s ease, stroke .15s ease; }
.eo-chip-g.on .eo-badge { fill: var(--eo); stroke: var(--eo); }
.eo-badge-t { fill: var(--text-2); font-family: inherit; font-size: 11px; font-weight: 800; text-anchor: middle; }
.eo-chip-g.on .eo-badge-t { fill: #06111f; }

/* Catalyst: the plan you wrote vs the plan Spark runs */
.viz-cat .cat-svg { display: block; width: 100%; height: auto; }
.viz-cat .cat-svg + .cat-svg { margin-top: 6px; padding-top: 10px; border-top: 1px dashed var(--border-soft); }
.cat-write { --cat: var(--muted); }
.cat-run   { --cat: #f76707; }
.cat-col-h { fill: var(--text-2); font-family: inherit; font-size: 12.5px; font-weight: 800; letter-spacing: .3px; }
.cat-col-sub { fill: var(--muted); font-size: 11px; font-weight: 700; }
.cat-row { cursor: pointer; transition: opacity .15s ease; }
.cat-row:focus { outline: none; }
.cat-row.dim { opacity: .34; }
.cat-box { fill: var(--bg-1); stroke: var(--border); stroke-width: 1.2; transition: fill .15s ease, stroke .15s ease; }
.cat-row.changed .cat-box { fill: color-mix(in srgb, var(--cat) 12%, var(--bg-1)); stroke: color-mix(in srgb, var(--cat) 55%, var(--border)); }
.cat-row.wall .cat-box { fill: color-mix(in srgb, #ff6b6b 13%, var(--bg-1)); stroke: color-mix(in srgb, #ff6b6b 55%, var(--border)); }
.cat-row.on .cat-box, .cat-row:focus-visible .cat-box { stroke: var(--cat); stroke-width: 2.2; fill: color-mix(in srgb, var(--cat) 16%, var(--bg-1)); }
.cat-stripe { fill: var(--cat); }
.cat-row.wall .cat-stripe { fill: #ff6b6b; }
.cat-op { fill: var(--text); font-family: var(--mono); font-size: 12px; font-weight: 600; }
.cat-detail { fill: var(--muted); font-family: var(--mono); font-size: 10.5px; text-anchor: end; }
.cat-row.changed .cat-detail { fill: var(--text-2); }

/* Driver vs Executors cluster diagram */
.viz-cr .cr-svg { display: block; width: 100%; height: auto; }
.cr-drv-box { fill: var(--bg-1); stroke: var(--border); stroke-width: 1.4; transition: fill .18s ease, stroke .18s ease; }
.cr-driver.hot .cr-drv-box { stroke: var(--brand); stroke-width: 2.2; }
.cr-driver.warn .cr-drv-box { fill: color-mix(in srgb, #ff6b6b 16%, var(--bg-1)); stroke: #ff6b6b; }
.cr-drv-t { fill: var(--text-2); font-family: inherit; font-size: 12px; font-weight: 700; text-anchor: middle; }
.cr-driver.warn .cr-drv-t { fill: var(--text); }
.cr-exec-box { fill: var(--bg-1); stroke: var(--border); stroke-width: 1.2; transition: stroke .18s ease; }
.cr-exec.hot .cr-exec-box, .cr-exec-box { }
.cr-exec-t { fill: var(--muted); font-family: inherit; font-size: 11px; font-weight: 800; }
.cr-part { fill: var(--bg-3); stroke: var(--border-soft); stroke-width: 1; transition: fill .18s ease, stroke .18s ease; }
.cr-part-t { fill: var(--muted); font-family: var(--mono); font-size: 10px; text-anchor: middle; }
.cr-svg[data-where="executors"] .cr-part, .cr-svg[data-where="shuffle"] .cr-part,
.cr-svg[data-where="storage"] .cr-part, .cr-svg[data-where="udf"] .cr-part { fill: color-mix(in srgb, var(--brand) 26%, var(--bg-3)); stroke: var(--brand); }
.cr-svg[data-where="executors"] .cr-exec-box, .cr-svg[data-where="shuffle"] .cr-exec-box,
.cr-svg[data-where="storage"] .cr-exec-box, .cr-svg[data-where="udf"] .cr-exec-box { stroke: var(--brand); stroke-width: 1.8; }
.cr-store-box { fill: var(--bg-1); stroke: var(--border); stroke-width: 1.2; transition: fill .18s ease, stroke .18s ease; }
.cr-storage.hot .cr-store-box { fill: color-mix(in srgb, #37b24d 16%, var(--bg-1)); stroke: #37b24d; }
.cr-store-t { fill: var(--muted); font-family: inherit; font-size: 11px; font-weight: 700; text-anchor: middle; }
.cr-arrow { opacity: 0; transition: opacity .2s ease; }
.cr-arrow.show { opacity: 1; }
.cr-line { stroke-width: 2; fill: none; }
.cr-arrow.funnel .cr-line, .cr-arrow.funnel .cr-head { stroke: #ff6b6b; fill: #ff6b6b; }
.cr-arrow.shuffle .cr-line, .cr-arrow.shuffle .cr-head { stroke: var(--brand); fill: var(--brand); }
.cr-arrow.store .cr-line, .cr-arrow.store .cr-head { stroke: #37b24d; fill: #37b24d; }
.cr-arrow.udf .cr-line { stroke: #b197fc; stroke-dasharray: 3 3; }
.cr-py { fill: color-mix(in srgb, #b197fc 20%, var(--bg-1)); stroke: #b197fc; stroke-width: 1; }
.cr-py-t { fill: var(--text-2); font-family: var(--mono); font-size: 10px; font-weight: 700; text-anchor: middle; }
.cr-ops { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.cr-op-btn { background: var(--bg-2); border: 1px solid var(--border); color: var(--text-2); font-size: 12px; font-weight: 700;
  font-family: inherit; padding: 5px 11px; border-radius: 999px; cursor: pointer; }
.cr-op-btn:hover { color: var(--text); border-color: var(--brand); }
.cr-op-btn.active { color: #06111f; background: var(--brand); border-color: transparent; }
.cr-op-btn.warn.active { background: #ff6b6b; }
@media (pointer: coarse) { .cr-op-btn { min-height: 32px; } }

/* Narrow vs Wide: stages & shuffles */
.viz-ss .ss-svg { display: block; width: 100%; height: auto; }
.ss-stage { fill: color-mix(in srgb, var(--brand) 9%, var(--bg-1)); stroke: color-mix(in srgb, var(--brand) 35%, var(--border)); stroke-width: 1; }
.ss-stage-t { fill: var(--brand-2); font-family: inherit; font-size: 10px; font-weight: 800; letter-spacing: .6px; text-anchor: middle; dominant-baseline: middle; }
.ss-op { cursor: pointer; transition: opacity .15s ease; }
.ss-op:focus { outline: none; }
.ss-op.dim { opacity: .38; }
.ss-box { fill: var(--bg-2); stroke: var(--border); stroke-width: 1.2; transition: stroke .15s ease, fill .15s ease; }
.ss-op.on .ss-box, .ss-op:focus-visible .ss-box { stroke: var(--brand); stroke-width: 2.2; fill: color-mix(in srgb, var(--brand) 12%, var(--bg-2)); }
.ss-op-t { fill: var(--text); font-family: var(--mono); font-size: 12px; font-weight: 600; }
.ss-badge { fill: var(--bg-3); stroke: var(--border-soft); stroke-width: 1; }
.ss-badge-t { fill: var(--muted); font-family: inherit; font-size: 10px; font-weight: 800; text-anchor: middle; dominant-baseline: middle; }
.ss-op.k-wide .ss-badge { fill: color-mix(in srgb, var(--brand) 22%, var(--bg-1)); stroke: var(--brand); }
.ss-op.k-wide .ss-badge-t { fill: var(--brand-2); }
.ss-op.k-source .ss-badge, .ss-op.k-action .ss-badge { fill: color-mix(in srgb, #4c8dff 20%, var(--bg-1)); stroke: #4c8dff; }
.ss-op.k-source .ss-badge-t, .ss-op.k-action .ss-badge-t { fill: #7fb0ff; }
.ss-div-line { stroke: var(--brand); stroke-width: 1.5; stroke-dasharray: 5 4; }
.ss-div-t { fill: var(--brand-2); font-family: inherit; font-size: 11px; font-weight: 800; text-anchor: end; }
.ss-mesh { stroke: color-mix(in srgb, var(--brand) 55%, transparent); stroke-width: 1; }
.ss-dot { fill: var(--brand); }

/* Window frame: partition → order → sliding frame */
.viz-wf .wf-svg { display: block; width: 100%; height: auto; }
.wf-frames { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.wf-fbtn { background: var(--bg-2); border: 1px solid var(--border); color: var(--text-2); font-size: 12px; font-weight: 700;
  font-family: inherit; padding: 5px 11px; border-radius: 999px; cursor: pointer; }
.wf-fbtn:hover { color: var(--text); border-color: var(--brand); }
.wf-fbtn.active { color: #06111f; background: var(--brand); border-color: transparent; }
.wf-h { fill: var(--muted); font-family: inherit; font-size: 11px; font-weight: 800; letter-spacing: .3px; }
.wf-hr { stroke: var(--border); stroke-width: 1; }
.wf-band.p0 { fill: color-mix(in srgb, var(--brand) 6%, var(--bg-1)); }
.wf-band.p1 { fill: color-mix(in srgb, #4c8dff 8%, var(--bg-1)); }
.wf-bracket { fill: color-mix(in srgb, var(--brand) 15%, transparent); stroke: var(--brand); stroke-width: 2; transition: y .18s ease, height .18s ease; }
.wf-row { cursor: pointer; }
.wf-row:focus { outline: none; }
.wf-hit { fill: transparent; }
.wf-cell { fill: var(--text-2); font-family: var(--mono); font-size: 12px; }
.wf-res { fill: var(--muted); font-family: var(--mono); font-size: 12px; font-weight: 700; }
.wf-row.inframe .wf-cell { fill: var(--text); }
.wf-row.inframe .wf-res { fill: var(--brand-2); }
.wf-row.cur .wf-hit { fill: color-mix(in srgb, var(--brand) 14%, transparent); stroke: var(--brand); stroke-width: 1.5; }
.wf-row.cur .wf-cell, .wf-row.cur .wf-res { fill: var(--text); font-weight: 800; }
@media (pointer: coarse) { .wf-fbtn { min-height: 32px; } }

/* shared: range slider row + svg arrow */
.viz-range-row { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; flex-wrap: wrap; }
.viz-range-lbl { font-size: 12px; font-weight: 700; color: var(--text-2); }
.viz-range { flex: 1 1 160px; min-width: 140px; accent-color: var(--brand); height: 4px; }
.viz-range-val { font-family: var(--mono); font-size: 12.5px; font-weight: 700; color: var(--brand-2); min-width: 92px; }
.ar-line { stroke-width: 2; fill: none; }

/* Join strategy: broadcast vs sort-merge */
.viz-js .js-svg { display: block; width: 100%; height: auto; }
.js-card-box { fill: var(--bg-1); stroke: var(--border); stroke-width: 1.3; }
.js-big .js-card-box { stroke: color-mix(in srgb, #4c8dff 55%, var(--border)); }
.js-small .js-card-box { stroke: color-mix(in srgb, var(--brand) 55%, var(--border)); }
.js-card-t { fill: var(--text); font-family: var(--mono); font-size: 12px; font-weight: 700; }
.js-card-tag { fill: var(--muted); font-family: inherit; font-size: 10.5px; font-weight: 700; }
.js-svg[data-mode="bcast"] .js-big .js-card-tag { fill: #37b24d; }
.js-svg[data-mode="smj"] .js-big .js-card-tag { fill: var(--brand-2); }
.js-size-track { fill: var(--bg-3); }
.js-size-fill { fill: var(--brand); }
.js-exec-box { fill: var(--bg-1); stroke: var(--border); stroke-width: 1.2; }
.js-exec-t { fill: var(--muted); font-family: inherit; font-size: 11px; font-weight: 800; }
.js-chip.big { fill: color-mix(in srgb, #4c8dff 20%, var(--bg-2)); stroke: color-mix(in srgb, #4c8dff 40%, var(--border)); stroke-width: 1; }
.js-chip-t { fill: var(--text-2); font-family: var(--mono); font-size: 10px; }
.js-exec-mode { fill: var(--brand-2); font-family: inherit; font-size: 11px; font-weight: 800; text-anchor: middle; }
.js-svg[data-mode="smj"] .js-exec-mode { fill: var(--brand-2); }
.js-arrow { opacity: 0; transition: opacity .2s ease; }
.js-arrow.show { opacity: 1; }
.js-arrow.bcast .ar-line, .js-arrow.bcast .ar-head { stroke: #37b24d; fill: #37b24d; }
.js-arrow.shuf .ar-line { stroke: var(--brand); stroke-dasharray: 5 4; }
.js-arrow.shuf .ar-head { fill: var(--brand); stroke: var(--brand); }

/* Data skew & salting */
.viz-sk .sk-svg { display: block; width: 100%; height: auto; }
.sk-axis { stroke: var(--border); stroke-width: 1.4; }
.sk-ylbl { fill: var(--muted); font-family: inherit; font-size: 10.5px; font-weight: 700; }
.sk-bar-base { fill: color-mix(in srgb, #4c8dff 40%, var(--bg-2)); transition: y .25s ease, height .25s ease; }
.sk-bar-hot { fill: #ff6b6b; transition: y .25s ease, height .25s ease, x .25s ease; }
.sk-bar-t { fill: var(--text-2); font-family: var(--mono); font-size: 11px; font-weight: 700; text-anchor: middle; transition: y .25s ease; }
.sk-bar-t.hotmax { fill: #ff6b6b; font-weight: 800; }
.sk-plab { fill: var(--muted); font-family: var(--mono); font-size: 10.5px; text-anchor: middle; }
.sk-slow { stroke: #ff6b6b; stroke-width: 1.4; stroke-dasharray: 5 4; transition: y1 .25s ease, y2 .25s ease; }
.sk-slow-t { fill: #ff6b6b; font-family: inherit; font-size: 10.5px; font-weight: 800; text-anchor: end; transition: y .25s ease; }

/* shared segmented toggle (workload / op switch) */
.viz-seg { display: inline-flex; flex-wrap: wrap; gap: 0; border: 1px solid var(--border); border-radius: 9px; overflow: hidden; margin-bottom: 12px; }
.viz-seg-btn { background: var(--bg-3); border: none; border-right: 1px solid var(--border); color: var(--text-2); font-size: 12px; font-weight: 700; padding: 7px 13px; cursor: pointer; transition: background var(--dur) var(--ease), color var(--dur) var(--ease); }
.viz-seg-btn:last-child { border-right: none; }
.viz-seg-btn:hover { color: var(--text); }
.viz-seg-btn.on { background: var(--brand); color: #06111f; }

/* memory, spill & OOM */
.viz-ms .ms-svg { display: block; width: 100%; height: auto; }
.ms-band { transition: none; }
.ms-res { fill: color-mix(in srgb, var(--muted) 30%, var(--bg-2)); }
.ms-exec { fill: color-mix(in srgb, #4c8dff 42%, var(--bg-2)); }
.ms-user { fill: color-mix(in srgb, var(--muted) 16%, var(--bg-2)); }
.ms-band-t { fill: var(--text); font-family: inherit; font-size: 11px; font-weight: 700; text-anchor: middle; }
.ms-band-s { fill: var(--text-2); font-family: var(--mono); font-size: 9.5px; text-anchor: middle; }
.ms-cap { fill: var(--muted); font-family: var(--mono); font-size: 10px; font-weight: 700; text-anchor: middle; }
.ms-axis { fill: var(--muted); font-family: inherit; font-size: 10.5px; font-weight: 700; text-anchor: middle; }
.ms-d-green { fill: color-mix(in srgb, var(--success, #2f9e44) 62%, var(--bg-2)); transition: y .2s ease, height .2s ease; }
.ms-d-green.ms-dim { fill: color-mix(in srgb, #ff6b6b 30%, var(--bg-2)); }
.ms-d-spill { fill: #f4a935; transition: y .2s ease, height .2s ease; }
.ms-d-oom { fill: #ff6b6b; transition: y .2s ease, height .2s ease; }
.ms-d-none { fill: transparent; }
.ms-d-top { fill: var(--text-2); font-family: var(--mono); font-size: 11px; font-weight: 700; text-anchor: middle; transition: y .2s ease; }
.ms-d-top.ms-spilltxt { fill: #f4a935; }
.ms-d-top.ms-oomtxt { fill: #ff6b6b; font-weight: 800; }
.ms-ceil { stroke: var(--brand-2); stroke-width: 1.4; stroke-dasharray: 5 4; }
.ms-ceil-t { fill: var(--brand-2); font-family: inherit; font-size: 10px; font-weight: 800; text-anchor: end; }
.ms-disk-box { fill: var(--bg-1); stroke: var(--border); stroke-width: 1.4; }
.ms-disk-fill { fill: color-mix(in srgb, #f4a935 55%, var(--bg-2)); transition: y .2s ease, height .2s ease; }
.ms-disk-t { fill: var(--muted); font-family: var(--mono); font-size: 10px; font-weight: 700; text-anchor: middle; }
.ms-disk-s { fill: var(--text-2); font-family: var(--mono); font-size: 10.5px; font-weight: 700; text-anchor: middle; }
.ms-disk-s.ms-dim { fill: var(--muted); }

/* repartition vs coalesce vs partitionBy */
.viz-po .po-svg { display: block; width: 100%; height: auto; }
.po-head { fill: var(--text-2); font-family: inherit; font-size: 11px; font-weight: 700; }
.po-slot { fill: var(--bg-1); stroke: var(--border-soft); stroke-width: 1; }
.po-bar { transition: y .25s ease, height .25s ease; }
.po-in { fill: color-mix(in srgb, var(--muted) 34%, var(--bg-2)); }
.po-rep { fill: color-mix(in srgb, #4c8dff 55%, var(--bg-2)); }
.po-coal { fill: color-mix(in srgb, var(--brand) 55%, var(--bg-2)); }
.po-bar-t { fill: var(--text-2); font-family: var(--mono); font-size: 10.5px; font-weight: 700; text-anchor: middle; }
.po-plab { fill: var(--muted); font-family: var(--mono); font-size: 10px; text-anchor: middle; }
.po-arr { stroke-width: 1.3; fill: none; }
.po-shuf { stroke: color-mix(in srgb, #ff6b6b 70%, var(--border)); stroke-dasharray: 3 3; opacity: .75; }
.po-merge { stroke: color-mix(in srgb, var(--brand) 75%, var(--border)); opacity: .85; }
.po-folder { fill: color-mix(in srgb, var(--brand-2) 20%, var(--bg-2)); stroke: var(--brand-2); stroke-width: 1.2; }
.po-folder-t { fill: var(--text-2); font-family: var(--mono); font-size: 9.5px; text-anchor: middle; }
.po-folder-k { fill: var(--brand-2); font-family: var(--mono); font-size: 12px; font-weight: 800; text-anchor: middle; }
.po-folder-f { fill: var(--muted); font-family: var(--mono); font-size: 8.5px; text-anchor: middle; }

/* indexed sequence */
.seq-row { display: flex; gap: 6px; flex-wrap: wrap; }
.seq-cell { display: flex; flex-direction: column; align-items: center; }
.seq-ipos, .seq-ineg { font-family: var(--mono); font-size: 11px; color: var(--muted); line-height: 1.6; }
.seq-val { font-family: var(--mono); font-size: 15px; font-weight: 700; color: var(--text); background: var(--bg-1); border: 1px solid var(--border); border-radius: 8px; min-width: 46px; text-align: center; padding: 10px 6px; }

/* dict hashing */
.dh-stage { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.dh-key, .dh-hash { font-family: var(--mono); font-weight: 700; font-size: 14px; background: var(--bg-1); border: 1px solid var(--border); border-radius: 8px; padding: 8px 14px; color: var(--brand-2); min-width: 54px; text-align: center; }
.dh-arrow { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.dh-table { display: grid; grid-template-columns: repeat(8, 1fr); gap: 6px; }
.dh-slot { background: var(--bg-1); border: 1px solid var(--border); border-radius: 8px; padding: 6px 4px; min-height: 58px; transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.dh-slot.active { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-glow); }
.dh-slot-i { font-family: var(--mono); font-size: 10px; color: var(--muted); text-align: center; }
.dh-slot-body { font-family: var(--mono); font-size: 10.5px; color: var(--text); text-align: center; margin-top: 3px; word-break: break-all; line-height: 1.4; }
@media (max-width: 620px) { .dh-table { grid-template-columns: repeat(4, 1fr); } }

/* recursion call stack */
.cs-stack { display: flex; flex-direction: column; gap: 6px; min-height: 60px; }
.cs-frame { background: var(--bg-1); border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px; font-family: var(--mono); font-size: 12.5px; display: flex; justify-content: space-between; gap: 12px; transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease); }
.cs-frame.top { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-glow); }
.cs-frame.resolved { border-color: var(--success); background: color-mix(in srgb, var(--success) 10%, var(--bg-1)); }
.cs-call { color: var(--text); font-weight: 700; }
.cs-ret { color: var(--success-2); font-weight: 700; }

/* Big-O growth explorer */
.gr-controls { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.gr-label { font-family: var(--mono); font-size: 13px; font-weight: 700; color: var(--text); min-width: 62px; }
.gr-slider { flex: 1; accent-color: var(--brand); }
.gr-bars { display: flex; flex-direction: column; gap: 7px; }
.gr-bar-row { display: grid; grid-template-columns: 78px 1fr 90px; align-items: center; gap: 10px; font-size: 12px; }
.gr-name { font-family: var(--mono); color: var(--text-2); font-weight: 700; }
.gr-track { background: var(--bg-1); border: 1px solid var(--border-soft); border-radius: 999px; height: 12px; overflow: hidden; }
.gr-fill { display: block; height: 100%; border-radius: 999px; transition: width var(--dur) var(--ease); }
.gr-fill.c0 { background: var(--green); } .gr-fill.c1 { background: var(--brand-2); }
.gr-fill.c2 { background: var(--brand); } .gr-fill.c3 { background: var(--amber); }
.gr-fill.c4 { background: #fb923c; } .gr-fill.c5 { background: var(--red); }
.gr-val { font-family: var(--mono); color: var(--muted); text-align: right; }

/* heap tree */
.hp-tree { display: flex; flex-direction: column; gap: 14px; align-items: center; margin-top: 16px; }
.hp-level { display: flex; gap: 22px; justify-content: center; }
.hp-node { width: 40px; height: 40px; border-radius: 50%; background: var(--bg-1); border: 1px solid var(--border); display: flex; align-items: center; justify-content: center; font-family: var(--mono); font-weight: 700; font-size: 14px; color: var(--text); }
.hp-node.root { border-color: var(--success); color: var(--success-2); box-shadow: 0 0 0 2px var(--success-glow); }

/* set operations / venn */
.vn-venn { position: relative; height: 160px; max-width: 380px; margin: 0 auto 4px; }
.vn-circle { position: absolute; top: 20px; width: 180px; height: 120px; border-radius: 50%; border: 2px solid; opacity: .8; }
.vn-a { left: 20px; border-color: var(--brand); background: color-mix(in srgb, var(--brand) 10%, transparent); }
.vn-b { right: 20px; border-color: var(--brand-2); background: color-mix(in srgb, var(--brand-2) 10%, transparent); }
.vn-only, .vn-mid { position: absolute; top: 66px; font-family: var(--mono); font-size: 13px; font-weight: 700; text-align: center; transition: color var(--dur) var(--ease), transform var(--dur) var(--ease); }
.vn-onlya { left: 34px; width: 90px; color: var(--text-2); }
.vn-onlyb { right: 34px; width: 90px; color: var(--text-2); }
.vn-mid { left: 50%; transform: translateX(-50%); width: 90px; color: var(--text-2); }
.vn-only.on, .vn-mid.on { color: var(--amber); transform: scale(1.18); }
.vn-mid.on { transform: translateX(-50%) scale(1.18); }

/* run / playground output */
.pyplay { margin: 12px 0 4px; }
.pyplay-code { width: 100%; box-sizing: border-box; background: var(--code-bg); color: #e6edf7; border: 1px solid var(--border); border-radius: var(--radius-sm); font-family: var(--mono); font-size: 13px; line-height: 1.6; padding: 14px 16px; resize: vertical; }
.pyplay-code:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-glow); }
.run-bar { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.run-btn { background: var(--success); border-color: var(--success); color: #052015; font-weight: 700; }
.run-btn:hover { filter: brightness(1.08); }
.run-btn:disabled { opacity: .6; cursor: default; }
.run-hint { font-size: 11.5px; }
.run-out { margin: 10px 0 0; background: var(--bg-2); border: 1px solid var(--border-soft); border-left: 3px solid var(--muted); border-radius: var(--radius-sm); padding: 11px 14px; font-family: var(--mono); font-size: 12.5px; line-height: 1.55; white-space: pre-wrap; overflow-x: auto; color: var(--text); }
.run-out.loading { border-left-color: var(--amber); color: var(--text-2); }
.run-out.ok { border-left-color: var(--success); }
.run-out.error { border-left-color: var(--red); color: var(--red); }
.py-playground { margin: 30px 34px 44px; background: var(--bg-1); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px 18px; box-shadow: inset 3px 0 0 var(--stripe-srs); }

/* python concepts strip on DSA problems */
.py-xlink-lead { font-size: 13.5px; color: var(--text-2); margin: 0 0 10px; }
.py-xlink-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.py-xlink-chip { font-weight: 650; }

/* merged-search cross block (both sidebars) */
.nav-xsearch { margin: 8px 6px 12px; padding: 8px 10px; background: var(--bg-2); border: 1px solid var(--border-soft); border-radius: var(--radius-sm); }
.nav-xsearch-head { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .5px; color: var(--muted); margin-bottom: 5px; }
.nav-xsearch-item { display: block; width: 100%; text-align: left; background: none; border: none; color: var(--brand-2); font-size: 12.5px; font-weight: 600; padding: 4px 6px; border-radius: 6px; cursor: pointer; }
.nav-xsearch-item:hover { background: var(--bg-3); color: var(--text); }

/* recognition practice button + review cards */
.py-rec-btn { width: 100%; margin-top: 10px; background: var(--bg-2); border: 1px solid var(--border); color: var(--text-2); font-weight: 700; font-size: 12.5px; padding: 8px 12px; border-radius: var(--radius-sm); cursor: pointer; }
.py-rec-btn:hover { border-color: var(--brand); color: var(--text); }
.py-rec-btn.has-due { background: color-mix(in srgb, var(--brand) 15%, var(--bg-2)); border-color: color-mix(in srgb, var(--brand) 45%, var(--border)); color: var(--text); }
.rv-card { text-align: center; }
.rv-progress { font-size: 12px; margin-bottom: 14px; }
.rv-front { font-size: 18px; font-weight: 700; color: var(--text); line-height: 1.4; margin-bottom: 14px; }
.rv-back { font-size: 16px; font-weight: 650; color: var(--brand-2); margin-bottom: 16px; transition: filter var(--dur) var(--ease); }
.rv-back.blurred { filter: blur(7px); user-select: none; }
.rv-grades { display: flex; gap: 8px; justify-content: center; margin-bottom: 14px; }
.rv-grade { font-weight: 700; }
.rv-again { color: var(--red); } .rv-hard { color: var(--amber); } .rv-good { color: var(--brand-2); } .rv-easy { color: var(--success-2); }
.rv-open { color: var(--muted); }
.rv-done { font-size: 16px; font-weight: 700; color: var(--success-2); text-align: center; margin-bottom: 14px; }
