/* =============================================================================
   lesson.css — the paged reader's chrome, plus the shared widget vocabulary
   every course builds its interactives out of. Loaded after site.css.
   ========================================================================== */

html{scroll-behavior:smooth}
body{margin:0}
h1{font-size:2.5rem}
h2{font-size:1.85rem; margin-top:0}
h3{font-size:1.2rem; margin-top:2em}
h4{font-size:1rem; margin-top:1.6em; color:var(--dim); text-transform:uppercase;
   letter-spacing:.08em; font-weight:700}
p{margin:0 0 1em}
ul,ol{margin:0 0 1em; padding-left:1.3em}
li{margin:.35em 0}
b,strong{color:var(--txt); font-weight:650}
pre{font-family:var(--mono); font-size:.85rem; background:var(--panel2); border:1px solid var(--line);
    padding:14px 16px; border-radius:10px; overflow:auto; line-height:1.55}
hr{border:none; border-top:1px solid var(--line); margin:2.5em 0}

/* ------------------------------------------------------------------ layout */
#toc{position:fixed; top:0; left:0; bottom:0; width:270px; overflow-y:auto; z-index:50;
  background:var(--bg2); border-right:1px solid var(--line); padding:22px 14px 40px}
#toc .brand{font-weight:750; font-size:.95rem; padding:0 10px 4px; display:block}
#toc .brandsub{font-size:.75rem; color:var(--dimmer); padding:0 10px 16px; display:block; line-height:1.4}
#toc a{display:flex; gap:9px; align-items:baseline; padding:6px 10px; border-radius:7px;
  color:var(--dim); font-size:.83rem; line-height:1.35; text-decoration:none; border-left:2px solid transparent}
#toc a:hover{background:var(--panel); color:var(--txt); text-decoration:none}
#toc a.active{background:var(--panel2); color:var(--txt); border-left-color:var(--accent); font-weight:600}
#toc a .n{font-family:var(--mono); font-size:.72rem; color:var(--dimmer); min-width:16px}
#toc a.active .n{color:var(--accent)}
#toc a.done .n::after{content:"✓"; color:var(--on)}
#toc .part{font-size:.68rem; text-transform:uppercase; letter-spacing:.1em; color:var(--dimmer);
  padding:16px 12px 5px; font-weight:700}
#tocProg{font-size:.7rem; color:var(--dimmer); padding:6px 12px 14px; font-family:var(--mono)}
/* The bar lives in the contents rail, beside the step list it describes, and not
   across the top of the page: a full-width strip up there was the first thing
   removed from this design for looking like a decoration rather than a fact. */
#tocProg .tp-bar{ display:block; height:5px; border-radius:99px; background:var(--panel3);
  overflow:hidden; margin:0 0 6px }
#tocProg .tp-bar i{ display:block; height:100%; background:var(--on); border-radius:99px;
  transition:width .32s cubic-bezier(.2,.7,.3,1) }
@media (prefers-reduced-motion:reduce){ #tocProg .tp-bar i{ transition:none } }
#tocProg .tp-n{ display:block }

main{margin-left:270px; padding:0 32px 110px; max-width:1180px}
main .wrap{max-width:820px; margin:0 auto; padding:0}
footer.lessonfoot{margin-left:270px; padding:30px 32px 70px; color:var(--dim); font-size:.85rem;
  border-top:1px solid var(--line)}

/* ------------------------------------------------------- paged reader panes */
body.paged .step{display:none; padding-top:18px}
body.paged .step.active{display:block}
body.paged:not(.noanim) .step.active{animation:stepIn .22s cubic-bezier(.2,.7,.3,1)}
@keyframes stepIn{from{opacity:0; transform:translateY(7px)} to{opacity:1; transform:none}}
body.paged main{padding-top:60px}
/* in paged mode the step owns the screen; a footer below it only adds a tail
   to scroll past on a phone */
body.paged footer.lessonfoot{display:none}
.stepnum{font-family:var(--mono); font-size:.75rem; letter-spacing:.14em; text-transform:uppercase;
  color:var(--accent); font-weight:700; margin-bottom:8px}

#top{position:fixed; top:0; left:270px; right:0; height:54px; z-index:56;
  display:flex; align-items:center; gap:12px; padding:0 18px;
  background:color-mix(in srgb, var(--bg) 90%, transparent);
  backdrop-filter:saturate(160%) blur(10px); border-bottom:1px solid var(--line)}
/* On a wide screen the route home is the first item in the contents rail, so
   the top bar does not repeat it. On a phone the rail is a drawer, and the only
   way out must not be hidden behind a hamburger, so the icon appears there. */
#top .home{display:none; align-items:center; justify-content:center; color:var(--txt);
  text-decoration:none; min-width:42px; min-height:42px; border-radius:var(--r-full)}
#top .home:hover{color:var(--accent); background:var(--panel2)}
#crumb{font-size:.82rem; color:var(--dim); overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; flex:1; min-width:0}
#crumb b{color:var(--txt)}
#crumb .ct{font-family:var(--mono); font-size:.72rem; color:var(--accent); margin-right:8px}
.iconbtn{font:inherit; font-size:.9rem; line-height:1; color:var(--txt); background:var(--panel2);
  border:1px solid var(--line2); border-radius:8px; padding:7px 11px; cursor:pointer; flex:none}
.iconbtn:hover:not(:disabled){border-color:var(--accent); color:var(--accent)}
.iconbtn:disabled{opacity:.35; cursor:not-allowed}
/* The theme control's two icons. Same three-state handling as the hub: an
   explicit choice either way, plus the untouched default that only
   prefers-color-scheme can tell apart. */
#themebtn{display:inline-flex; align-items:center; justify-content:center}
#themebtn svg{display:block}
#themebtn .i-sun{display:none}
:root[data-theme="dark"] #themebtn .i-sun{display:block}
:root[data-theme="dark"] #themebtn .i-moon{display:none}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) #themebtn .i-sun{display:block}
  :root:not([data-theme="light"]) #themebtn .i-moon{display:none}
}
/* The completion sound, off by default and saying so. The crossed-out speaker is
   the resting state, and the button is dimmed until it is switched on, so the
   page reads as quiet rather than as muted-for-now. */
#soundbtn{display:inline-flex; align-items:center; justify-content:center; opacity:.62}
#soundbtn.on{opacity:1; color:var(--accent); border-color:var(--accent)}
#soundbtn svg{display:block}
#soundbtn .i-snd{display:none}
#soundbtn.on .i-snd{display:block}
#soundbtn.on .i-mute{display:none}

#navtoggle{display:none}


/* What to build with the course you have just finished. Sits above the prev/next
   pair on the last step, because a reader who has reached the end is at the
   moment they are most likely to make something, and until now nothing on the
   page told them the projects existed. */
.whatnext{ margin:38px 0 0; padding:20px 22px 22px; border:1px solid var(--line2);
  border-radius:14px; background:var(--panel) }
.whatnext h3{ margin:0 0 6px; font-size:1.1rem }
.whatnext > p{ margin:0 0 16px; color:var(--dim); font-size:.94rem; max-width:62ch }
.wn-grid{ display:grid; gap:12px; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)) }
.wn-card{ display:flex; flex-direction:column; gap:6px; padding:14px 16px;
  border:1px solid var(--line); border-radius:11px; background:var(--panel2);
  text-decoration:none; color:inherit; transition:border-color .14s }
.wn-card:hover{ border-color:var(--accent2); text-decoration:none }
.wn-card.pending{ opacity:.7 }
.wn-card.pending:hover{ border-color:var(--line) }
.wn-t{ font-weight:650; color:var(--txt); font-size:.98rem; line-height:1.3 }
.wn-h{ font-size:.87rem; color:var(--dim) }
.wn-soon{ font-family:var(--mono); font-size:.64rem; letter-spacing:.1em;
  text-transform:uppercase; color:var(--hot); font-weight:700 }

.stepnav{display:flex; gap:12px; margin:38px 0 8px; border-top:1px solid var(--line); padding-top:20px}
.stepnav a{flex:1; display:block; padding:12px 15px; border:1px solid var(--line); border-radius:11px;
  background:var(--panel); text-decoration:none; transition:.14s; min-width:0}
.stepnav a:hover{border-color:var(--accent); background:var(--panel2); text-decoration:none}
.stepnav .dir{display:block; font-size:.68rem; letter-spacing:.12em; text-transform:uppercase;
  color:var(--dim); font-weight:700; margin-bottom:3px}
.stepnav .ttl{display:block; color:var(--txt); font-weight:600; font-size:.92rem;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.stepnav a.nx{text-align:right}
.stepnav a.ghost{visibility:hidden}

#coverGrid{display:grid; grid-template-columns:repeat(auto-fill,minmax(210px,1fr)); gap:9px; margin:22px 0}
#coverGrid a{display:block; padding:10px 13px; border:1px solid var(--line); border-radius:10px;
  background:var(--panel); text-decoration:none; transition:.14s}
#coverGrid a:hover{border-color:var(--accent); background:var(--panel2); text-decoration:none}
#coverGrid .n{font-family:var(--mono); font-size:.68rem; color:var(--dimmer)}
#coverGrid .t{display:block; color:var(--txt); font-size:.86rem; font-weight:600; margin-top:2px}
#coverGrid a.done .n::after{content:" ✓"; color:var(--on)}

#scrim{position:fixed; inset:0; background:rgba(0,0,0,.5); z-index:49; display:none}
#scrim.on{display:block}
.skip{position:absolute; left:-9999px}
.skip:focus{left:8px; top:8px; z-index:99; background:var(--panel); color:var(--txt);
  padding:8px 14px; border-radius:8px; border:1px solid var(--accent)}

/* ------------------------------------------------------- widget containers */
.lab{background:var(--panel); border:1px solid var(--line); border-radius:14px; margin:26px 0;
  box-shadow:var(--shadow); overflow:hidden}
.lab-head{display:flex; align-items:center; gap:10px; padding:11px 16px; background:var(--panel2);
  border-bottom:1px solid var(--line); font-size:.78rem; font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; color:var(--dim)}
.lab-head .dot{width:8px; height:8px; border-radius:50%; background:var(--accent); flex:none}
.lab-body{padding:18px 16px}
.lab-foot{padding:10px 16px 14px; font-size:.85rem; color:var(--dim); border-top:1px dashed var(--line);
  background:var(--panel2)}
.lab-foot b{color:var(--txt)}
/* A wide lab is allowed to bleed into the margins, so a widget gets more room
   than a line of prose wants. Two things were wrong with it, and together they
   put every wide lab on the site 130px to the left of its own step's heading.

   FIRST, THE BLEED WAS DEFEATED IN ONE DIRECTION ONLY. The old rule paired
   width:calc(100% + 260px) with margin-left:-130px, which is symmetric and
   correct on its own. But .lab, .lab-body{max-width:100%} further down this file
   (added later, to stop a long console line dragging a lab off the page) clamps
   that computed width straight back to the column width. max-width beats width
   whatever the specificity, so the widening was silently cancelled while the
   leftward shift survived. The lab ended up the same width as the prose and
   130px left of it: 132 wide labs across 14 courses, at every viewport over
   1240px. max-width:none is restated here so the two rules stop fighting.

   SECOND, 1240px WAS NEVER MEASURED. Slack per side is
   (viewport - rail - column) / 2, and with a 270px contents rail and an 820px
   column that is 85px at 1240px and 103px at 1280px. A 130px bleed needs 130.
   So the breakpoint was 160px too low and the intended layout would have
   overflowed the page even if it had worked. 1400px leaves 155px per side before
   the scrollbar, which clears 130 with room for the gutter. Below it a wide lab
   is simply the full column width, which is what a reader wants on a laptop and
   is exactly aligned with the prose. */
.lab.wide{width:100%}
@media (min-width:1400px){
  .lab.wide{width:calc(100% + 260px); max-width:none; margin-left:-130px}
}

.callout{border-left:3px solid var(--accent); background:var(--panel2); padding:12px 16px;
  border-radius:0 10px 10px 0; margin:20px 0; font-size:.95rem}
.callout.key{border-color:var(--on)}
.callout.warn{border-color:var(--hot)}
.callout .tag{display:block; font-size:.7rem; font-weight:750; letter-spacing:.12em;
  text-transform:uppercase; color:var(--accent); margin-bottom:4px}
.callout.key .tag{color:var(--on)}
.callout.warn .tag{color:var(--hot)}
.callout p:last-child{margin-bottom:0}

.quiz{background:var(--panel); border:1px solid var(--line); border-left:3px solid var(--accent2);
  border-radius:0 12px 12px 0; padding:16px; margin:24px 0}
.quiz .q{font-weight:650; margin-bottom:12px}
.quiz .q::before{content:"CHECK YOURSELF"; display:block; font-size:.68rem; letter-spacing:.13em;
  color:var(--accent2); font-weight:800; margin-bottom:6px}
.quiz .opt{display:block; width:100%; text-align:left; font:inherit; font-size:.9rem; color:var(--txt);
  background:var(--panel2); border:1px solid var(--line); border-radius:9px; padding:9px 13px;
  margin-bottom:7px; cursor:pointer; transition:.12s}
.quiz .opt:hover{border-color:var(--accent2)}
.quiz .opt.right{background:color-mix(in srgb, var(--on) 20%, transparent); border-color:var(--on)}
.quiz .opt.wrong{background:color-mix(in srgb, var(--red) 18%, transparent); border-color:var(--red)}
.quiz .fb{font-size:.88rem; color:var(--dim); margin-top:10px; display:none}
.quiz .fb.show{display:block}
/* The answer-specific half. The shared feedback below explains the right answer;
   this one addresses the choice actually made, which is what a reader who got it
   wrong is asking about. Bordered rather than coloured alone, and it names itself
   in words, because nothing on this site may depend on colour to be understood. */
.quiz .fb-why{ display:none; font-size:.88rem; margin-top:10px; padding:10px 13px;
  border-left:3px solid var(--on); background:var(--panel2); border-radius:0 8px 8px 0 }
.quiz .fb-why.show{ display:block }
.quiz .fb-why.bad{ border-left-color:var(--accent2) }
.quiz .fb-why .lbl{ display:block; font-family:var(--mono); font-size:.66rem;
  letter-spacing:.12em; text-transform:uppercase; font-weight:700;
  color:var(--on); margin-bottom:4px }
.quiz .fb-why.bad .lbl{ color:var(--accent2) }

/* ----------------------------------------------------------------- controls */
/* the single vertical gap between stacked blocks in a lab */
.lab-body{ --stack:12px }

.row{display:flex; gap:14px; align-items:center; flex-wrap:wrap}
.row.center{justify-content:center}
.col{display:flex; flex-direction:column; gap:6px; align-items:center}
.grid2{display:grid; grid-template-columns:1fr 1fr; gap:16px}
.btnrow{display:flex; gap:8px; flex-wrap:wrap}
.btn{font:inherit; font-size:.85rem; font-weight:600; color:var(--txt); background:var(--panel2);
  border:1px solid var(--line2); border-radius:9px; padding:7px 14px; cursor:pointer; transition:.12s;
  display:inline-flex; align-items:center; gap:7px}
.btn:hover:not(:disabled){background:var(--panel3); border-color:var(--accent)}
.btn:active{transform:translateY(1px)}
/* --on-accent, not #fff. White on the dark theme's lighter teal measures
   2.79:1, under the 4.5:1 floor; the near-black it resolves to there measures
   6.55:1. The light theme's deeper teal keeps white, at 5.49:1. */
.btn.primary,.btn.sel{background:var(--accent); border-color:var(--accent); color:var(--on-accent)}
/* Hover has to put the accent background BACK. .btn:hover above carries the
   same specificity and sets --panel3, so without this an accent button turns
   near-white on hover while its text stays light: in the light theme that is
   white on #efefec, 1.15:1, an empty-looking button. A filter alone cannot fix
   it, because by then the background it is brightening is already the wrong
   one. */
.btn.primary:hover:not(:disabled),.btn.sel:hover:not(:disabled){
  background:var(--accent); border-color:var(--accent); filter:brightness(1.12)}
.btn.sm{padding:4px 10px; font-size:.78rem}
.btn:disabled{opacity:.4; cursor:not-allowed}
select,input[type=text],input[type=number],textarea{font:inherit; font-size:.85rem; font-family:var(--mono);
  color:var(--txt); background:var(--panel2); border:1px solid var(--line2); border-radius:8px; padding:6px 9px}
input[type=range]{accent-color:var(--accent); width:150px}
label.fld{display:flex; flex-direction:column; gap:4px; font-size:.72rem; color:var(--dim);
  text-transform:uppercase; letter-spacing:.07em; font-weight:700; min-width:0; max-width:100%}
label.fld select{max-width:100%}

.mini{font-size:.78rem; color:var(--dim)}
.mono{font-family:var(--mono)}
.big{font-family:var(--mono); font-size:1.5rem; font-weight:700}
.badge{font-family:var(--mono); font-size:.7rem; padding:2px 7px; border-radius:5px;
  background:var(--panel3); border:1px solid var(--line); color:var(--dim)}
.badge.on{background:color-mix(in srgb,var(--on) 22%,transparent); border-color:var(--on); color:var(--on)}
.badge.warn{background:color-mix(in srgb,var(--hot) 20%,transparent); border-color:var(--hot); color:var(--hot)}
.narrate{font-size:.88rem; padding:10px 14px; background:var(--panel3); border-radius:9px;
  border:1px solid var(--line); margin-top:12px; min-height:44px}
.narrate b{color:var(--hot)}
.narrate .lbl{font-family:var(--mono); font-size:.72rem; color:var(--dim); display:block;
  margin-bottom:3px; text-transform:uppercase; letter-spacing:.08em}

table.tt{border-collapse:collapse; font-family:var(--mono); font-size:.82rem; margin:6px 0}
table.tt th,table.tt td{border:1px solid var(--line); padding:5px 12px; text-align:center}
table.tt th{background:var(--panel2); color:var(--dim); font-size:.72rem; letter-spacing:.06em;
  text-transform:uppercase}
table.tt tr.hl td{background:color-mix(in srgb, var(--accent) 22%, transparent); color:var(--txt); font-weight:700}

/* ------------------------------------------- data-structure specific pieces */
.cells{display:flex; gap:4px; flex-wrap:wrap; align-items:flex-end}
.cell{min-width:46px; height:52px; border-radius:8px; border:1px solid var(--line2);
  background:var(--panel2); color:var(--txt); font-family:var(--mono); font-size:1rem; font-weight:700;
  display:flex; align-items:center; justify-content:center; transition:.18s; flex:none; position:relative}
.cell.empty{color:var(--dimmer); border-style:dashed; background:transparent}
.cell.hit{background:var(--accent); border-color:var(--accent); color:#fff}
.cell.moved{background:color-mix(in srgb,var(--hot) 30%,transparent); border-color:var(--hot)}
.cell.new{background:color-mix(in srgb,var(--on) 30%,transparent); border-color:var(--on)}
.cell.dim{opacity:.42}
.cellwrap{display:flex; flex-direction:column; align-items:center; gap:3px}
.cellwrap .ix{font-family:var(--mono); font-size:.62rem; color:var(--dimmer)}
.cellwrap .addr{font-family:var(--mono); font-size:.58rem; color:var(--dimmer)}
svg.viz{max-width:100%; height:auto; display:block; margin:0 auto}
svg.viz text{font-family:var(--mono); font-size:11px; fill:var(--txt)}
svg.viz .nd{fill:var(--panel2); stroke:var(--line2); stroke-width:1.6}
svg.viz .nd.hit{fill:var(--accent); stroke:var(--accent)}
svg.viz .nd.path{fill:color-mix(in srgb,var(--hot) 30%,transparent); stroke:var(--hot)}
svg.viz .nd.new{fill:color-mix(in srgb,var(--on) 30%,transparent); stroke:var(--on)}
svg.viz .lk{stroke:var(--line2); stroke-width:1.8; fill:none}
svg.viz .lk.hot{stroke:var(--hot); stroke-width:2.4}
.scrollx{overflow-x:auto; padding-bottom:4px}
.statrow{display:flex; gap:8px; flex-wrap:wrap; margin-top:var(--stack, 12px)}

/* ------------------------------------------------------------------ mobile */
@media (max-width:960px){
  body{font-size:16px}
  #toc{transform:translateX(-100%); transition:transform .22s; width:262px; box-shadow:var(--shadow)}
  #toc.open{transform:none}
  #navtoggle{display:inline-flex}
  /* The rail that used to share this rule is gone, and removing it took the
     declaration with it: a regex for #rail{...} matched the tail of
     "#top,#rail{left:0}", so {left:0} vanished and "#top," was welded onto
     the selector below. #top kept left:270px on a phone, which put the whole
     top bar in a hundred-pixel strip down the right-hand side, and it also
     inherited display:inline-flex from the rule it had been joined to. */
  #top{left:0}
  #top .home{display:inline-flex}
  main,footer.lessonfoot{margin-left:0; padding-left:16px; padding-right:16px}
  h1{font-size:2rem} h2{font-size:1.5rem}
  .grid2{grid-template-columns:1fr}
  .lab.wide{width:100%; margin-left:0}
}
@media (prefers-reduced-motion: reduce){
  html{scroll-behavior:auto}
  body.paged .step.active{animation:none}
  .cell{transition:none}
}

/* ---- w-codepad.css ---- */
/* ===== code scratchpad ==================================================== */
/* .btn and .cp-* set display, which would beat the browser's own rule for the
   hidden attribute, so say it once here and use hidden freely everywhere else. */
#w-codepad [hidden]{display:none !important}

#w-codepad .cp-grid{display:grid; grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);
  gap:14px; margin:14px 0 16px; align-items:start}

/* the editor and the frozen listing share one set of font metrics, so a line
   sits in the same place whichever of the two you are looking at */
#w-codepad .cp-ed,
#w-codepad .cp-listing{width:100%; font-family:var(--mono); font-size:.8rem; line-height:1.7;
  background:var(--panel2); border:1px solid var(--line2); border-radius:10px}
#w-codepad .cp-ed{min-height:230px; padding:10px 12px; resize:vertical; white-space:pre;
  overflow:auto; tab-size:2; color:var(--txt)}
#w-codepad .cp-listing{min-height:230px; padding:10px 0;
  position:relative}
#w-codepad .cp-line{display:flex; gap:10px; padding:0 12px; white-space:pre}
#w-codepad .cp-ln{color:var(--dimmer); min-width:2.2ch; text-align:right;
  -webkit-user-select:none; user-select:none; flex:none}
#w-codepad .cp-lt{color:var(--txt); white-space:pre}
#w-codepad .cp-line.cur{background:color-mix(in srgb, var(--accent) 24%, transparent)}
#w-codepad .cp-line.cur .cp-ln{color:var(--accent)}
#w-codepad .cp-line.err{background:color-mix(in srgb, var(--red) 20%, transparent)}
#w-codepad .cp-line.err .cp-ln{color:var(--red)}

/* the vocabulary, next to the box it describes */
#w-codepad .cp-api{background:var(--panel2); border:1px solid var(--line); border-radius:10px;
  padding:10px 14px 12px}
#w-codepad .cp-api-h{font-size:.68rem; font-weight:800; letter-spacing:.11em; text-transform:uppercase;
  color:var(--dim); margin:4px 0 6px}
#w-codepad .cp-api dl{margin:0}
#w-codepad .cp-api dt{font-family:var(--mono); font-size:.76rem; color:var(--accent); font-weight:700; margin-top:6px}
#w-codepad .cp-api dd{margin:0; font-size:.78rem; color:var(--dim); line-height:1.5}
#w-codepad .cp-api dd i{color:var(--txt); font-style:normal; font-family:var(--mono)}
#w-codepad .cp-api .cp-c{font-family:var(--mono); font-size:.68rem; color:var(--dimmer); display:block}
#w-codepad .cp-api p{margin:4px 0 0}

#w-codepad .cp-arr{margin:6px 0 4px; min-height:58px}
#w-codepad .cp-arr .cell{font-size:.9rem; padding:0 5px}
#w-codepad .cp-vars .badge{color:var(--txt)}

/* the error area, which is meant to be read rather than skipped */
#w-codepad .cp-err{margin-top:12px; padding:10px 14px; border-left:3px solid var(--red);
  border-radius:0 10px 10px 0; background:color-mix(in srgb, var(--red) 13%, transparent);
  font-size:.88rem; line-height:1.5}
#w-codepad .cp-errlab{display:block; font-family:var(--mono); font-size:.7rem; font-weight:800;
  letter-spacing:.1em; text-transform:uppercase; color:var(--red); margin-bottom:3px}
#w-codepad .cp-errmsg{color:var(--txt)}

#w-codepad .cp-outhead{font-size:.68rem; font-weight:800; letter-spacing:.11em; text-transform:uppercase;
  color:var(--dim); margin:18px 0 6px}
#w-codepad .cp-out{background:var(--panel2); border:1px solid var(--line); border-radius:10px;
  padding:8px 12px; font-size:.8rem}
#w-codepad .cp-outline{display:flex; gap:10px; align-items:baseline}
#w-codepad .cp-outline .cp-ln{font-family:var(--mono); font-size:.68rem; min-width:5.5ch; text-align:right}
#w-codepad .cp-outtext{font-family:var(--mono); color:var(--txt); white-space:pre-wrap; word-break:break-word}

#w-codepad .cp-ex{display:grid; grid-template-columns:repeat(auto-fill,minmax(210px,1fr)); gap:8px}
#w-codepad .cp-ex .btn{display:flex; flex-direction:column; align-items:flex-start; gap:2px;
  text-align:left; padding:8px 12px}
#w-codepad .cp-goal{font-size:.7rem; font-weight:400; color:var(--dim); line-height:1.35; white-space:normal}

@media (max-width:760px){
  #w-codepad .cp-grid{grid-template-columns:1fr}
  #w-codepad .cp-ed,#w-codepad .cp-listing{min-height:190px}
}
@media (max-width:420px){
  #w-codepad .cp-ed,#w-codepad .cp-listing{font-size:.74rem}
  #w-codepad .cp-ex{grid-template-columns:1fr}
}

/* ---- w-binsearch.css ---- */
/* ===== guess my number (Step 9 · halving before the tree) ===== */
.bs-head{display:flex; flex-direction:column; gap:8px; margin-bottom:8px}
.bs-hint{font-size:.8rem; color:var(--dim)}
.bs-intro{font-size:.86rem; color:var(--dim); margin:10px 0 12px}
.bs-intro b{color:var(--txt)}

.bs-barwrap{margin:16px 0 4px}
.bs-bar{position:relative; height:30px; border-radius:8px; background:var(--panel3);
  border:1px solid var(--line); overflow:hidden}
.bs-bar.gone{border-color:var(--red)}
.bs-alive{position:absolute; top:0; bottom:0; left:0; width:100%;
  background:color-mix(in srgb, var(--accent) 45%, transparent); transition:left .25s, width .25s}
.bs-alive.won{background:color-mix(in srgb, var(--on) 55%, transparent)}
.bs-mark{position:absolute; top:0; bottom:0; width:2px; background:var(--hot)}
.bs-ends{display:flex; justify-content:space-between; gap:10px; margin-top:5px;
  font-family:var(--mono); font-size:.68rem; color:var(--dimmer)}
.bs-ends .mid{color:var(--dim); text-align:center}

.bs-ask{font-family:var(--mono); font-size:1rem; color:var(--txt); margin:14px 0 10px}
.bs-ask b{font-size:1.6rem; font-weight:700; color:var(--accent)}

.bs-log{margin:12px 0}
.bs-log tr.waste td{background:color-mix(in srgb, var(--hot) 16%, transparent)}
.bs-log tr.good td{background:color-mix(in srgb, var(--on) 16%, transparent)}

.bs-arr{flex-wrap:nowrap}
.bs-arr .cell{min-width:54px; height:46px; font-size:.76rem}
.bs-arr.tight .cell{min-width:42px; height:42px; font-size:.64rem}

@media (max-width:520px){
  .bs-ask{font-size:.9rem}
  .bs-ask b{font-size:1.25rem}
  .bs-ends{font-size:.62rem}
}
@media (prefers-reduced-motion: reduce){
  .bs-alive{transition:none}
}

/* ---- w-play.css ---- */
/* ===== structure playground (Step 14) ===== */
.play-chain{display:flex; flex-wrap:wrap; gap:4px; align-items:center}
.play-chain .play-head{font-size:.68rem; text-transform:uppercase; letter-spacing:.08em;
  color:var(--dim); font-weight:700; margin-right:2px}
.play-chain .play-arrow{font-family:var(--mono); font-size:.8rem; color:var(--dimmer); align-self:center}

.play-buckets{display:grid; grid-template-columns:repeat(auto-fill,minmax(76px,1fr)); gap:5px}
.play-bucket{border:1px solid var(--line); border-radius:8px; padding:5px 7px; background:var(--panel2);
  min-height:46px}
.play-bucket.chain{border-color:var(--hot)}
.play-bucket.hit{border-color:var(--accent); background:color-mix(in srgb,var(--accent) 12%,transparent)}
.play-bucket .bn{font-family:var(--mono); font-size:.56rem; color:var(--dimmer)}
.play-bucket .bv{font-family:var(--mono); font-size:.74rem; font-weight:600}
.play-bucket .bv.on{color:var(--accent)}

.play-bars{margin:4px 0 6px}
.play-barrow{display:grid; grid-template-columns:104px 1fr 92px; gap:9px; align-items:center;
  width:100%; font:inherit; text-align:left; color:inherit; background:none; cursor:pointer;
  border:1px solid transparent; border-radius:8px; padding:3px 5px; margin-bottom:3px}
.play-barrow:hover{border-color:var(--line2); background:var(--panel2)}
.play-barrow .nm{font-size:.76rem; color:var(--dim); text-align:right; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap}
.play-barrow .na{font-size:.7rem; color:var(--dimmer)}
.play-barrow .num{font-family:var(--mono); font-size:.76rem; font-weight:700; white-space:nowrap}
.play-barrow .own{color:var(--hot); margin-left:2px}
.play-track{display:block; height:18px; border-radius:5px; background:var(--panel3); overflow:hidden}
.play-fill{display:block; height:100%; background:var(--accent); transition:width .25s}
.play-fill.cheap{background:var(--on)}
.play-fill.dear{background:var(--hot)}

.play-cant{list-style:none; margin:8px 0 0; padding:0; font-size:.78rem; color:var(--dim)}
.play-cant li{margin:.3em 0; padding-left:14px; position:relative}
.play-cant li::before{content:"×"; position:absolute; left:0; color:var(--red); font-weight:700}
.play-cant b{color:var(--txt)}

.play-log{margin-top:8px; border:1px solid var(--line); border-radius:9px; background:var(--panel2);
  }
.play-log .lrow{display:flex; gap:10px; align-items:baseline; flex-wrap:wrap;
  padding:5px 11px; border-bottom:1px solid var(--line); font-size:.76rem}
.play-log .lrow:last-child{border-bottom:none}
.play-log .lop{flex:1 1 150px; min-width:0; color:var(--dim)}
.play-log .lst{font-family:var(--mono); font-weight:700; color:var(--txt)}

@media (max-width:560px){
  .play-barrow{grid-template-columns:74px 1fr 66px; gap:6px}
  .play-barrow .nm{font-size:.7rem}
  .play-barrow .num{font-size:.68rem}
  .play-buckets{grid-template-columns:repeat(auto-fill,minmax(62px,1fr))}
}
@media (prefers-reduced-motion: reduce){
  .play-fill{transition:none}
}

/* ---------------------------------------------------- touch ergonomics ----
   Header controls need to be comfortably tappable, and the way back to the
   course list must not disappear on a phone — it used to be display:none
   below 960px, which left no route home. */
@media (max-width:960px){
  #top{gap:8px; padding:0 10px}
  .iconbtn{min-width:42px; min-height:42px; justify-content:center; padding:9px 12px}
  .langbtn{min-height:42px; padding:0 12px; font-size:.85rem}
  #crumb{font-size:.78rem}
}
/* Six controls plus a breadcrumb will not fit a phone on one line, so the
   breadcrumb drops to its own row and the page offset grows to match. */
@media (max-width:560px){
  #top{height:auto; min-height:50px; flex-wrap:wrap; row-gap:2px; padding:5px 8px}
  #crumb{order:9; flex-basis:100%; min-width:100%; font-size:.76rem; line-height:1.35;
    white-space:normal; max-height:2.7em; overflow:hidden}
  #crumb .ct{margin-right:6px}
    body.paged main{padding-top:96px}
}
@media (max-width:420px){
  #top{gap:5px}
  .iconbtn{min-width:40px; min-height:40px; padding:8px 8px}
  .langbtn{min-height:40px; padding:0 8px; font-size:.8rem}
}
/* stack the prev/next cards rather than squeezing two into 380px */
@media (max-width:520px){
  .stepnav{flex-direction:column; gap:8px}
  .stepnav a.ghost{display:none}
  .stepnav a.nx{text-align:left}
}
/* any wide diagram scrolls inside its own box instead of the page */
@media (max-width:760px){
  .dpwrap, .scrollx{-webkit-overflow-scrolling:touch}
  table.tt, table.pipe{font-size:.72rem}
  .lab-body{padding:14px 11px}
  .lab-head{padding:10px 11px; font-size:.72rem}
  .lab-foot{padding:10px 11px 12px}
}

/* ------------------------------------------------------- layout rhythm ----
   Two structural fixes that account for most of the alignment complaints.

   1. A .row that mixes stacked label.fld controls with bare buttons or badges
      used to centre them all against the tallest item, so the slider, the text
      input and the buttons each sat at a different height. Bottom-aligning the
      row puts every control on one line, and bottom-aligning inside each field
      keeps that true in browsers without :has().

   2. Consecutive rows inside a lab had no vertical separation, so stacked bit
      rows (A over B) touched. */
label.fld{justify-content:flex-end}
.row:has(> label.fld){align-items:flex-end}
.btnrow{align-items:center}

/* ---------------------------------------------------- spacing inside a lab
   One rule, not a list of pairs.

   This used to enumerate the combinations: .row + .row, .btnrow + .row,
   .statrow + .row, and so on. Every new kind of block needed another pair
   added by hand, and whoever added the block was never the person who
   remembered. Two of them shipped touching: a button row flush against the
   panel below it, and an editor flush against its own controls.

   So the rule is now the general one. Any two things stacked directly inside
   a lab get a gap, whatever they are, including kinds that do not exist yet.
   Only direct children: rows and grids lay their own contents out with gap,
   and adding margins inside them would fight that. */
.lab-body > * + *{ margin-top:var(--stack) }

/* An unclassed <div> inside a lab is a plain wrapper, never a layout container,
   so its children stack and need the same gap as anything else. Every touching
   pair found by measurement was inside one of these: the rule reached direct
   children of .lab-body and stopped, and a widget that wrapped two rows in a
   bare div slipped through. Inline flex and grid are excluded, since those space
   themselves with gap. */
.lab-body div:not([class]):not([style*="flex"]):not([style*="grid"]) > * + *{
  margin-top:var(--stack) }

/* the same inside a two-column layout's columns, where blocks also stack */
.lab-body .grid2 > div > * + *,
.lab-body .col > * + *{ margin-top:var(--stack) }

/* a caption belongs to the thing above it rather than floating between */
.lab-body .screen-note + *{ margin-top:var(--stack) }
.lab-body > .mini + *{ margin-top:8px }   /* a caption sits close to what it labels, not against it */

/* a value sitting after a bit row needs room to breathe, and a fixed minimum so
   stacked rows line their numbers up in a column */
.row > .big{margin-left:4px; min-width:4.5ch}

/* labels beside a control row should align to the control, not float mid-height */
.row > .swlbl{align-self:center; line-height:1.2}

/* dpwrap can appear nested rather than as a direct child, so it keeps its own */
.lab-body .dpwrap + *,
.lab-body * + .dpwrap{margin-top:var(--stack)}


/* ------------------------------------------------------- dig-deeper notes ----
   Readers arrive with very different starting points. A 12-year-old and a
   professional refreshing their memory should be able to read the same page,
   so anything that might be a jump gets an optional note attached rather than
   being explained inline for everyone.

   Three kinds, because "I am lost" and "I want more" are different needs:
     background  a prerequisite the main text assumed
     clarify     the same idea said a second way
     deeper      detail for the curious, safe to skip

   Built on <details>, so it opens with the keyboard, is announced correctly by
   a screen reader, and still works if the script never loads.               */
.dig{
  margin:14px 0 18px;
  border-left:2px solid var(--line2);
  padding-left:0;
  background:none;
}
.dig > summary{
  display:inline-flex; align-items:center; gap:8px;
  margin-left:14px; padding:5px 12px 5px 10px;
  font-family:var(--mono); font-size:.74rem; letter-spacing:.03em;
  color:var(--dim); background:var(--panel2);
  border:1px solid var(--line); border-radius:var(--r-full,999px);
  cursor:pointer; list-style:none; user-select:none;
  transition:border-color .14s, color .14s, background .14s;
}
.dig > summary::-webkit-details-marker{ display:none }
.dig > summary::before{
  content:"+"; font-weight:700; font-size:.9rem; line-height:1;
  color:var(--accent); width:9px; text-align:center;
}
.dig[open] > summary::before{ content:"\2212" }        /* a true minus sign */
.dig > summary:hover{ color:var(--txt); border-color:var(--accent); background:var(--panel3) }
.dig > summary:focus-visible{ outline:2px solid var(--accent); outline-offset:2px }

/* The step heading takes focus on every step change, so a screen reader lands on
   the new step instead of the top of the document. That is worth keeping. The
   box the browser draws round it is not: it appeared after every press of Next
   and sat there until the reader clicked something else.

   :focus-visible is the whole answer. A browser does not match it for a script
   moving focus to a heading, so the ring goes; it does match when focus arrives
   by keyboard, which is what the skip link does, so a keyboard reader still sees
   where they landed. Suppressing :focus outright would have taken that away. */
.step h1[tabindex="-1"]:focus:not(:focus-visible),
.step h2[tabindex="-1"]:focus:not(:focus-visible),
.chapter h1[tabindex="-1"]:focus:not(:focus-visible),
.chapter h2[tabindex="-1"]:focus:not(:focus-visible){ outline:none }
.dig[open]{ border-left-color:var(--accent) }

.dig-body{ padding:12px 0 2px 14px; max-width:66ch }
.dig-body > *:last-child{ margin-bottom:0 }
.dig-body p{ font-size:.96em; color:var(--dim) }
.dig-body .lab{ margin:14px 0 4px }

/* the kind shows as a quiet prefix, so a reader can tell at a glance whether a
   note is a rescue or a bonus */
.dig > summary .kind{
  text-transform:uppercase; letter-spacing:.1em; font-size:.63rem;
  color:var(--dimmer); padding-right:8px; margin-right:2px;
  border-right:1px solid var(--line2);
}
.dig[data-kind="deeper"]{ border-left-style:dashed }
.dig[data-kind="deeper"] > summary::before{ content:"\203A"; font-size:1rem }
.dig[data-kind="deeper"][open] > summary::before{ content:"\2304" }

@media (max-width:560px){
  .dig > summary{ margin-left:10px; font-size:.72rem }
  .dig-body{ padding-left:10px }
}
@media (prefers-reduced-motion: reduce){
  .dig > summary{ transition:none }
}

/* ============================================================================
   Code editor and program tracer.

   Shared, not per-course: the Software stream reuses it in every step, and
   Language Engineering runs learner programs through the same surface.

   How the highlighting works: a <pre> holds the coloured copy and does all the
   sizing, and a transparent <textarea> sits exactly on top of it with a visible
   caret. Because both hold the same text at the same metrics, the box grows to
   fit and the two layers can never drift apart. Nothing listens for scroll:
   the editor has no inner scrolling of its own, so there is nothing to keep in
   step. Long lines scroll the whole pair sideways as one unit.

   The line height is set in pixels on purpose. The error marker and the "line
   about to run" band are positioned by arithmetic, and that arithmetic has to
   be exact.
   ========================================================================= */
.ed{ --ed-lh:21px; --ed-pad:9px;
  border:1px solid var(--line); border-radius:var(--r-md); background:var(--panel2); overflow:hidden }
.ed:focus-within{ border-color:var(--accent) }
.ed-scroll{ overflow-x:auto; overflow-y:hidden; -webkit-overflow-scrolling:touch }
.ed-grid{ display:flex; min-width:max-content;
  font-family:var(--mono); font-size:.8rem; line-height:var(--ed-lh) }
.ed-gutter{ flex:0 0 auto; padding:var(--ed-pad) 8px var(--ed-pad) 10px; text-align:right;
  color:var(--dimmer); background:var(--panel3); border-right:1px solid var(--line);
  user-select:none; position:relative; z-index:2 }
.ed-gutter span{ display:block; height:var(--ed-lh) }
.ed-gutter span.on{ color:var(--on-accent); background:var(--accent); margin:0 -8px 0 -10px;
  padding:0 8px 0 10px; font-weight:600 }
.ed-gutter span.err{ color:var(--paper); background:var(--red); margin:0 -8px 0 -10px;
  padding:0 8px 0 10px; font-weight:600 }
.ed-code{ position:relative; flex:1 1 auto; min-width:22ch }
.ed-hl,.ed-ta{ margin:0; padding:var(--ed-pad) 12px; font:inherit; letter-spacing:0;
  white-space:pre; tab-size:2; border:0; background:none }
.ed-hl{ pointer-events:none; position:relative; z-index:1; min-height:calc(var(--ed-lh) + var(--ed-pad)*2) }
.ed-ta{ position:absolute; inset:0; z-index:2; width:100%; height:100%;
  color:transparent; caret-color:var(--accent); resize:none; overflow:hidden; outline:0;
  -webkit-text-fill-color:transparent }
.ed-ta::selection{ background:var(--accent); color:transparent; -webkit-text-fill-color:transparent }
.ed-band{ position:absolute; left:0; right:0; height:var(--ed-lh); z-index:0; pointer-events:none }
.ed-band.now{ background:color-mix(in srgb, var(--accent) 16%, transparent) }
.ed-band.bad{ background:color-mix(in srgb, var(--red) 18%, transparent) }
.ed[data-readonly="1"] .ed-ta{ caret-color:transparent }
.ed[data-readonly="1"]{ background:var(--panel3) }

/* what the program printed */
.ed-out{ margin-top:var(--stack, 12px); border:1px solid var(--line); border-radius:var(--r-md);
  background:var(--bg2); padding:9px 12px; font-family:var(--mono); font-size:.8rem;
  line-height:1.6; overflow:auto; max-width:100% }
.ed-out .lbl{ font-size:.7rem; color:var(--dim); text-transform:uppercase; letter-spacing:.08em;
  display:block; margin-bottom:5px }
.ed-out .oline{ white-space:pre-wrap; word-break:break-word }
.ed-out .oline.dim{ color:var(--dim) }
/* The picked-out line. Widgets were doing this inline with --panel3, which in
   the light theme is #efefec sitting on a #f7f7f5 panel: a difference of four
   levels of grey, invisible in practice. A tint of the accent reads in both
   themes because it differs in hue and not only in lightness, and the left bar
   survives even where a background is already coloured. */
.lit{ background:color-mix(in srgb, var(--accent) 15%, transparent);
  border-radius:4px; box-shadow:inset 2.5px 0 0 var(--accent) }
.ed-out .oerr{ color:var(--red); white-space:pre-wrap }
.ed-out .oerr b{ color:var(--red) }

/* pass or fail, always in words as well as colour */
.verdict{ display:flex; gap:9px; align-items:flex-start; margin-top:var(--stack, 12px); padding:10px 12px;
  border-radius:var(--r-md); border:1px solid var(--line); background:var(--panel3);
  font-size:.86rem }
.verdict .mk{ flex:0 0 auto; font-family:var(--mono); font-weight:700; font-size:1rem; line-height:1.3 }
.verdict.ok{ border-color:var(--on); background:color-mix(in srgb, var(--on) 10%, var(--panel3)) }
.verdict.ok .mk{ color:var(--on) }
.verdict.no{ border-color:var(--red); background:color-mix(in srgb, var(--red) 9%, var(--panel3)) }
.verdict.no .mk{ color:var(--red) }
.verdict code{ font-size:.82rem }

/* the memory view beside a running program */
.mem{ display:flex; flex-wrap:wrap; gap:8px; margin-top:var(--stack, 12px); min-height:52px }
.mem-box{ border:1px solid var(--line); border-radius:var(--r-sm); background:var(--panel3);
  padding:5px 9px; min-width:74px }
.mem-box .k{ font-family:var(--mono); font-size:.68rem; color:var(--dim); display:block;
  text-transform:none; letter-spacing:.02em }
.mem-box .v{ font-family:var(--mono); font-size:.85rem; color:var(--txt); word-break:break-all }
.mem-box.changed{ border-color:var(--accent); background:color-mix(in srgb, var(--accent) 12%, var(--panel3)) }
.mem-empty{ font-size:.84rem; color:var(--dim); padding:6px 2px }

/* scrubber */
.scrub{ display:flex; align-items:center; gap:10px; margin-top:var(--stack, 12px); flex-wrap:wrap }
.scrub input[type=range]{ flex:1 1 180px; min-width:140px }
.scrub .at{ font-family:var(--mono); font-size:.76rem; color:var(--dim); white-space:nowrap }

/* a fake app screen, for the steps that draw one */
.screen{ border:1px solid var(--line); border-radius:var(--r-md); background:var(--paper);
  padding:12px 14px; min-height:96px }
.screen.plain{ font-family:var(--sans) }
.screen h4{ margin:0 0 8px; font-size:1rem }
.screen .qrow{ display:flex; align-items:center; gap:9px; padding:6px 0;
  border-bottom:1px dashed var(--line); font-size:.9rem }
.screen .qrow:last-child{ border-bottom:0 }
.screen .qrow.done .ttl{ text-decoration:line-through; color:var(--dim) }
.screen .qrow .ttl{ flex:1 1 auto }
.screen .stale{ outline:2px dashed var(--red); outline-offset:3px }
.screen-note{ font-size:.76rem; color:var(--dim); font-family:var(--mono); margin-top:6px }
/* Unstyled, for the step that takes the style layer away.

   The revert is scoped to the CONTENTS. Applying it to the container as well
   stripped the container's own outer margin, so the panel jumped up and touched
   the buttons above it the moment a reader flipped Style off. That gap is page
   chrome and has nothing to do with the demonstration: what the step is showing
   is that the content inside loses its styling, not that the lab loses its
   layout. */
.screen.nostyle *{ all:revert; font-family:serif; font-size:16px; color:#000; background:#fff }
.screen.nostyle{ font-family:serif; font-size:16px; color:#000; background:#fff;
  border-color:#999; border-radius:0; box-shadow:none }

@media (max-width:700px){
  .ed-grid{ font-size:.76rem }
  .ed-code{ min-width:18ch }
  .mem-box{ min-width:64px }
}

/* Tap targets. The chrome buttons were given a mobile minimum long ago and the
   buttons inside labs never were, so every lab control on the site sat at 38px
   against a 40px floor. Measured, not eyeballed: see the note in SPEC 7. */
@media (max-width:760px){
  .btn{ min-height:40px; padding:8px 14px }
  .btn.mini{ min-height:40px; padding:6px 10px }
  .lab-body input[type=text],
  .lab-body input[type=number],
  .lab-body select{ min-height:40px }
  /* a range input needs room round the thumb, not a taller track */
  .lab-body input[type=range]{ padding:12px 0 }
  .cell{ min-height:40px }
}

/* The copyright, at the foot of the main column, under whichever step is open.
   footer.lessonfoot cannot carry it: the paged reader hides that, because a
   footer under one step of twenty is a footer nobody reaches. */
.bodyfoot{ margin:34px 0 60px; padding-top:16px; border-top:1px solid var(--line);
  color:var(--dimmer); font-size:.76rem; line-height:1.5 }

/* ---------------------------------------------------- what to do, up front
   Every lab was laid out head, widget, guidance: the instructions sat below
   the thing they instruct. A reader who already knows what a register file is
   does not mind. A twelve-year-old meets six controls with no idea which to
   press, and leaves.

   .lab-try goes ABOVE the widget and answers only two questions: what do I
   press first, and what should I expect to see. What to NOTICE stays in
   .lab-foot, where it belongs, because it only means anything after you have
   pressed something. */
.lab-try{ padding:9px 16px 10px; font-size:.85rem; color:var(--dim);
  background:var(--panel3); border-bottom:1px dashed var(--line) }
.lab-try b{ color:var(--txt) }
.lab-try .go{ font-family:var(--mono); font-size:.7rem; letter-spacing:.09em;
  text-transform:uppercase; color:var(--accent); font-weight:700; display:block; margin-bottom:3px }


/* ------------------------------------------------- no scrollbars inside a widget
   A panel that scrolls inside itself hides its own content. A reader looking at a
   file-descriptor table sees six rows and a scrollbar and has no idea whether the
   interesting one is row seven, because the widget has quietly become a window
   onto something bigger.

   So: bound the DATA, not the height. A panel shows everything it holds, and a
   thing that could grow without limit (a log, a trace) keeps only as many entries
   as are worth showing and says so.

   The one exception is sideways: a table genuinely wider than a phone gets its own
   horizontal scroller, because the alternative is a page that scrolls sideways as
   a whole, which is worse. Even then it should fit on a desktop. */
.lab-body [style*="max-height"]{ max-height:none !important }
.ed-out, .mem, .screen, .listing, .console{ max-height:none }

/* what a capped panel says instead of hiding rows behind a scrollbar */
.more-note{ font-family:var(--mono); font-size:.72rem; color:var(--dim); padding:6px 2px 0;
  border-top:1px dashed var(--line); margin-top:6px }

/* a wide table should fit before it scrolls: tighten it rather than clip it */
.lab-body table.tt{ font-size:.78rem }
.lab-body table.tt th,.lab-body table.tt td{ padding:4px 8px }
@media (max-width:760px){
  .lab-body table.tt{ font-size:.72rem }
  .lab-body table.tt th,.lab-body table.tt td{ padding:3px 5px }
}


/* ------------------------------------------------- nothing wider than the column
   Removing the fixed heights from the panels also removed their overflow, and
   overflow was doing two jobs. Without it a long console line or a wide table
   stopped being contained sideways and pushed the whole lab card out past the
   right edge of the page, taking its text and buttons with it.

   So overflow comes back, but with no max-height: the panel grows downwards to
   fit everything, which is what a reader needs, and scrolls only sideways, which
   is the one direction where the alternative is worse.

   The guards below are the belt to that brace. A grid or flex child refuses to
   shrink below its content unless it is told it may, which is what min-width:0
   is for, and it is the usual cause of a layout that will not fit. */
.lab, .lab-body{ max-width:100%; min-width:0 }
.lab-body > *{ max-width:100%; min-width:0 }
.lab-body pre, .lab-body table{ max-width:100% }
.lab-body .grid2, .lab-body .row, .lab-body .btnrow, .lab-body .cells{ min-width:0 }
.lab-body .grid2 > *{ min-width:0 }
.ed, .ed-code{ min-width:0; max-width:100% }
.screen{ max-width:100%; overflow-x:auto }
.mem{ max-width:100% }

/* A table too wide for the column scrolls inside its own box rather than
   dragging the page sideways. */
.lab-body table{ display:block; overflow-x:auto; white-space:nowrap }
.lab-body table.tt{ width:auto }


/* the route home, first item in the contents rail */
.tochome{ display:block; margin:0 0 14px; padding:9px 14px; font-size:.82rem; font-weight:650;
  color:var(--dim); text-decoration:none; border-bottom:1px solid var(--line) }
.tochome:hover{ color:var(--accent); background:var(--panel2); text-decoration:none }
@media (max-width:960px){
  /* in the drawer it is still the first thing, and still the way out */
  .tochome{ margin-bottom:10px }
}
