:root{
  --bg:#0d1117; --bg2:#131a23; --panel:#171f29; --panel2:#1e2733;
  --fg:#e9eef4; --fg-dim:#c2ccd8; --muted:#8b98a7; --rule:#243040;
  --sky:#4aa8e8; --sky-dim:rgba(74,168,232,.14);
  --go:#3fbf80; --stop:#ef5a4c; --amber:#f0a830; --violet:#b47cf0;
}
*{box-sizing:border-box}
/* Smooth scrolling is set per call, not globally. As a document rule it also
   catches every incidental scroll the browser decides to make on its own, and
   a page swap that lands at the top then reads as the new lesson streaming past
   in reverse. Only a click on an in page anchor should glide. */
html{scroll-behavior:auto;scroll-padding-top:104px}
body{margin:0;background:var(--bg);color:var(--fg);
  font:17px/1.68 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,Helvetica,sans-serif;
  -webkit-font-smoothing:antialiased}

/* masthead + nav */
.masthead{position:sticky;top:0;z-index:20;background:rgba(13,17,23,.94);
  backdrop-filter:blur(10px);border-bottom:1px solid var(--rule)}
.mh-inner{max-width:820px;margin:0 auto;padding:13px 22px;display:flex;align-items:baseline;gap:11px}
.mh-brand{font-weight:800;letter-spacing:-.02em;font-size:16px;color:var(--sky)}
.mh-course{font-size:13px;color:var(--muted);letter-spacing:.13em;text-transform:uppercase;font-weight:600}
.levelnav{position:sticky;top:50px;z-index:19;background:rgba(19,26,35,.96);
  backdrop-filter:blur(10px);border-bottom:1px solid var(--rule);overflow-x:auto;
  -webkit-overflow-scrolling:touch;scrollbar-width:none}
.levelnav::-webkit-scrollbar{display:none}
.ln-inner{max-width:820px;margin:0 auto;padding:0 22px;display:flex;gap:3px;white-space:nowrap}
.levelnav a{color:var(--muted);text-decoration:none;font-size:12.5px;font-weight:600;
  padding:11px 11px;border-bottom:2px solid transparent}
.levelnav a:hover{color:var(--sky);border-bottom-color:var(--sky)}

main{max-width:820px;margin:0 auto;padding:0 22px 64px}

/* type */
h1{font-size:2.7rem;line-height:1.06;letter-spacing:-.035em;margin:44px 0 10px}
h2{font-size:1.62rem;letter-spacing:-.022em;line-height:1.2;margin:0 0 6px}
h3{font-size:1.19rem;margin:2.2em 0 .35em;letter-spacing:-.01em}
/* Every other h4 context (.practice, .tool, .live, .pre) already overrides to
   white - this base rule was the one left dim, which meant a section header
   ("Layers, not another product") read as LESS prominent than an inline
   <strong> lead-in phrase ("Useful clue, not proof.") sitting right next to
   it: strong is #fff at weight 650, this was --fg-dim with no weight bump at
   all. White + heavier weight than strong fixes the inversion everywhere a
   plain content h4 is used, not just this one lesson. */
h4{font-size:1.08rem;font-weight:800;margin:1.7em 0 .35em;color:#fff}
p{margin:.85em 0;color:var(--fg-dim)}
li{margin:.42em 0;color:var(--fg-dim)}
.etag{color:inherit;text-decoration:none;white-space:nowrap}
.etag:hover{text-decoration:underline}
ul,ol{padding-left:1.3em;margin:.8em 0}
strong{color:#fff;font-weight:650}
a{color:var(--sky)}
code{font:.87em ui-monospace,SFMono-Regular,Menlo,monospace;background:var(--panel2);
  padding:1.5px 6px;border-radius:4px;color:var(--fg)}
.lead{font-size:1.13rem;color:var(--fg);line-height:1.6}

/* level header block */
.level{border-top:1px solid var(--rule);margin-top:64px;padding-top:40px}
.level:first-of-type{border-top:0}
.lv-tag{display:inline-block;font-size:11.5px;font-weight:800;letter-spacing:.14em;
  color:var(--sky);background:var(--sky-dim);padding:4px 11px;border-radius:20px;margin-bottom:12px}
.lv-goal{background:linear-gradient(180deg,rgba(63,191,128,.1),transparent);
  border:1px solid rgba(63,191,128,.28);border-radius:10px;padding:13px 17px;margin:18px 0 26px}
.lv-goal .lbl{display:block;font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  font-weight:800;color:var(--go);margin-bottom:4px}
.lv-goal p{margin:0;color:var(--fg)}

/* callouts */
.box{border:1px solid var(--rule);border-left:4px solid var(--sky);background:var(--panel);
  border-radius:0 10px 10px 0;padding:16px 20px;margin:1.6em 0}
.box .lbl{display:block;font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;
  font-weight:800;color:var(--sky);margin-bottom:6px}
.box p:first-of-type{margin-top:0}.box p:last-child{margin-bottom:0}
.box.key{border-left-color:var(--go)} .box.key .lbl{color:var(--go)}
.box.warn{border-left-color:var(--amber)} .box.warn .lbl{color:var(--amber)}
.box.game{border-left-color:var(--violet)} .box.game .lbl{color:var(--violet)}
.box.safety{border-left-color:var(--stop)} .box.safety .lbl{color:var(--stop)}

/* catalog chips */
.cat{display:flex;flex-wrap:wrap;gap:7px;margin:20px 0 6px}
.cat b{font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--muted);
  width:100%;font-weight:800}
.chip{font-size:12.5px;font-weight:650;padding:3px 11px;border-radius:6px;
  background:var(--panel2);border:1px solid var(--rule);color:var(--fg-dim)}
.chip.com{border-color:#3a4757} .chip.unc{border-color:rgba(63,191,128,.4);color:var(--go)}
.chip.rare{border-color:rgba(74,168,232,.45);color:var(--sky)}
.chip.leg{border-color:rgba(180,124,240,.45);color:var(--violet)}
.chip.sea{border-color:rgba(240,168,48,.45);color:var(--amber)}

/* entry card for a catalog storm type */
.entry{background:var(--panel);border:1px solid var(--rule);border-radius:12px;
  padding:20px 22px;margin:22px 0}
.entry-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:2px}
.entry-name{font-size:1.14rem;font-weight:700;color:#fff}
.tell{font-size:1.02rem;color:var(--go);font-weight:600;margin:10px 0 12px;
  padding-left:13px;border-left:3px solid var(--go)}

/* The routine's SEE/SUSPECT/VERIFY dividers - the landing page's own
   Section One/Two/Three kicker-plus-rule, not the storm-catalog .tell
   bar, since these are step headers, not a one-line "the tell" it is
   easy to confuse them with. */
.routine-step{display:block;font-size:11px;font-weight:800;letter-spacing:.19em;
  text-transform:uppercase;color:var(--go);margin:1.9em 0 13px;padding-bottom:9px;
  border-bottom:1px solid var(--rule)}
.entry p:last-child{margin-bottom:0}

/* figures */
figure{margin:1.9em 0}
figure svg{width:100%;height:auto;display:block;border:1px solid var(--rule);
  border-radius:10px;background:#0a0e13}
figcaption{font-size:13.5px;color:var(--muted);margin-top:9px;line-height:1.55}
.shot-box{border:2px dashed #33445a;border-radius:10px;background:
  repeating-linear-gradient(45deg,#111823,#111823 11px,#141c28 11px,#141c28 22px);
  padding:24px 22px;text-align:left}
.shot-tag{display:inline-block;font-size:10.5px;font-weight:800;letter-spacing:.13em;
  color:var(--amber);border:1px solid rgba(240,168,48,.4);padding:3px 9px;border-radius:5px}
.shot-spec{margin:11px 0 0;color:var(--fg-dim);font-size:14.5px;line-height:1.55}

/* practice */
.practice{border:1px solid rgba(74,168,232,.32);border-radius:12px;
  background:linear-gradient(180deg,rgba(74,168,232,.08),transparent);padding:20px 22px;margin:26px 0}
.practice .lbl{display:block;font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  font-weight:800;color:var(--sky);margin-bottom:7px}
.practice h4{margin-top:0;color:#fff}
details{margin-top:12px;border-top:1px solid var(--rule);padding-top:12px}
summary{cursor:pointer;font-weight:650;color:var(--sky);font-size:14.5px;list-style:none}
summary::-webkit-details-marker{display:none}
summary::before{content:"► ";font-size:11px}
details[open] summary::before{content:"▼ "}
details p{font-size:15px}

/* tables */
.tw{overflow-x:auto;margin:1.5em 0}
table{border-collapse:collapse;width:100%;font-size:14.5px;min-width:520px}
th,td{border:1px solid var(--rule);padding:9px 13px;text-align:left;vertical-align:top;color:var(--fg-dim)}
th{background:var(--panel2);color:#fff;font-weight:650}
td:first-child{font-weight:600;color:var(--fg)}

/* A green/red checklist rather than a plain table, for "what radar can and
   cannot do" - the whole point is the contrast, and a table makes you read
   left-to-right per row instead of feeling the two columns as two lists.
   A real 2-column grid (items in document order: good1, cannot1, good2,
   cannot2, ...) rather than two independent flex columns, so a row whose
   text wraps to two lines pushes its PARTNER row down with it instead of
   the two columns drifting out of alignment with each other. */
.capgrid{display:grid;grid-template-columns:1fr 1fr;column-gap:28px;row-gap:11px;margin:1.5em 0}
.cap-head{display:block;font-size:12px;letter-spacing:.08em;text-transform:uppercase;
  font-weight:800;margin-bottom:2px}
.cap-head.go{color:var(--go)}
.cap-head.no{color:var(--stop)}
.cap-item{display:flex;align-items:flex-start;gap:10px;font-size:14.5px;color:var(--fg-dim);
  line-height:1.5}
.cap-ico{flex-shrink:0;width:22px;height:22px;border-radius:50%;font-style:normal;
  display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:800;margin-top:1px}
.cap-ico.go{background:rgba(63,191,128,.16);color:var(--go)}
.cap-ico.no{background:rgba(239,90,76,.16);color:var(--stop)}
@media(max-width:640px){.capgrid{grid-template-columns:1fr;row-gap:11px}}

footer{border-top:1px solid var(--rule);margin-top:70px;padding-top:24px;
  font-size:13.5px;color:var(--muted)}
footer strong{color:var(--fg-dim)}

@media(max-width:640px){
  body{font-size:16.5px} h1{font-size:2rem} h2{font-size:1.38rem}
  main{padding:0 17px 52px} .mh-inner,.ln-inner{padding-left:17px;padding-right:17px}
  html{scroll-padding-top:96px}
}
@media print{
  .masthead,.levelnav{display:none} .level{page-break-before:always}
  body{background:#fff;color:#000} p,li,td{color:#222}
  details{display:block} details[open] summary{color:#000}
}

/* ---------- Lesson 0's on ramp, on the index ----------
   Above the ten and visibly not one of them. The way out is in the block itself,
   because a course that promises ninety minutes cannot quietly become a hundred
   and five for the reader who did not need this. */
.onramp{border:1px solid rgba(63,191,128,.3);border-radius:13px;padding:18px 20px 16px;
  margin:0 0 34px;background:linear-gradient(180deg,rgba(63,191,128,.08),transparent 70%)}
.onramp .kicker{color:var(--go);margin-bottom:11px}
.or-row{display:flex;align-items:baseline;gap:15px;text-decoration:none;padding:4px 0}
.or-row .n{font-weight:800;font-size:20px;line-height:1;color:var(--go);opacity:.75;
  font-variant-numeric:tabular-nums}
.or-row .t{display:block;font-size:1.06rem;font-weight:700;color:#fff}
.or-row .t em{font-style:normal;font-size:11px;font-weight:800;letter-spacing:.13em;
  text-transform:uppercase;color:var(--go);border:1px solid rgba(63,191,128,.45);
  border-radius:20px;padding:2px 8px;margin-left:9px;vertical-align:2px}
.or-row .d{display:block;font-size:14.5px;color:var(--muted);margin-top:3px}
.or-row:hover .t{color:var(--go)}
.or-skip{margin:12px 0 0;font-size:13.5px;line-height:1.6;color:var(--muted)}

/* Lesson 0's own header bar: no track, because there is no progress to report on
   a lesson that does not count toward anything */
.pbar.zero .pbar-in{gap:14px;flex-wrap:wrap}
.pbar.zero .pbar-txt{color:var(--go)}
.pbar-note{font-size:12px;color:var(--muted)}

/* Earl asides */
.earl{display:flex;gap:18px;align-items:flex-start;margin:2em 0;padding:18px 20px;
  background:linear-gradient(180deg,rgba(240,168,48,.07),rgba(240,168,48,.02));
  border:1px solid rgba(240,168,48,.26);border-radius:14px}
.earl-face{width:78px;height:78px;flex:0 0 78px;border-radius:50%}
.earl-body{min-width:0}
.earl-name{display:block;font-size:10.5px;letter-spacing:.15em;text-transform:uppercase;
  font-weight:800;color:var(--amber);margin-bottom:5px}
.earl-body p{margin:0;color:var(--fg);font-size:16px;line-height:1.6}
.appshot{text-align:center;margin:2em 0}
.appshot img{max-width:290px;width:100%;border-radius:16px;
  border:1px solid var(--rule);box-shadow:0 10px 34px rgba(0,0,0,.5)}
@media(max-width:520px){
  .earl{gap:14px;padding:15px 16px}
  .earl-face{width:62px;height:62px;flex-basis:62px}
  .earl-body p{font-size:15.5px}
}
@media print{.earl{background:#faf6ee;border-color:#ddc9a0}.earl-body p{color:#111}}

/* quiz */
.quiz{border:1px solid var(--rule);border-radius:14px;background:var(--panel);
  padding:22px 24px;margin:2.4em 0}
.qlbl{display:block;font-size:10.5px;letter-spacing:.15em;text-transform:uppercase;
  font-weight:800;color:var(--sky);margin-bottom:14px}
.qlist{list-style:none;padding:0;margin:0;counter-reset:q}
.qitem{counter-increment:q;padding:16px 0;border-top:1px solid var(--rule);margin:0}
.qitem:first-child{border-top:0;padding-top:0}
.qprompt{margin:0 0 12px;color:var(--fg);font-weight:600;line-height:1.5}
.qprompt::before{content:counter(q) ". ";color:var(--sky);font-weight:800}
.qopts{display:flex;flex-direction:column;gap:7px}
.qopt{text-align:left;font:inherit;font-size:15px;color:var(--fg-dim);cursor:pointer;
  background:var(--panel2);border:1px solid var(--rule);border-radius:9px;
  padding:10px 14px;transition:border-color .12s,background .12s}
.qopt:hover:not(.locked){border-color:var(--sky);color:var(--fg)}
.qopt.locked{cursor:default}
.qopt.right{border-color:var(--go);background:rgba(63,191,128,.13);color:#fff}
.qopt.right::after{content:" ✓";color:var(--go);font-weight:800}
.qopt.wrong{border-color:var(--stop);background:rgba(239,90,76,.11);color:#fff}
.qopt.wrong::after{content:" ✕";color:var(--stop);font-weight:800}
.qwhy{display:none;margin:12px 0 0;padding:12px 15px;border-radius:9px;font-size:14.5px;
  line-height:1.6;background:rgba(74,168,232,.09);border-left:3px solid var(--sky);color:var(--fg-dim)}
.qitem.done .qwhy{display:block}
.qscore{margin:16px 0 0;padding-top:14px;border-top:1px solid var(--rule);
  font-weight:650;color:var(--go);font-size:15px}

/* tool stub */
.tool{border:2px dashed #33445a;border-radius:14px;padding:22px 24px;margin:2.2em 0;
  background:repeating-linear-gradient(45deg,#111823,#111823 11px,#141c28 11px,#141c28 22px)}
.tool-lbl{display:inline-block;font-size:10.5px;font-weight:800;letter-spacing:.13em;
  text-transform:uppercase;color:var(--amber);border:1px solid rgba(240,168,48,.4);
  padding:3px 9px;border-radius:5px}
.tool h4{margin:12px 0 6px;color:#fff;font-size:1.06rem}
.tool p{margin:0;font-size:14.5px}

/* certificate */
.cert{background:linear-gradient(150deg,#1a2230,#12181f);border:2px solid rgba(240,168,48,.4);
  border-radius:16px;padding:32px 30px;margin:2.4em 0;text-align:center}
.cert-mark{display:flex;justify-content:center;margin-bottom:14px}
.cert-mark svg{width:52px;height:52px}
.cert-top{font-size:11px;letter-spacing:.22em;text-transform:uppercase;color:var(--amber);font-weight:800}
.cert h3{margin:10px 0 4px;font-size:1.7rem;color:#fff;letter-spacing:-.02em}
.cert .cert-sub{color:var(--muted);font-size:14px;margin:0 0 22px}
.cert-name{border:0;border-bottom:2px solid rgba(240,168,48,.5);background:transparent;
  color:#fff;font:inherit;font-size:1.15rem;text-align:center;padding:8px 12px;
  width:min(340px,100%);margin-bottom:6px}
.cert-name::placeholder{color:#5c6773}
.cert-hint{font-size:12.5px;color:var(--muted);margin:0 0 22px}
.cert-sig{margin-top:24px;padding-top:18px;border-top:1px solid var(--rule);
  display:flex;align-items:center;justify-content:center}
.cert-sig-img{height:64px;width:auto}
.gate{background:var(--panel);border:1px solid var(--rule);border-radius:12px;
  padding:18px 20px;margin:1.6em 0}
.gate label{display:block;font-size:13px;color:var(--muted);margin-bottom:8px}
.gate input[type=email]{width:100%;background:var(--panel2);border:1px solid var(--rule);
  border-radius:9px;color:var(--fg);font:inherit;font-size:15px;padding:11px 14px}
.gate button{margin-top:11px;background:var(--amber);color:#12181f;border:0;border-radius:9px;
  font:inherit;font-weight:750;font-size:15px;padding:11px 22px;cursor:pointer}
.gate .fineprint{font-size:12px;color:var(--muted);margin:10px 0 0}

/* live interactive */
.live{border:1px solid rgba(74,168,232,.34);border-radius:14px;padding:22px 24px;margin:2.2em 0;
  background:linear-gradient(180deg,rgba(74,168,232,.07),transparent)}
.live-lbl{display:inline-block;font-size:10.5px;font-weight:800;letter-spacing:.14em;
  text-transform:uppercase;color:var(--sky)}
.live h4{margin:9px 0 5px;color:#fff;font-size:1.1rem}
.live-intro{margin:0 0 18px;font-size:14.5px;color:var(--fg-dim)}
.wd-wrap{display:flex;gap:26px;align-items:flex-start;flex-wrap:wrap}
.wd-stage{flex:0 0 300px;max-width:100%}
.wd-stage svg{width:100%;height:auto;background:#0a0e13;border:1px solid var(--rule);border-radius:12px}
.wd-side{flex:1;min-width:230px}
.wd-q{font-weight:650;color:var(--fg);margin:0 0 12px;font-size:15.5px}
.wd-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:7px}
.wd-btn{font:inherit;font-size:14px;font-weight:650;color:var(--fg-dim);background:var(--panel2);
  border:1px solid var(--rule);border-radius:9px;padding:10px 4px;cursor:pointer;transition:.12s}
.wd-btn:hover:not(:disabled){border-color:var(--sky);color:#fff}
.wd-btn:disabled{cursor:default;opacity:.5}
.wd-btn.right{border-color:var(--go);background:rgba(63,191,128,.16);color:#fff;opacity:1}
.wd-btn.wrong{border-color:var(--stop);background:rgba(239,90,76,.14);color:#fff;opacity:1}
.wd-fb{margin:14px 0 0;font-size:14.5px;line-height:1.6;color:var(--fg-dim);min-height:3.2em}
.wd-fb b{color:#fff}
.wd-bar{display:flex;align-items:center;gap:14px;margin-top:14px;flex-wrap:wrap}
.wd-next{font:inherit;font-size:14.5px;font-weight:700;background:var(--sky);color:#0d1117;
  border:0;border-radius:9px;padding:10px 20px;cursor:pointer}
.wd-next[hidden]{display:none}
.wd-score{font-size:13.5px;color:var(--muted);font-weight:650}
@media(max-width:560px){.wd-wrap{gap:18px}.wd-stage{flex-basis:100%}}
@media print{.live{break-inside:avoid}.wd-grid{display:none}}

/* ============ drill engine ============ */
.dr{display:flex;gap:26px;align-items:flex-start;flex-wrap:wrap}
.dr-stage{flex:0 0 320px;max-width:100%}
.dr-stage svg{width:100%;height:auto;display:block;border:1px solid var(--rule);border-radius:12px}
.dr-side{flex:1;min-width:250px}
.dr-prompt{margin:0 0 14px;font-weight:650;color:var(--fg);font-size:16px;line-height:1.45}
.dr-choices{display:grid;gap:8px}
.dr-choice{font:inherit;font-size:15px;font-weight:600;text-align:left;color:var(--fg-dim);
  background:var(--panel2);border:1px solid var(--rule);border-radius:10px;
  padding:12px 15px;cursor:pointer;transition:border-color .12s,color .12s,background .12s}
.dr-choice:hover:not(:disabled){border-color:var(--sky);color:#fff}
.dr-choice:disabled{cursor:default;opacity:.45}
.dr-choice.is-right{border-color:var(--go);background:rgba(63,191,128,.16);color:#fff;opacity:1}
.dr-choice.is-wrong{border-color:var(--stop);background:rgba(239,90,76,.13);color:#fff;opacity:1}
.dr-fb{margin-top:16px}
.dr-fb.show{padding:14px 16px;border-radius:11px;border-left:3px solid var(--rule);
  background:var(--panel)}
.dr-fb.ok{border-left-color:var(--go);background:rgba(63,191,128,.09)}
.dr-fb.no{border-left-color:var(--amber);background:rgba(240,168,48,.08)}
.dr-fb.done{border-left-color:var(--sky);background:rgba(74,168,232,.09)}
.dr-verdict{margin:0 0 7px;color:var(--fg);font-size:15.5px}
.dr-verdict b{color:#fff}
.dr-tell{margin:0;font-size:14.5px;line-height:1.6;color:var(--fg-dim)}
.dr-tell span{display:block;font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  font-weight:800;color:var(--muted);margin-bottom:4px}
.dr-bar{display:flex;align-items:center;gap:14px;margin-top:15px;flex-wrap:wrap}
.dr-next{font:inherit;font-size:14.5px;font-weight:700;background:var(--sky);color:#0d1117;
  border:0;border-radius:9px;padding:11px 22px;cursor:pointer}
.dr-next[hidden]{display:none}
.dr-progress{font-size:13px;color:var(--muted);font-weight:650}
@media(max-width:600px){.dr-stage{flex-basis:100%}}

/* Read the pattern (Lesson 8 capstone): a small section label above the
   prompt so "Round A" and "Round B" read as distinct without a full divider.
   Both rounds render as a plain SVG sized to the shared dr-stage box, so no
   extra image-frame classes are needed here. */
.rp-section{display:block;font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  font-weight:800;color:var(--sky);margin-bottom:8px}

/* ============ site chrome ============ */
.crumb{font-size:12.5px;color:var(--muted);margin:34px 0 0;letter-spacing:.02em}
.crumb a{color:var(--muted);text-decoration:none}
.crumb a:hover{color:var(--sky)}
.pbar{position:sticky;top:50px;z-index:18;background:rgba(13,17,23,.95);
  backdrop-filter:blur(10px);border-bottom:1px solid var(--rule)}
.pbar-in{max-width:820px;margin:0 auto;padding:9px 22px;display:flex;align-items:center;gap:12px}
.pbar-track{flex:1;height:5px;background:var(--panel2);border-radius:3px;overflow:hidden}
.pbar-fill{height:100%;background:linear-gradient(90deg,var(--sky),var(--go));
  border-radius:3px;transition:width .4s ease}
.pbar-txt{font-size:11.5px;color:var(--muted);font-weight:700;letter-spacing:.06em;white-space:nowrap}
.pbar-chevs{display:flex;gap:6px}
.pbar-chev{display:flex;align-items:center;justify-content:center;width:26px;height:26px;
  border:1px solid var(--rule);border-radius:7px;color:var(--muted);text-decoration:none;
  font-size:17px;line-height:1;padding-bottom:2px}
.pbar-chev:hover{border-color:var(--sky);color:var(--fg)}
.pbar.zero .pbar-chevs{margin-left:auto}
.pagenav{display:flex;gap:12px;margin:56px 0 0;padding-top:26px;border-top:1px solid var(--rule);
  flex-wrap:wrap}
.pagenav a{flex:1;min-width:210px;text-decoration:none;border:1px solid var(--rule);
  border-radius:12px;padding:15px 18px;background:var(--panel);transition:border-color .14s}
.pagenav a:hover{border-color:var(--sky)}
.pagenav .dir{display:block;font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  font-weight:800;color:var(--muted);margin-bottom:4px}
.pagenav .ttl{color:#fff;font-weight:700;font-size:1.02rem}
.pagenav .fwd{text-align:right}
@media(max-width:600px){.pagenav{flex-direction:column}.pagenav .fwd{order:-1;text-align:left}}
.pagenav .fwd .dir{color:var(--sky)}

/* ============ landing page ============ */
.hero{padding:52px 0 10px}
.hero h1{font-size:3.1rem;margin:0 0 12px}
.hero .tag{font-size:1.18rem;color:var(--fg);max-width:620px;line-height:1.55}
.lessons{display:grid;gap:12px;margin:34px 0}
.lcard{display:flex;gap:16px;align-items:baseline;text-decoration:none;border:1px solid var(--rule);
  border-radius:13px;padding:17px 20px;background:var(--panel);transition:border-color .14s,transform .14s}
.lcard:hover{border-color:var(--sky);transform:translateX(3px)}
.lcard .n{font-size:12px;font-weight:800;color:var(--sky);letter-spacing:.1em;flex:0 0 auto;
  min-width:26px}
.lcard .t{color:#fff;font-weight:700;font-size:1.06rem;display:block;margin-bottom:2px}
.lcard .d{color:var(--fg-dim);font-size:14.5px;line-height:1.5}
.lcard .done{margin-left:auto;color:var(--go);font-size:12px;font-weight:800;flex:0 0 auto}
.startbtn{display:inline-block;background:var(--sky);color:#0d1117;text-decoration:none;
  font-weight:750;font-size:1.02rem;padding:14px 30px;border-radius:11px;margin-top:6px}
.meta{display:flex;gap:26px;flex-wrap:wrap;margin:26px 0 0;padding-top:20px;
  border-top:1px solid var(--rule)}
.meta div{font-size:13.5px;color:var(--muted)}
.meta b{display:block;color:#fff;font-size:1.32rem;font-weight:750;margin-bottom:2px}

/* dBZ explorer */
.dbz-read{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.dbz-val{font-size:2.6rem;font-weight:800;color:#fff;line-height:1;letter-spacing:-.03em}
.dbz-unit{font-size:13px;color:var(--muted);font-weight:700;letter-spacing:.1em}
.dbz-sw{width:52px;height:52px;border-radius:11px;border:1px solid var(--rule);margin-left:auto;
  transition:background .15s}
.dbz-read.hot .dbz-val{color:var(--stop)}
.dbz-range,.lake-range{width:100%;accent-color:var(--sky);margin:4px 0}
.dbz-scale{display:flex;justify-content:space-between;font-size:11.5px;color:var(--muted);
  margin-bottom:14px}
.dbz-name{margin:0 0 5px;font-size:1.14rem;font-weight:750;color:#fff}
.dbz-body{margin:0;font-size:14.5px;color:var(--fg-dim);line-height:1.6;min-height:3em}
/* One big wind arrow over the stage rather than a paragraph underneath it -
   the label names the direction air is FROM, the arrow glyph itself rotates
   to the direction it (and the bands) are going, in the same motion as the
   slider. */
.lake-banner{display:flex;align-items:center;gap:10px;padding:9px 12px;margin-bottom:8px;
  font-size:13px;font-weight:800;letter-spacing:.08em;color:var(--fg-dim)}
.lake-banner b{color:#fff;font-size:15px}
.lake-arrow{display:inline-block;margin-left:auto;font-size:30px;line-height:1;color:var(--sky);
  transition:transform .25s ease}
.pred-stage{cursor:default}
.pred-stage.armed{cursor:crosshair}
.pred-stage.armed svg{outline:2px solid var(--sky);outline-offset:2px;border-radius:12px}

/* ---------- unlabeled gallery figures ---------- */
.shot{margin:2.2em 0}
.gallery{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}
.gallery:has(.gp:only-child){grid-template-columns:1fr;max-width:340px;margin:0 auto}
/* a single inline specimen is a figure in its own right, not a gallery cell that
   lost its partner, so it gets the width a figure deserves */
.gallery.one{grid-template-columns:1fr;max-width:440px;margin:0 auto}
/* five cells do not divide by two. Three across leaves a tidy 3 + 2 and the
   cells stay big enough to read, because these are colour fields rather than
   anything with detail in it. */
.gallery.three{grid-template-columns:repeat(3,1fr);gap:11px}
@media(max-width:680px){.gallery.three{grid-template-columns:repeat(2,1fr)}}
/* A landscape specimen is usually two panels side by side, and 440px turns each
   of them into a thumbnail. Give the wide ones the column. */
.gallery.one.wide{max-width:100%}
.gp{position:relative}
.gp svg,.gp-svg svg{width:100%;height:auto;display:block;
  border:1px solid var(--rule);border-radius:11px;background:#0a0e13}
.gp-n{display:block;margin-top:7px;font-size:12.5px;color:var(--muted);
  letter-spacing:.03em;text-align:center}
@media(max-width:560px){.gallery{grid-template-columns:1fr;max-width:330px;margin:0 auto}}

/* A single specimen with a color key beside it rather than under it - the key
   reads as a legend for the image, not another caption competing with it. */
.spec-legend-row{display:flex;align-items:flex-start;gap:22px;margin:2.2em 0}
.spec-legend-row .shot{margin:0}
.spec-legend-row .gallery.one{margin:0;max-width:380px}
.legend-key{flex:0 0 210px;display:flex;flex-direction:column;gap:11px;padding-top:6px}
.lk-item{font-size:14px;color:var(--fg-dim);display:flex;align-items:center;gap:9px}
.lk-item strong{color:#fff}
.lk-label{white-space:nowrap}
.lk-swatch{width:15px;height:15px;border-radius:4px;flex-shrink:0}
@media(max-width:680px){.spec-legend-row{flex-direction:column}
  .spec-legend-row .gallery.one{max-width:440px;margin:0 auto}
  .legend-key{flex:1 1 auto;flex-direction:row;flex-wrap:wrap;padding-top:0}}

/* ---------- the permit ---------- */
.cert.locked{opacity:.55;filter:saturate(.4)}
.cert.locked .cert-name,.cert.locked .cert-save{pointer-events:none;opacity:.5}
.cert-lock{margin:20px 0 0;padding-top:16px;border-top:1px solid var(--rule);
  font-size:13.5px;color:var(--muted);line-height:1.6}
.cert-lock b{color:var(--fg)}
.cert-save{margin-top:8px;font:inherit;font-size:15px;font-weight:700;cursor:pointer;
  background:var(--amber);color:#12181f;border:0;border-radius:10px;padding:11px 20px}
.cert-save:hover{filter:brightness(1.08)}
.cert.earned{box-shadow:0 0 44px rgba(240,168,48,.14)}

.dr-fallback{color:var(--muted);font-size:14.5px;margin:0}

h2[id],h3[id],section[id],.level{scroll-margin-top:112px}

.codes{display:flex;flex-wrap:wrap;gap:8px;margin:1.6em 0;justify-content:center}
.codes span{font:700 15px/1 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  letter-spacing:.09em;color:var(--fg-dim);background:var(--panel2);
  border:1px solid var(--rule);border-radius:7px;padding:9px 13px}

/* brand lockup */
.mh-inner{padding:10px 22px}
.mh-logolink{display:block;line-height:0}
.mh-logo{height:34px;width:auto;display:block}
@media(max-width:520px){.mh-logo{height:30px}}

/* the product one-liner under the legend is retired: the label above the legend
   names the layer, and Earl carries the words when words are needed */
.rl-dock .ra-note{display:none}

/* ============================ landing page ============================ */
main.wide{max-width:1060px;padding:0 40px}
.kicker{display:block;font-size:11px;font-weight:800;letter-spacing:.19em;
  text-transform:uppercase;color:#55697d}
.mh-nav{margin-left:auto;display:flex;gap:24px;font-size:13.5px;align-items:center}
/* the landing masthead lines up with the landing column, not the lesson column,
   and centers its row so the CTA pill hangs level with the links */
body.home .mh-inner{max-width:1060px;padding:12px 40px;align-items:center}
.mh-nav a{color:var(--muted);text-decoration:none}
.mh-nav a:hover{color:var(--fg)}
.mh-nav a.on{color:var(--fg);font-weight:650}
.mh-nav a.mh-cta{background:var(--sky);color:#08131d;font-weight:750;
  padding:8px 17px;border-radius:999px;white-space:nowrap}
.mh-nav a.mh-cta:hover{color:#08131d;filter:brightness(1.08)}
/* the radar nav item exists only when a feed is configured, like the launcher */
.mh-nav [data-open-radar]{display:none}
body.rl-maybe .mh-nav [data-open-radar]{display:inline}
/* the home page opens the scope from the nav, not from a corner button */
body.home .rl-launch{display:none}
@media(max-width:720px){
  .mh-nav a:not(.mh-cta),body.rl-maybe .mh-nav [data-open-radar]{display:none}
  .mh-nav{gap:0}
  .mh-nav a.mh-cta{padding:7px 14px;font-size:13px}}

.hero2{display:grid;grid-template-columns:1.12fr .88fr;gap:52px;align-items:center;
  padding:66px 0 58px}
.hero-copy{display:flex;flex-direction:column;gap:22px}
.hero2 h1{font-size:clamp(38px,5.2vw,60px);line-height:1.03;letter-spacing:-.035em;
  font-weight:800;margin:0}
.hero2 h1 span{color:var(--sky)}
.hero2 .tag{margin:0;font-size:18px;line-height:1.6;color:var(--fg-dim);max-width:30em}
/* The hero column is a flex stack with a 22px gap, which is right between the
   headline and the copy and too much between two paragraphs of the same copy. */
.hero2 .tag + .tag{margin-top:-10px}
.hero-cta{display:flex;align-items:center;gap:16px;margin:6px 0 0;flex-wrap:wrap}
.hero-note{font-size:14px;color:var(--muted)}
.hero-fig{margin:0;position:relative}
.hero-fig img{width:100%;aspect-ratio:1;object-fit:cover;display:block;
  border-radius:14px;border:1px solid var(--rule)}
.heroloop{position:relative;aspect-ratio:1;border-radius:14px;overflow:hidden;
  border:1px solid var(--rule)}
.heroloop img{position:absolute;inset:0;border:0;border-radius:0;opacity:0;
  transition:opacity .5s ease}
.heroloop img.on{opacity:1}
.hero-fig figcaption{position:absolute;left:13px;right:13px;bottom:13px;
  background:rgba(13,17,23,.88);border:1px solid var(--rule);border-radius:9px;
  padding:9px 12px;font-size:10.5px;line-height:1.45;color:var(--muted)}
.hero-fig figcaption b{display:block;font-size:11.5px;color:var(--fg);margin-bottom:2px}
@media(max-width:820px){.hero2{grid-template-columns:1fr;gap:34px;padding:44px 0 40px}}

.proof{border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);
  background:#0a0e14;margin:0 -40px;padding:42px 40px}
.proof-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:18px;margin-bottom:24px;flex-wrap:wrap}
.proof-head h2{margin:0;font-size:25px;letter-spacing:-.025em}
.proof-head span{font-size:13.5px;color:var(--muted)}
.proof-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:18px}
.pc{margin:0;display:flex;flex-direction:column;gap:8px}
.pc img{width:100%;aspect-ratio:1;object-fit:cover;display:block;border-radius:10px;
  border:1px solid var(--rule)}
.pc figcaption{font-size:12px;color:var(--muted)}
@media(max-width:720px){.proof-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}

.lessons2{padding:8px 0 10px}
.lessons2 h2{margin:0 0 6px;font-size:29px;letter-spacing:-.03em}
.lessons2 .sub{margin:0 0 28px;color:var(--muted);font-size:15px}
/* One column of rows, not two columns of cards. Ten boxes in a 2 by 2 grid per act
   makes the reader choose thirty times over; a single ordered run makes the point
   the course is actually making, which is that these go in order. */
.act{margin-bottom:30px}
.act-head{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;
  padding:0 12px 9px 0;border-bottom:1px solid var(--rule);margin-bottom:2px}
.act-head .kicker{margin:0}
.act-head p{margin:0;font-size:13px;line-height:1.5;color:var(--muted)}
/* Sits directly above the "3/3" column each .lrow prints on the right, so
   that column reads as a column instead of a number with no header. */
.act-col{margin-left:auto;flex:0 0 auto;font-size:10.5px;font-weight:800;
  letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
.llist{display:flex;flex-direction:column}
.lrow{display:flex;align-items:baseline;gap:16px;text-decoration:none;
  padding:14px 12px 14px 2px;border-bottom:1px solid var(--rule);
  border-radius:8px;transition:background .14s,padding-left .14s}
.lrow:last-child{border-bottom:0}
.lrow:hover{background:var(--bg2);padding-left:10px}
.lrow:focus-visible{outline:2px solid var(--sky);outline-offset:-2px}
.lrow .n{font-size:12px;font-weight:800;letter-spacing:.02em;flex:0 0 auto;
  font-variant-numeric:tabular-nums;min-width:22px}
.lr-txt{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}
.lrow .t{font-weight:700;font-size:16.5px;color:var(--fg)}
.lrow .d{font-size:14px;line-height:1.5;color:var(--muted)}
.lrow .done{flex:0 0 auto;font-size:10.5px;font-weight:800;color:var(--muted);
  letter-spacing:.06em;font-variant-numeric:tabular-nums}
.lrow.is-done .done{color:var(--tint)}
.lrow.is-done .t{color:var(--tint)}
@media(max-width:560px){.lrow{gap:11px;padding-right:2px}}

/* Earl and the live sample sit above the two columns they belong to */
.whowrap{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:34px 40px;padding:16px 0 34px;align-items:start}
.whowrap h2{margin:0 0 10px;font-size:22px;letter-spacing:-.025em}
.whowrap p{margin:0 0 12px;font-size:15.5px;line-height:1.65;color:var(--fg-dim)}
/* Earl and the sample share a grid row, and both stretch to it. Earl is the
   taller of the two by nature, so the row takes his height and the radar image
   flexes to fill exactly that, which is why the two blocks line up bottom to
   bottom at any width without a hard coded number anywhere. */
.whowrap .earl{margin:0;align-self:stretch}
.earl-intro{align-items:flex-end;overflow:visible}
.earl-intro .earl-hero{width:132px;flex:0 0 132px;height:auto;margin-top:-40px;
  filter:drop-shadow(0 8px 18px rgba(0,0,0,.45))}
.earl-intro .earl-body{align-self:center}
@media(max-width:720px){.earl-intro .earl-hero{width:104px;flex-basis:104px;margin-top:-26px}}
/* the launcher's pill, worn by the flip image as a picture of itself: same dress
   as .rl-launch, but decoration here, not a control */
.flip-badge{position:absolute;top:10px;right:10px;z-index:2;
  display:flex;align-items:center;gap:9px;padding:9px 14px 9px 11px;
  border-radius:999px;font-size:13.5px;font-weight:650;color:#fff;
  background:rgba(16,22,31,.92);border:1px solid var(--rule);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  box-shadow:0 6px 26px rgba(0,0,0,.45);pointer-events:none}
.flip-badge svg{width:16px;height:16px;flex:0 0 16px;color:var(--sky)}
/* the stage's loading spinner: shown while national loop frames land */
.ra-spinbox{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  display:flex;flex-direction:column;align-items:center;gap:10px;
  z-index:4;pointer-events:none}
.ra-spinbox[hidden]{display:none}
.ra-spinbox i{width:34px;height:34px;border-radius:50%;
  border:3px solid rgba(255,255,255,.16);border-top-color:var(--sky);
  animation:raspin .8s linear infinite}
.ra-spinbox span{font-size:11.5px;font-weight:650;letter-spacing:.05em;
  color:var(--fg-dim);background:rgba(10,14,20,.72);padding:4px 11px;
  border-radius:8px}
@keyframes raspin{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.ra-spinbox i{animation-duration:2.4s}}
@media(max-width:720px){.whowrap{grid-template-columns:1fr;gap:26px}
  /* stacked, each picture leads its own words: Earl, his text, the radar, its
     text - rather than the two pictures piling up back to back */
  .whowrap>:nth-child(1){order:1}
  .whowrap>:nth-child(3){order:2}
  .whowrap>:nth-child(2){order:3}
  .whowrap>:nth-child(4){order:4}}

/* the two pictures, live, on the front page */
.flip{display:flex;flex-direction:column;gap:10px;align-self:stretch;min-height:0}
.flip-stage{position:relative;border:1px solid var(--rule);border-radius:12px;
  overflow:hidden;background:#000;flex:1;min-height:190px}
/* the crop favours the lower half, where the radar site marker sits */
.flip-stage img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:50% 62%;opacity:0;transition:opacity .22s ease}
.flip-stage img.on{opacity:1}
.flip-ctl{display:flex;gap:8px}
.flip-ctl button{flex:1;font-weight:700;font-size:13px;line-height:1;color:var(--muted);
  background:var(--bg2);border:1px solid var(--rule);border-radius:9px;
  padding:10px 12px;cursor:pointer;transition:color .14s,border-color .14s,background .14s}
.flip-ctl button:hover{color:var(--fg);border-color:var(--sky)}
.flip-ctl button.on{background:var(--sky);border-color:var(--sky);color:#0d1117}
.flip-ctl button:focus-visible{outline:2px solid var(--sky);outline-offset:2px}
@media(prefers-reduced-motion:reduce){.flip-stage img{transition:none}}

/* Who the course is for, said once, right under the promise. It is a claim about
   the reader, not a footnote, so it is sized like one and given room to breathe
   before the section beneath it. The three colors are the three section tints,
   which quietly says the course is built in three parts. */
.audience{max-width:41em;margin:26px auto 50px;font-size:21px;line-height:1.52;
  color:var(--fg);text-align:center;letter-spacing:-.015em;font-weight:400}
.audience b{font-weight:640}
.audience .a1{color:var(--sky)}
.audience .a2{color:var(--go)}
.audience .a3{color:var(--amber)}
@media(max-width:680px){.audience{font-size:18px;margin:26px auto 38px}}
.endcta{margin:26px 0 46px;text-align:center}

.foot{border-top:1px solid var(--rule);background:#0a0e14;margin-top:20px}
.foot-in{max-width:1060px;margin:0 auto;padding:42px 40px 30px}
.foot-cols{display:grid;grid-template-columns:1.45fr 1fr 1.45fr .95fr;gap:34px;
  padding-bottom:30px;align-items:start}
.foot-cols>div{display:flex;flex-direction:column;gap:9px}
.foot-cols a,.foot-cols span:not(.kicker){font-size:13.5px;line-height:1.5;
  color:var(--muted);text-decoration:none}
.foot-cols a:hover{color:var(--sky)}
.foot-brand p{margin:4px 0 0;font-size:13px;line-height:1.6;color:var(--muted);max-width:26em}
/* a block SVG in a flex column stretches to the column and then centers its own
   artwork inside that box, which reads as a stray indent once the column is
   narrow. Shrink the box to the mark. */
.foot-brand .mh-logo{height:32px;align-self:flex-start;max-width:100%}
/* the one column that is selling something. A left rule rather than a box: it
   marks the column as the destination without turning the footer into a banner */
.foot-cols>div.foot-game{gap:7px;padding-left:17px;border-left:2px solid rgba(74,168,232,.42)}
.foot-game .kicker{color:var(--sky)}
.foot-cols .fg-name{font-size:16px;font-weight:750;color:var(--fg);line-height:1.25}
.foot-cols span.fg-line{font-size:13px;color:var(--fg-dim);line-height:1.45}
.foot-cols a.fg-cta{margin-top:6px;font-size:13.5px;font-weight:750;color:var(--sky);
  align-self:flex-start}
.fg-arw{display:inline-block;transition:transform .16s ease}
.foot-cols a.fg-cta:hover{color:#7cc3f2}
.foot-cols a.fg-cta:hover .fg-arw{transform:translateX(3px)}
@media(prefers-reduced-motion:reduce){.fg-arw{transition:none}
  .foot-cols a.fg-cta:hover .fg-arw{transform:none}}

.foot-fine{border-top:1px solid #16202c;padding-top:18px}

.foot-legal{display:flex;justify-content:space-between;gap:24px;align-items:flex-start}
.foot-fine p{margin:0;font-size:12px;line-height:1.6;color:#55697d;max-width:60em}
.foot-fine span{font-size:12px;color:#55697d;white-space:nowrap}
.foot-copy{display:flex;flex-direction:column;align-items:flex-end;gap:4px;flex:0 0 auto}
.foot-copy a{font-size:12px;color:#55697d;text-decoration:none;white-space:nowrap}
.foot-copy a:hover{text-decoration:underline}
.foot-fine p.foot-credit{margin:0 0 15px;font-size:11px;line-height:1.6;color:#465768}
.foot-cols>div{min-width:0}
.foot-cols a,.foot-cols span:not(.kicker){overflow-wrap:anywhere}
@media(max-width:820px){.foot-cols{grid-template-columns:1fr 1fr;gap:26px 30px}
  .foot-legal{flex-direction:column;gap:12px}}
@media(max-width:560px){.foot-cols{grid-template-columns:1fr;gap:22px}
  .foot-in{padding:34px 22px 26px}
  .foot-game{padding-left:15px}
  main.wide{padding:0 22px}
  .proof{margin:0 -22px;padding:32px 22px}}

/* real radar specimens */
.rimg{width:100%;height:auto;display:block;border:1px solid var(--rule);border-radius:12px;
  background:#000}
.rfade{position:relative;display:block;max-width:460px;margin:0 auto}
.rfade .rf-cc{position:absolute;inset:0;opacity:0;animation:rfX 3.4s ease-in-out infinite}
.rf-tag{position:absolute;left:9px;bottom:9px;font-size:10px;font-weight:800;
  letter-spacing:.08em;font-style:normal;color:#cfe3f5;background:rgba(8,13,19,.75);
  padding:3px 9px;border-radius:6px}
.rf-tag.rf-a{animation:rfY 3.4s ease-in-out infinite}
.rf-tag.rf-b{opacity:0;animation:rfX 3.4s ease-in-out infinite}
@keyframes rfX{0%,36%{opacity:0}52%,86%{opacity:1}100%{opacity:0}}
@keyframes rfY{0%,36%{opacity:1}52%,86%{opacity:0}100%{opacity:1}}
@media(prefers-reduced-motion:reduce){
  .rfade{display:grid;grid-template-columns:1fr 1fr;gap:6px;max-width:100%}
  .rfade .rf-cc{position:static;opacity:1;animation:none}
  .rf-tag{display:none}}

.dr-stage .rimg{border-radius:12px}

/* Lesson 1: the product switch, shaped like the layer picker in a radar app */
/* ---------- Lesson 1: the preflight radar ----------
   Shaped like a radar app rather than a figure with a caption. Controls sit on the
   map, the second product lives behind a layers button, and the play control is
   where a play control goes. The lesson asks the reader to go and find four things
   in software they already have, so the four things should look like software
   rather than like a diagram of software. */
.ra{position:relative;border:1px solid var(--rule);border-radius:14px;overflow:hidden;
  background:#000;max-width:560px;margin:0 auto}
.ra-stage{position:relative;aspect-ratio:1}
.ra-stage img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .16s ease}
.ra-stage img.on{opacity:1}
/* A frame that was already cached swaps instantly, which is what playback needs. One
   that had to be fetched fades up, so a cold open or a product change arrives rather
   than snapping. */
.rl-dock .ra-stage img.on.rl-wait{opacity:0}
.rl-dock .ra-stage img{transition:opacity .22s ease}

.ra-top,.ra-bot{position:absolute;left:0;right:0;display:flex;align-items:center;
  gap:10px;padding:11px;pointer-events:none}
.ra-top{top:0;justify-content:space-between;
  background:linear-gradient(180deg,rgba(4,7,11,.72),transparent)}
.ra-bot{bottom:0;background:linear-gradient(0deg,rgba(4,7,11,.8),transparent)}
.ra-top>*,.ra-bot>*{pointer-events:auto}

/* One pill: the site chip and the zoom buttons together, so "what am I looking
   at" and "how far zoomed in" read as one control rather than a chip next to
   an unrelated pair of icons. The chip's name/subtitle stack vertically -
   bold NATIONAL or the site name on top, a smaller line about zoom below it -
   instead of sitting side by side, so the subtitle reads as commentary on the
   name rather than a second label competing with it. */
.ra-viewpill{display:flex;align-items:stretch;border-radius:999px;
  background:rgba(10,14,20,.7);border:1px solid rgba(255,255,255,.16);
  -webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);color:#fff;
  overflow:hidden;
  /* the national label ("NATIONAL" / "zoom in for one radar") is the widest
     this pill is ever asked to show, so that width is floor, not a target - a
     shorter site name should not make the whole zoom control shrink and
     shift the zoom buttons around every time the reader changes sites. Only
     a min: a longer city+state name is still free to grow past it. */
  min-width:216px}
.ra-chip{display:flex;align-items:center;gap:8px;padding:6px 12px 6px 10px;
  background:none;border:0;color:inherit;line-height:1;flex:1}
.ra-chip svg{width:15px;height:15px;flex:0 0 15px;color:var(--sky)}
.ra-chip-text{display:flex;flex-direction:column;align-items:flex-start;gap:1px}
.ra-chip-text b{font-size:12.5px;font-weight:800;letter-spacing:.07em}
.ra-sub{font-size:10px;font-weight:600;color:#9fb0c2}
.ra-zoomgrp{display:flex;align-items:stretch;border-left:1px solid rgba(255,255,255,.16)}
.ra-zbtn{display:grid;place-items:center;width:30px;padding:0;cursor:pointer;
  background:none;border:0;color:#fff}
.ra-zbtn svg{width:14px;height:14px}
.ra-zbtn:hover{color:var(--sky);background:rgba(255,255,255,.07)}
.ra-zbtn:focus-visible{outline:2px solid var(--sky);outline-offset:-2px}
.ra-zbtn + .ra-zbtn{border-left:1px solid rgba(255,255,255,.16)}

.ra-icon{display:grid;place-items:center;width:36px;height:36px;padding:0;cursor:pointer;
  border-radius:10px;background:rgba(10,14,20,.7);border:1px solid rgba(255,255,255,.16);
  color:#fff;-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px)}
.ra-icon svg{width:17px;height:17px}
.ra-icon:hover{border-color:var(--sky);color:var(--sky)}
.ra-icon:focus-visible{outline:2px solid var(--sky);outline-offset:2px}
.ra-icon.on{background:var(--sky);border-color:var(--sky);color:#08131d}
/* says "the other product is in here" until somebody opens it once */
.ra-hint{animation:rahint 2.4s ease-out infinite}
@keyframes rahint{
  0%{box-shadow:0 0 0 0 rgba(74,168,232,.55)}
  70%{box-shadow:0 0 0 11px rgba(74,168,232,0)}
  100%{box-shadow:0 0 0 0 rgba(74,168,232,0)}}

.ra-track{flex:1;height:3px;border-radius:2px;background:rgba(255,255,255,.22);overflow:hidden}
.ra-fill{display:block;height:100%;width:0;background:var(--sky);
  transition:width .18s linear}
.ra-time{font-size:11.5px;color:#cfdae6;white-space:nowrap;font-variant-numeric:tabular-nums}

.ra-panel{position:absolute;top:0;right:0;bottom:0;width:min(74%,238px);
  padding:12px;display:flex;flex-direction:column;gap:7px;
  background:rgba(8,12,18,.9);-webkit-backdrop-filter:blur(11px);backdrop-filter:blur(11px);
  border-left:1px solid rgba(255,255,255,.14);
  transform:translateX(101%);transition:transform .2s ease;visibility:hidden}
.ra-panel.on{transform:none;visibility:visible}
.ra-phead{display:flex;align-items:center;justify-content:space-between;
  font-weight:800;font-size:10.5px;line-height:1;letter-spacing:.15em;text-transform:uppercase;color:#8fa2b5;
  padding-bottom:9px;margin-bottom:2px;border-bottom:1px solid rgba(255,255,255,.12);flex:none}
/* the title/close row stays a plain, non-scrolling sibling; only the option list
   below it scrolls (same split as .rl-sites already uses for its search+list) -
   position:sticky here fought iOS Safari's rubber-band overscroll, which would
   let scrolled-past options bleed into the gap above the "stuck" header during
   the bounce. A genuinely separate scroll region sidesteps that entirely. */
.ra-plist{overflow-y:auto;-webkit-overflow-scrolling:touch;flex:1;min-height:0;
  display:flex;flex-direction:column;gap:7px}
.ra-x{padding:0;width:22px;height:22px;display:grid;place-items:center;cursor:pointer;
  background:none;border:0;color:#8fa2b5;border-radius:6px}
.ra-x svg{width:13px;height:13px}
.ra-x:hover{color:#fff}
.ra-opt{display:flex;align-items:center;gap:9px;width:100%;text-align:left;cursor:pointer;
  padding:9px 10px;border-radius:9px;color:#c7d3e0;font:inherit;
  background:rgba(255,255,255,.05);border:1px solid transparent}
.ra-opt b{font-size:13.5px;font-weight:650;flex:1;color:inherit}
.ra-opt em{font:800 10px/1 ui-monospace,SFMono-Regular,Menlo,monospace;font-style:normal;
  letter-spacing:.05em;color:#7d8fa2}
.ra-dot{width:13px;height:13px;flex:0 0 13px;border-radius:50%;
  border:1.5px solid rgba(255,255,255,.35)}
.ra-opt:hover{border-color:rgba(74,168,232,.5);color:#fff}
.ra-opt:focus-visible{outline:2px solid var(--sky);outline-offset:1px}
.ra-opt.on{background:var(--sky-dim);border-color:var(--sky);color:#fff}
.ra-opt.on .ra-dot{border-color:var(--sky);box-shadow:inset 0 0 0 3px var(--sky)}
.ra-opt.on em{color:var(--sky)}
.ra-opt:disabled{opacity:.34;cursor:default}
.ra-opt:disabled:hover{border-color:transparent;color:#c7d3e0}
.ra-pnote{margin:auto 0 0;font-size:11.5px;line-height:1.5;color:#7d8fa2}
.rl-tilts{display:flex;flex-direction:column;gap:7px;margin-top:2px;
  padding-top:11px;border-top:1px solid rgba(255,255,255,.12)}
.rl-tilts[hidden]{display:none}
.rl-tilts .ra-pnote{margin:0 0 2px}

.ra-note{max-width:560px;margin:15px auto 0;font-size:14.5px;line-height:1.6;
  color:var(--fg-dim);min-height:3.3em}
.ra-cred{max-width:560px;margin:9px auto 0;padding-top:11px;
  border-top:1px solid var(--rule);font-size:11.5px;line-height:1.55;color:#5c6b7c}
/* on a narrow stage a 74% panel leaves a sliver of map and clips the site chip
   in half, which reads as broken rather than as an overlay. Full width sheet. */
@media(max-width:520px){.ra-panel{width:100%;border-left:0}
  .ra-note{min-height:0}}
@media(prefers-reduced-motion:reduce){
  .ra-hint{animation:none}
  .ra-panel,.ra-stage img,.ra-fill{transition:none}}

/* the whole opening block: heading, the radar, and the errand it sets up, in one
   container instead of a widget followed by a box repeating what the widget said */
.pre{border:1px solid rgba(63,191,128,.28);border-radius:14px;margin:10px 0 34px;
  padding:22px 24px 24px;background:linear-gradient(180deg,rgba(63,191,128,.07),transparent 55%)}
.pre-lbl{display:block;font-weight:800;font-size:10.5px;line-height:1;letter-spacing:.15em;text-transform:uppercase;
  color:var(--go);margin-bottom:9px}
.pre h4{margin:0 0 8px;font-size:1.16rem;color:#fff}
.pre>p{margin:.7em 0}
.pre ul{margin:.9em 0}
.pre>p:last-child{margin-bottom:0}
@media(max-width:560px){.pre{padding:18px 16px 20px}}


/* Lesson 6: the Motion game, isolated in its own document */
.mg{display:flex;justify-content:center}
.mg-note{display:flex;align-items:center;gap:10px;padding:14px 4px;
  color:var(--muted);font-size:13.5px;line-height:1.5}
.mg-note[hidden]{display:none}
.mg-spin{width:16px;height:16px;border:2px solid var(--rule);
  border-top-color:var(--sky);border-radius:50%;flex:0 0 16px;
  animation:mgspin .8s linear infinite}
@keyframes mgspin{to{transform:rotate(1turn)}}
@media(prefers-reduced-motion:reduce){.mg-spin{animation:none}}

.mg-frame{width:100%;max-width:492px;height:940px;border:0;display:block;
  background:#0a0e14;border-radius:16px;overflow:hidden}

/* The catalog ladder in Lesson 7. The bottom four rungs only need recognizing,
   so they get a row of compact cards rather than four pages of prose. */
.minirow{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin:20px 0 26px}
.mini{background:var(--bg2);border:1px solid var(--rule);border-radius:11px;
  padding:13px 15px;display:flex;flex-direction:column;gap:5px}
/* a strip of the actual thing, above the words describing it. 3:1 so it reads as
   a band of weather rather than a thumbnail, and roughly the height of the text
   under it so neither half dominates the card. */
.mini-img{display:block;width:100%;aspect-ratio:3/1;object-fit:cover;
  border-radius:8px;border:1px solid var(--rule);background:#0a0e13;margin-bottom:4px}
.mini-name{font-weight:700;font-size:15.5px;color:var(--fg)}
.mini-tell{font-size:14px;line-height:1.5;color:var(--go);font-weight:600}
.mini-so{font-size:13.5px;line-height:1.55;color:var(--muted)}
@media(max-width:560px){.minirow{grid-template-columns:1fr}}

/* Lesson 4: the storm motion slider. One control, and everything else in the
   panel is derived from it, including the picture. The two color swatches are
   filled from the same velocity scale the echo is painted with, so the chip
   beside a number is literally the color that number would be on a screen. */
.srm{display:grid;grid-template-columns:minmax(0,330px) minmax(0,1fr);gap:26px;
  align-items:start}
.srm-stage svg{width:100%;height:auto;display:block;border-radius:10px;
  border:1px solid var(--rule)}
.srm-lab{display:block;font-size:12px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.srm-headline{display:flex;align-items:baseline;gap:7px;margin:2px 0 2px}
.srm-mv{font-size:2.5rem;font-weight:800;color:#fff;line-height:1.05;
  letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.srm-unit{font-size:13px;color:var(--muted);font-weight:700;letter-spacing:.1em}
.srm-range{width:100%;accent-color:var(--sky);margin:2px 0}
.srm-ticks{display:flex;justify-content:space-between;font-size:11.5px;
  color:var(--muted);margin-bottom:16px}
.srm-rows{border-top:1px solid var(--rule)}
.srm-row{display:flex;align-items:center;gap:11px;padding:9px 0;
  border-bottom:1px solid var(--rule)}
.srm-sw{width:22px;height:22px;border-radius:6px;flex:0 0 auto;
  border:1px solid var(--rule);transition:background .12s}
.srm-blank{background:none;border-color:transparent}
.srm-what{font-size:14px;color:var(--fg-dim);line-height:1.35}
.srm-what b{color:#fff}
.srm-num{margin-left:auto;font-size:15px;font-weight:750;color:#fff;
  white-space:nowrap;font-variant-numeric:tabular-nums}
.srm-gap .srm-what{color:var(--muted)}
.srm-fixed{color:var(--amber)}
.srm-say{margin:15px 0 14px;font-size:14.5px;line-height:1.6;color:var(--fg-dim);
  min-height:5.2em}
.srm-say b{color:#fff}
.srm.hidden-couplet .srm-say b{color:var(--stop)}
.srm-zero{background:none;border:1px solid var(--rule);color:var(--fg);
  font:inherit;font-size:13.5px;font-weight:650;padding:9px 15px;border-radius:8px;
  cursor:pointer;transition:border-color .14s,color .14s}
.srm-zero:hover{border-color:var(--sky);color:var(--sky)}
.srm-zero:focus-visible{outline:2px solid var(--sky);outline-offset:2px}
@media(max-width:720px){.srm{grid-template-columns:1fr;gap:18px}
  .srm-say{min-height:0}}

/* Lesson 7: the notch hunt. The cursor is the whole affordance here, so the
   live state has to look clickable and the answered state has to stop looking
   clickable the instant it is answered. */
.nh-stage svg{width:100%;height:auto;display:block;border-radius:10px;
  border:1px solid var(--rule)}
.nh-stage svg.nh-live{cursor:crosshair}
.nh-ov{pointer-events:none}
.dr-none{color:var(--muted);font-size:14px;padding:20px}

/* ---------- Lesson 7: scrub the warning ----------
   A timeline the reader owns, and a verdict that is measured rather than asserted.
   The bar chart is real pixel counts off the six frames, which is the only reason
   the closing claim (it finished smaller than it started) is allowed to be made. */
.ws{max-width:560px;margin:0 auto}
.ws-app{position:relative;border:1px solid var(--rule);border-radius:13px;
  overflow:hidden;background:#000;aspect-ratio:1}
.ws-app img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
/* the polygon is a layer, and behaves like one: it fades in over whatever
   frame is underneath rather than being baked into a picture */
.ws-poly{opacity:0;transition:opacity .2s ease;pointer-events:none}
.ws-poly.on{opacity:1}
.ws-state{margin:12px 0 0;font-size:14.5px;line-height:1.6;color:var(--muted)}
.ws-live{color:#ff8a80}
.ws-stop.warn i{background:#54303a}
.ws-stop.warn.on i{background:#c82c24;box-shadow:0 0 0 4px rgba(200,44,36,.22)}
@media(prefers-reduced-motion:reduce){.ws-poly{transition:none}}
.ws-stamp{position:absolute;left:11px;top:11px;padding:5px 11px;border-radius:999px;
  background:rgba(10,14,20,.72);border:1px solid rgba(255,255,255,.16);color:#fff;
  font-weight:700;font-size:12px;line-height:1;letter-spacing:.05em;
  -webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px)}
.ws-alert{position:absolute;left:11px;right:11px;bottom:11px;padding:8px 12px;
  border-radius:9px;background:rgba(200,44,36,.92);color:#fff;
  font-weight:800;font-size:12.5px;line-height:1.3;letter-spacing:.05em;text-transform:uppercase}

.ws-line{display:flex;gap:2px;margin:14px 0 0;position:relative}
.ws-stop{flex:1;display:flex;flex-direction:column;align-items:center;gap:7px;
  padding:9px 0 6px;cursor:pointer;background:none;border:0;font:inherit;
  color:var(--muted);border-top:2px solid var(--rule)}
.ws-stop i{width:9px;height:9px;border-radius:50%;background:#38485a;display:block}
.ws-stop span{font-size:11.5px;font-variant-numeric:tabular-nums}
.ws-stop:hover{color:var(--fg)}
.ws-stop:hover i{background:var(--sky)}
.ws-stop:focus-visible{outline:2px solid var(--sky);outline-offset:-2px;border-radius:6px}
.ws-stop.on{color:#fff}
.ws-stop.on i{background:var(--sky);box-shadow:0 0 0 4px var(--sky-dim)}
/* the warned half of the timeline, only once the reader has committed */
.ws-line .ws-stop:nth-child(n+4){border-top-color:#54303a}
.ws-line.warned .ws-stop:nth-child(n+4){border-top-color:#c82c24}
.ws-line .ws-stop:nth-child(4) span::after{content:" ▲";color:#c82c24;font-size:9px}

.ws-ask p{margin:14px 0 12px;font-size:15px;line-height:1.6;color:var(--fg-dim)}
.ws-go{font:inherit;font-size:14.5px;font-weight:700;cursor:pointer;padding:10px 18px;
  border-radius:10px;background:var(--sky);color:#08131d;border:0}
.ws-go b{font-variant-numeric:tabular-nums}
.ws-go:hover{background:#7cc3f2}
.ws-go:focus-visible{outline:2px solid var(--sky);outline-offset:2px}
.ws-alt{background:none;border:1px solid var(--sky);color:var(--sky);margin-top:6px}
.ws-alt:hover{background:var(--sky-dim)}

.ws-out{margin-top:14px}
.ws-out p{margin:.75em 0;font-size:15px;line-height:1.6;color:var(--fg-dim)}
.ws-head{font-size:16px !important;color:#fff !important}
.ws-head b{color:#ff8a80}
.ws-bars{display:flex;align-items:flex-end;gap:8px;height:104px;margin:16px 0 10px;
  padding-bottom:20px;border-bottom:1px solid var(--rule)}
.ws-b{flex:1;display:flex;flex-direction:column;justify-content:flex-end;height:100%;
  position:relative}
.ws-b i{display:block;width:100%;background:#2f6f9e;border-radius:3px 3px 0 0}
.ws-b.warn i{background:#c82c24}
.ws-b span{position:absolute;left:0;right:0;bottom:-19px;text-align:center;
  font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums}
@media(max-width:560px){.ws-stop span{font-size:10.5px}}

/* ---------- Lesson 8: watch the wind field ----------
   No drag, no question: a real eye-locked velocity loop plays underneath a
   fixed overlay (motion arrow, quadrant readouts), so the only thing left to
   look at is the real wind field changing while the storm's own rotation
   never does. The coastline scrolling past is the real coastline in the real
   frames - nothing here is drawn any more. */
.wf-frame{position:relative;border:1px solid var(--rule);border-radius:12px;
  overflow:hidden;background:#0a1119}
.wf-img{display:block;width:100%;height:auto}
.wf-overlay{position:absolute;inset:0;width:100%;height:100%}
.wf-quad b{font-size:20px}
.wf-note{margin-top:12px;font-size:14.5px;line-height:1.6;color:var(--muted)}
.wf-note b{color:var(--fg)}

/* Lesson 10: the case exam. Evidence accumulates down the left as products are
   revealed, so by the last question the reader is looking at the whole stack
   they reasoned from rather than one picture at a time. */
.cx{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:26px;
  align-items:start}
.cx-side{position:sticky;top:78px}
.cx-head{margin:0 0 4px;font-size:15px;color:var(--fg)}
.cx-note{margin:0 0 14px;font-size:13.5px;line-height:1.55;color:var(--muted)}
.cx-shot{margin:0 0 14px}
.cx-shot img{width:100%;height:auto;display:block;border-radius:9px;
  border:1px solid var(--rule)}
.cx-shot figcaption{margin-top:6px;font-size:11.5px;color:var(--muted);line-height:1.45}
.cx-case{margin:0 0 4px;font-size:11.5px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--sky)}
.cx-prompt{margin:0 0 14px;font-size:16px;line-height:1.55;color:#fff;font-weight:600}
.cx-opts{display:flex;flex-direction:column;gap:9px}
.cx-opt{text-align:left;font:inherit;font-size:14.5px;line-height:1.5;
  background:var(--bg2);color:var(--fg-dim);border:1px solid var(--rule);
  border-radius:9px;padding:12px 14px;cursor:pointer;
  transition:border-color .13s,color .13s,background .13s}
.cx-opt:hover:not(:disabled){border-color:var(--sky);color:#fff}
.cx-opt:disabled{cursor:default}
.cx-opt.ok{border-color:var(--go);color:#fff;background:rgba(63,191,128,.12)}
.cx-opt.no{border-color:var(--stop);color:#fff;background:rgba(239,90,76,.12)}
.cx-why{margin:0;font-size:14.5px;line-height:1.6;color:var(--fg-dim)}
.cx-why.ok,.cx-why.no{margin:15px 0 0;padding-left:13px;border-left:3px solid var(--rule)}
.cx-why.ok{border-left-color:var(--go)}
.cx-why.no{border-left-color:var(--stop)}
.cx-why b{color:#fff}
.cx-bar{display:flex;align-items:center;gap:14px;margin-top:16px}
.cx-next{background:var(--sky);border:0;color:#0d1117;font:inherit;font-size:14px;
  font-weight:700;padding:10px 17px;border-radius:8px;cursor:pointer}
.cx-next:hover{filter:brightness(1.08)}
.cx-prog{font-size:12.5px;color:var(--muted);margin-left:auto}
@media(max-width:760px){.cx{grid-template-columns:1fr;gap:18px}
  .cx-side{position:static}}

/* ===================== live panel: launcher and the two layouts =====================

   The scope itself is the .ra-* chrome above, unchanged, because Lesson 1's whole
   argument is "this is what every radar app looks like, here are the four controls"
   and a live panel that looked different would undercut the lesson that sent the
   reader looking for them.

   What is added here is only how the panel arrives: a launcher, a docked column on
   a wide screen, and a sheet over the content on a narrow one. Splitting the
   viewport on a phone costs the reading area of a course that is mostly reading and
   still leaves the scope too small to spot a hook in, so the phone gets a sheet.

   Everything is position:fixed, so no page has to change shape to hold it. The one
   exception is the desktop dock, which pays out padding on <body> so a sticky
   column does not sit on top of the prose it is meant to sit beside. */

.rl-launch{position:fixed;right:16px;bottom:16px;z-index:39;
  display:flex;align-items:center;gap:9px;padding:10px 15px 10px 12px;
  border-radius:999px;cursor:pointer;font:inherit;font-size:13.5px;font-weight:650;
  color:#fff;background:rgba(16,22,31,.92);border:1px solid var(--rule);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  box-shadow:0 6px 26px rgba(0,0,0,.45)}
.rl-launch svg{width:16px;height:16px;flex:0 0 16px;color:var(--sky)}
.rl-launch:hover{border-color:var(--sky)}
.rl-launch:focus-visible{outline:2px solid var(--sky);outline-offset:3px}
/* a live dot, because the one thing the launcher has to promise is that it is live */
.rl-live{width:7px;height:7px;border-radius:50%;background:var(--go);flex:0 0 7px;
  box-shadow:0 0 0 0 rgba(63,191,128,.6);animation:rlpulse 2.6s ease-out infinite}
@keyframes rlpulse{
  0%{box-shadow:0 0 0 0 rgba(63,191,128,.55)}
  70%{box-shadow:0 0 0 8px rgba(63,191,128,0)}
  100%{box-shadow:0 0 0 0 rgba(63,191,128,0)}}
body.rl-open .rl-launch{display:none}

.rl-dock{position:fixed;z-index:40;background:var(--bg2);
  border-left:1px solid var(--rule);display:flex;flex-direction:column;
  transition:transform .26s ease;overscroll-behavior:contain}
.rl-dhead{display:flex;align-items:center;gap:10px;padding:12px 14px;
  border-bottom:1px solid var(--rule)}
.rl-dtitle{font-weight:800;font-size:10.5px;line-height:1;letter-spacing:.15em;text-transform:uppercase;
  color:var(--muted);flex:1}
.rl-close{display:grid;place-items:center;width:30px;height:30px;padding:0;cursor:pointer;
  border-radius:8px;background:none;border:1px solid transparent;color:var(--muted)}
.rl-close svg{width:14px;height:14px}
.rl-close:hover{color:#fff;border-color:var(--rule)}
.rl-close:focus-visible{outline:2px solid var(--sky);outline-offset:1px}
/* A column, so the scope can take whatever height the text below it does not.
   min-height:0 is the load bearing part: a flex child defaults to min-height:auto and
   refuses to shrink below its content, which is what leaves a slab of dead panel
   under a square scope on a tall screen. */
.rl-body{padding:14px;flex:1;min-height:0;display:flex;flex-direction:column;
  overflow-y:auto}
/* the scope fills the dock rather than sitting at the widget's 560px, and drops the
   rounded card border, because inside a dock it is the whole surface */
/* margin:0 is load bearing. The widget version centres itself with margin:0 auto,
   and an auto margin on the cross axis of a flex column stops the item stretching,
   so .ra collapsed to the width of its contents, which are absolutely positioned and
   therefore nothing at all. A 2px wide scope with no error anywhere. */
.rl-body .ra{max-width:none;margin:0;width:100%;border-radius:11px;
  flex:1 1 auto;min-height:min(58vh,420px)}
/* The stage is square everywhere else in the course, where it sits in a column of
   prose. Here it is the whole surface and has to fill it, so the aspect ratio moves
   off the box and onto the layers inside, which stay square and crop. */
.rl-dock .ra-stage{aspect-ratio:auto;position:absolute;inset:0}
/* flex-shrink:0 is the fix, not min-height. As flex items in a column these were
   being squashed to zero height by the scope's flex:1 while their text carried on
   drawing outside the box, so the caption sat on top of the rule under it. The scope
   is the only thing here that should give. */
.rl-body .ra-note{max-width:none;margin:12px 0 0;font-size:13.5px;min-height:0;
  flex-shrink:0}
.rl-legend,.rl-legal{flex-shrink:0}
.rl-body .ra-cred{max-width:none}

/* the permanent lines. Decision 5: attribution, the feed's age and the
   not-for-warnings line are prominent rather than tucked away, and the panel is
   the closest thing this project has built to the line between "imagery to
   practise on" and "your weather safety tool" */
.rl-legal{margin:13px 0 0;padding-top:12px;border-top:1px solid var(--rule);
  font-size:11.5px;line-height:1.6;color:#5c6b7c}
.rl-legal b{color:var(--amber);font-weight:700}

/* wide: a docked column beside the lesson, with the page making room for it */
@media(min-width:1180px){
  .rl-dock{top:0;right:0;bottom:0;width:min(34vw,430px);transform:translateX(101%)}
  body.rl-open .rl-dock{transform:none}
  body.rl-open{padding-right:min(34vw,430px)}
  /* the masthead is sticky and full width, so it needs the same room */
  body.rl-open .masthead,body.rl-open .levelnav{padding-right:0}
}

/* narrow: a sheet over the content, dismissible, never a split viewport */
@media(max-width:1179px){
  /* max-height rather than height: the sheet is as tall as what is in it, so a
     short panel does not leave a slab of dead space over the lesson, and a tall one
     still stops short of the top and keeps the page visible behind it */
  /* full screen, not a partial sheet: the map deserves the whole display, and the
     site's own masthead has nothing to say while the radar is up */
  .rl-dock{left:0;right:0;bottom:0;top:0;height:100vh;height:100dvh;max-height:none;
    border-left:0;border-top:0;
    border-radius:0;transform:translateY(101%);
    box-shadow:0 -10px 40px rgba(0,0,0,.5)}
  body.rl-open .rl-dock{transform:none}
  /* a grab handle says "this pulls down", which is the gesture the shape promises */
  .rl-grab{width:38px;height:4px;border-radius:2px;background:var(--rule);
    margin:8px auto 0}
  .rl-scrim{position:fixed;inset:0;z-index:39;background:rgba(4,7,11,.55);
    opacity:0;pointer-events:none;transition:opacity .26s ease}
  body.rl-open .rl-scrim{opacity:1;pointer-events:auto}
}
@media(min-width:1180px){.rl-grab,.rl-scrim{display:none}}

@media(prefers-reduced-motion:reduce){
  .rl-dock{transition:none}
  .rl-scrim{transition:none}
  .rl-live{animation:none}
}

/* the panel's own additions to the .ra-* vocabulary: a site list, a grabbable
   scrub track, the feed age, and the designed empty state */

/* school.css gives .ra overflow:hidden, which clips the parked panels but still
   makes .ra a scroll container: a closed .ra-panel sits at translateX(101%) and
   pushes scrollWidth past clientWidth. Focusing the site search then scrolls the
   whole scope sideways under its own frame. overflow:clip clips identically and
   never becomes scrollable. The Lesson 1 widget never focuses inside a panel, so
   it never trips this. */
.rl-dock .ra{overflow:clip}

.ra-panel.rl-sites{width:min(86%,300px)}
.rl-list{overflow-y:auto;flex:1;margin:0 -4px;padding:0 4px;
  display:flex;flex-direction:column;gap:5px}
.rl-search{width:100%;padding:8px 10px;border-radius:8px;font:inherit;font-size:13.5px;
  background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.14);color:#fff}
/* iOS Safari auto-zooms the page to fit any focused input under 16px, which on
   this search box reads as the whole scope suddenly zooming in on tap. Bumping it
   to 16px on mobile (desktop keeps the tighter 13.5px) is the standard fix - the
   browser has nothing left to zoom in to help with. Placed after the base rule,
   not just inside a narrower media query, because an earlier-in-file media rule
   loses a cascade tie to a later unconditional one of equal specificity. */
@media(max-width:520px){.rl-search{font-size:16px}}
.rl-search::placeholder{color:#7d8fa2}
.rl-search:focus{outline:2px solid var(--sky);outline-offset:1px}
.rl-site{display:flex;align-items:baseline;gap:8px;width:100%;text-align:left;
  cursor:pointer;padding:7px 9px;border-radius:8px;color:#c7d3e0;font:inherit;
  background:rgba(255,255,255,.05);border:1px solid transparent}
.rl-site b{font:800 12px/1.3 ui-monospace,SFMono-Regular,Menlo,monospace;
  letter-spacing:.05em;color:#8fa2b5;flex:0 0 34px}
.rl-site span{font-size:13px;flex:1}
.rl-site:hover{border-color:rgba(74,168,232,.5);color:#fff}
.rl-site.on{background:var(--sky-dim);border-color:var(--sky);color:#fff}
.rl-site.on b{color:var(--sky)}

/* the site chip is a button here rather than a label, because it opens the picker */
.rl-dock .ra-chip{cursor:pointer;font:inherit}
.rl-dock .ra-chip:hover{color:var(--sky)}
.rl-dock .ra-chip:hover svg{color:var(--sky)}
.rl-dock .ra-chip:focus-visible{outline:2px solid var(--sky);outline-offset:-2px}

/* a 3px line is the right look and a poor touch target, so the hit area grows with
   a pseudo element rather than by thickening the line */
.rl-dock .ra-track{cursor:pointer;position:relative;overflow:visible}
.rl-dock .ra-track::after{content:"";position:absolute;left:0;right:0;top:-10px;bottom:-10px}
.rl-dock .ra-fill{border-radius:2px}
/* the fill runs smoothly across a frame's dwell time, and snaps with no animation
   when the loop wraps, because a bar sliding backwards reads as rewinding */
.rl-dock .ra-fill{transition:width linear}
.rl-dock .ra-fill.rl-jump{transition:none}
.rl-dock .ra-track:focus-visible{outline:2px solid var(--sky);outline-offset:6px}

.rl-age{font-size:11.5px;color:#9fb0c2;white-space:nowrap;font-variant-numeric:tabular-nums}
.rl-age.stale{color:var(--amber)}

/* Decision 4: never an empty scope with no explanation */
.rl-empty{position:absolute;inset:0;display:none;place-items:center;text-align:center;
  padding:30px;background:#000;color:var(--fg-dim);font-size:14px;line-height:1.6}
.rl-empty.on{display:grid}

/* the quiet network state keeps the archived case visible behind the explanation,
   because the point is to show the reader something rather than to cover it up */
.rl-empty.quiet{background:linear-gradient(0deg,rgba(4,7,11,.93),rgba(4,7,11,.62));
  align-content:center;gap:9px}
.rl-empty p{margin:0}
.rl-empty .rl-arch{font-size:12.5px;color:var(--muted)}

/* the map under the radar, and the radar's own position over it */

.rl-dot{position:absolute;width:5px;height:5px;
  transform:translate(-50%,-50%);
  border-radius:50%;background:#38e0d0;opacity:0;
  transition:opacity .16s ease;
  box-shadow:0 0 0 1.5px rgba(4,7,11,.75)}
.rl-dot.on{opacity:.92}
@media(prefers-reduced-motion:reduce){.rl-dot{transition:none}}

/* the probe: a tap's real reading, pinned to the world point it was read from.
   pointer-events:none like every other overlay dot - the stage's own gesture
   code hit-tests it manually (same reason .rl-radar is none), so a tap on the
   marker itself is not a separate click target racing the pan/zoom handling */
.rl-probe{position:absolute;transform:translate(-50%,calc(-100% - 10px));
  pointer-events:none;white-space:nowrap;
  background:rgba(8,12,18,.92);color:#fff;border:1px solid var(--sky);
  border-radius:8px;padding:4px 9px;font:800 12px/1.2 ui-monospace,SFMono-Regular,Menlo,monospace;
  box-shadow:0 2px 8px rgba(0,0,0,.45)}
.rl-probe::after{content:"";position:absolute;left:50%;top:100%;
  transform:translateX(-50%);border:5px solid transparent;border-top-color:var(--sky)}

/* zoom. The wrapper is what the interim scale acts on, so the site dot and the
   overlays stay put while the map and the radar under them grow. */
/* THE WORLD LAYERS. Every image is pinned to a rectangle in one shared world
   coordinate system and positioned by the camera with a single translate+scale,
   transform-origin top left, computed in JS each frame. There is no wrapper being
   scaled, no frame element, and no CSS transition on geometry: the camera is the
   only thing that moves, and it is driven by fingers or by an eased rAF animation.
   That is what makes a detail-level change incapable of shifting the picture. */
/* The selector strength matters: the Lesson 1 widget declares `.ra-stage img` at
   opacity 0 until an .on class arrives, and width:100%. World layers are governed by
   the camera alone, so this must outweigh that rule or every layer is invisible and
   stage-sized - loaded, positioned, and showing nothing. */
.rl-lyrbox{position:absolute;inset:0;pointer-events:none}
.rl-dock .ra-stage img.rl-lyr{position:absolute;left:0;top:0;right:auto;bottom:auto;
  width:auto;height:auto;max-width:none;max-height:none;object-fit:fill;
  opacity:1;transition:none;transform-origin:0 0;will-change:transform;
  pointer-events:none}
/* No disc clip. The old architecture cropped renders to an inscribed circle, which
   at close levels threw away real data: the window is far inside the radar's actual
   460 km reach, so the corners are as genuine as the middle. The true range limit is
   already in the render's own transparency, and where a product runs out (velocity
   and CC at 300 km) the data itself ends in a ring, honestly, with the map beyond. */
/* the archive specimen simply fills the stage; it is not part of the world */
.rl-dock .ra-stage img.rl-arch-img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;opacity:1;transition:none}
/* Superseded: the stage now owns every gesture on it, see the rule further down.
   Two touch-action declarations on one element is a coin toss decided by source
   order, which is not a thing to leave in a stylesheet. */
.rl-tools{display:flex;align-items:center;gap:7px;pointer-events:auto}
.ra-icon:disabled{opacity:.34;cursor:default}
.ra-icon:disabled:hover{border-color:rgba(255,255,255,.16);color:#fff}


/* ---- the map layer, now wider than the view so it can be panned ----
   The base map is rendered `pad` times wider than the frame and the radar is not:
   the radar is supposed to end, in a ring at the edge of its coverage, and what you
   drag around inside is the map. */
/* The radar is a disc, not a rectangle. Unclipped it ends on the frame edge, which
   is invisible while it fills the view and becomes an obviously wrong straight line
   the moment anybody pans. Clipping to the inscribed circle makes the edge read as
   what it is, the limit of one radar's coverage, and costs only the frame corners,
   which are the longest ranges and the highest beam anyway. */

.rl-dock .ra-stage{cursor:grab;-webkit-tap-highlight-color:transparent}
.rl-dock .ra-stage:active{cursor:grabbing}
/* The stage owns every gesture that starts on it: one finger pans, two pinch. That
   costs dragging the SHEET up and down from the map, which is the right trade, since
   the sheet has a header and a grab handle to drag and the map has nothing else.

   The rest of this is about long press. On a phone, holding a finger on an image
   offers to save it and holding it on text starts a selection, and both fire in the
   middle of somebody trying to move the map. */
.rl-dock .ra-stage{touch-action:none;
  -webkit-user-select:none;user-select:none;
  -webkit-touch-callout:none}
.rl-dock .ra-stage img{-webkit-user-drag:none;-webkit-touch-callout:none;
  pointer-events:none}
.rl-cities{-webkit-user-select:none;user-select:none}
/* .ra-stage img sets inset:0 and is one specificity point heavier than a bare
   class, so this has to name both or the map silently renders at view size */


/* city labels are DOM, so they stay one size at every zoom and need no font in the
   render container */
/* Full stage overlays now, sitting OUTSIDE the scaled wrapper. Their contents are
   positioned in pixels by placeOverlays(), so nothing here scales and the text is
   drawn once at its real size. overflow:hidden clips the ones that fall outside. */
.rl-cities{position:absolute;inset:0;overflow:hidden;pointer-events:none}
/* Labels hold their size because nothing scales them: they live outside the scaled
   wrapper and placeOverlays() puts them where the transform would have. Cancelling
   the scale on them instead kept the size but not the crispness, because the text
   was still being rasterised at the composite scale and redrawn every frame. */
.rl-cities i{position:absolute;transform:translate(-50%,-50%);
  transition:opacity .3s ease;
  display:flex;align-items:center;gap:4px;white-space:nowrap}
/* newly in view, and on the way out */
.rl-cities i.rl-in,.rl-cities i.rl-out{opacity:0}
.rl-cities b{width:3px;height:3px;border-radius:50%;background:#8fa2b5;flex:0 0 3px}
.rl-cities span{font:600 10.5px/1 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,sans-serif;
  color:#b8c4d2;letter-spacing:.01em;
  text-shadow:0 0 3px #000,0 0 6px #000,0 1px 2px #000}

/* ---- ground temperature: real station readings, a layer rather than a product ---- */
.rl-temps{position:absolute;inset:0;overflow:hidden;pointer-events:none}
.rl-temp{position:absolute;transform:translate(-50%,-50%);transition:opacity .3s ease;
  display:flex;align-items:center;justify-content:center;min-width:28px;height:19px;
  padding:0 5px;border-radius:10px;font:800 10.5px/1 ui-monospace,SFMono-Regular,Menlo,monospace;
  color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.55);
  box-shadow:0 1px 3px rgba(0,0,0,.4);white-space:nowrap}
.rl-temp.rl-in,.rl-temp.rl-out{opacity:0}

/* ---- the strip legend ---- */
.rl-legend{margin:11px 0 0}
/* the name of the layer the bar describes, in the course's small-caps voice */
.rl-lname{font-weight:800;font-size:10.5px;line-height:1;letter-spacing:.13em;
  text-transform:uppercase;color:#8fa2b5;text-align:left;margin:0 0 6px}
/* the exclusive door into Products, matching RadarScope/MyRadar tapping the
   name beside the legend - no toolbar icon duplicates this any more. Only
   cursor/layout/focus are set here: .rl-lname's own caps/weight/spacing must
   NOT be touched (an earlier version reset font/text-transform/letter-spacing
   to "inherit" on this same element, which - same specificity, later in the
   file - silently overrode .rl-lname's uppercase rather than merely adding a
   click target on top of it). */
.rl-lname-btn{cursor:pointer;background:none;border:0;padding:0;
  display:inline-flex;align-items:center;gap:4px}
.rl-lname-btn::after{content:"";width:0;height:0;margin-top:1px;
  border-left:4px solid transparent;border-right:4px solid transparent;
  border-top:5px solid currentColor;opacity:.7}
.rl-lname-btn:hover,.rl-lname-btn:focus-visible{color:var(--sky)}
.rl-lname-btn:focus-visible{outline:2px solid var(--sky);outline-offset:2px;border-radius:3px}
.rl-bar{height:10px;border-radius:3px;border:1px solid var(--rule)}
.rl-ticks{position:relative;height:15px;margin-top:3px}
.rl-ticks span{position:absolute;transform:translateX(-50%);
  font:600 10px/1 ui-monospace,SFMono-Regular,Menlo,monospace;color:#8fa2b5;
  font-variant-numeric:tabular-nums}
/* the unit sits on the left, where no ramp has a tick: on the right it lands under
   the topmost label on every one of the three products */
.rl-ticks b{position:absolute;left:0;top:0;font-weight:600;font-size:10px;line-height:1;color:#5c6b7c;
  letter-spacing:.06em}

/* ---- radar dots: a radar is a place you can go, so its dot is a button ---- */
.rl-radars{position:absolute;inset:0;overflow:hidden}
.rl-radar{position:absolute;transform:translate(-50%,-50%);
  transition:opacity .3s ease;
  display:flex;
  flex-direction:column;align-items:center;gap:2px;padding:5px;cursor:pointer;
  background:none;border:0;font:inherit;color:#8fa2b5;line-height:1}
.rl-radar.rl-in,.rl-radar.rl-out{opacity:0}
.rl-radar i{width:7px;height:7px;border-radius:50%;background:#7d8fa2;
  border:1.5px solid rgba(4,7,11,.8);transition:background .15s,transform .15s}
.rl-radar span{font:700 9.5px/1 ui-monospace,SFMono-Regular,Menlo,monospace;
  letter-spacing:.04em;opacity:0;transition:opacity .15s;
  text-shadow:0 0 3px #000,0 0 6px #000}
.rl-radar:hover i,.rl-radar:focus-visible i{background:var(--sky);transform:scale(1.35)}
.rl-radar:hover span,.rl-radar:focus-visible span{opacity:1;color:var(--sky)}
.rl-radar:focus-visible{outline:2px solid var(--sky);outline-offset:1px;border-radius:6px}
/* the ones with the most happening, so a national view suggests where to look */
.rl-radar.hot i{background:var(--amber);box-shadow:0 0 7px rgba(240,168,48,.65)}
.rl-radar.hot span{opacity:1;color:var(--amber)}

/* ---- the national view is a different shape from a single scope ---- */
/* The single-site layers COVER, because a scope should fill its frame and the
   corners are the least useful part of it. The national strip has to CONTAIN
   instead: it is 2.26 wide in a column that is taller than it is wide, and cropping
   it to fill would cut off exactly the coasts somebody zoomed out to see. */
/* Nationally the frame takes the composite's shape and CONTAINS rather than covers:
   a 2.26 wide strip cropped to fill a tall column would cut off the coasts somebody
   zoomed out to see. The map is not padded in this view, so every layer is 100%. */
/* a mosaic has no single centre, so nothing is clipped to a disc */
.rl-archmode .rl-lyr,.rl-archmode .rl-cities,.rl-archmode .rl-radars,
.rl-archmode .rl-temps,.rl-archmode .rl-dot,.rl-archmode .rl-probe{display:none !important}

/* At national scale the whole country is a few hundred pixels wide, so the dots
   shrink and the call signs go away except on the busiest few and whatever the
   pointer is on. The dots are what you are choosing between; the writing is not. */
.rl-natlbl .rl-radar{padding:3px}
.rl-natlbl .rl-radar i{width:5px;height:5px;border-width:1px}
.rl-natlbl .rl-radar span{font-size:8.5px}
.rl-natlbl .rl-cities span{font-size:9px;color:#8fa2b5}
.rl-natlbl .rl-cities b{width:2px;height:2px;flex-basis:2px}
/* the dots stay tappable through the image layer's pointer-events:none */
.rl-radars{pointer-events:none}
/* The dots take no pointer events at all: a finger landing on one belongs to the
   pan or pinch, and selection is a tap recognised by the gesture system and
   hit-tested afterwards. Keyboard users still reach the real buttons by tab, so the
   click handlers stay wired. .hov is the mouse hover, applied by the same hit test
   for the same reason. */
.rl-radar{pointer-events:none;touch-action:none;-webkit-tap-highlight-color:transparent}
.rl-radar.hov i{background:var(--sky);transform:scale(1.35)}
.rl-radar.hov span{opacity:1;color:var(--sky)}

/* the gesture trace, only ever built when ?rsdebug=1 is on the URL */
.rl-debug{position:absolute;left:8px;bottom:8px;z-index:5;pointer-events:none;
  white-space:pre;font:600 9.5px/1.35 ui-monospace,SFMono-Regular,Menlo,monospace;
  color:#7dffd8;background:rgba(4,7,11,.82);border:1px solid rgba(125,255,216,.3);
  border-radius:6px;padding:6px 8px;max-width:calc(100% - 16px);overflow:hidden}

/* TRY IT LIVE: the callout each lesson will use to point at the live radar. Styled
   after the launcher, live dot included, so the reader learns one shape for "this
   opens the radar". Hidden unless the panel is actually available, the same
   degrade-to-absent the launcher follows, so the offline bundle never shows a
   button that goes nowhere. */
.rl-try{display:none;align-items:center;gap:8px;padding:8px 15px;
  border-radius:999px;cursor:pointer;font:inherit;font-size:12px;font-weight:800;
  letter-spacing:.11em;text-transform:uppercase;color:#fff;
  background:rgba(16,22,31,.92);border:1px solid var(--sky)}
.rl-try i{width:7px;height:7px;border-radius:50%;background:var(--go);flex:0 0 7px;
  box-shadow:0 0 0 0 rgba(63,191,128,.55);animation:rlpulse 2.6s ease-out infinite}
.rl-try:hover{background:var(--sky);color:#08131d}
.rl-try:hover i{background:#08131d}
.rl-try:focus-visible{outline:2px solid var(--sky);outline-offset:3px}
body.rl-maybe .rl-try,body.rl-avail .rl-try{display:inline-flex}
/* the nudge under the launcher pill lives and dies with the pill itself */
.rl-trynote{display:none;margin-top:7px;font-size:13px;color:var(--muted)}
body.rl-maybe .rl-trynote,body.rl-avail .rl-trynote{display:block}
/* until the feed answers, both dots wear amber and hold still: checking, not live */
body.rl-maybe:not(.rl-avail) .rl-try i,
body.rl-maybe:not(.rl-avail) .rl-launch .rl-live{background:var(--amber);
  animation:none;box-shadow:none}
@media(prefers-reduced-motion:reduce){.rl-try i{animation:none}}

/* ---- Earl's guide ----
   Never over the map: he is a coach, not a curtain. On a sheet he sits in the flow
   above the scope, pushing it down; on the docked desktop layout the same node is
   lifted out and floated to the left of the dock, over the lesson. */
/* On a sheet Earl rises from the bottom edge, sitting below the legend and over
   the not-for-warnings text, so the whole map stays on screen while he talks. The
   legal line is never gone, only briefly understudied, and it returns the moment
   the tour ends. */
.rl-guide{position:absolute;left:10px;right:10px;z-index:6;margin:0;
  bottom:calc(10px + env(safe-area-inset-bottom, 0px))}
.rl-gbox{position:relative;display:flex;gap:11px;
  padding:14px 15px;border-radius:14px;
  background:rgba(10,14,20,.94);border:1px solid rgba(240,168,48,.45);
  -webkit-backdrop-filter:blur(9px);backdrop-filter:blur(9px);
  box-shadow:0 18px 44px rgba(0,0,0,.6),0 5px 14px rgba(0,0,0,.42)}
.rl-gbox{z-index:1}
/* Earl stands behind the box on its right shoulder, mirrored so he faces the
   words; the box paints over his waist, so he never covers a control or a line
   of text, and never the play button the third step points at */
.rl-dock img.rl-gearl,img.rl-gearl{position:absolute;right:16px;bottom:100%;
  margin-bottom:-24px;width:66px;height:auto;max-width:none;opacity:1;z-index:0;
  transition:none;transform:scaleX(-1);
  filter:drop-shadow(0 7px 14px rgba(0,0,0,.5));pointer-events:none}
@media(min-width:1180px){
  .rl-guide{position:fixed;left:auto;bottom:auto;top:50%;transform:translateY(-50%);
    right:calc(min(34vw,430px) + 18px);width:min(330px,40vw);margin:0;z-index:41}
  img.rl-gearl{width:78px;margin-bottom:-28px}
}

.rl-gname{display:block;font-weight:800;font-size:10px;line-height:1;
  letter-spacing:.14em;text-transform:uppercase;color:var(--amber);margin:2px 0 5px}
.rl-gtext{margin:0;font-size:13.5px;line-height:1.55;color:var(--fg)}
.rl-grow{display:flex;align-items:center;gap:5px;margin-top:9px}
.rl-grow i{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.22)}
.rl-grow i.on{background:var(--amber)}
.rl-gnext{margin-left:auto;font:inherit;font-size:12px;font-weight:700;
  cursor:pointer;padding:5px 13px;border-radius:999px;color:#08131d;
  background:var(--amber);border:0}
.rl-gnext:hover{filter:brightness(1.1)}
.rl-gx{position:absolute;top:7px;right:7px}
/* the control Earl is talking about wears the course's own "in here" pulse */
.rl-ginline{color:var(--sky);font-weight:800;letter-spacing:.07em;
  text-transform:uppercase}
.rl-gnext.rl-b-go{background:var(--go)}
.rl-gnext.rl-b-stop{background:var(--stop);color:#fff}
.rl-gnext.rl-b-dim{background:var(--panel2);color:var(--fg-dim);
  border:1px solid var(--rule)}
.rl-gbtns{margin-left:auto;display:flex;gap:7px;flex-wrap:wrap;justify-content:flex-end}
.rl-gbtns .rl-gnext{margin-left:0}
.rl-glow{animation:rahint 2.4s ease-out infinite;border-color:var(--sky) !important}
@media(prefers-reduced-motion:reduce){
  .rl-glow{animation:none;box-shadow:0 0 0 3px rgba(74,168,232,.55)}}

/* On a phone the box gives up half its height: the portrait goes, the name joins
   the sentence, and the type tightens. Earl is still Earl; he just talks closer to
   the mic so the map keeps the room. Last in the file on purpose: these override
   the base guide rules above by source order. */
@media(max-width:1179px){
  .rl-guide{bottom:calc(6px + env(safe-area-inset-bottom,0px))}
  .rl-gbox{padding:7px 10px}
  .rl-gwrap{padding-right:16px}
  .rl-gname{display:inline;margin:0 6px 0 0;font-size:10px}
  .rl-gtext{display:inline;font-size:12px;line-height:1.3}
  .rl-grow{margin-top:4px}
  .rl-grow i{width:5px;height:5px}
  .rl-gnext{padding:3px 10px;font-size:10.5px}
  .rl-gx{top:4px;right:4px}
  img.rl-gearl{width:58px;margin-bottom:-18px}
}


/* ------------------------- notes mode (author only) ------------------------- */
/* dormant unless notes.js armed itself; nothing here paints without .rs-notes */
.rs-notesbar{position:fixed;left:14px;bottom:14px;z-index:60;display:flex;
  gap:9px;align-items:center;padding:8px 12px;border-radius:999px;
  font-size:12.5px;font-weight:650;color:var(--fg);
  background:rgba(16,22,31,.95);border:1px solid var(--amber);
  box-shadow:0 6px 26px rgba(0,0,0,.45)}
.rs-notesbar b{color:var(--amber)}
.rs-notesbar button{font:inherit;font-size:11.5px;color:var(--fg-dim);
  background:var(--panel2);border:1px solid var(--rule);border-radius:999px;
  padding:4px 10px;cursor:pointer}
.rs-notesbar button:hover{border-color:var(--amber);color:var(--fg)}
body.rs-notes main :is(p,li,h1,h2,h3,h4,figcaption,blockquote,td,dt,dd){cursor:pointer}
body.rs-notes main :is(p,li,h1,h2,h3,h4,figcaption,blockquote,td,dt,dd):hover{
  outline:2px dashed rgba(240,168,48,.55);outline-offset:3px}
.rs-noted{outline:2px solid rgba(240,168,48,.6)!important;outline-offset:3px}
.rs-noteed{position:fixed;left:0;right:0;bottom:0;z-index:61;
  background:#101623;border-top:1px solid var(--amber);
  padding:12px 14px calc(12px + env(safe-area-inset-bottom,0px));
  box-shadow:0 -10px 34px rgba(0,0,0,.5)}
.rs-nq{font-size:11.5px;color:var(--muted);margin-bottom:7px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rs-noteed textarea{width:100%;box-sizing:border-box;font:inherit;font-size:14px;
  color:var(--fg);background:#0a0e14;border:1px solid var(--rule);
  border-radius:9px;padding:9px 11px;resize:vertical}
.rs-nrow{display:flex;gap:9px;align-items:center;margin-top:9px}
.rs-ngap{flex:1}
.rs-nrow button{font:inherit;font-size:12.5px;font-weight:650;cursor:pointer;
  border-radius:999px;padding:6px 15px;color:var(--fg-dim);
  background:var(--panel2);border:1px solid var(--rule)}
.rs-nrow .rs-nsave{background:var(--amber);border-color:var(--amber);color:#1a1206}


/* ------------------------------ the storm lab ------------------------------ */
.slab{display:grid;grid-template-columns:minmax(0,1fr) 250px;gap:18px;
  margin:1.6em 0;align-items:stretch}
.slab-stage svg{width:100%;height:auto;display:block;border-radius:12px;
  border:1px solid var(--rule)}
.slab-panel{display:flex;flex-direction:column;gap:14px;justify-content:center}
.slab-panel label{font-size:13px;font-weight:700;color:var(--fg)}
.slab-panel label i{display:block;font-style:normal;font-weight:400;
  font-size:11.5px;color:var(--muted);margin:2px 0 5px}
.slab-panel input[type=range]{width:100%;accent-color:var(--amber)}
.slab-verdict{grid-column:1/-1;margin:0;font-size:15px;line-height:1.55;
  color:var(--fg-dim);background:var(--panel);border:1px solid rgba(240,168,48,.4);
  border-radius:12px;padding:12px 16px}
.slab-verdict b{color:var(--amber);font-size:15.5px;margin-right:2px}
@media(max-width:720px){.slab{grid-template-columns:1fr;gap:14px}}


/* --------------------------- the start-school modal --------------------------- */
.startmodal{position:fixed;inset:0;z-index:70}
.startmodal[hidden]{display:none}
.sm-scrim{position:absolute;inset:0;background:rgba(4,8,14,.72);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.sm-card{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(440px,calc(100vw - 30px));background:var(--panel);
  border:1px solid var(--rule);border-radius:16px;padding:20px 20px 12px;
  box-shadow:0 24px 70px rgba(0,0,0,.6)}
.sm-card h3{margin:0 0 15px;font-size:18px;letter-spacing:-.02em}
.sm-x{position:absolute;top:10px;right:10px;font:inherit;font-size:14px;
  color:var(--muted);background:none;border:0;cursor:pointer;padding:6px}
.sm-x:hover{color:var(--fg)}
.sm-opt{display:block;padding:13px 15px;margin:0 0 11px;border-radius:12px;
  border:1px solid var(--rule);background:var(--bg2);text-decoration:none}
.sm-opt:hover{border-color:var(--sky)}
.sm-k{display:block;font-size:11.5px;font-weight:800;letter-spacing:.09em;
  text-transform:uppercase;color:var(--sky);margin-bottom:5px}
.sm-d{display:block;font-size:13.5px;line-height:1.5;color:var(--fg-dim);
  margin-bottom:7px}
.sm-go{display:block;font-size:13px;font-weight:700;color:var(--sky)}
.sm-note{display:block;font-size:11.5px;color:var(--muted);margin-top:8px;
  padding-top:8px;border-top:1px dashed var(--rule)}


/* the naming box's convention rows: a small icon beside each convention */
.nrow{display:flex;gap:13px;align-items:flex-start}
.nrow + .nrow{margin-top:10px}
.nrow .nicon{flex:0 0 44px;width:44px;height:44px;margin-top:2px}
.nrow p{margin:0}


/* the quiet line under Chase the Core: the game this course feeds into */
.mg-plug{font-size:13px;color:var(--muted);margin:10px 2px 0;line-height:1.55}
.mg-plug a{color:var(--sky);text-decoration:none;font-weight:650;white-space:nowrap}
.mg-plug a:hover{text-decoration:underline}


/* velocity's two directions wear their own colors wherever prose names them */
.v-in{color:var(--go)}
.v-out{color:var(--stop)}
.v-amb{color:var(--amber)}
.v-yel{color:#e8d44d}
.v-zero{color:var(--muted)}
.v-rf{color:var(--violet)}


/* ----------------------------- the beam machine ----------------------------- */
.bm{margin:1.6em 0}
.bm-stage svg{width:100%;height:auto;display:block;border-radius:12px;
  border:1px solid var(--rule)}
.bm-ctl{display:flex;gap:8px;margin-top:10px}
.bm-ctl button{flex:1;font:inherit;font-size:12.5px;font-weight:800;
  letter-spacing:.08em;color:var(--muted);background:var(--panel2);
  border:1px solid var(--rule);border-radius:9px;padding:9px 6px;cursor:pointer}
.bm-ctl button:hover{color:var(--fg)}
.bm-ctl button.on{background:var(--sky);border-color:var(--sky);color:#08131d}
.bm-sub{margin-top:10px;min-height:34px}
.bm-lab{display:flex;align-items:center;gap:12px;font-size:12.5px;font-weight:700;
  color:var(--muted);white-space:nowrap}
.bm-lab input[type=range]{flex:1;accent-color:var(--sky)}
.bm-read{margin:8px 2px 0;font-size:14px;line-height:1.6;color:var(--fg-dim);
  min-height:66px}
.rg{max-width:560px;margin:0 auto}
.rg-tabs{display:flex;gap:8px;flex-wrap:wrap}
.rg-tabs button{flex:1;min-width:96px;font:inherit;font-size:11px;font-weight:800;
  letter-spacing:.06em;color:var(--muted);background:var(--panel2);
  border:1px solid var(--rule);border-radius:9px;padding:8px 4px;cursor:pointer}
.rg-tabs button:hover{color:var(--fg)}
.rg-tabs button.on{background:var(--sky);border-color:var(--sky);color:#08131d}
.rg-stage{margin-top:10px}
.rg-stage img{width:100%;display:block;border:1px solid var(--rule);border-radius:10px}
.rg-flip{display:flex;gap:8px;margin-top:10px;justify-content:center}
.rg-flip button{font:inherit;font-size:11.5px;font-weight:800;letter-spacing:.06em;
  color:var(--muted);background:var(--panel2);border:1px solid var(--rule);
  border-radius:999px;padding:7px 20px;cursor:pointer}
.rg-flip button.on{background:var(--sky);border-color:var(--sky);color:#08131d}
.rg-cap{margin:10px 2px 0;font-size:14px;line-height:1.6;color:var(--fg-dim);min-height:88px}
.rg-cred{font-size:11px;color:var(--muted)}
.hh{max-width:520px;margin:0 auto}
.hh-stage{position:relative}
.hh-ring{position:absolute;border:3px solid var(--go);border-radius:50%;
  pointer-events:none;box-shadow:0 0 0 2px rgba(8,13,19,.55)}
.hh-ring.confirm{border-style:dashed;border-color:var(--sky)}
.hh-ring-lbl{position:absolute;transform:translateX(-50%);white-space:nowrap;
  font-size:10px;font-weight:800;letter-spacing:.05em;color:var(--sky);
  background:rgba(8,13,19,.78);border:1px solid var(--rule);border-radius:5px;
  padding:2px 7px;pointer-events:none}
.hh-prod{position:absolute;top:8px;left:8px;font-size:10.5px;font-weight:800;
  letter-spacing:.08em;color:var(--fg);background:rgba(8,13,19,.72);
  border:1px solid var(--rule);border-radius:6px;padding:3px 8px;
  pointer-events:none}
.hh-motion{position:absolute;top:8px;right:8px;display:flex;align-items:center;
  gap:4px;font-size:10.5px;font-weight:800;letter-spacing:.05em;color:var(--fg);
  background:rgba(8,13,19,.72);border:1px solid var(--rule);border-radius:6px;
  padding:3px 8px;pointer-events:none}
.hh-motion[hidden]{display:none}
.hh-motion svg{width:13px;height:13px;flex:none}
.hh-cand{position:absolute;width:22px;height:22px;margin:-11px 0 0 -11px;
  border-radius:50%;border:2px solid var(--fg-dim);background:rgba(8,13,19,.22);
  color:var(--fg);font:inherit;font-size:10.5px;font-weight:800;cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  box-shadow:0 0 0 2px rgba(8,13,19,.3);text-shadow:0 1px 2px rgba(8,13,19,.9)}
.hh-cand:hover{border-color:var(--sky)}
.hh-cand.right{border-color:var(--go);background:rgba(63,191,128,.22);
  color:var(--go)}
.hh-cand.wrong{border-color:var(--stop);background:rgba(239,90,76,.22);
  color:var(--stop)}
.hh-cand[disabled]{cursor:default;pointer-events:none}
.hh-row{display:flex;align-items:center;gap:10px;margin-top:10px}
.hh-prog{font-size:11.5px;font-weight:800;letter-spacing:.06em;color:var(--muted)}
.hh-row button{font:inherit;font-size:12px;font-weight:800;letter-spacing:.05em;
  color:var(--fg);background:var(--panel2);border:1px solid var(--rule);
  border-radius:9px;padding:8px 16px;cursor:pointer;margin-left:auto}
.hh-row button:hover{border-color:var(--sky)}
.hh-read{margin:8px 2px 0;font-size:14px;line-height:1.6;color:var(--fg-dim);min-height:66px}
.rl{max-width:660px;margin:0 auto}
.rl-ends{display:flex;justify-content:space-between;font-size:11px;font-weight:800;
  letter-spacing:.06em;color:var(--muted);margin-bottom:6px}
.rl-scroll{overflow-x:auto;padding-bottom:2px}
.rl-rack{position:relative;height:138px}
.rl-tile{position:absolute;top:0;width:100px;height:138px;touch-action:none;cursor:grab;
  user-select:none;-webkit-user-select:none;border:2px solid var(--rule);
  border-radius:10px;overflow:hidden;background:var(--panel2)}
.rl-tile img{display:block;width:100px;height:100px;object-fit:cover;pointer-events:none}
.rl-name{display:flex;align-items:center;justify-content:center;height:38px;
  font-size:10px;font-weight:700;line-height:1.25;padding:2px 6px;
  color:var(--fg-dim);text-align:center}
.rl-tile.dragging{cursor:grabbing;box-shadow:0 8px 18px rgba(0,0,0,.45)}
.rl-tile.right{border-color:var(--go)}
.rl-tile.wrong{border-color:var(--stop)}
.cw{max-width:460px;margin:0 auto}
.cw-stage{position:relative;border-radius:12px;overflow:hidden}
.cw-stage img{display:block;width:100%;height:auto}
.cw-prod,.cw-stamp{position:absolute;top:8px;font-size:10.5px;font-weight:800;
  letter-spacing:.08em;color:var(--fg);background:rgba(8,13,19,.72);
  border:1px solid var(--rule);border-radius:6px;padding:3px 8px}
.cw-prod{left:8px}
.cw-stamp{right:8px}
.cw-ask{margin:10px 2px 0;font-size:14px;line-height:1.5;color:var(--fg-dim)}
.cw-row{display:flex;gap:10px;margin-top:10px}
.cw-row[hidden]{display:none}
.cw-row button{flex:1;font:inherit;font-size:13px;font-weight:800;letter-spacing:.05em;
  color:var(--fg);background:var(--panel2);border:1px solid var(--rule);
  border-radius:9px;padding:11px 16px;cursor:pointer}
.cw-warn:hover{border-color:var(--stop)}
.cw-hold:hover{border-color:var(--sky)}
.cw-cap{margin:0 0 8px;font-size:13px;color:var(--muted)}
.cw-tl-head{display:grid;grid-template-columns:52px 1fr 1fr;gap:6px;
  font-size:10.5px;font-weight:800;letter-spacing:.05em;color:var(--muted);
  padding:0 2px;margin-bottom:2px}
.cw-tl-head span:not(:first-child){text-align:center}
.cw-tl{display:grid;grid-template-columns:52px 1fr 1fr;gap:6px;align-items:center;
  padding:5px 2px;border-top:1px solid var(--rule);position:relative}
.cw-tl.cw-real{background:rgba(74,168,232,.08)}
.cw-tl-t{font-size:12px;font-weight:700;color:var(--fg-dim)}
.cw-tl-d{text-align:center;font-size:11.5px;font-weight:800;letter-spacing:.04em;
  border-radius:6px;padding:4px 0}
.cw-tl-d.warn{color:var(--stop);background:rgba(239,90,76,.14)}
.cw-tl-d.hold{color:var(--muted);background:rgba(139,152,167,.10)}
.cw-tl-real{grid-column:1 / -1;font-size:10.5px;font-weight:700;color:var(--sky);
  letter-spacing:.02em}
.cw-summary p{margin:12px 2px 0;font-size:14px;line-height:1.6;color:var(--fg-dim)}
.cw-again{margin-top:12px;font:inherit;font-size:12px;font-weight:800;
  letter-spacing:.05em;color:var(--fg);background:var(--panel2);
  border:1px solid var(--rule);border-radius:9px;padding:8px 16px;cursor:pointer}
.cw-again:hover{border-color:var(--sky)}
.rl-row{display:flex;gap:10px;margin-top:14px}
.rl-row button{font:inherit;font-size:12px;font-weight:800;letter-spacing:.05em;
  color:var(--fg);background:var(--panel2);border:1px solid var(--rule);
  border-radius:9px;padding:8px 16px;cursor:pointer}
.rl-row button:hover{border-color:var(--sky)}
.rl-read{margin:10px 2px 0;font-size:14px;line-height:1.6;color:var(--fg-dim)}
.hs{max-width:520px;margin:0 auto}
.hs-tabs{display:flex;gap:8px;margin-bottom:10px}
.hs-tabs button{flex:1;font:inherit;font-size:10.5px;font-weight:800;
  letter-spacing:.05em;color:var(--muted);background:var(--panel2);
  border:1px solid var(--rule);border-radius:9px;padding:7px 4px;cursor:pointer}
.hs-tabs button:hover{color:var(--fg)}
.hs-tabs button.on{background:var(--sky);border-color:var(--sky);color:#08131d}
.hs-stage{position:relative}
.hs-stage svg{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
.hs-row{display:flex;align-items:center;gap:10px;margin-top:10px}
.hs-prog{font-size:11.5px;font-weight:800;letter-spacing:.06em;color:var(--muted);margin:0 auto}
.hs-row button{font:inherit;font-size:12px;font-weight:800;letter-spacing:.05em;
  color:var(--fg);background:var(--panel2);border:1px solid var(--rule);
  border-radius:9px;padding:8px 16px;cursor:pointer}
.hs-row button:hover{border-color:var(--sky)}
.hs-row button:disabled{opacity:.35;cursor:default}
.hs-row .hs-fwd{background:var(--sky);border-color:var(--sky);color:#08131d}
.hs-cap{margin:8px 2px 0;font-size:14px;line-height:1.6;color:var(--fg-dim);min-height:88px}
.hs-cap b{color:var(--fg)}
@keyframes hsSpin{to{stroke-dashoffset:-10}}
.hs-spin{animation:hsSpin 1.2s linear infinite}
.gp-wrap{position:relative;display:block}
.gp-wrap svg{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;
  background:none;border:0;border-radius:0}
@keyframes hsFlow{to{stroke-dashoffset:-6.4}}
.hs-flow{animation:hsFlow .9s linear infinite}
@media(prefers-reduced-motion:reduce){.hs-spin,.hs-flow{animation:none}}
.wp{max-width:440px;margin:0 auto}
.wp-frame{position:relative}
.wp-stage{position:relative;display:block;width:100%;border-radius:12px;overflow:hidden;
  border:0;padding:0;margin:0;cursor:pointer;background:none;font:inherit}
.wp-img{display:block;width:100%;height:auto;pointer-events:none}
.wp-poly{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
.wp-badge{position:absolute;top:8px;left:8px;z-index:2;font-size:10px;font-weight:800;
  letter-spacing:.08em;text-transform:uppercase;color:#1a1200;
  background:var(--amber);border-radius:6px;padding:4px 9px;
  box-shadow:0 0 0 2px rgba(8,13,19,.5)}
.wp-hint{position:absolute;top:8px;right:8px;z-index:2;font-size:10.5px;
  font-weight:800;letter-spacing:.05em;color:var(--fg);
  background:rgba(8,13,19,.72);border:1px solid var(--rule);border-radius:6px;
  padding:3px 8px}
.wp-stage:hover .wp-hint{border-color:var(--sky)}
.wp-cred{margin:8px 2px 0;font-size:12px;color:var(--muted);text-align:center}
.wp-warn{position:absolute;z-index:3;left:5%;right:5%;top:50%;
  transform:translateY(-50%);max-height:88%;overflow-y:auto;
  background:var(--panel);border:1px solid var(--rule);border-radius:12px;
  padding:16px 16px 14px;box-shadow:0 12px 32px rgba(0,0,0,.55)}
.wp-warn-x{position:absolute;top:8px;right:8px;width:26px;height:26px;
  border-radius:50%;border:1px solid var(--rule);background:var(--panel2);
  color:var(--fg-dim);font-size:12px;line-height:1;cursor:pointer}
.wp-warn-x:hover{border-color:var(--sky);color:var(--fg)}
.wp-warn .box.warn{margin-right:26px}
.wp-foot{margin:10px 2px 0;font-size:12.5px;line-height:1.55;color:var(--fg-dim)}
