/* Shared styles for the DSA visualizer pages. Page-specific pieces live in each page's <style>. */
/* Colour, font and type-scale tokens come from theme.css (shared with Senior loop), linked before this file.
   Visualizer names below are aliases onto the shared tokens, so the drawing libs and page styles keep working. */
:root{
  --mark:var(--dsa);           /* the DSA track's marker blue */
  --mark-tint:var(--dsa-tint);
  --on-mark:var(--on-track);
  --sheet:var(--board);        /* code and inset backgrounds */
  --grid:var(--frame-2);
  --display:var(--hand);
  --radius:10px;
  --dur:900ms;
  --cell:48px;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--board);color:var(--ink);font-family:var(--body);
  font-size:var(--fs-body);line-height:var(--lh-body);-webkit-font-smoothing:antialiased
}
.still *{transition:none !important}
.wrap{max-width:960px;margin:0 auto;padding-inline:22px}
/* inline-block: a short snippet moves to the next line whole instead of splitting mid-token; one longer than
   the line still wraps inside its own box (max-width), so nothing overflows at 360px */
code{
  font-family:var(--mono);font-size:var(--fs-code);background:var(--sheet);border:1px solid var(--rule);padding:1px 5px;border-radius:4px;
  display:inline-block;max-width:100%;overflow-wrap:anywhere;line-height:var(--lh-label)
}
button{font:inherit;color:inherit}
sup,sub,small{font-size:var(--fs-label)}
:focus-visible{outline:2px solid var(--mark);outline-offset:2px}

/* ══ masthead: same pattern as a Senior loop lesson head ══ */
.mast{background:var(--board);border-bottom:1px solid var(--frame-2)}
.mast-in{max-width:960px;margin:0 auto;padding:26px 22px 26px}
.pn{margin:0 0 20px;font-size:var(--fs-label);line-height:var(--lh-label);display:flex;align-items:center;gap:4px 16px;white-space:nowrap}
.pn a{color:var(--ink-3);text-decoration:none;display:inline-flex;align-items:center;gap:.5ch;min-height:24px;min-width:0}
.pn a > span{min-width:0;overflow:hidden;text-overflow:ellipsis}
.pn a:first-child{color:var(--ink-2);font-weight:600;flex:none}
.pn a:hover{color:var(--mark)}
.theme-btn{
  flex:none;margin-left:auto;width:34px;height:32px;display:grid;place-items:center;border:1px solid var(--frame-2);border-radius:8px;
  background:var(--paper);color:var(--ink-2);cursor:pointer
}
.theme-btn:hover{color:var(--ink);border-color:var(--ink-4)}
.theme-btn[aria-pressed="true"]{background:var(--ink);color:var(--paper);border-color:var(--ink)}
.kicker{
  font-size:var(--fs-label);line-height:var(--lh-label);font-weight:700;
  color:var(--mark);margin:0 0 10px
}
h1{
  font-family:var(--hand);font-weight:700;font-variation-settings:"INFM" 40;font-size:var(--fs-display);
  line-height:var(--lh-display);letter-spacing:-.015em;margin:0;text-wrap:balance
}
h1 em{font-style:normal;color:inherit}
.stand{font-size:var(--fs-prose);line-height:var(--lh-prose);color:var(--ink);margin:14px 0 0;max-width:var(--measure)}
.facts{display:flex;flex-wrap:wrap;gap:8px;margin-top:18px}
.fact{display:flex;align-items:baseline;gap:7px;padding:6px 11px;border:1px solid var(--frame-2);border-radius:20px;background:var(--paper)}
.fact b{font-family:var(--mono);font-weight:700;font-size:var(--fs-label);font-stretch:condensed;color:var(--ink)}
.fact span{font-size:var(--fs-label);color:var(--ink-3)}

/* ══ labels + inputs ══ */
.lbl{
  font-size:var(--fs-label);line-height:var(--lh-label);font-weight:700;
  color:var(--ink-2);margin:0 0 12px;display:flex;gap:10px;align-items:baseline;flex-wrap:wrap
}
.lbl span{color:var(--ink-3);font-weight:400}
.input{padding-top:30px}
/* the input form sits in a disclosure (viz.js): open with no summary on wider screens, folded on phones */
.inbox{margin:0}
.inbox > summary{display:none}
.fields{display:grid;grid-template-columns:1fr auto;gap:8px;align-items:end}
.fields .lbl{margin-bottom:8px}
.fields input{
  width:100%;height:44px;padding:0 14px;font-family:var(--mono);font-size:var(--fs-small);
  border:1px solid var(--frame-2);border-radius:8px;background:var(--paper);color:var(--ink)
}
.fields input:focus-visible{outline:2px solid var(--mark);outline-offset:0;border-color:transparent}
.hint{font-size:var(--fs-label);line-height:var(--lh-label);color:var(--ink-3);margin:8px 0 0}
.presets{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.btn{
  height:34px;padding:0 12px;border:1px solid var(--frame-2);border-radius:8px;background:var(--paper);
  font-size:var(--fs-label);cursor:pointer;white-space:nowrap
}
.btn:hover{border-color:var(--ink-3)}
.btn.solid{height:44px;padding:0 18px;background:var(--ink);color:var(--paper);border-color:var(--ink);font-size:var(--fs-small);font-weight:700;border-radius:9px}
.btn.solid:hover{background:var(--ink-2)}
.err{font-size:var(--fs-small);line-height:var(--lh-small);color:var(--bad);min-height:1.5em;margin:8px 0 0}

/* ══ stage ══ */
.stage{margin-top:12px;padding:22px 22px 18px;border:1px solid var(--rule);border-radius:var(--radius);background:var(--paper);overflow-x:clip}
/* clip: hidden pointers keep their last transform; after a resize it must not widen the page */
.badges{display:flex;align-items:center;flex-wrap:wrap;gap:10px;font-size:var(--fs-small);line-height:var(--lh-label);font-variant-numeric:tabular-nums}
.lb{padding:5px 10px;border:1.5px solid var(--rule);border-radius:5px;transition:background-color .25s, border-color .25s, color .25s, opacity .25s}
.lb.probe{background:var(--probe-tint);border-color:var(--probe)}
.lb.hit{background:var(--mark);border-color:var(--mark);color:var(--on-mark)}
.lb.ok{border-color:var(--ok);color:var(--ok)}
.lb:is(.probe,.hit,.ok){font-weight:700}
/* not set yet: an empty slot, not a disabled control. Dashed outline + lighter text, still readable
   (ink-3 text >= 5.8:1, ink-4 outline >= 3.7:1 on paper, both themes); set states add fill + weight */
.lb.off{color:var(--ink-3);border-color:var(--ink-4);border-style:dashed;background:none}
.op{color:var(--ink-3);font-weight:700}

/* array of cells with a pointer; offsets are measured from .arr-wrap */
.arr-wrap{position:relative;padding-bottom:40px}
.arr{display:flex;flex-wrap:wrap;gap:36px 8px;padding-top:36px}
.cell{width:var(--cell);display:flex;flex-direction:column;align-items:center;transition:opacity .3s}
.box{
  width:var(--cell);height:var(--cell);display:grid;place-items:center;border:1.5px solid var(--ink-4);border-radius:6px;
  background:var(--paper);font-family:var(--mono);font-weight:700;font-size:var(--fs-small);
  transition:transform calc(var(--dur) * .35) cubic-bezier(.2,.8,.2,1), background-color .25s, border-color .25s, color .25s, box-shadow .25s;
}
.box.sm,.chip.sm{font-size:var(--fs-label);font-stretch:condensed}
.idx{font-family:var(--mono);font-size:var(--fs-label);color:var(--ink-3);margin-top:5px;line-height:1.3}
.cell.used .box{background:var(--grid);border-color:var(--grid);color:var(--ink-2)}
.cell.cur .box{
  background:var(--probe-tint);border-color:var(--ink);border-width:2px;transform:translateY(-6px);
  box-shadow:0 12px 18px -10px var(--shadow)
}
.cell.cur .idx{color:var(--ink);font-weight:700}
.cell.ok .box{background:var(--ok-tint);border-color:var(--ok);color:var(--ok)}
.cell.hit .box{background:var(--mark);border-color:var(--mark);color:var(--on-mark)}
.cell.hit .idx{color:var(--mark);font-weight:700}
.cell.skip{opacity:.35}
.cell.skip .box{border-style:dashed}
.ptr{
  position:absolute;left:0;top:0;width:var(--cell);display:flex;flex-direction:column;align-items:center;gap:2px;
  font-family:var(--mono);font-size:var(--fs-label);font-stretch:semi-condensed;font-weight:700;line-height:14px;color:var(--ink);pointer-events:none;
  transition:transform calc(var(--dur) * .4) cubic-bezier(.2,.8,.2,1), opacity .2s
}
.ptr svg{width:10px;height:7px;fill:currentColor}
.ptr.off{opacity:0}
.arc{position:absolute;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none}
.arc path{fill:none;stroke:var(--mark);stroke-width:2;stroke-linecap:round;opacity:0;transition:opacity .2s}
.arc.on path{opacity:1}

/* hash buckets */
.buckets{display:grid;grid-template-columns:repeat(8,minmax(0,1fr));gap:6px}
.bucket{
  border:1.5px solid var(--rule);border-radius:6px;background:var(--sheet);min-height:112px;
  display:flex;flex-direction:column;transition:background-color .25s, border-color .25s
}
.bh{
  font-family:var(--mono);font-size:var(--fs-label);color:var(--ink-3);text-align:center;padding:5px 0;
  border-bottom:1px solid var(--rule);transition:color .25s
}
.bb{display:flex;flex-direction:column;align-items:center;gap:4px;padding:6px}
.bucket.probe{background:var(--probe-tint);border-color:var(--probe)}
.bucket.probe .bh{color:var(--ink);font-weight:700}
.bucket.hit{border-color:var(--mark)}
.chip{
  width:100%;max-width:44px;height:28px;display:grid;place-items:center;border:1px solid var(--ink-4);
  border-radius:4px;background:var(--paper);font-family:var(--mono);font-weight:700;font-size:var(--fs-label);position:relative
}
.chip.hit{background:var(--mark);border-color:var(--mark);color:var(--on-mark)}

.banner{
  margin-top:18px;min-height:50px;padding:13px 16px;border:1px solid transparent;border-radius:var(--radius);
  font-size:var(--fs-small);line-height:var(--lh-small);opacity:0;transform:translateY(8px);overflow-wrap:anywhere;
  transition:opacity .35s, transform .35s cubic-bezier(.2,.8,.2,1)
}
.banner.show{opacity:1;transform:none}
.banner:not(.show){display:none}   /* no empty slot under the picture until there is a result */
@starting-style{.banner.show{opacity:0;transform:translateY(8px)}}
.banner.hit{background:var(--mark-tint);border-color:var(--mark)}
.banner.hit b{color:var(--mark)}
.banner.ok{background:var(--ok-tint);border-color:var(--ok)}
.banner.ok b{color:var(--ok)}

/* ══ code + variables ══ */
.lower{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,1fr);gap:18px;margin-top:22px}
.code{
  background:var(--paper);border:1px solid var(--rule);border-radius:var(--radius);padding:12px 0;
  font-family:var(--mono);font-size:var(--fs-code);line-height:1.8;overflow-x:auto;font-variant-ligatures:none;position:relative
}
.ln{display:block;white-space:pre;padding:0 16px 0 40px;position:relative;transition:background-color .2s}
.ln::before{content:attr(data-n);position:absolute;left:8px;color:var(--ink-3)}
.ln::after{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:transparent;transition:background-color .2s}
.ln.in::after{background:var(--ink-4)}
.ln.on{background:var(--probe-tint)}
.ln.on::after{background:var(--mark)}
.k{color:var(--mark)}
.fn{color:var(--ink-2);font-weight:600}
.cm{color:var(--ink-3)}
.vars{border:1px solid var(--rule);border-radius:var(--radius);padding:14px 16px;background:var(--paper);align-self:start}
.vars dl{display:grid;grid-template-columns:auto 1fr;gap:6px 16px;margin:0;font-family:var(--mono);font-size:var(--fs-code)}
.vars dt{color:var(--ink-3)}
.vars dd{margin:0;font-weight:700;overflow-wrap:anywhere}
/* step narration: directly under the picture at every width (viz.js moves it there) */
.msg{
  font-size:var(--fs-prose);line-height:var(--lh-prose);overflow-wrap:anywhere;margin:10px 0 0;padding:12px 16px 12px 18px;min-height:calc(3em + 24px);
  background:var(--paper);border:1px solid var(--rule);border-radius:var(--radius);box-shadow:inset 3px 0 0 var(--mark)
}
.msg b{color:var(--mark);font-weight:700}

/* phones: "Show full code" (viz.js); compact code hides .far lines, see the 640px block */
.codebox{min-width:0}   /* a grid item: let the code scroll sideways instead of widening the page */
.codemore{
  display:none;width:100%;min-height:36px;margin-top:6px;border:1px solid var(--frame-2);border-radius:8px;background:var(--paper);
  font-size:var(--fs-label);color:var(--ink-2);cursor:pointer
}
.codemore:hover{border-color:var(--ink-3)}

/* predict mode: prompt and result above the code; lines become buttons while asking */
.pq{
  margin:0 0 8px;padding:8px 12px;border:1px solid var(--rule);border-radius:8px;background:var(--sheet);
  font-size:var(--fs-small);line-height:var(--lh-small);color:var(--ink-2)
}
.pq:empty{display:none}
.pq.ask{background:var(--probe-tint);border-color:var(--probe);color:var(--ink)}
.pq.right{background:var(--ok-tint);border-color:var(--ok);color:var(--ink)}
.pq.right b{color:var(--ok)}
.pq.wrong{background:var(--bad-tint);border-color:var(--bad);color:var(--ink)}
.pq.wrong b{color:var(--bad)}
.code.asking .ln{cursor:pointer}
.code.asking .ln:hover{background:var(--mark-tint)}
.code.asking .ln:focus-visible{outline:2px solid var(--mark);outline-offset:-2px;background:var(--mark-tint)}
.ln.miss{outline:2px dashed var(--bad);outline-offset:-2px}

/* Mark solved: on the masthead facts row (viz.js puts it inside .facts), and at the end of the run */
.solve{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px;margin-top:16px;font-size:var(--fs-small)}
.sv-c{display:flex;flex-wrap:wrap;gap:6px}
.sv-q{color:var(--ink-2)}
.sv-ok{color:var(--ok);font-weight:700}
.sv-mark{border-color:var(--ok);color:var(--ok);font-weight:700}
.sv-mark:hover{background:var(--ok-tint);border-color:var(--ok)}
.sv-skip{color:var(--ink-3)}
.sv-err{color:var(--bad);flex-basis:100%}
.facts .solve{margin:0 0 0 4px}
.endcard{margin-top:10px;padding:10px 14px;border:1px dashed var(--frame-2);border-radius:var(--radius);background:var(--paper)}
.endcard .solve{margin:0}

/* ══ notes ══ */
.notes{margin-top:34px;padding-bottom:30px}
.notes ol{margin:0;padding:0;list-style:none;counter-reset:n;max-width:var(--measure);font-size:var(--fs-prose);line-height:var(--lh-prose)}
.notes li{position:relative;padding-left:34px;margin-bottom:10px;color:var(--ink-2);counter-increment:n}
.notes li::before{
  content:counter(n,decimal-leading-zero);position:absolute;left:0;top:5px;
  font-family:var(--mono);font-size:var(--fs-label);font-weight:700;color:var(--mark)
}
.notes b{color:var(--ink);font-weight:700}

/* ══ controls (markup injected by viz.js) ══ */
.ctl{position:sticky;bottom:0;z-index:10;background:var(--glass);backdrop-filter:blur(10px);border-top:1px solid var(--rule)}
.ctl-in{max-width:960px;margin:0 auto;padding:10px 22px;display:flex;align-items:center;gap:10px 16px;flex-wrap:wrap}
.btns{display:flex;gap:6px}
.ib{
  width:40px;height:40px;display:grid;place-items:center;border:1px solid var(--frame-2);border-radius:9px;
  background:var(--paper);cursor:pointer
}
.ib:hover{border-color:var(--ink-3)}
.ib svg{width:18px;height:18px}
.ib.play{
  width:auto;display:flex;gap:8px;padding:0 16px 0 13px;background:var(--ink);color:var(--paper);border-color:var(--ink);
  font-size:var(--fs-small);font-weight:700
}
.scrubg{flex:1;min-width:160px;display:flex;align-items:center;gap:10px}
input[type=range]{accent-color:var(--mark);margin:0;height:24px;cursor:pointer}
#scrub{flex:1;min-width:0}
.stepno,.speed{font-size:var(--fs-label);color:var(--ink-3);font-variant-numeric:tabular-nums;white-space:nowrap}
.stepno{min-width:5ch;text-align:right;font-family:var(--mono);font-stretch:condensed}
.speed{display:flex;align-items:center;gap:8px}
.speed input{width:90px}
.speed output{font-family:var(--mono);font-stretch:condensed;color:var(--ink);font-weight:700;min-width:4ch}
.keys{font-size:var(--fs-label);color:var(--ink-3)}
.ib.pt{width:auto;padding:0 12px;font-size:var(--fs-label);font-weight:600;color:var(--ink-2)}
.ib.pt[aria-pressed="true"]{background:var(--mark-tint);border-color:var(--mark);color:var(--ink);font-weight:700}
html{scroll-padding-bottom:calc(var(--ctl-h, 64px) + 8px)}

/* ══ workbench: on wide screens the stage and the code/vars panel sit side by side, so the picture,
   the highlighted line and the step message are all visible at once (viz.js wraps them in .bench) ══ */
.bench{scroll-margin-top:8px}
@media (min-width:1100px){
  .wrap,.mast-in,.ctl-in{max-width:1360px}
  .bench{display:grid;grid-template-columns:minmax(0,1fr) 440px;gap:16px;align-items:start;margin-top:12px}
  .bench .stage{margin-top:0}
  .bench .lower{
    position:sticky;top:8px;display:flex;flex-direction:column;gap:12px;margin-top:0;
    max-height:calc(100vh - var(--ctl-h, 64px) - 16px)   /* the code scrolls inside; viz.js keeps the highlight in view */
  }
  .bench .codebox{display:flex;flex-direction:column;min-height:0}
  .bench .code{line-height:1.6;padding:10px 0;min-height:120px}
  .bench .vars{padding:12px 14px;flex:none;align-self:stretch}
  .bench .vars dl{gap:4px 14px}
  /* picture taller than the window (viz.js sets .dock): the narration rides at the bottom of the window,
     above the playback bar, until the end of the picture scrolls into view */
  .view.dock .msg{position:sticky;bottom:calc(var(--ctl-h, 64px) + 8px);z-index:3;box-shadow:inset 3px 0 0 var(--mark), 0 -10px 20px -12px var(--shadow)}
}
@media (max-width:760px){
  .lower{grid-template-columns:1fr}
  .keys{display:none}
}
/* phones: picture, narration, then state, then ~5 lines of code around the highlight */
@media (max-width:640px){
  /* the picture on the first screen: a shorter masthead, the input folded into one line above the stage */
  .mast-in{padding:14px 16px 16px}
  .pn{margin-bottom:10px}
  .kicker{margin-bottom:6px}
  h1{font-size:var(--fs-headline);line-height:var(--lh-headline)}
  .stand{margin-top:8px;font-size:var(--fs-small);line-height:var(--lh-small)}   /* ~45 characters a line, not ~38 */
  .facts{margin-top:12px;gap:6px}
  .fact{padding:4px 10px}
  .facts .solve{margin:0}
  .facts .solve .btn{height:32px}
  .inbox{margin-top:12px}
  .inbox > summary{
    display:flex;align-items:center;gap:10px;min-height:44px;padding:0 12px 0 14px;cursor:pointer;list-style:none;
    border:1px solid var(--frame-2);border-radius:9px;background:var(--paper);font-size:var(--fs-small)
  }
  .inbox > summary::-webkit-details-marker{display:none}
  .inbox > summary:hover{border-color:var(--ink-3)}
  .in-k{flex:none;font-size:var(--fs-label);color:var(--ink-3)}
  .in-v{
    flex:1;min-width:0;margin:6px 0;overflow:hidden;overflow-wrap:anywhere;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;
    font-family:var(--mono);font-size:var(--fs-label);line-height:var(--lh-label);font-weight:700;color:var(--ink)
  }
  .in-a{flex:none;display:flex;align-items:center;gap:6px;font-size:var(--fs-label);font-weight:700;color:var(--mark)}
  .in-a::before{content:"Change"}
  .inbox[open] .in-a::before{content:"Close"}
  .in-a svg{width:12px;height:12px;transition:transform .2s}
  .inbox[open] .in-a svg{transform:rotate(180deg)}
  .inbox .input{padding-top:14px}
  .lower{margin-top:14px}
  .lower .vars{order:-1}
  .codemore{display:block}
  .code.compact .ln.far{display:none}
  .code.compact.asking .ln.far{display:block}
}
@media (max-width:520px){
  :root{--cell:40px}
  .wrap,.mast-in,.ctl-in{padding-inline:16px}
  .stage{padding:16px 12px 14px}
  .buckets{gap:4px}
  .bb{padding:4px 3px}
  .ib.play span{display:none}
  .ib.play{padding:0 11px}
  .scrubg{order:2;flex:1 1 200px}
  .ib.pt{order:2;height:36px}
  /* prev/next: the short word, not a cut-off title (the full title stays in each link's aria-label) */
  .pn{gap:4px 6px}
  .pn a{min-height:32px;padding-inline:4px}
  .pn a:first-child{padding-left:0;margin-right:auto}
  .pn a > span{display:none}
  .pn a[aria-label^="Previous"]::after{content:"Prev"}
  .pn a[aria-label^="Next"]::before{content:"Next"}
  .theme-btn{margin-left:6px}
  .speed span{display:none}
  .speed input{width:80px}
}
@media (prefers-reduced-motion: reduce){
  .ptr{transition:opacity .2s}
  .cell.cur .box{transform:none}
  .banner{transform:none}
  .in-a svg{transition:none}
}
