/* Shared lab chrome. The styling every lab page has in common: theme tokens,
   layout, tabs, callouts, the plain-English on-ramp, diagrams and print rules.
   This was thirteen byte-identical copies, which is how the typography drifted:
   a callout with no size rule of its own needed thirteen separate patches, and
   one lab shipped with a stale copy because it was generated from an older
   snapshot. Each lab still carries its own <style> after this one, holding only
   the rules that lab actually needs. */
/* self-hosted, same subsets the portfolio serves, no external requests */
  @font-face{font-family:'Inter';font-style:normal;font-weight:400 600;font-display:swap;src:url(fonts/inter-normal-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Inter';font-style:normal;font-weight:400 600;font-display:swap;src:url(fonts/inter-normal-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Newsreader';font-style:normal;font-weight:400 500;font-display:swap;src:url(fonts/newsreader-normal-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Newsreader';font-style:normal;font-weight:400 500;font-display:swap;src:url(fonts/newsreader-normal-latin-ext.woff2) format('woff2');unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
:root{
    /* light, the portfolio's paper palette */
    --bg:#FBFAF7; --panel:#FFFFFF; --panel2:#F4F1EA; --line:#E4E0D8; --line2:#D8D3C9;
    --text:#14181C; --muted:#565C63; --dim:#63696F;
    --blue:#34618F; --teal:#1F7A75; --violet:#6B4F9E; --amber:#96601C;
    --green:#2C6B52; --red:#A33A41; --orange:#A2551F;
    --gcpblue:#2D6CB5; --awsorange:#96601C; --azblue:#0E7490;
    --wire:#B5AFA4; --dot:#ECE8DF; --sel:#F4EDE0;
    --n-blue:#EAF0F7; --n-violet:#F1EDF8; --n-teal:#E6F2F0; --n-amber:#F9F0E0;
    --regA:#5E9C87; --regB:#7FA3C6;
    --exam-text:#7A4E06; --plain-text:#14524F; --alert-text:#8C2F36;
    /* One accent for everything the reader can act on: links, the active tab,
       the focus ring. It was three (amber tabs, teal links, a violet eyebrow) 
       none of which meant anything. --accent was also declared only in
       styles.css, which the labs do not load, so eight of them asked for a
       colour that did not exist and silently got body grey. */
    --accent:#1F7A75; --accent-soft:#E6F2F0; --accent-line:#9CC9C4;
    --display:'Newsreader',Georgia,'Times New Roman',serif;
    --sans:'Inter','Helvetica Neue',Helvetica,Arial,sans-serif;
    --mono:ui-monospace,SFMono-Regular,'SF Mono',Menlo,monospace;
  }
:root[data-theme="dark"]{
    --bg:#16191D; --panel:#1C2025; --panel2:#212529; --line:#2C3137; --line2:#3A4046;
    --text:#E8E4DC; --muted:#A8ADB4; --dim:#8B9198;
    --blue:#7FB0E0; --teal:#4BB3AC; --violet:#B49AE8; --amber:#DDA053;
    --green:#6FBF95; --red:#E08A8A; --orange:#E5A173;
    --gcpblue:#7FB0E0; --awsorange:#DDA053; --azblue:#6CC5E0;
    --wire:#4E555C; --dot:#23272C; --sel:#2B2721;
    --n-blue:#1E2630; --n-violet:#241F2E; --n-teal:#17282A; --n-amber:#2A2419;
    --regA:#3F6F63; --regB:#3D5A74;
    --exam-text:#E6CFA4; --plain-text:#A8DDD6; --alert-text:#EDB0B0;
    --accent:#4BB3AC; --accent-soft:#17282A; --accent-line:#2F6D68;
  }
*{box-sizing:border-box; margin:0; padding:0}
html,body{background:var(--bg); color:var(--text); font:15.5px/1.62 var(--sans); -webkit-font-smoothing:antialiased}
body{min-height:100vh; padding:26px 20px 60px}
.wrap{max-width:1280px; margin:0 auto}
.eyebrow{font-family:var(--mono); font-size:11px; letter-spacing:.1em; color:var(--dim); margin-bottom:10px}
h1{font-family:var(--display); font-size:clamp(26px,3.4vw,38px); font-weight:500; letter-spacing:-.018em; line-height:1.05}
h1 .thin{color:var(--muted); font-weight:400}
.sub{color:var(--muted); font-size:14.5px; margin-top:8px; max-width:68ch; line-height:1.72}
.tabs{display:flex; gap:8px; margin:22px 0 18px; flex-wrap:wrap}
.tab{cursor:pointer; font-family:var(--mono); font-size:12.5px; color:var(--muted);
    background:var(--panel2); border:1px solid var(--line2); border-radius:8px; padding:9px 16px; transition:.15s}
.tab:hover{color:var(--text); border-color:var(--muted)}
.tab.on{color:var(--accent); border-color:var(--accent-line); background:var(--accent-soft)}
.tab:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.pane{display:none}
.pane.on{display:block; animation:fade .25s ease}
@keyframes fade{from{opacity:0; transform:translateY(4px)} to{opacity:1; transform:none}}
.card{background:var(--panel); border:1px solid var(--line); border-radius:10px; padding:16px 18px}
h2.sec{font-size:12px; font-family:var(--mono); letter-spacing:.18em; text-transform:uppercase; color:var(--dim); margin-bottom:12px}

.lab-foot{margin-top:34px; padding-top:16px; border-top:1px solid var(--line);
    font-size:12.5px; color:var(--muted); text-align:center}
.lab-foot a{color:var(--teal); text-decoration:none;
    border-bottom:1px solid color-mix(in srgb, var(--teal) 40%, transparent)}
.lab-foot a:hover{border-bottom-color:var(--teal)}
.lab-foot a:focus-visible{outline:2px solid var(--teal); outline-offset:2px; border-radius:3px}
/* ---- pillars ---- */
  .pillars-layout{display:grid; grid-template-columns:minmax(280px,1fr) minmax(0,1.7fr); gap:16px; align-items:start}
@media (max-width:900px){.pillars-layout{grid-template-columns:1fr}}
.pillar-list{display:flex; flex-direction:column; gap:8px}
.pillar{cursor:pointer; text-align:left; background:var(--panel2); border:1px solid var(--line2); border-radius:8px;
    padding:11px 14px; color:var(--text); font-family:inherit; font-size:14px; font-weight:500; transition:.15s;
    display:flex; justify-content:space-between; align-items:center; gap:10px}
.pillar small{display:block; color:var(--muted); font-weight:400; font-size:11.5px; margin-top:2px}
.pillar .tag{font-family:var(--mono); font-size:10px; color:var(--dim); letter-spacing:.1em; flex:0 0 auto}
.pillar:hover{border-color:var(--teal)}
.pillar.on{border-color:var(--amber); background:var(--sel)}
.pillar:focus-visible{outline:2px solid var(--teal); outline-offset:2px}
.detail h3{font-family:var(--display); font-size:21px; font-weight:500; letter-spacing:-.012em; margin-bottom:4px}
.detail .cat{font-family:var(--mono); font-size:11px; color:var(--teal); letter-spacing:.14em; text-transform:uppercase; margin-bottom:10px}
.detail p.lead{color:var(--muted); font-size:13.5px; line-height:1.65; margin-bottom:14px}
.detail h4{font-size:12px; font-family:var(--mono); letter-spacing:.16em; text-transform:uppercase; color:var(--dim); margin:16px 0 8px}
.kv{display:flex; flex-direction:column; gap:8px}
.kv .row{display:grid; grid-template-columns:170px 1fr; gap:12px; font-size:13px; line-height:1.55; padding:8px 10px; background:var(--panel2); border:1px solid var(--line); border-radius:7px}
.kv .k{color:var(--teal); font-weight:500}
.kv .v{color:var(--muted)}
.kv .v b{color:var(--text); font-weight:500}
@media (max-width:640px){.kv .row{grid-template-columns:1fr}}
.exam-line{border-left:2px solid var(--orange); padding:8px 12px; margin-top:8px; font-family:var(--mono); font-size:12px; color:var(--exam-text); line-height:1.6; background:rgba(251,146,60,.05); border-radius:0 7px 7px 0}
.exam-line b{color:var(--orange); font-weight:500}
.plain-line{border-left:2px solid var(--teal); padding:9px 12px; margin:0 0 14px; font-size:13px; color:var(--plain-text); line-height:1.65; background:rgba(45,212,191,.05); border-radius:0 7px 7px 0}
.plain-line b{color:var(--teal); font-weight:500}
.plain-inline{display:block; margin-bottom:9px; padding:8px 11px; border-left:2px solid var(--teal); background:rgba(45,212,191,.05); border-radius:0 7px 7px 0; color:var(--plain-text)}
/* ---- DR ---- */
  .dr-layout{display:grid; grid-template-columns:minmax(0,1.7fr) minmax(300px,1fr); gap:16px; align-items:start}
@media (max-width:960px){.dr-layout{grid-template-columns:1fr}}
.strats{display:grid; grid-template-columns:1fr 1fr; gap:8px}
.strat{cursor:pointer; text-align:left; border:1px solid var(--line2); background:var(--panel2); color:var(--text);
    border-radius:8px; padding:9px 11px; font-family:inherit; font-size:13px; font-weight:500; transition:.15s}
.strat small{display:block; color:var(--muted); font-weight:400; font-size:11px; margin-top:2px}
.strat:hover{border-color:var(--teal)}
.strat.on{border-color:var(--amber); background:var(--sel)}
.gauges{margin-top:14px; display:flex; flex-direction:column; gap:10px}
.gauge label{font-family:var(--mono); font-size:11px; color:var(--dim); letter-spacing:.14em; display:flex; justify-content:space-between}
.gauge label b{color:var(--text); font-weight:500; letter-spacing:0}
.bar{height:8px; background:var(--panel2); border:1px solid var(--line); border-radius:99px; margin-top:5px; overflow:hidden}
.bar i{display:block; height:100%; border-radius:99px; transition:width .6s ease, background .3s}
.btn{cursor:pointer; font-family:var(--mono); font-size:12px; color:var(--text); background:transparent; border:1px solid var(--line2); border-radius:6px; padding:7px 14px}
.btn:hover{border-color:var(--muted)}
.btn.primary{border-color:var(--red); color:var(--red)}
.btn.primary:hover{background:rgba(248,113,113,.1)}
.drlog{font-family:var(--mono); font-size:12px; line-height:1.55; display:flex; flex-direction:column; gap:6px; margin-top:12px; max-height:190px; overflow-y:auto}
.drlog div{color:var(--muted); animation:fade .25s ease}
.drlog div.ok{color:var(--green)}
.drlog div.bad{color:var(--red)}
.drlog div b{color:var(--text)}
.rnode rect{transition:opacity .4s, stroke .4s}
.rnode text{transition:opacity .4s}
.dimmed{opacity:.22}
.halfdim{opacity:.55}
.flow{stroke-dasharray:6 6; animation:flowmove 1s linear infinite}
@keyframes flowmove{to{stroke-dashoffset:-24}}
@media (prefers-reduced-motion: reduce){.flow{animation:none}}
/* ---- translator ---- */
  .search{width:100%; background:var(--panel2); border:1px solid var(--line2); color:var(--text); border-radius:8px;
    font-family:var(--mono); font-size:13px; padding:10px 14px; margin-bottom:12px}
.search:focus{outline:2px solid var(--teal); outline-offset:1px}
.cats{display:flex; gap:7px; flex-wrap:wrap; margin-bottom:14px}
.catf{cursor:pointer; font-family:var(--mono); font-size:11px; color:var(--muted); background:var(--panel2);
    border:1px solid var(--line2); border-radius:99px; padding:4px 11px}
.catf.on{color:var(--teal); border-color:var(--teal)}
table.map{width:100%; border-collapse:collapse; font-size:13px}
table.map th{font-family:var(--mono); font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--dim); text-align:left; padding:8px 10px; border-bottom:1px solid var(--line2)}
table.map td{padding:9px 10px; border-bottom:1px solid var(--line); vertical-align:top; line-height:1.5}
table.map td.aws{color:var(--awsorange); font-weight:500; white-space:normal}
table.map td.gcp{color:var(--gcpblue); font-weight:500}
table.map td.az{color:var(--azblue); font-weight:500}
table.map td.note{color:var(--muted); font-size:12.5px}
table.map td.catcell{font-family:var(--mono); font-size:10.5px; color:var(--dim); text-transform:uppercase; letter-spacing:.08em; white-space:nowrap}
table.map td.trig{color:var(--text); font-weight:500}
table.map td.ans{color:var(--teal); font-weight:500}
.drill-q{font-family:var(--display); font-size:20px; font-weight:500; line-height:1.3; margin-bottom:10px}
.drill-a{border-left:2px solid var(--teal); background:var(--n-teal); padding:10px 13px; border-radius:0 7px 7px 0; margin-top:10px}
.drill-a b{color:var(--teal)}
/* ---- diffs ---- */
  .diff-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(520px,1fr)); gap:12px}
.diff{background:var(--panel); border:1px solid var(--line); border-radius:10px; padding:15px 17px}
.diff h3{font-family:var(--display); font-size:17px; font-weight:500; letter-spacing:-.01em; margin-bottom:8px}
.diff .vs{display:grid; grid-template-columns:repeat(3,1fr); gap:10px; margin:10px 0}
@media (max-width:900px){.diff .vs{grid-template-columns:1fr}}
.diff .side{background:var(--panel2); border:1px solid var(--line); border-radius:7px; padding:9px 11px; font-size:12.5px; line-height:1.55; color:var(--muted)}
.diff .side b{display:block; font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; margin-bottom:5px; font-weight:500}
.diff .side.aws b{color:var(--awsorange)}
.diff .side.gcp b{color:var(--gcpblue)}
.diff .side.az b{color:var(--azblue)}
.diff p.why{font-size:12.5px; color:var(--muted); line-height:1.6}
.diff p.why b{color:var(--text); font-weight:500}
/* ---- diagrams ---- */
  .diagram{margin:2px 0 14px; background:var(--panel2); border:1px solid var(--line); border-radius:9px; padding:12px 12px 10px}
.diagram svg{width:100%; height:auto; display:block}
.diagcap{font-size:12.5px; color:var(--muted); line-height:1.6; margin-top:9px; padding-top:9px; border-top:1px dashed var(--line2)}
.diagcap b{color:var(--teal); font-weight:500}
.diff .diagram{margin:10px 0 12px; padding:10px}
.diff .diagcap{font-size:12px}
/* ---- journey ---- */
  .jour-layout{display:grid; grid-template-columns:minmax(0,1.75fr) minmax(290px,1fr); gap:16px; align-items:start}
@media (max-width:980px){.jour-layout{grid-template-columns:1fr}}
.jnode{cursor:pointer}
.jnode rect{transition:opacity .35s, stroke .35s}
.jnode.dim{opacity:.3}
.jnode.on rect{stroke:var(--amber); stroke-width:2.2}
.jwire{transition:opacity .35s, stroke .35s}
.jwire.lit{stroke:var(--amber); opacity:1}
#packet{transition:transform .7s cubic-bezier(.4,.1,.3,1)}
@media (prefers-reduced-motion: reduce){#packet{transition:none}}
.jstep .role{font-family:var(--mono); font-size:11px; color:var(--teal); letter-spacing:.14em; text-transform:uppercase; margin-bottom:7px}
.jstep h3{font-family:var(--display); font-size:19px; font-weight:500; letter-spacing:-.01em; margin-bottom:8px}
.jstep p.say{font-size:13.5px; color:var(--plain-text); line-height:1.7; margin-bottom:11px}
.jstep p.tech{font-size:12.5px; color:var(--muted); line-height:1.6; margin-bottom:11px}
.jstep p.tech b{color:var(--text); font-weight:500}
.jstep .without{border-left:2px solid var(--red); background:rgba(248,113,113,.06); padding:8px 11px;
    border-radius:0 7px 7px 0; font-size:12.5px; color:var(--alert-text); line-height:1.6}
.jstep .without b{color:var(--red); font-weight:500}
.jlist{display:flex; flex-direction:column; gap:6px}
.jitem{cursor:pointer; text-align:left; background:var(--panel2); border:1px solid var(--line2); color:var(--muted);
    border-radius:7px; padding:8px 11px; font-family:inherit; font-size:12.5px; display:flex; gap:10px; align-items:baseline; width:100%}
.jitem .n{font-family:var(--mono); font-size:10.5px; color:var(--dim); flex:0 0 auto}
.jitem.on{border-color:var(--amber); color:var(--text); background:var(--sel)}
.jitem:hover{border-color:var(--teal)}
.jitem:focus-visible{outline:2px solid var(--teal); outline-offset:2px}
.prog{height:4px; background:var(--panel2); border:1px solid var(--line); border-radius:99px; overflow:hidden; margin:12px 0 0}
.prog i{display:block; height:100%; background:var(--amber); transition:width .45s ease}
/* ---- network simulator ---- */
  .sim-layout{display:grid; grid-template-columns:minmax(0,1.75fr) minmax(285px,1fr); gap:16px; align-items:start}
@media (max-width:980px){.sim-layout{grid-template-columns:1fr}}
.segmented{display:flex; gap:6px; flex-wrap:wrap; margin-bottom:14px}
.seg{cursor:pointer; font-family:var(--mono); font-size:12px; color:var(--muted);
    background:var(--panel2); border:1px solid var(--line2); border-radius:7px; padding:7px 12px}
.seg:hover{border-color:var(--teal); color:var(--text)}
.seg.on{color:var(--amber); border-color:var(--amber); background:var(--sel)}
.seg:focus-visible{outline:2px solid var(--teal); outline-offset:2px}
.scene{display:none}
.scene.on{display:block}
.stage{position:relative; height:392px; background:var(--panel2); border:1px solid var(--line); border-radius:9px; overflow:hidden}
.nd{position:absolute; transform:translate(-50%,-50%); padding:8px 13px; border-radius:7px; text-align:center;
    font-size:12.5px; font-weight:500; color:var(--text); background:var(--panel); border:1.5px solid var(--line2);
    z-index:10; white-space:nowrap; transition:border-color .3s, box-shadow .3s}
.nd small{display:block; font-family:var(--mono); font-size:10px; color:var(--muted); font-weight:400; margin-top:2px}
.nd.net{border-color:var(--blue)}
.nd.gw{border-color:var(--violet)}
.nd.vm{border-color:var(--teal)}
.nd.nat{border-color:var(--amber)}
.nd.db{border-color:var(--green)}
.nd.hit{box-shadow:0 0 0 3px var(--sel)}
.nd.deny{border-color:var(--red); box-shadow:0 0 0 3px rgba(248,113,113,.18)}
.zone{position:absolute; border:1.5px dashed var(--line2); border-radius:9px}
.zone.pub{border-color:var(--green)}
.zone.priv{border-color:var(--red)}
.zone.fw{border-color:var(--red)}
.zone .zl{position:absolute; top:-9px; left:12px; padding:0 6px; background:var(--panel2);
    font-family:var(--mono); font-size:10px; letter-spacing:.1em; text-transform:uppercase; color:var(--muted)}
.pkt{position:absolute; width:14px; height:14px; border-radius:50%; transform:translate(-50%,-50%);
    background:var(--amber); box-shadow:0 0 10px var(--amber); z-index:60; opacity:0;
    transition:left .65s linear, top .65s linear, background .25s, box-shadow .25s}
@media (prefers-reduced-motion: reduce){.pkt{transition:background .25s}}
.term{background:var(--panel2); border:1px solid var(--line); border-radius:9px; padding:12px;
    font-family:var(--mono); font-size:11.5px; line-height:1.65; height:158px; overflow-y:auto; margin-top:12px}
.term div{margin-bottom:4px}
.term .ok{color:var(--green)}
.term .no{color:var(--red)}
.term .i{color:var(--muted)}
.term b{color:var(--text); font-weight:500}
.toggles{display:flex; flex-direction:column; gap:9px; margin-bottom:6px}
.toggles label{display:flex; align-items:center; gap:9px; font-size:13px; color:var(--muted); cursor:pointer}
.toggles input{accent-color:var(--amber); width:16px; height:16px}
.simnote{font-size:12.5px; color:var(--muted); line-height:1.6; margin-top:10px}
.simnote b{color:var(--teal); font-weight:500}
.cidr-out .r{display:flex; justify-content:space-between; gap:12px; padding:7px 0; border-bottom:1px dashed var(--line); font-size:13px; color:var(--muted)}
.cidr-out .r:last-child{border-bottom:0}
.cidr-out .r b{font-family:var(--mono); color:var(--text); font-weight:500}
input[type=range]{width:100%; accent-color:var(--amber)}
input.ip{width:100%; background:var(--panel2); border:1px solid var(--line2); color:var(--text); border-radius:7px;
    font-family:var(--mono); font-size:13px; padding:9px 12px}
input.ip.bad{border-color:var(--red)}
/* ---- OSI ---- */
  .osi-layout{display:grid; grid-template-columns:minmax(255px,1fr) minmax(0,1.65fr); gap:16px; align-items:start}
@media (max-width:980px){.osi-layout{grid-template-columns:1fr}}
.osi-stack{display:flex; flex-direction:column; gap:5px}
.osi-l{cursor:pointer; text-align:left; border:1px solid var(--line2); background:var(--panel2); color:var(--text);
    border-radius:7px; padding:9px 12px; font-family:inherit; font-size:13px; font-weight:500; display:flex; gap:10px; width:100%}
.osi-l .lv{font-family:var(--mono); font-size:10.5px; color:var(--dim); flex:0 0 20px; padding-top:2px}
.osi-l small{display:block; color:var(--muted); font-size:11.5px; font-weight:400; margin-top:3px}
/* What the data is called at this layer. The seven-layer reference explained
   what each layer decides and never what the request physically is by then,
   which is the part that makes encapsulation concrete. */
.osi-l .osi-unit{margin-left:auto; align-self:flex-start; flex:0 0 auto;
  font-family:var(--mono); font-size:9.5px; letter-spacing:.06em; color:var(--dim);
  border:1px solid var(--line2); border-radius:99px; padding:2px 7px; font-weight:400}
.osi-l.on .osi-unit{color:var(--amber); border-color:var(--amber)}
.osi-l:hover{border-color:var(--teal)}
.osi-l.on{border-color:var(--amber); background:var(--sel)}
.osi-l:focus-visible{outline:2px solid var(--teal); outline-offset:2px}
.vs2{display:grid; grid-template-columns:1fr 1fr; gap:10px; margin:12px 0}
@media (max-width:600px){.vs2{grid-template-columns:1fr}}
.vs2 .col{background:var(--panel2); border:1px solid var(--line); border-radius:7px; padding:10px 12px;
    font-size:12.5px; line-height:1.6; color:var(--muted)}
.vs2 .col b{display:block; font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; margin-bottom:6px; font-weight:500}
.vs2 .col.aws b{color:var(--awsorange)}
.vs2 .col.gcp b{color:var(--gcpblue)}
table.osi{width:100%; border-collapse:collapse; font-size:12.5px}
table.osi th{font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; text-transform:uppercase;
    color:var(--dim); text-align:left; padding:7px 9px; border-bottom:1px solid var(--line2)}
table.osi td{padding:8px 9px; border-bottom:1px solid var(--line); vertical-align:top; line-height:1.55; color:var(--muted)}
table.osi td b{color:var(--text); font-weight:500}
table.osi tr:last-child td{border-bottom:0}
.code{background:var(--panel2); border:1px solid var(--line); border-radius:8px; padding:12px; overflow-x:auto; margin-top:10px}
.code pre{margin:0}
.code code{font-family:var(--mono); font-size:11.5px; line-height:1.75; color:var(--text); white-space:pre}
.tk-c{color:var(--dim); font-style:normal}
.tk-k{color:var(--teal); font-style:normal}
.tk-s{color:var(--amber); font-style:normal}
.cmd{font-family:var(--mono); font-size:12px; background:var(--panel2); border:1px solid var(--line);
    border-left:2px solid var(--teal); border-radius:0 7px 7px 0; padding:8px 11px; color:var(--plain-text); margin-top:4px}
/* ---- plain-English on-ramp above every simulation ---- */
  .simplain{border:1px dashed var(--line2); border-radius:11px; padding:12px 14px; margin:0 0 14px;
    background:var(--panel2); font-size:12.5px; line-height:1.68}
.simplain .sp-row{display:flex; gap:10px; margin-bottom:8px}
.simplain .sp-row:last-child{margin-bottom:0}
.simplain .sp-k{flex:none; width:76px; font-family:var(--mono); font-size:9.5px; letter-spacing:.08em;
    text-transform:uppercase; color:var(--muted); padding-top:3px; text-align:right}
.simplain .sp-words{display:flex; flex-wrap:wrap; gap:6px}
.simplain .sp-w{border:1px solid var(--line2); border-radius:7px; padding:2px 8px; font-size:11.5px;
    background:var(--panel); color:var(--muted)}
.simplain .sp-w b{font-family:var(--mono); font-size:10.5px; color:var(--amber); font-weight:500}
@media (max-width:640px){.simplain .sp-row{flex-direction:column; gap:3px}
    .simplain .sp-k{width:auto; text-align:left}}
/* ---- shared row / note utilities used by the simulations ---- */
  .lzok{color:var(--green); font-size:12.5px; line-height:1.65}
.lzbad{color:var(--red); font-size:12.5px; line-height:1.65}
.lzwarn{color:var(--amber); font-size:12.5px; line-height:1.65}
.lzrow{display:flex; gap:9px; align-items:flex-start; margin-bottom:8px; font-size:12.5px; line-height:1.6}
.lzrow .lzmark{flex:none; width:15px; font-weight:700; font-family:var(--mono); font-size:13px}
.lzhop{display:flex; gap:10px; align-items:flex-start; padding:9px 12px; margin-bottom:6px;
    border-left:3px solid var(--teal); border-radius:0 9px 9px 0; background:var(--panel2)}
.lzhop .n2{flex:none; width:19px; height:19px; border-radius:50%; background:var(--sel); color:var(--amber);
    font-family:var(--mono); font-size:10.5px; display:grid; place-items:center; margin-top:1px}
.lzhop b{font-size:12.5px; font-weight:600}
.lzhop small{display:block; color:var(--muted); font-size:11.5px; line-height:1.55; margin-top:2px}
/* ================= INTERFACE ================= */
  /* one global motion guard rather than per-component handling */
  @media (prefers-reduced-motion: reduce){
    *,*::before,*::after{animation-duration:.001ms !important; animation-iteration-count:1 !important;
      transition-duration:.001ms !important; scroll-behavior:auto !important}
  }
html{scroll-behavior:smooth}
/* ---- reading progress ---- */
  .rprog{position:fixed; inset:0 0 auto 0; height:2px; z-index:60; background:transparent; pointer-events:none}
.rprog i{display:block; height:100%; width:0; background:linear-gradient(90deg,var(--teal),var(--violet));
    transition:width .12s linear}
/* ---- sticky, single-row tab bar ---- */
  .tabwrap{position:sticky; top:0; z-index:50; margin:22px 0 20px;
    background:color-mix(in srgb, var(--bg) 88%, transparent); backdrop-filter:blur(10px);
    border-bottom:1px solid var(--line); padding:9px 0 10px}
.tabwrap::before,.tabwrap::after{content:""; position:absolute; top:0; bottom:0; width:36px; pointer-events:none; z-index:2}
.tabwrap::before{left:0; background:linear-gradient(90deg,var(--bg),transparent)}
.tabwrap::after{right:0; background:linear-gradient(270deg,var(--bg),transparent)}
.tabs{display:flex; gap:7px; flex-wrap:nowrap; overflow-x:auto; scrollbar-width:none;
    scroll-snap-type:x proximity; padding:2px 30px; margin:0}
.tabs::-webkit-scrollbar{display:none}
.tab{flex:0 0 auto; scroll-snap-align:center; cursor:pointer; font-family:var(--mono); font-size:12px;
    color:var(--muted); background:transparent; border:1px solid transparent; border-radius:99px;
    padding:7px 14px; transition:color .15s, background .15s, border-color .15s; white-space:nowrap}
.tab:hover{color:var(--text); background:var(--panel2)}
.tab.on{color:var(--accent); border-color:var(--accent-line); background:var(--accent-soft)}
.tab:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.tab .tcount{display:inline-block; margin-left:7px; font-size:9.5px; opacity:.7;
    border:1px solid currentColor; border-radius:99px; padding:0 5px; line-height:1.5}
/* ---- layout with the section rail ---- */
  .labgrid{display:grid; grid-template-columns:minmax(0,1fr) 208px; gap:26px; align-items:start}
.railcol{position:sticky; top:72px; max-height:calc(100vh - 96px); overflow-y:auto; scrollbar-width:thin;
    padding-right:2px}
.railhead{font-family:var(--mono); font-size:9.5px; letter-spacing:.14em; text-transform:uppercase;
    color:var(--dim); margin:0 0 10px 10px}
.rail{display:flex; flex-direction:column; gap:1px; border-left:1px solid var(--line); padding-left:0}
.rail a{display:flex; gap:7px; align-items:baseline; padding:5px 8px 5px 11px; margin-left:-1px;
    border-left:2px solid transparent; font-size:11.5px; line-height:1.4; color:var(--muted);
    text-decoration:none; transition:color .15s, border-color .15s}
.rail a:hover{color:var(--text)}
.rail a.on{color:var(--amber); border-left-color:var(--amber)}
.rail a i{flex:none; width:5px; height:5px; border-radius:50%; background:var(--teal); margin-top:6px; opacity:0}
.rail a.sim i{opacity:1}
.rail a:focus-visible{outline:2px solid var(--teal); outline-offset:-2px}
@media (max-width:1180px){.labgrid{grid-template-columns:minmax(0,1fr)} .railcol{display:none}}
/* ---- a simulation card should look like one ---- */
  .card.issim{border-left:3px solid var(--teal); background:
    linear-gradient(180deg, color-mix(in srgb, var(--teal) 4%, var(--panel)) 0 64px, var(--panel) 64px)}
.card.issim > h2.sec::before{content:"interactive"; display:inline-block; vertical-align:middle;
    font-family:var(--mono); font-size:9px; letter-spacing:.12em; text-transform:uppercase; color:var(--teal);
    border:1px solid var(--teal); border-radius:99px; padding:2px 7px; margin-right:9px; transform:translateY(-2px)}
/* ---- command palette ---- */
  .cmdk{position:fixed; inset:0; z-index:80; display:none; padding:12vh 16px 16px;
    background:color-mix(in srgb, var(--bg) 72%, transparent); backdrop-filter:blur(6px)}
.cmdk.on{display:block; animation:cmdIn .16s ease}
@keyframes cmdIn{from{opacity:0} to{opacity:1}}
.cmdbox{max-width:620px; margin:0 auto; background:var(--panel); border:1px solid var(--line2);
    border-radius:14px; box-shadow:0 24px 60px rgba(0,0,0,.22); overflow:hidden}
.cmdbox input{width:100%; border:0; border-bottom:1px solid var(--line); background:transparent;
    color:var(--text); font:inherit; font-size:15px; padding:15px 18px; outline:none}
.cmdlist{max-height:46vh; overflow-y:auto; padding:6px}
.cmdlist button{display:block; width:100%; text-align:left; border:0; background:transparent; color:inherit;
    font:inherit; padding:9px 12px; border-radius:9px; cursor:pointer; line-height:1.4}
.cmdlist button .cmdtab{display:block; font-family:var(--mono); font-size:9.5px; letter-spacing:.1em;
    text-transform:uppercase; color:var(--dim); margin-bottom:2px}
.cmdlist button .cmdname{font-size:13px}
.cmdlist button.on,.cmdlist button:hover{background:var(--panel2)}
.cmdlist button.on .cmdname{color:var(--amber)}
.cmdnone{padding:16px 18px; color:var(--muted); font-size:13px}
.cmdfoot{border-top:1px solid var(--line); padding:8px 14px; font-family:var(--mono); font-size:10px;
    color:var(--dim); display:flex; gap:14px; flex-wrap:wrap}
.cmdfoot b{font-weight:400; color:var(--muted)}

/* ---- typography, aligned across every page ----
     div.note and div.ok carried no size of their own, so they inherited the
     body default and rendered larger and tighter than the callouts beside
     them. .k holds inline code identifiers and was rendering in the body
     face. Measured in a browser rather than assumed. */
  div.note{font-size:12.5px; line-height:1.65; color:var(--muted)}
div.ok{font-size:12.5px; line-height:1.65}
.k{font-family:var(--mono); font-size:.94em}

/* ---- the top bar ----
   Every lab used to open with seventeen controls: twelve sibling-lab chips
   plus back, topics, profile, theme and the palette hint, wrapping to three
   rows above the title. The chips were in no order, while the dashboard has
   grouped and numbered the labs into three tracks all along. They now live
   behind one menu that carries that order, and the page says where the reader
   is standing. Twelve of these were also 2,722 bytes of inline style per page;
   cloud.html had a different header again. */
.topnav{display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:22px}
.tn{cursor:pointer; font-family:var(--mono); font-size:12px; color:var(--muted); background:transparent;
    border:1px solid var(--line2); border-radius:8px; padding:6px 12px; text-decoration:none;
    display:inline-flex; align-items:center; gap:6px; transition:color .15s, border-color .15s, background .15s}
.tn:hover{color:var(--text); border-color:var(--muted)}
.tn:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.tn.on{color:var(--accent); border-color:var(--accent-line); background:var(--accent-soft)}
.tn-accent{color:var(--accent)}
.tn-quiet{border-color:transparent}
.tn-quiet:hover{border-color:var(--line2)}
.tnspace{flex:1 1 auto}
.tn b{font-weight:500; opacity:.75}

/* where this lab sits in its track, the dashboard's reading order, on the page */
.track{font-family:var(--mono); font-size:12px; color:var(--dim); margin-top:10px}
.track .tkname{color:var(--muted)}
.track a{color:var(--accent); text-decoration:none; border-bottom:1px solid var(--accent-line)}
.track a:hover{color:var(--text); border-bottom-color:var(--muted)}

/* the labs menu */
.labwrap{position:relative}
.labmenu{position:absolute; z-index:60; top:calc(100% + 6px); left:0; width:min(560px,92vw);
    background:var(--panel); border:1px solid var(--line2); border-radius:12px; padding:14px 16px 16px;
    box-shadow:0 12px 30px rgba(0,0,0,.13)}
:root[data-theme="dark"] .labmenu{box-shadow:0 12px 30px rgba(0,0,0,.45)}
.labmenu[hidden]{display:none}
.lmgrp{margin-top:14px}
.lmgrp:first-child{margin-top:2px}
.lmgrp h4{font-family:var(--mono); font-size:10.5px; letter-spacing:.1em; text-transform:uppercase;
    color:var(--dim); font-weight:400; margin-bottom:7px}
.lmlist{display:grid; grid-template-columns:1fr 1fr; gap:3px}
@media (max-width:560px){.lmlist{grid-template-columns:1fr}}
.lmlist a{display:flex; align-items:baseline; gap:8px; text-decoration:none; color:var(--text);
    font-size:13px; border-radius:7px; padding:5px 8px; line-height:1.45}
.lmlist a:hover{background:var(--panel2)}
.lmlist a:focus-visible{outline:2px solid var(--accent); outline-offset:-2px}
.lmlist a.here{color:var(--accent); background:var(--accent-soft)}
.lmlist a i{font-style:normal; font-family:var(--mono); font-size:10.5px; color:var(--dim);
    border:1px solid var(--line2); border-radius:99px; min-width:17px; height:17px;
    display:inline-flex; align-items:center; justify-content:center; flex:0 0 auto}
.lmlist a.here i{color:var(--accent); border-color:var(--accent-line)}

/* ---- reading measure ----
   Prose set across the full 1240px column runs to about 150 characters a line,
   which is roughly twice a comfortable measure, and the eye loses its place on
   the return sweep. Only prose is constrained. Diagrams, simulations, tables
   and the code blocks keep the whole width, because they are read by scanning
   rather than line by line, and narrowing them would break their layout. */
.plain-line, div.note, div.ok, .simnote{max-width:82ch}

/* ---- motion ----
   Every simulation rebuilds its output with innerHTML, so its elements mount
   fresh on every interaction. These entrance animations run on mount, which
   means every click gets a visible response with no per-sim JS: conclusion
   blocks slide in, bars grow from zero, a chosen token pops into place.

   Two deliberate limits. Outputs driven by a range slider re-render on every
   input event, and a restarting entrance animation under a drag reads as
   flicker, so those containers opt out with .live. And everything here sits
   behind prefers-reduced-motion, because motion that teaches one reader can
   make another one ill. */
@media (prefers-reduced-motion: no-preference){
  .ok,.lzbad,.lzwarn,.lzhop{animation:simIn .28s ease both}
  .lzhop:nth-of-type(2){animation-delay:.05s}
  .lzhop:nth-of-type(3){animation-delay:.1s}
  .lzhop:nth-of-type(4){animation-delay:.15s}
  .lzhop:nth-of-type(5){animation-delay:.2s}
  .lzhop:nth-of-type(6){animation-delay:.25s}
  .live .ok,.live .lzbad,.live .lzwarn,.live .lzhop{animation:none}
  .abar{transform-origin:left; animation:growX .5s cubic-bezier(.25,.7,.3,1) both}
  .tpop{animation:pop .32s cubic-bezier(.3,1.4,.5,1) both}
  .tpulse{animation:softpulse 1.1s ease-in-out infinite}
}
@keyframes simIn{from{opacity:0; transform:translateY(5px)} to{opacity:1; transform:none}}
@keyframes growX{from{transform:scaleX(0)}}
@keyframes pop{from{transform:scale(.4); opacity:0}}
@keyframes softpulse{0%,100%{opacity:1} 50%{opacity:.35}}
/* the playback strip shared by the "watch it happen" modes */
.pbclock{font-family:var(--mono); font-size:12px; color:var(--muted); display:flex;
  justify-content:space-between; align-items:baseline; margin-bottom:8px}
.pbclock b{font-size:16px; color:var(--text); font-variant-numeric:tabular-nums}
.pbchips{display:flex; flex-wrap:wrap; gap:3px; margin-bottom:10px}
.pbchips i{width:13px; height:13px; border-radius:3px; background:var(--wire); opacity:.45; transition:background .2s, opacity .2s}
.pbchips i.you{background:var(--accent); opacity:1; outline:2px solid var(--accent); outline-offset:1px}
.pbchips i.busy{background:var(--amber); opacity:1}
.pbchips i.done{background:var(--green); opacity:.8}
.pbchips i.dead{background:var(--red); opacity:1}

/* the theme switch crossfades instead of hard-cutting: app code puts this
   class on <html> for the duration of the fade, then removes it */
html.theme-fade, html.theme-fade *, html.theme-fade *::before, html.theme-fade *::after{
  transition:background-color .35s ease, color .35s ease, border-color .35s ease,
             fill .35s ease, stroke .35s ease, box-shadow .35s ease !important}

/* lab + simulation bookmark control in the header */
.bmwrap{position:relative;display:inline-flex}
#bmBtn.on{color:var(--accent);border-color:var(--accent)}
.bmmenu{position:absolute;top:calc(100% + 6px);right:0;z-index:40;min-width:260px;
  background:var(--panel);border:1px solid var(--line2);border-radius:11px;
  box-shadow:0 12px 34px rgba(0,0,0,.18);padding:6px}
.bmrow{display:flex;gap:10px;align-items:flex-start;width:100%;text-align:left;
  background:transparent;border:none;border-radius:8px;padding:8px 10px;cursor:pointer;color:var(--text)}
.bmrow:hover{background:var(--sel)}
.bmrow i{font-style:normal;font-size:15px;line-height:1.2;color:var(--muted)}
.bmrow.on i{color:var(--accent)}
.bmrow b{display:block;font-weight:600;font-size:12.5px}
.bmrow small{display:block;color:var(--muted);font-size:11px;margin-top:1px;
  max-width:210px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bmrow:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
