:root{--brand:#8C1630;--brand-dark:#6E1126;--brand-tint:#F9EBEE;--ink:#2A3441;--body:#3A3F47;--slate:#6B7686;--line:#E3E8EF;--cloud:#F5F6F8;--good:#1E8E5A;--true:#146B3F;--false:#B3261E;--navy:#27466B;--navy-2:#33567F;--gold:#DCA845;--sans:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;--mono:ui-monospace,Menlo,Consolas,monospace}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{font-family:var(--sans);color:var(--body);background:#fff;line-height:1.7;-webkit-font-smoothing:antialiased}
a{color:var(--brand-dark);text-decoration:none}a:hover{text-decoration:underline}
/* Screen-reader-only utility. Guide pages load only this file, not site.css, but they do load
   site.js — which appends " (opens in a new tab)" with this class to practice-app links.
   Without this rule that text renders visibly. Keep in sync with site.css and org.css. */
.kx-sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);clip-path:inset(50%);white-space:nowrap;border:0}
.wrap{max-width:760px;margin:0 auto;padding:0 22px}
header{position:sticky;top:0;z-index:50;background:rgba(255,255,255,.92);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
header .wrap{max-width:1080px;display:flex;align-items:center;gap:16px;height:64px}
.logo{display:flex;align-items:center;gap:10px;font-weight:800;color:var(--ink);font-size:19px;letter-spacing:-.02em}
.logo .mk{width:34px;height:34px;display:grid;place-items:center}
.logo .mk img{width:100%;height:100%;object-fit:contain;display:block;border-radius:7px}
header nav{margin-left:auto;display:flex;gap:20px}
header nav a{color:var(--slate);font-weight:500;font-size:15px}header nav a:hover{color:var(--ink);text-decoration:none}
.crumb{font-size:13px;color:var(--slate);padding:20px 0 0}.crumb a{color:var(--slate)}
article{padding:14px 0 50px}
article h1{color:var(--ink);font-size:34px;font-weight:800;letter-spacing:-.02em;margin:12px 0 6px;line-height:1.15}
.dek{color:var(--slate);font-size:17px;margin-bottom:8px}
.badge{display:inline-block;background:var(--brand-tint);color:var(--brand-dark);font-size:12px;font-weight:600;padding:4px 11px;border-radius:999px;margin:10px 0 22px}
article h2{color:var(--ink);font-size:23px;font-weight:700;margin:34px 0 10px;letter-spacing:-.01em}
article h3{color:var(--ink);font-size:18px;font-weight:600;margin:22px 0 8px}
article p{margin:12px 0;font-size:17px}
article ul,article ol{margin:12px 0 12px 22px}article li{margin:8px 0;font-size:17px}
article strong{color:var(--ink)}
.key{background:var(--cloud);border:1px solid var(--line);border-left:3px solid var(--brand);border-radius:0 10px 10px 0;padding:14px 18px;margin:20px 0}.key b{color:var(--ink)}
table.cmp{width:100%;border-collapse:collapse;margin:18px 0;font-size:15px}
table.cmp th,table.cmp td{border:1px solid var(--line);padding:10px 12px;text-align:left;vertical-align:top}
table.cmp th{background:var(--cloud);color:var(--ink);font-weight:600}

/* --- truth values: 1 green, 0 red (2026-08-28) -------------------------------
   Matches the legend in Finley's own course notes, where 1 = True is written in
   green and 0 = False in red. In a 16-row truth table the colour is what lets a
   reader scan a column and see its shape without reading digit by digit.
   Applied ONLY to tables where every data cell is 0 or 1 — step numbers and
   remainders are also 0s and 1s and must NOT be coloured.
   Colour is never the only signal: the digit itself still carries the meaning,
   which is what keeps this readable for colour-blind readers and in print. */
table.cmp .v1{color:var(--true);font-weight:700}
table.cmp .v0{color:var(--false);font-weight:700}
table.cmp .v1,table.cmp .v0{text-align:center;font-variant-numeric:tabular-nums;
  letter-spacing:.02em}
.cta{background:var(--brand);color:#fff;border-radius:16px;padding:26px;margin:32px 0;text-align:center}
.cta h3{color:#fff;font-size:20px;margin:0 0 6px}
.cta p{color:rgba(255,255,255,.9);margin:0 0 16px;font-size:15px}
.cta a{display:inline-block;background:#fff;color:var(--brand-dark);font-weight:600;padding:12px 22px;border-radius:11px}.cta a:hover{text-decoration:none}
.faq details{border-bottom:1px solid var(--line);padding:16px 0}
.faq summary{font-weight:600;color:var(--ink);font-size:17px;cursor:pointer;list-style:none;display:flex;justify-content:space-between;gap:10px}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:'+';color:var(--brand);font-size:22px;line-height:1}
.faq details[open] summary::after{content:'\2013'}
.faq p{font-size:15px}
.related{background:var(--cloud);border-radius:12px;padding:18px 20px;margin:26px 0}
.related h3{margin:0 0 8px;font-size:13px;text-transform:uppercase;letter-spacing:.05em;color:var(--slate)}
.related a{display:block;margin:6px 0}
footer{background:var(--ink);color:#c9ccd2;padding:36px 0 26px;font-size:14px;margin-top:20px}
footer .wrap{max-width:1080px}
footer a{color:#c9ccd2}footer a:hover{color:#fff}
.legal{border-top:1px solid #2c313a;margin-top:18px;padding-top:16px;font-size:12px;color:#8b909a;line-height:1.6}
.hub-hero{background:linear-gradient(180deg,var(--cloud),#fff);padding:44px 0 20px}
.hub-hero h1{color:var(--ink);font-size:38px;font-weight:800;letter-spacing:-.02em}
.hub-hero p{color:var(--slate);font-size:17px;margin-top:10px}
.domain{margin:28px 0}
.domain h2{font-size:20px;color:var(--ink);border-bottom:2px solid var(--brand-tint);padding-bottom:6px}
.glist{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px}
.glist a{background:#fff;border:1px solid var(--line);border-radius:10px;padding:12px 14px;color:var(--ink);font-weight:500;font-size:15px}
.glist a:hover{border-color:var(--brand);text-decoration:none}
.glist span.soon{background:var(--cloud);border:1px dashed var(--line);border-radius:10px;padding:12px 14px;color:var(--slate);font-size:15px}
@media(max-width:640px){.glist{grid-template-columns:1fr}article h1{font-size:28px}.hub-hero h1{font-size:30px}}
@media(max-width:520px){
  header .wrap{gap:10px;height:58px;padding:0 14px}
  .logo .mk{width:28px;height:28px}
  header nav{gap:12px}header nav a{font-size:13.5px;white-space:nowrap}
  header nav a:first-child{display:none} /* logo is Home */
}

/* --- phone header: mark only, no wordmark ---
   The mark and the words say the same thing, and on a phone the bar has no room
   for both. The wordmark is a bare text node inside .logo (not its own element),
   so font-size:0 on the parent is what removes it without touching the markup in
   every guide file; .mk is sized in px and is unaffected. The link keeps its
   accessible name from the image's alt text, so a screen reader loses nothing.
   Placed after the 520px block on purpose — it has to win at every phone width. */
@media(max-width:760px){
  .logo{font-size:0;gap:0}
  .logo .mk{width:32px;height:32px}
}
.totop{position:fixed;right:18px;bottom:calc(18px + env(safe-area-inset-bottom,0px));width:44px;height:44px;border-radius:50%;background:var(--navy);color:var(--gold);border:none;box-shadow:0 6px 18px rgba(20,40,70,.28);display:grid;place-items:center;cursor:pointer;opacity:0;pointer-events:none;transform:translateY(8px);transition:opacity .2s,transform .2s;z-index:60}
.totop.show{opacity:1;pointer-events:auto;transform:none}
.totop:hover{background:var(--navy-2)}
.totop svg{width:20px;height:20px}
@media (prefers-reduced-motion:reduce){.totop{transition:none}}

/* --- Multi-subject guides hub (T-021, 2026-08-04) --- */
.subject{margin:34px 0 8px;padding-top:26px;border-top:1px solid var(--line)}
.subject:first-of-type{border-top:0;padding-top:6px}
.subject-head{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap}
.subject-head h2{font-size:22px;color:var(--ink);font-weight:700;letter-spacing:-.01em}
.pill{display:inline-block;font-size:11.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;padding:3px 10px;border-radius:999px}
.pill.live{background:#E6F4EC;color:var(--good)}
.pill.prep{background:var(--cloud);color:var(--slate);border:1px solid var(--line)}
.subject-note{color:var(--slate);font-size:15.5px;margin:8px 0 0}
.roadmap{background:var(--cloud);border:1px solid var(--line);border-radius:12px;padding:14px 18px;margin:14px 0 0}
.roadmap h3{font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--slate);font-weight:600;margin:0 0 6px}
.roadmap p{margin:0;font-size:15px;color:var(--body)}
.empty{border:1px dashed var(--line);border-radius:12px;padding:16px 18px;margin:14px 0 0;color:var(--slate);font-size:15.5px}
.empty a{font-weight:600}

/* --- Code listings (Java guides, 2026-08-15) ---------------------------------
   guide.css had no pre/code rules at all, because the only guides that existed
   were prose and math. Added, not overridden: nothing above this comment changes.
   .out marks a listing that is OUTPUT or a compiler message rather than source,
   so a reader can tell at a glance what they are meant to type and what they are
   meant to see back. */
article pre{background:#1E2430;color:#E8ECF2;border-radius:12px;padding:15px 18px;margin:18px 0;
  overflow-x:auto;font-family:var(--mono);font-size:14px;line-height:1.6;tab-size:4}
article pre code{background:none;border:0;color:inherit;padding:0;font-size:inherit}
article pre .cm{color:#93A3B8;font-style:italic}
article pre.out{background:var(--cloud);color:var(--ink);border:1px solid var(--line)}
article pre.out .cm{color:var(--slate)}
article code{background:var(--cloud);border:1px solid var(--line);border-radius:5px;
  padding:1px 5px;font-family:var(--mono);font-size:.9em;color:var(--ink);
  overflow-wrap:break-word}
article table.cmp code{font-size:.86em;padding:0 3px}
.filename{display:block;font-family:var(--mono);font-size:12.5px;color:var(--slate);margin:18px 0 6px}
.filename + pre{margin-top:0}
@media(max-width:640px){
  article pre{font-size:12.5px;padding:13px 14px;border-radius:10px}
  /* A four-column comparison table with inline code in it cannot compress below
     about 400px, which pushed the whole page sideways on a 390px phone. Let the
     table scroll inside its own box instead of widening the document. Cells still
     wrap normally — this is not white-space:nowrap. */
  article table.cmp{display:block;width:100%;max-width:100%;overflow-x:auto}
}

/* ============================================================================
   GUIDES CATALOG (2026-08-15)
   Split layout: sticky subject rail + searchable, sortable card grid.

   PROGRESSIVE ENHANCEMENT: every card is present in the HTML. catalog.js adds
   .catalog-ready to <html>, and ONLY the interactive controls are gated on it —
   with JS off the reader still gets every card, just without filtering. Never
   hide .cards or .gcard behind that class.

   --sc is the subject accent, set inline per card and per rail row so one rule
   set serves every subject. Java and Security+ share the CS crimson on purpose
   (Finley, 2026-08-14: "all computer science course the same red"); the subject
   tag text is what distinguishes them, not the color.
   ========================================================================== */
/* The article .wrap is 760px, which is right for prose and far too narrow for a
   two-column catalog — it left the card grid 468px wide. Catalog pages opt into a
   wider container; the hero lead is capped separately so line length stays readable. */
.wrap.wide{max-width:1080px}
.hub-hero .wrap.wide p{max-width:660px}
.catalog{display:grid;grid-template-columns:216px minmax(0,1fr);gap:38px;align-items:start;margin:24px 0 8px}
/* min-width:0 is load-bearing: .subjects scrolls horizontally on mobile, and without
   it that overflowing row forces its grid track wider than the viewport (measured:
   613px of track inside a 390px screen, 245px of page overflow). */
.cat-side,.cat-main{min-width:0}

/* --- subject rail --- */
.cat-side{position:sticky;top:80px}
.cat-side .railhead{font-size:11.5px;text-transform:uppercase;letter-spacing:.07em;
  color:var(--slate);font-weight:700;margin:0 0 9px;padding:0 10px}
.subjects{display:flex;flex-direction:column;gap:1px;list-style:none;margin:0;padding:0}
.subj{display:flex;align-items:center;gap:9px;width:100%;text-align:left;background:none;
  border:0;border-radius:9px;padding:8px 10px;font:inherit;font-size:14.5px;color:var(--body);
  cursor:pointer;line-height:1.3}
.subj:hover{background:var(--cloud);color:var(--ink)}
.subj:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
.subj .dot{width:8px;height:8px;border-radius:50%;background:var(--sc,var(--slate));flex:none}
.subj .n{margin-left:auto;font-size:12.5px;color:var(--slate);font-variant-numeric:tabular-nums}
.subj[aria-pressed="true"]{background:var(--cloud);color:var(--ink);font-weight:600;
  box-shadow:inset 2px 0 0 var(--sc,var(--brand))}
.subj[aria-pressed="true"] .n{color:var(--ink)}
.subj[disabled]{opacity:.45;cursor:default}
.subj[disabled]:hover{background:none;color:var(--body)}
.cat-planned{margin:15px 10px 0;padding-top:13px;border-top:1px solid var(--line);
  font-size:12.5px;color:var(--slate);line-height:1.5}
.cat-planned b{color:var(--ink);font-weight:600}

/* --- toolbar --- */
.cat-tools{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:13px}
.searchbox{position:relative;flex:1 1 220px;min-width:180px}
.searchbox svg{position:absolute;left:13px;top:50%;transform:translateY(-50%);
  width:16px;height:16px;color:var(--slate);pointer-events:none}
.searchbox input{width:100%;padding:11px 34px 11px 37px;border:1px solid var(--line);
  border-radius:11px;font:inherit;font-size:15px;color:var(--ink);background:#fff;
  -webkit-appearance:none;appearance:none}
.searchbox input::-webkit-search-cancel-button{-webkit-appearance:none}
.searchbox input:focus{outline:2px solid var(--brand);outline-offset:1px;border-color:transparent}
.searchclear{position:absolute;right:6px;top:50%;transform:translateY(-50%);width:26px;height:26px;
  border:0;background:none;border-radius:50%;color:var(--slate);cursor:pointer;display:none;
  align-items:center;justify-content:center;font-size:17px;line-height:1;padding:0}
.searchclear:hover{background:var(--cloud);color:var(--ink)}
.searchclear.show{display:flex}
.sortwrap{display:flex;align-items:center;gap:8px;font-size:14px;color:var(--slate);flex:none}
.sortwrap select{padding:10px 11px;border:1px solid var(--line);border-radius:11px;
  font:inherit;font-size:14.5px;color:var(--ink);background:#fff;cursor:pointer}
.sortwrap select:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
.cat-count{font-size:13px;color:var(--slate);margin:0 0 14px;min-height:19px}

/* --- cards --- */
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(236px,1fr));gap:14px;
  list-style:none;margin:0;padding:0}
.gcard{position:relative;isolation:isolate;display:flex;flex-direction:column;background:#fff;
  border:1px solid var(--line);border-top:3px solid var(--sc,var(--brand));border-radius:14px;
  padding:15px 17px 14px;transition:transform .18s ease,box-shadow .18s ease}
.gcard:hover{transform:translateY(-2px);box-shadow:0 10px 26px rgba(30,40,60,.10)}
.gcard:focus-within{box-shadow:0 0 0 2px var(--sc,var(--brand))}
.gcard .subj-tag{font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--sc,var(--brand))}
.gcard h3{margin:9px 0 0;font-size:16px;line-height:1.34;color:var(--ink);font-weight:700}
.gcard h3 a{color:inherit;text-decoration:none}
.gcard h3 a:hover{text-decoration:none}
/* Whole-card click target — and the bug it took two wrong fixes to find.
   This ::after belongs to the <a>, so `inset:0` resolves against the nearest
   POSITIONED ancestor. Originally that was .gcard and the overlay covered the whole
   card. The dressing pass added `.gcard > *{position:relative;z-index:1}` (to keep
   the new wash off the text) which silently made h3 the containing block — the
   overlay collapsed to the title's own 215x21 box, and "Read →" in the footer
   became dead. Raising the ::after did nothing, because a child cannot paint above
   its parent's sibling; raising h3 did nothing, because that only moved the box it
   was already trapped in. The fix is to stop positioning the children at all and
   push the decorative layers to z-index -1 instead, so .gcard is once again the
   containing block. Keep it that way: adding position:relative to any .gcard child
   silently shrinks this hit area back down. */
.gcard h3 a::after{content:"";position:absolute;inset:0;border-radius:14px}
.gcard:has(h3 a){cursor:pointer}
/* The placeholder card has no title link and carries two real links in its footer;
   they must stay individually clickable, so no overlay is generated for it. */
.gcard.is-soon .foot a{position:relative;z-index:3}
.gcard p{margin:7px 0 0;font-size:13.5px;color:var(--slate);line-height:1.55}
.gcard .foot{margin-top:auto;padding-top:13px;display:flex;align-items:center;
  justify-content:space-between;gap:10px;font-size:12.5px;color:var(--slate)}
.gcard .go2{color:var(--sc,var(--brand));font-weight:600;white-space:nowrap}
.gcard:hover .go2{text-decoration:underline}
.gcard.is-soon{border-style:dashed;border-top-style:solid;background:var(--cloud)}
.gcard.is-soon:hover{transform:none;box-shadow:none}
.gcard.is-soon h3{color:var(--slate)}
.gcard[hidden]{display:none}
.cat-empty{border:1px dashed var(--line);border-radius:12px;padding:22px;text-align:center;
  color:var(--slate);font-size:15px}
.cat-empty button{background:none;border:0;color:var(--brand-dark);font:inherit;font-weight:600;
  text-decoration:underline;cursor:pointer;padding:0}

/* controls only exist once JS is running; cards never depend on it */
.cat-tools,.cat-count,.cat-empty{display:none}
.catalog-ready .cat-tools{display:flex}
.catalog-ready .cat-count{display:block}
html:not(.catalog-ready) .subj{cursor:default}

@media(max-width:900px){
  .catalog{grid-template-columns:1fr;gap:18px}
  .cat-side{position:static}
  .cat-side .railhead{padding:0}
  .subjects{flex-direction:row;flex-wrap:nowrap;overflow-x:auto;gap:7px;padding-bottom:4px;
    scrollbar-width:thin;-webkit-overflow-scrolling:touch;max-width:100%;min-width:0}
  .subj{width:auto;flex:none;border:1px solid var(--line);border-radius:999px;padding:7px 13px;
    font-size:14px;white-space:nowrap}
  /* Neutral fill, subject-colored border. brand-tint is pink, which fought the
     navy "All guides" row it was most often applied to. */
  .subj[aria-pressed="true"]{box-shadow:inset 0 0 0 1px var(--sc,var(--brand));
    border-color:var(--sc,var(--brand));background:var(--cloud)}
  .cat-planned{margin-left:0;margin-right:0}
}
@media(max-width:520px){
  .cards{grid-template-columns:1fr}
  .sortwrap{flex:1 1 100%}
  .sortwrap select{flex:1}
}
@media (prefers-reduced-motion:reduce){
  .gcard{transition:none}
  .gcard:hover{transform:none}
}

/* ============================================================================
   CATALOG DRESSING (2026-08-15) — "too sterile" pass.
   Everything here is decoration over facts already on the page: the stat strip
   counts real cards, the New badge is driven by a real publish date and expires
   on its own, and the icons are subject identity rather than clip art. Nothing
   below invents information.
   ========================================================================== */

/* --- deep hero: the old one was a pale grey wash, which is why the page read
   as a spreadsheet. Navy matches .exam-hero on the marketing pages. --- */
.hub-hero.deep{position:relative;overflow:hidden;padding:50px 0 0;
  background:linear-gradient(155deg,#2C4E75 0%,#27466B 45%,#1D3452 100%)}
/* faint dot field: texture that survives on any screen without being a picture */
.hub-hero.deep::before{content:"";position:absolute;inset:0;pointer-events:none;
  background-image:radial-gradient(rgba(255,255,255,.16) 1px,transparent 1px);
  background-size:22px 22px;
  -webkit-mask-image:linear-gradient(115deg,#000 0%,transparent 62%);
          mask-image:linear-gradient(115deg,#000 0%,transparent 62%)}
/* the four subject accents as a single band across the bottom edge */
.hub-hero.deep::after{content:"";position:absolute;left:0;right:0;bottom:0;height:3px;
  background:var(--band,linear-gradient(90deg,#27466B,#27466B))}
.hub-hero.deep .wrap{position:relative;z-index:1}
.hub-hero.deep h1{color:#fff}
.hub-hero.deep p{color:rgba(255,255,255,.80)}
.hub-eyebrow{display:inline-block;font-size:11.5px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--gold);margin-bottom:9px}

/* --- stat strip: derived counts, sitting on the hero's lower edge --- */
.hub-stats{display:flex;flex-wrap:wrap;gap:0;margin:26px 0 0;padding:0;list-style:none;
  border-top:1px solid rgba(255,255,255,.14)}
.hub-stats li{padding:14px 26px 16px;border-right:1px solid rgba(255,255,255,.12);line-height:1.25}
.hub-stats li:first-child{padding-left:0}
.hub-stats li:last-child{border-right:0}
.hub-stats b{display:block;color:#fff;font-size:23px;font-weight:800;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.hub-stats span{font-size:12px;color:rgba(255,255,255,.62);text-transform:uppercase;
  letter-spacing:.06em;font-weight:600}

/* --- subject icons --- */
.sicon{width:16px;height:16px;flex:none;color:var(--sc,var(--slate))}
.subj .sicon{width:15px;height:15px}
.gcard .subj-tag{display:flex;align-items:center;gap:6px;width:100%}
.gcard .subj-tag .sicon{width:14px;height:14px}

/* --- card: watermark, hover motion, badge --- */
.gcard{overflow:hidden}
.gcard .mark{position:absolute;right:-14px;bottom:-16px;width:104px;height:104px;
  color:var(--sc,var(--brand));opacity:.055;pointer-events:none;z-index:-1;
  transition:opacity .25s ease,transform .25s ease}
.gcard:hover .mark{opacity:.10;transform:scale(1.06) rotate(-4deg)}
/* Wash and watermark sit at z-index -1: above the card's own white background,
   below its in-flow text. That is what lets the card's children stay UNPOSITIONED,
   which is the whole point — see the click-target note below. isolation:isolate
   keeps these negative layers from escaping behind the card entirely. */
.gcard::before{content:"";position:absolute;inset:0;pointer-events:none;border-radius:0 0 13px 13px;
  background:radial-gradient(120% 80% at 100% 0%,var(--sc,var(--brand)) 0%,transparent 62%);
  opacity:0;transition:opacity .22s ease;z-index:-1}
.gcard:hover::before{opacity:.05}
.gcard .go2 .arw{display:inline-block;transition:transform .2s ease}
.gcard:hover .go2 .arw{transform:translateX(4px)}
.badge-new{display:none;margin-left:auto;padding:2px 7px;border-radius:999px;font-size:9.5px;
  font-weight:800;letter-spacing:.08em;background:var(--gold);color:#3A2B08;flex:none}
.gcard.is-new .badge-new{display:inline-block}

/* --- toolbar polish --- */
.searchbox kbd{position:absolute;right:38px;top:50%;transform:translateY(-50%);
  font:600 11px/1 var(--mono);color:var(--slate);background:var(--cloud);
  border:1px solid var(--line);border-bottom-width:2px;border-radius:5px;padding:4px 6px;
  pointer-events:none;transition:opacity .15s}
.searchbox input:focus ~ kbd,.searchbox input:not(:placeholder-shown) ~ kbd{opacity:0}
@media(max-width:640px){.searchbox kbd{display:none}}

/* --- rail rows carry their subject color on hover --- */
.subj:hover .sicon{color:var(--sc)}
.subj[aria-pressed="true"] .sicon{color:var(--sc)}

/* --- one-shot entrance; never re-runs on filter (JS removes .intro) --- */
.cards.intro .gcard{opacity:0;animation:cardIn .42s ease forwards}
@keyframes cardIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.cards.intro .gcard:nth-child(1){animation-delay:.02s}
.cards.intro .gcard:nth-child(2){animation-delay:.06s}
.cards.intro .gcard:nth-child(3){animation-delay:.10s}
.cards.intro .gcard:nth-child(4){animation-delay:.14s}
.cards.intro .gcard:nth-child(5){animation-delay:.18s}
.cards.intro .gcard:nth-child(6){animation-delay:.22s}
.cards.intro .gcard:nth-child(7){animation-delay:.26s}
.cards.intro .gcard:nth-child(n+8){animation-delay:.30s}

@media(max-width:900px){
  .hub-stats li{padding:12px 18px 13px}
  .hub-stats b{font-size:20px}
}
@media(max-width:560px){
  .hub-stats{gap:0}
  .hub-stats li{flex:1 1 50%;border-right:0;padding:11px 0 12px;
    border-bottom:1px solid rgba(255,255,255,.10)}
  .hub-stats li:nth-child(odd){padding-right:14px}
  .hub-stats li:nth-child(even){padding-left:14px;border-left:1px solid rgba(255,255,255,.10)}
}
@media (prefers-reduced-motion:reduce){
  .gcard .mark,.gcard::before,.gcard .go2 .arw{transition:none}
  .gcard:hover .mark{transform:none}
  .gcard:hover .go2 .arw{transform:none}
  .cards.intro .gcard{opacity:1;animation:none}
}

/* ============================================================================
   GUIDE ARTICLE SHELL (2026-08-15)
   Brings guide pages up to the catalog's standard: subject-colored hero, sticky
   contents rail, reading progress, prev/next nav, and typed callouts.

   --sc is set once on <body data-subject>, so a guide only ever declares its
   subject in ONE place and every accent on the page follows from it.
   ========================================================================== */
body[data-subject="java"]     {--sc:#8C1630;--sc-dark:#6E1126;--sc-tint:#F9EBEE}
body[data-subject="calculus"] {--sc:#5A3BD1;--sc-dark:#4326A8;--sc-tint:#EFEBFB}
body[data-subject="secplus"]  {--sc:#8C1630;--sc-dark:#6E1126;--sc-tint:#F9EBEE}
body[data-subject="nclex"]    {--sc:#356548;--sc-dark:#264A35;--sc-tint:#E6F4EC}
[data-subject="discrete-math"]{--sc:#0E7490;--sc-dark:#0A5567;--sc-tint:#E2F2F7}
body[data-subject="python"]   {--sc:#9A3412;--sc-dark:#71260C;--sc-tint:#FCEEE8}
body[data-subject="networking"]{--sc:#27466B;--sc-dark:#1C3350;--sc-tint:#E8EDF4}
/* Biology (2026-09-19). Deeper and bluer than NCLEX's #356548 so the two greens stay
   distinguishable; they never appear together, as biology is /courses/ only and has no
   guides. These are the exact greens the course pages already used for their live state,
   so the token introduces no new hue. */
body[data-subject="biology"]  {--sc:#1F5C3D;--sc-dark:#16402B;--sc-tint:#E7F1EA}

/* reading progress — fixed hairline under the sticky header */
.readbar{position:fixed;top:0;left:0;height:3px;width:0;background:var(--sc,var(--brand));
  z-index:100;transition:width .08s linear;will-change:width}

/* --- hero --- */
.g-hero{position:relative;overflow:hidden;padding:34px 0 30px;
  background:linear-gradient(150deg,var(--sc-dark,#6E1126),var(--sc,#8C1630) 78%)}
.g-hero::before{content:"";position:absolute;inset:0;pointer-events:none;
  background-image:radial-gradient(rgba(255,255,255,.17) 1px,transparent 1px);
  background-size:20px 20px;
  -webkit-mask-image:linear-gradient(120deg,#000,transparent 60%);
          mask-image:linear-gradient(120deg,#000,transparent 60%)}
.g-hero .wrap{position:relative;z-index:1}
.g-hero .crumb{padding:0 0 14px;color:rgba(255,255,255,.62)}
.g-hero .crumb a{color:rgba(255,255,255,.82)}
.g-meta{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:11px;
  font-size:11.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:rgba(255,255,255,.86)}
.g-meta .sicon{width:15px;height:15px;color:#fff}
.g-meta .sep{width:3px;height:3px;border-radius:50%;background:rgba(255,255,255,.45)}
.g-meta .verified{display:inline-flex;align-items:center;gap:5px;background:rgba(255,255,255,.14);
  border:1px solid rgba(255,255,255,.22);border-radius:999px;padding:3px 9px;letter-spacing:.05em}
.g-hero h1{color:#fff;font-size:37px;line-height:1.14;letter-spacing:-.022em;margin:0}
.g-hero .dek{color:rgba(255,255,255,.80);font-size:17.5px;margin:12px 0 0;max-width:660px}

/* --- two-column body: article + sticky contents --- */
.g-layout{display:grid;grid-template-columns:minmax(0,1fr) 226px;gap:46px;align-items:start}
.g-layout > article{padding-top:6px;min-width:0}
.toc{position:sticky;top:82px;padding-top:30px;min-width:0}
.toc h2{font-size:11.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--slate);
  font-weight:700;margin:0 0 10px}
.toc ol{list-style:none;margin:0;padding:0;border-left:2px solid var(--line)}
.toc li{margin:0}
.toc a{display:block;padding:6px 0 6px 13px;margin-left:-2px;font-size:13.5px;line-height:1.42;
  color:var(--slate);border-left:2px solid transparent}
.toc a:hover{color:var(--ink);text-decoration:none;border-left-color:var(--line)}
.toc a.on{color:var(--sc,var(--brand));font-weight:600;border-left-color:var(--sc,var(--brand))}
/* the <details> wrapper is the mobile affordance; on desktop the rail is always
   open and the <h2> is the heading, so the summary must not also render */
.toc details > summary{display:none}
.toc .backtop{display:block;width:100%;text-align:left;margin-top:14px;padding:12px 0 0;
  border:0;border-top:1px solid var(--line);font:inherit;font-size:12.5px;color:var(--slate);
  background:none;cursor:pointer}
.toc .backtop:hover{color:var(--ink)}

/* section anchors must clear the sticky header when jumped to */
article h2[id],article h3[id]{scroll-margin-top:84px}
/* The section links stay invisible, including on hover — a "#" appearing beside a
   heading reads as a rendering glitch to most readers, and on touch there is no
   hover at all, so it just sits there. The links remain in the DOM and reachable:
   keyboard focus still reveals one, and the href still works when shared. */
.anchor{opacity:0;margin-left:8px;font-weight:400;color:var(--sc,var(--brand));
  text-decoration:none;transition:opacity .15s}
.anchor:focus-visible{opacity:1}

/* --- typed callouts --- */
.callout{border:1px solid var(--line);border-left:3px solid var(--sc,var(--brand));
  border-radius:0 10px 10px 0;padding:14px 18px;margin:20px 0;background:var(--cloud)}
.callout .ct{display:flex;align-items:center;gap:7px;font-size:11px;font-weight:700;
  letter-spacing:.07em;text-transform:uppercase;color:var(--sc-dark,var(--brand-dark));margin-bottom:5px}
.callout .ct svg{width:14px;height:14px}
.callout p{margin:0;font-size:16px}
.callout p + p{margin-top:9px}
.callout.warn{border-left-color:#B4541A;background:#FDF4EC}
.callout.warn .ct{color:#8C3F12}
.callout.check{border-left-color:var(--good);background:#EEF7F1}
.callout.check .ct{color:#166B44}

/* --- inline figures ---
   Wrapper for the small explanatory diagrams. The SVGs inside are authored with
   currentColor and var(--sc), so one figure works on every subject's accent and
   inverts correctly when printed. Nothing here is subject-specific. */
.fig{margin:22px 0;padding:0}
.fig svg{display:block;width:100%;height:auto;color:var(--ink)}
.fig figcaption{margin-top:9px;font-size:14px;line-height:1.5;color:var(--slate);
  border-left:2px solid var(--sc,var(--brand));padding-left:11px}

/* --- prev / next --- */
.g-nav{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin:36px 0 0}
.g-nav a{display:flex;flex-direction:column;gap:4px;border:1px solid var(--line);border-radius:13px;
  padding:14px 17px;background:#fff;transition:border-color .18s,transform .18s}
.g-nav a:hover{border-color:var(--sc,var(--brand));text-decoration:none;transform:translateY(-2px)}
.g-nav .lbl{font-size:11px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--slate)}
.g-nav .ttl{color:var(--ink);font-weight:650;font-size:15px;line-height:1.35}
.g-nav .next{text-align:right}
.g-nav a:only-child{grid-column:1 / -1}

/* the article CTA follows the subject rather than always being crimson */
.cta{background:var(--sc,var(--brand))}
.cta a{color:var(--sc-dark,var(--brand-dark))}
.badge{background:var(--sc-tint,var(--brand-tint));color:var(--sc-dark,var(--brand-dark))}
.key{border-left-color:var(--sc,var(--brand))}
.faq summary::after{color:var(--sc,var(--brand))}
article a{color:var(--sc-dark,var(--brand-dark))}

@media(max-width:1040px){
  .g-layout{grid-template-columns:1fr;gap:0}
  .toc{position:static;padding:0;margin:22px 0 4px;border:1px solid var(--line);border-radius:12px;
    background:var(--cloud)}
  .toc-wrap{padding:0}
  .toc details > summary{display:flex;list-style:none;cursor:pointer;padding:12px 16px;font-size:13.5px;
    font-weight:600;color:var(--ink);display:flex;justify-content:space-between;align-items:center}
  .toc details > summary::-webkit-details-marker{display:none}
  .toc details > summary::after{content:'+';color:var(--sc,var(--brand));font-size:19px;line-height:1}
  .toc details[open] > summary::after{content:'\2013'}
  .toc h2{display:none}
  .toc ol{border-left:0;padding:0 16px 12px}
  .toc a{padding:5px 0;border-left:0}
  .toc a.on{border-left:0}
  .toc .backtop{display:none}
}
@media(max-width:640px){
  .g-hero{padding:26px 0 24px}
  .g-hero h1{font-size:27px}
  .g-hero .dek{font-size:16px}
  .g-nav{grid-template-columns:1fr}
  .g-nav .next{text-align:left}
}
@media (prefers-reduced-motion:reduce){
  .readbar{transition:none}
  .g-nav a{transition:none}
  .g-nav a:hover{transform:none}
}


/* ============================================================================
   STUDY HALL — GUIDES (2026-08-27, phase 2 of the approved revamp).
   Guide pages load only this file, so the sitewide block in site.css cannot
   reach them; these rules mirror it. Same restraint: layout, subject accents
   and the white reading surface of an article are untouched — an article is
   for reading, and parchment behind 17px body copy all the way down a long
   explainer is worse, not warmer. The collegiate material goes where the
   brand speaks: headings, the hub hero, and the tables.
   ========================================================================= */
:root{--parchment:#F9F5EA;--parchment-deep:#F3EDDC;--line-parch:#E6DFC9;
  --serif:Georgia,"Iowan Old Style","Palatino Linotype","Book Antiqua",serif}

article h1,article h2,.hub-hero h1,.cta h3{font-family:var(--serif)}
article h1,.hub-hero h1{letter-spacing:-.015em}

/* The hub hero keeps its existing deep-navy dot-field treatment (.hub-hero.deep):
   it already reads as the interior-page counterpart to the homepage's parchment
   band, exactly as the exam heroes do, and the gold chalk stroke + lamp below
   land better on navy than they would on cream. Nothing to restyle here. */

/* Banker's lamp beside the hub headline — the study-hall mark from the homepage. */
.hub-hero .wrap.wide{position:relative}
.hub-lamp{position:absolute;right:8px;top:-4px;width:72px;height:auto;pointer-events:none;opacity:.92}
@media(max-width:860px){.hub-lamp{display:none}}

/* Chalk underline, same gesture and geometry as site.css. */
h1{text-wrap:balance}
.nb{white-space:nowrap}
.chalk{position:relative;display:inline-block}
.chalk svg{position:absolute;left:-2%;bottom:-.2em;width:104%;height:.4em;pointer-events:none}

/* Warm the cool greys so guides sit in the same paper stock as the rest. */
.key{border-color:var(--line-parch);background:var(--parchment)}
table.cmp th{background:var(--parchment-deep)}
table.cmp th,table.cmp td{border-color:var(--line-parch)}

/* =====================================================================
   Header share + search (2026-08-27) — injected by /site.js into
   `header .wrap` on guide pages (which never load site.css, so these
   styles live here; keep behavior in sync with site.css's block).
   White-header variants of .hdr-share / .hdr-search.
   ===================================================================== */
header .hdr-share,header .hdr-search-toggle{position:relative;display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:9px;border:1px solid var(--line);background:#fff;color:var(--slate);cursor:pointer;padding:0;flex:none}
header .hdr-share:hover,header .hdr-search-toggle:hover{color:var(--ink);border-color:var(--slate)}
header .hdr-share svg,header .hdr-search-toggle svg{width:17px;height:17px}
header .hdr-share .ic-check{display:none}
header .hdr-share.done .ic-share{display:none}
header .hdr-share.done .ic-check{display:block;color:var(--good)}
header .hdr-share .hdr-share-tip{display:none;position:absolute;top:calc(100% + 10px);right:0;background:var(--ink);color:#fff;font-size:12.5px;font-weight:600;padding:5px 10px;border-radius:7px;white-space:nowrap;box-shadow:0 8px 18px rgba(42,52,65,.28);z-index:61}
header .hdr-share.done .hdr-share-tip{display:block}
header .hdr-search{position:relative;display:flex;align-items:center;flex:none}
header .hdr-search-toggle{display:none}
header .hdr-search-panel{position:relative;display:flex;margin:0}
header .hdr-search-input{width:140px;transition:width .18s;border:1px solid var(--line);background:#fff;color:var(--ink);border-radius:9px;padding:7px 11px;font:inherit;font-size:13.5px;line-height:1.2}
header .hdr-search-input::placeholder{color:var(--slate)}
header .hdr-search-input:focus{width:200px;outline:2px solid var(--brand);outline-offset:1px}
header .hdr-search-list{display:none;position:absolute;top:calc(100% + 8px);right:0;min-width:300px;max-width:min(92vw,380px);background:#fff;color:var(--ink);border:1px solid var(--line);border-radius:12px;box-shadow:0 18px 38px rgba(42,52,65,.18);list-style:none;margin:0;padding:6px;z-index:60;max-height:min(60vh,420px);overflow:auto;text-align:left}
header .hdr-search-list.open{display:block}
header .hdr-search-list li{display:flex;flex-direction:column;gap:1px;padding:9px 10px;border-radius:8px;cursor:pointer}
header .hdr-search-list li:hover,header .hdr-search-list li.active{background:var(--cloud)}
header .hdr-search-list li.active{outline:2px solid var(--brand);outline-offset:-2px}
header .hdr-search-list .rt{font-weight:700;font-size:14px;color:var(--navy);line-height:1.3}
header .hdr-search-list .rm{font-size:12px;color:var(--slate);font-weight:500}
header .hdr-search-list li.see-all{display:block;font-weight:700;font-size:13.5px;color:var(--navy);border-top:1px solid var(--line);border-radius:0;margin-top:4px;padding-top:11px}
header .hdr-share:focus-visible,header .hdr-search-toggle:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
@media(max-width:760px){
  /* The injected icons must never widen the page: let the nav shrink and
     scroll internally instead (the guides hub's 4-link nav + logo + two
     icons exceeds 390px otherwise — measured 60px of document overflow,
     the exact class of bug fixed on the homepage 2026-08-27). */
  header .wrap{min-width:0}
  header nav{min-width:0;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
  header nav::-webkit-scrollbar{display:none}
  /* header (sticky, positioned) is the containing block: the expanded search
     row spans the full width directly under the bar. */
  header .hdr-search{position:static}
  header .hdr-search-toggle{display:inline-flex}
  header .hdr-search .hdr-search-panel{display:none;position:absolute;top:100%;left:0;right:0;background:#fff;padding:10px 14px 12px;border-bottom:1px solid var(--line);box-shadow:0 14px 26px rgba(42,52,65,.14);z-index:52}
  header .hdr-search.open .hdr-search-panel{display:flex;flex-direction:column}
  header .hdr-search .hdr-search-input{width:100%;font-size:16px} /* 16px stops iOS focus zoom */
  header .hdr-search .hdr-search-input:focus{width:100%}
  header .hdr-search .hdr-search-list{position:static;min-width:0;max-width:none;width:100%;margin-top:8px;box-shadow:none;border:1px solid var(--line);max-height:min(55vh,380px)}
}


/* ===================================================================
   End-of-guide actions + print                          added 2026-08-28
   Share reuses site.js's sharePage() via [data-share-page]. Feedback is a
   mailto, matching app-core's "(mailto, no backend)" pattern — no server, no
   fetch, nothing sent unless the reader sends it. Print is a stylesheet, not a
   generator: "Save as PDF" is the browser's own dialog, so there is no PDF
   library to ship and the output always matches what the reader sees.
   =================================================================== */
.g-actions{display:flex;flex-wrap:wrap;gap:10px;margin:30px 0 10px}
.g-actions .ga{display:inline-flex;align-items:center;gap:8px;font:inherit;font-size:.88rem;
  padding:9px 15px;border:1px solid var(--line,#e3ddd2);border-radius:10px;background:transparent;
  color:inherit;text-decoration:none;cursor:pointer;transition:border-color .15s,background .15s}
.g-actions .ga:hover{border-color:var(--sc,var(--brand));background:var(--sc-tint,transparent)}
.g-actions .ga svg{width:16px;height:16px;flex:none;color:var(--sc,var(--brand))}
.g-actions-note{font-size:.88rem;color:var(--muted);margin:0 0 8px}
.print-only{display:none}

@media print{
  /* --- printed guide, 2026-08-28 -------------------------------------------
     Modelled on the Cruising Costs product-setup sheet: a masthead with the mark,
     a rule, numbered sections, tinted callouts, and a fine-print footer.
     The masthead REUSES the page's own <header> rather than adding print-only
     markup to every guide file — one rule here covers every subject, including
     guides not written yet. */
  .readbar,.toc,aside.toc,.g-actions,.g-actions-note,
  .related,.cta,.g-nav,.backtop,.anchor{display:none !important}

  header{display:block !important;position:static !important;background:none !important;
    -webkit-backdrop-filter:none !important;backdrop-filter:none !important;
    border-bottom:1.6pt solid #000 !important;margin:0 0 12pt;padding:0}
  header .wrap{display:flex !important;align-items:center;gap:9pt;height:auto;
    max-width:none;padding:0 0 7pt;margin:0}
  /* Only the mark survives. site.js injects a search field, a share button and a
     menu button into this header at runtime; showing <header> for the masthead
     would print all three. Anything that is not the logo goes. */
  header .wrap > *:not(.logo){display:none !important}
  header nav,.hdr-search,.hdr-share,.menu-btn,header .cta{display:none !important}
  /* forced: the phone rule zeroes .logo's font-size, and some paper widths match it */
  .logo{font-size:12.5pt !important;gap:9pt !important;color:#000 !important;
    font-weight:800;letter-spacing:-.01em}
  .logo .mk{width:26pt !important;height:26pt !important}
  .logo .mk img{width:100%;height:100%;object-fit:contain}
  /* the subject sits opposite the mark, like the Cruising Costs rev line */
  header .wrap::after{content:"Study guide";margin-left:auto;font-size:8.5pt;
    letter-spacing:.14em;text-transform:uppercase;color:#555;font-weight:600}
  body[data-subject="discrete-math"] header .wrap::after{content:"Discrete Math · study guide"}
  body[data-subject="java"] header .wrap::after{content:"Java · study guide"}
  body[data-subject="python"] header .wrap::after{content:"Python · study guide"}
  body[data-subject="calculus"] header .wrap::after{content:"Calculus · study guide"}
  body[data-subject="networking"] header .wrap::after{content:"Networking · study guide"}

  /* numbered sections, as on the reference sheet */
  article{counter-reset:sec}
  article h2{counter-increment:sec}
  article h2::before{content:counter(sec) "\00a0\00a0·\00a0\00a0";color:#777;font-weight:600}

  footer{display:block !important;background:none !important;color:#333 !important;
    margin:10pt 0 0;padding:6pt 0 0;border-top:.6pt solid #999;font-size:7.5pt;
    page-break-inside:avoid;break-inside:avoid}
  footer .wrap{max-width:none;padding:0}
  footer p:first-child,footer .legal{display:block}
  footer p:nth-child(2){display:none} /* the nav row of links is noise on paper */
  footer a{color:#333 !important;text-decoration:none}
  footer .legal{border:0;margin:2pt 0 0;padding:0;font-size:7pt;color:#666 !important;line-height:1.35}
  html,body{background:#fff !important;color:#000 !important;font-size:11.5pt}
  .wrap,.wrap.wide,.g-layout{max-width:none;width:auto;margin:0;padding:0;display:block}
  /* The hero is white-on-navy on screen. Drop the navy and the white text goes
     invisible on paper — force every part of it back to ink. */
  .g-hero{padding:0 0 9pt;border:0;background:none !important}
  .g-hero::before{display:none !important}
  .g-hero .crumb{display:none !important} /* the trail is navigation, not content */
  .g-hero h1{color:#000 !important;font-size:20pt;line-height:1.14;margin:0 0 5pt}
  .g-hero .dek{color:#333 !important;font-size:10.5pt;margin:0 0 7pt;max-width:none}
  .g-meta{font-size:8.5pt;color:#555 !important;letter-spacing:.06em;
    border-top:.5pt solid #CCC;padding-top:5pt;margin-top:2pt}
  .g-meta .sicon{display:none}
  article{max-width:none}
  h2{font-size:13pt;margin-top:14pt;page-break-after:avoid;break-after:avoid}
  h3{page-break-after:avoid;break-after:avoid}
  p,li{orphans:3;widows:3}
  /* A table or a callout split across a page break is unreadable. */
  table,.callout,pre,figure{page-break-inside:avoid;break-inside:avoid}
  .fig{margin:14pt 0}
  .fig svg{color:#000;max-width:132mm}
  .fig figcaption{font-size:9pt;color:#333 !important;border-left:1pt solid #000}
  table{border-collapse:collapse;width:100%}
  /* colour does not survive most printers — the bold weight and the digit do */
  table.cmp .v1,table.cmp .v0{color:#000 !important;font-weight:700}
  th,td{border:.5pt solid #B0B0B0;padding:3.5pt 6pt}
  table.cmp th{background:#F0EDE8 !important;font-size:9.5pt}
  .callout{border:.6pt solid #B9A38C;border-left:2.5pt solid #8C1630;background:#FAF6F2 !important;
    padding:9pt 11pt;border-radius:2pt}
  .callout .ct{color:#8C1630 !important;font-size:8.5pt}
  a{color:#000 !important;text-decoration:none}
  .print-only{display:block}

  /* --- practice page (2026-08-28) -------------------------------------------
     Starts its own sheet, so the printed guide always ends on something worth
     keeping instead of a lone QR code. The QR follows it on the same page.
     Screen-hidden: this is a paper artefact, and on screen the practice app is
     one click away. */
  .practice{page-break-before:always;break-before:page}
  .practice h2{margin:0 0 3pt;font-size:15pt}
  .practice h2::before{content:none}          /* outside the numbered section run */
  .practice .pintro{font-size:9.5pt;color:#555;margin:0 0 12pt}
  .practice ol{margin:0;padding-left:16pt;counter-reset:none}
  .practice ol > li{margin:0 0 10pt;font-size:10pt;line-height:1.45;
    page-break-inside:avoid;break-inside:avoid}
  .practice pre{margin:4pt 0 0;font-size:9pt;background:#F7F7F5;border:.4pt solid #DDD;
    padding:5pt 7pt;border-radius:2pt}
  .practice .work{display:block;border-bottom:.4pt solid #CFCFCF;height:13pt;margin-top:5pt}
  .answers{margin-top:12pt;padding-top:6pt;border-top:.6pt solid #999;
    font-size:8.5pt;line-height:1.55;color:#333;page-break-inside:avoid}
  /* the label only — a child selector, or every bold inside an answer turns into
     an uppercase block and the maths becomes unreadable */
  .answers > strong{display:block;font-size:9pt;color:#000;margin-bottom:3pt;
    letter-spacing:.1em;text-transform:uppercase}
  .answers li strong{display:inline;font-size:inherit;letter-spacing:normal;
    text-transform:none;color:#000}
  .answers ol{padding-left:14pt;margin:0}
  .answers li{margin:0 0 3pt;font-size:8.5pt}

  /* guide.js opens every FAQ on beforeprint — CSS cannot do it, because Chrome
     does not slot a closed <details>. These rules handle the rest: the +/- is an
     affordance with nothing to click on paper. */
  .faq summary{cursor:auto;display:block}
  .faq summary::after{content:"" !important;display:none}
  .faq details{padding:9pt 0;border-bottom:.5pt solid #CCC;page-break-inside:avoid;break-inside:avoid}
  .faq summary{font-size:10.5pt;margin-bottom:3pt}
  .faq p{font-size:9.5pt}

  /* the hero already carries a rule; the extra article padding just made a hole */
  article{padding-top:0}
  /* Kept small on purpose. At 96pt tall with a 20pt margin this block could not
     fit under the last section and got pushed onto a page of its own, which is a
     page a reader would throw away. Roughly half the height now, so it lands at
     the foot of the last page of content. */
  .print-qr{display:flex !important;gap:8pt;align-items:center;margin-top:10pt;padding-top:6pt;
    border-top:.6pt solid #999;page-break-inside:avoid;break-inside:avoid}
  .print-qr .qr{flex:none;width:54pt;height:54pt}  /* 0.51mm per module — below ~0.40mm it stops scanning */
  .print-qr-txt{display:flex;flex-direction:column;gap:0;font-size:8pt;line-height:1.35}
  .print-qr-txt strong{font-size:9pt}
  .print-qr-txt span{color:#555;word-break:break-all}
  @page{margin:14mm 15mm 16mm}
}


/* ============================================================================
   CROSS-DOCUMENT VIEW TRANSITIONS  (added 2026-09-19)
   Adopted from the Awwwards Developer Award feed, where every winner fakes this
   with a JavaScript router because they are single-page apps. We are 64 static
   same-origin files, which is the case the native feature exists for, so our
   cost is CSS and theirs is a framework.

   MUST live in BOTH site.css and guides/guide.css: the page being left and the
   page being entered each have to opt in, or the transition fires one way only.

   Chrome/Edge 126+, Safari 18.2+. Firefox ignores the at-rule and navigates
   normally, so there is no fallback to write and no degraded state.

   The header is named rather than cross-faded: it is identical on every page,
   and holding it still is what stops a navigation reading as a page load. The
   name must be unique per document. Verified 2026-09-19: all 64 non-app pages
   render exactly one <header>. A duplicate name makes the browser skip the
   whole transition SILENTLY, so re-check that before adding any second header.
   ========================================================================== */
@view-transition{navigation:auto}
@media (prefers-reduced-motion:reduce){@view-transition{navigation:none}}
@media (prefers-reduced-motion:no-preference){
  ::view-transition-old(root){animation:kx-vt-out .18s ease-in both}
  ::view-transition-new(root){animation:kx-vt-in .22s ease-out both}
  @keyframes kx-vt-out{to{opacity:0;transform:translateY(-6px)}}
  @keyframes kx-vt-in{from{opacity:0;transform:translateY(8px)}}
  body[data-subject] > header{view-transition-name:kx-header}
}

/* ----------------------------------------------------------------------------
   READING PROGRESS, DRIVEN BY THE SCROLL RATHER THAN BY JAVASCRIPT
   (added 2026-09-19)

   What this replaces: guide.js ran a requestAnimationFrame callback on every
   scroll frame that called getBoundingClientRect() (a forced layout read) and
   then wrote bar.style.width (a layout-triggering property). The old
   `will-change:width` above could never help, because width is not a
   compositable property. That is the textbook shape of scroll jank, on the page
   type we have the most of.

   Range note: `entry 0% exit 0%` reproduces the old arithmetic exactly.
   The old code was pct = (viewportHeight - articleTop) / articleHeight.
   entry 0% is the article's top edge reaching the bottom of the viewport
   (old pct = 0); exit 0% is its bottom edge reaching the same line (pct = 100).

   Scoped to `.g-layout > article` on purpose, and the scoping was WRONG on the
   first attempt: `body > .wrap > article` matched nothing, because the real
   chain is body > div.wrap.wide > div.g-layout > article. The rule parsed, the
   stylesheet validated, and the bar simply never moved. Caught by rendering the
   page in Chromium and reading the computed style, not by reading the CSS.
   A duplicate --kx-article name would make the timeline ambiguous, so the
   selector has to stay 1:1. Verified 2026-09-19 across all 49 pages that load
   this stylesheet: 46 hold exactly one .g-layout and one <article> and carry a
   readbar; the other 3 (guides/index, guides/python/index, research/p-vs-np)
   have no readbar at all. index.html and /ai/ hold several <article> elements
   but load site.css, not this file.

   Chrome/Edge 115+, Safari 26+. Firefox has no scroll-driven animations, so the
   @supports gate fails there and guide.js keeps the old path untouched.
   Do NOT reach for scroll-timeline-polyfill; it is incomplete and buggy.

   NOT gated on prefers-reduced-motion, deliberately, and the first draft here
   was gated and WRONG. A scroll-driven animation produces no motion of its own:
   it is a direct readout of scroll position, like the scrollbar, and it cannot
   move unless the user moves it. Gating it meant a reduced-motion visitor got
   `width:0` from the rule above with the script standing down, so the bar was
   silently deleted for exactly the audience most likely to want a progress cue.
   Measured in Chromium under emulated `prefers-reduced-motion: reduce`.
   -------------------------------------------------------------------------- */
@supports ((animation-timeline: view()) and (animation-range: entry 0% exit 0%)){
  html{timeline-scope:--kx-article}   /* .readbar is not inside <article> */
  .g-layout > article{view-timeline:--kx-article block}

  .readbar{
    width:100%;
    transform:scaleX(0);
    transform-origin:0 50%;
    transition:none;          /* the timeline drives it, not a clock */
    will-change:transform;    /* replaces the inert will-change:width */
    animation:kx-read auto linear both;
  }
  /* animation-timeline and animation-range MUST come after the `animation`
     shorthand, which resets both. Separate rule so that stays obvious. */
  .readbar{animation-timeline:--kx-article;animation-range:entry 0% exit 0%}

  @keyframes kx-read{from{transform:scaleX(0)}to{transform:scaleX(1)}}
}

/* ----------------------------------------------------------------------------
   TEXT WRAP LADDER  (added 2026-09-19)
   Balance for short headings, pretty for body copy. `pretty` is scoped to
   article: it is a look-back algorithm and costs real layout time on long
   pages, for no gain on one-line strings.
   balance: Baseline 2024-05-13. pretty: Chrome/Edge 117+, Safari 26+, not
   Firefox. Both ignored where unsupported.
   -------------------------------------------------------------------------- */
h2,h3,.dek{text-wrap:balance}
article p,article li,blockquote{text-wrap:pretty}


/* ===================================================================
   Site navigation pass                                   added 2026-09-30
   One main menu on every page (Home, Practice tests, Courses, Guides, The
   Science). The section you are in is marked .on; the exact landing page
   also carries aria-current="page". Breadcrumbs are <nav class="crumb">.
   =================================================================== */
header nav a.on{color:var(--ink);font-weight:600;text-decoration:underline;text-decoration-thickness:2px;
  text-underline-offset:8px;text-decoration-color:#DCA845}
.class-pages{margin:10px 0 0}
header nav a{white-space:nowrap}
/* Tablet widths: five menu items plus search and share do not fit beside the
   wordmark, so the mark alone stands for the brand, as it already does on phones. */
@media(max-width:1000px){.logo{font-size:0;gap:0}}
/* Phones: the menu gets its own full-width row under the logo, so every item is
   visible instead of hidden past the right edge of a scrolling strip. */
@media(max-width:640px){
  header .wrap{flex-wrap:wrap;height:auto;row-gap:0;padding-top:8px;padding-bottom:0}
  header .logo{height:42px}
  header .hdr-search{margin-left:auto}
  header nav{order:9;flex:1 0 100%;margin-left:0;gap:14px;padding:4px 0 10px}
  /* Home is back: the logo alone is not an obvious way home. The extra .wrap
     outranks the older 520px/600px rules (here and in research.css) that hid it. */
  header .wrap nav a:first-child{display:inline}
  header nav a{font-size:13.5px}
  article h2[id],article h3[id]{scroll-margin-top:118px}
}
@media(max-width:380px){header nav{gap:11px}header .wrap nav a{font-size:13px}}

/* Next-step links under the guide hero (2026-10-19) */
.g-hero .g-next{display:flex;flex-wrap:wrap;gap:10px;margin:18px 0 0}
.g-hero .g-next a{display:inline-flex;align-items:center;font-weight:600;font-size:14.5px;line-height:1.3;padding:9px 16px;border-radius:999px}
.g-hero .g-next a:hover{text-decoration:none}
.g-hero .g-next .g-next-app{background:#fff;color:var(--sc-dark,var(--brand-dark))}
.g-hero .g-next .g-next-app:hover{background:#f3f3f3}
.g-hero .g-next .g-next-hub{border:1px solid rgba(255,255,255,.55);color:#fff}
.g-hero .g-next .g-next-hub:hover{background:rgba(255,255,255,.1)}
.g-hero .g-next a:focus-visible{outline:2px solid #fff;outline-offset:2px}
@media print{.g-hero .g-next{display:none}}

/* What the user typed, in console-input listings (2026-10-19) */
pre.out b.typed{font-weight:800;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px}

/* Using AI course (2026-10-21): its own teal, and two callouts used only in its modules */
body[data-subject="ai"]  {--sc:#115E59;--sc-dark:#0B403C;--sc-tint:#E3F2F0}
.callout.case{border-left-color:#8A5A12;background:#FBF6EC}
.callout.case .ct{color:#6E470E}
.callout.tryai{border-left-color:var(--sc,#115E59);background:var(--sc-tint,#E3F2F0)}
.callout.tryai .ct{color:var(--sc-dark,#0B403C)}
.callout.tryai pre{margin:10px 0 4px;white-space:pre-wrap}
body[data-subject="ai"] article pre{white-space:pre-wrap;word-break:break-word}
@media (max-width:640px){body[data-subject="ai"] article table.cmp{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;font-size:14px}body[data-subject="ai"] article table.cmp th,body[data-subject="ai"] article table.cmp td{padding:8px 9px;min-width:88px}}
