/* ═══════════════════════════════════════════════════════════
   Google Cloud Services Explained — shared.css
   ─────────────────────────────────────────────────────────── */

/* ── Variables ───────────────────────────────────────────────
   Unified IT Playbook design tokens (shared vocabulary with
   portal.css). Light is the default (:root); dark overrides live
   in [data-theme="dark"]. Brand accents (violet #7C3AED / blue
   #4285F4 / cyan) are constant across themes.
   Derived from the Claude Design "IT Playbook" handoff.
   ──────────────────────────────────────────────────────────── */
:root{
  /* ---- Brand (constant across themes) ---- */
  --accent-violet:#7c3aed;--accent-blue:#4285f4;--accent-cyan:#15b6cf;
  --grad-brand:linear-gradient(135deg,#7c3aed 0%,#4285f4 100%);
  --grad-audio:linear-gradient(90deg,#15b6cf,#4285f4);

  /* ---- Surfaces / text / borders (LIGHT) ---- */
  --bg-deep:#eef0f6;--bg-raised:#ffffff;--surface:#ffffff;--surface-hover:#f1f3f9;
  --fg:#0c1018;--fg-muted:#4a5365;--fg-subtle:#5b6478;
  --border:rgba(12,16,24,.10);--border-strong:rgba(12,16,24,.18);--border-bright:rgba(124,58,237,.45);
  --primary:#4285f4;--primary-hover:#3b78e0;--primary-press:#2f66c8;--on-primary:#ffffff;
  /* ---- Code blocks (LIGHT) ---- */
  --code-bg:#f6f8fb;--code-fg:#1f2533;--code-bd:rgba(12,16,24,.12);
  --code-cmt:#7a8595;--code-k:#0550ae;--code-s:#0a7b34;--code-n:#953800;--code-nm:#6f42c1;--code-path:#9a3d00;--code-ds:#0550ae;

  /* ---- Radii ---- */
  --r-xs:6px;--r-sm:8px;--r-md:12px;--r-lg:16px;--r-xl:22px;--r-2xl:28px;--r-pill:999px;
  /* ---- Spacing (4px base) ---- */
  --s-1:4px;--s-2:8px;--s-3:12px;--s-4:16px;--s-5:20px;--s-6:24px;
  --s-8:32px;--s-10:40px;--s-12:48px;--s-16:64px;--s-20:80px;--s-24:96px;
  /* ---- Elevation (LIGHT) ---- */
  --shadow-sm:0 1px 2px rgba(20,30,60,.08);
  --shadow-md:0 6px 18px -6px rgba(20,30,60,.14);
  --shadow-lg:0 20px 50px -16px rgba(20,30,60,.22);
  --shadow-card:0 1px 0 rgba(255,255,255,.7) inset,0 14px 34px -20px rgba(20,30,60,.30);
  /* ---- Motion ---- */
  --ease-out:cubic-bezier(.2,.7,.2,1);--ease-spring:cubic-bezier(.34,1.56,.64,1);
  --dur-fast:.14s;--dur:.24s;--dur-slow:.5s;
  /* ---- Themed scrollbar (LIGHT) ---- */
  --sb-track:var(--bg-deep);--sb-thumb:var(--border-strong);--sb-thumb-hover:var(--fg-subtle);
  /* ---- Reading scale (text-size control, Phase 4) ---- */
  --reading-scale:1;

  /* ---- Legacy course aliases (retuned to the new palette) ---- */
  --bg:#f6f7fb;--bg-sb:#f1f3f9;--bg-surf:#eef0f6;
  --bd:#d9dee8;--bd2:#e7eaf1;
  --tx:#0c1018;--tx2:#4a5365;--tx3:#5b6478;
  --ac:#1a64d4;--ac-dim:#e9f0fe;--ac-dk:#14509f;--tip-bg:#ffffff;--tip-tx:#0c1018;--tip-bd:#e3e5e8;
  --c-err:#c5221f;--c-err-bg:#fce8e6;--c-err-bd:#f5c6c5;
  --c-ok:#137333;--c-ok-bg:#e6f4ea;--c-ok-bd:#a8d5b5;
  --c-warn:#e37400;--c-warn-bg:#fef9e7;--c-warn-bd:#fcd380;
  --c-info:#1557b0;--c-info-bg:#e8f0fe;--c-info-bd:#aecbfa;
  --tag-compute-bg:#e3f2fd;--tag-compute-tx:#0d47a1;
  --tag-storage-bg:#fce4ec;--tag-storage-tx:#880e4f;
  --tag-db-bg:#e8eaf6;--tag-db-tx:#283593;
  --tag-serverless-bg:#e8f5e9;--tag-serverless-tx:#1b5e20;
  --tag-managed-bg:#f1f3f4;--tag-managed-tx:#5f6368;
  --tag-infra-bg:#f3e5f5;--tag-infra-tx:#4a148c;
  --tag-analytics-bg:#e0f2f1;--tag-analytics-tx:#004d40;
  --tag-nosql-bg:#fff8e1;--tag-nosql-tx:#e65100;
  --fn:'Plus Jakarta Sans',-apple-system,sans-serif;
  --fd:'Instrument Serif',Georgia,serif;
  --fm:'JetBrains Mono',monospace;
  --sw:268px;--hh:58px;--cw:880px;--rw:280px;
}

/* Dark is the DEFAULT theme: these values apply unless the user explicitly
   picks light ([data-theme="light"]). data-theme="dark" still matches this,
   so the JS toggle + all [data-theme="dark"] component rules keep working. */
:root:not([data-theme="light"]){
  /* ---- Brand tints shift slightly brighter on dark ---- */
  --accent-cyan:#22d3ee;
  --grad-audio:linear-gradient(90deg,#22d3ee,#6e8bff);
  /* ---- Surfaces / text / borders (DARK) ---- */
  --bg-deep:#07090e;--bg-raised:#11141e;--surface:#1b2030;--surface-hover:#232a3c;
  --fg:#eef1f8;--fg-muted:#98a2b8;--fg-subtle:#79839a;
  --border:rgba(255,255,255,.08);--border-strong:rgba(255,255,255,.15);--border-bright:rgba(124,58,237,.55);
  --primary:#6e8bff;--primary-hover:#8aa0ff;--primary-press:#5572f0;--on-primary:#0a0c12;
  /* ---- Code blocks (DARK) ---- */
  --code-bg:#0e1320;--code-fg:#c9d4e6;--code-bd:rgba(255,255,255,.10);
  --code-cmt:#6b7689;--code-k:#79b8ff;--code-s:#7ee787;--code-n:#ffa657;--code-nm:#d2a8ff;--code-path:#ffb38a;--code-ds:#79b8ff;
  /* ---- Elevation (DARK) ---- */
  --shadow-sm:0 1px 2px rgba(0,0,0,.4);
  --shadow-md:0 6px 18px -6px rgba(0,0,0,.55);
  --shadow-lg:0 20px 50px -16px rgba(0,0,0,.7);
  --shadow-card:0 1px 0 rgba(255,255,255,.04) inset,0 12px 32px -16px rgba(0,0,0,.7);

  /* ---- Legacy course aliases (DARK) ---- */
  --bg:#0b0e16;--bg-sb:#0f131d;--bg-surf:#161a25;
  --bd:#2a3142;--bd2:#222838;
  --tx:#eef1f8;--tx2:#98a2b8;--tx3:#79839a;
  --ac:#6e8bff;--ac-dim:#1c2742;--ac-dk:#8aa0ff;--tip-bg:#1b2030;--tip-tx:#eef1f8;--tip-bd:#2a3142;
  --c-err:#ff6b6b;--c-err-bg:#2d1a1a;--c-err-bd:#5c2b2b;
  --c-ok:#69db7c;--c-ok-bg:#1a2d1e;--c-ok-bd:#2b5c36;
  --c-warn:#e89c00;--c-warn-bg:#2a2000;--c-warn-bd:#5c4500;
  --c-info:#4dabf7;--c-info-bg:#1c3a5e;--c-info-bd:#2d5a8e;
  --tag-compute-bg:#1c2a3a;--tag-compute-tx:#74b8f7;
  --tag-storage-bg:#2a1a20;--tag-storage-tx:#f7a8c4;
  --tag-db-bg:#1e1c3a;--tag-db-tx:#9e9ef7;
  --tag-serverless-bg:#1a2a1e;--tag-serverless-tx:#69db7c;
  --tag-managed-bg:#25262b;--tag-managed-tx:#909296;
  --tag-infra-bg:#2a1a30;--tag-infra-tx:#c99ef0;
  --tag-analytics-bg:#1a2a28;--tag-analytics-tx:#63d4c5;
  --tag-nosql-bg:#2a2010;--tag-nosql-tx:#f0c070;
}

/* ── Icon toggle ─────────────────────────────────────────── */
.icon-sun{display:none}
[data-theme="dark"] .icon-sun{display:block}
[data-theme="dark"] .icon-moon{display:none}

/* ── Reset ───────────────────────────────────────────────── */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth;font-size:17px}
body{font-family:var(--fn);color:var(--tx);background:var(--bg);line-height:1.8;-webkit-font-smoothing:antialiased}
a{color:var(--ac);text-decoration:none}
a:hover{text-decoration:underline}
img{display:block}

/* ── Themed scrollbars (follow light/dark) ───────────────── */
html{scrollbar-width:thin;scrollbar-color:var(--sb-thumb) var(--sb-track)}
::-webkit-scrollbar{width:12px;height:12px}
::-webkit-scrollbar-track{background:var(--sb-track)}
::-webkit-scrollbar-thumb{background:var(--sb-thumb);border-radius:7px;border:3px solid var(--sb-track);background-clip:padding-box}
::-webkit-scrollbar-thumb:hover{background:var(--sb-thumb-hover);background-clip:padding-box}

/* ── Header ──────────────────────────────────────────────── */
.site-header{position:fixed;top:0;left:0;right:0;height:var(--hh);background:var(--bg);border-bottom:1px solid var(--bd);display:flex;align-items:center;padding:0 1.25rem 0 calc(var(--sw) + 1.5rem);z-index:200;gap:1rem}
.header-brand{display:flex;align-items:center;gap:.6rem;position:fixed;left:0;top:0;width:var(--sw);height:var(--hh);padding:0 1.25rem;border-bottom:1px solid var(--bd);background:var(--bg);z-index:201}
/* Portal brand (logo + name) in the top-left, mirroring the dashboard. */
.header-brand .brand-link{display:flex;align-items:center;gap:9px;text-decoration:none;color:var(--tx)}
.header-brand .brand-mark{height:20px;width:auto;display:block}
.header-brand .brand-name{font-family:var(--fn);font-weight:700;font-size:16px;letter-spacing:-.01em;color:var(--tx)}
.header-brand .brand-link:hover .brand-name{color:var(--primary)}
/* The portal logo also rides the top-right as .academy-home — but that's a
   duplicate once the left shows the portal brand, so hide it on desktop; the
   mobile header (no left brand) brings it back (see the ≤767 block). */
.academy-home{display:none;align-items:center;flex:none;text-decoration:none;order:1}
.academy-home img{height:17px;width:auto;display:block}
.academy-home:hover{opacity:.82}
.brand-title{font-size:13px;font-weight:600;color:var(--tx);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.3}
.brand-sub{font-size:11px;color:var(--tx3)}
.hc{display:flex;align-items:center;justify-content:center;gap:.45rem;font-size:13px;color:var(--tx2);flex:1;overflow:hidden}
.hc a{color:var(--ac);white-space:nowrap}
.hc-sep{color:var(--tx3)}
.hc-cur{color:var(--tx);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* icon-only theme toggle (mirrors the dashboard) */
.theme-btn{width:36px;height:36px;padding:0;border:1px solid var(--bd);border-radius:var(--r-md);color:var(--tx2);background:var(--bg-sb);display:grid;place-items:center;cursor:pointer;flex-shrink:0;transition:background .15s,color .15s}
.theme-btn:hover{background:var(--bg-surf);color:var(--tx)}
.theme-btn svg{width:16px;height:16px}
.theme-btn #theme-label{display:none}   /* icon only — hide the Light/Dark word */
.auth-chip-wrap{position:relative;flex-shrink:0}
/* avatar pill (mirrors the dashboard user button) */
.auth-chip{font:inherit;font-size:13px;font-weight:500;display:inline-flex;align-items:center;gap:8px;padding:4px 11px 4px 4px;border:1px solid var(--bd);border-radius:var(--r-pill);color:var(--tx);background:var(--bg-sb);cursor:pointer;text-decoration:none;transition:background .15s}
.auth-chip:hover{background:var(--bg-surf);text-decoration:none}
.auth-chip img,.auth-chip .ac-av{width:28px;height:28px;border-radius:50%;flex-shrink:0}
.auth-chip .ac-av{background:var(--grad-brand);color:#fff;font-size:11px;font-weight:700;display:grid;place-items:center}
.auth-chip .ac-name{max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.goal-star{font-size:13px;line-height:1;margin:0 1px}
.goal-star[hidden]{display:none}
.auth-chip .ac-chev{display:grid;place-items:center;color:var(--tx3);flex-shrink:0}
.auth-chip .ac-chev svg{width:14px;height:14px}
.auth-chip.signin{padding:7px 15px;font-weight:600;color:var(--tx2)}
.auth-menu{position:absolute;right:0;top:calc(100% + 8px);width:248px;background:var(--bg-raised);border:1px solid var(--bd);border-radius:var(--r-lg);box-shadow:0 14px 32px -12px rgba(0,0,0,.45);padding:8px;display:none;flex-direction:column;z-index:210}
.auth-menu.open{display:flex}
.auth-menu .menu-head{display:flex;gap:11px;align-items:center;padding:10px 10px 12px}
.auth-menu .ac-av.lg{width:40px;height:40px;border-radius:50%;background:var(--grad-brand);color:#fff;font-size:14px;font-weight:700;display:grid;place-items:center;flex:none}
.auth-menu .menu-id{min-width:0}
.auth-menu .menu-id b{display:block;font-size:14px;font-weight:600;color:var(--tx);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.auth-menu .menu-id span{display:block;font-size:12px;color:var(--tx3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.auth-menu a,.auth-menu button{display:flex;align-items:center;gap:11px;width:100%;font:inherit;font-size:14px;text-align:left;padding:9px 11px;border:none;background:none;color:var(--tx2);border-radius:var(--r-md);cursor:pointer;text-decoration:none}
.auth-menu a:hover,.auth-menu button:hover{background:var(--bg-surf);color:var(--tx);text-decoration:none}
.auth-menu a svg,.auth-menu button svg{width:16px;height:16px;flex:none}
.auth-menu .menu-sep{height:1px;background:var(--bd);margin:6px 4px}
.auth-menu .auth-menu-out{color:var(--c-err)}
body.paywalled{overflow:hidden}
/* Scrolls when the card is taller than the viewport (short phones + the
   signed-in variant, which adds the plan picker). `margin:auto` centres the
   card in both axes without the top-clipping that align-items:center causes
   inside an overflowing flex container. */
.paywall{position:fixed;inset:0;z-index:500;display:flex;padding:24px;overflow-y:auto;background:rgba(0,0,0,.55);backdrop-filter:blur(8px)}
.paywall-card{max-width:420px;width:100%;margin:auto;background:var(--bg-surf,var(--bg));border:1px solid var(--bd);border-radius:16px;padding:36px 32px;text-align:center;box-shadow:0 30px 80px -20px rgba(0,0,0,.5)}
.paywall-badge{display:inline-block;font-size:12px;font-weight:700;letter-spacing:.5px;color:#fff;background:var(--ac);padding:5px 14px;border-radius:999px;margin-bottom:16px}
.paywall-card h2{font-size:24px;margin:0 0 10px;color:var(--tx)}
.paywall-card p{color:var(--tx2);line-height:1.5;margin:0 0 24px;font-size:15px}
.paywall-plans{display:flex;gap:10px;margin:0 0 18px}
.pw-opt{flex:1;display:flex;flex-direction:column;gap:2px;align-items:center;padding:12px;border:1px solid var(--bd);border-radius:12px;background:transparent;color:var(--tx2);cursor:pointer;font:inherit;transition:border-color .15s,background .15s}
.pw-opt b{font-size:15px;color:var(--tx)}
.pw-opt span{font-size:13px}
.pw-opt.is-active{border-color:var(--ac);background:rgba(125,125,125,.10)}
.pw-opt.is-active b{color:var(--ac)}
.paywall-cta{width:100%;font:inherit;font-weight:700;font-size:16px;padding:14px;border:none;border-radius:12px;color:#fff;background:var(--ac);cursor:pointer;transition:background .15s}
.paywall-cta:hover{background:var(--ac-dk,var(--ac))}
.paywall-cta:disabled{opacity:.7;cursor:default}
.paywall-note{font-size:13px;color:var(--tx3,var(--tx2));margin:14px 0 0}
.paywall-alt{display:block;margin-top:10px;width:100%;box-sizing:border-box;font-weight:600;font-size:15px;padding:13px;border:1px solid var(--bd);border-radius:12px;color:var(--tx);text-decoration:none;transition:border-color .15s,background .15s}
.paywall-alt:hover{border-color:var(--ac);background:rgba(125,125,125,.10)}
.paywall-back{display:inline-block;margin-top:18px;font-size:14px;color:var(--ac);text-decoration:none}
.paywall-back:hover{text-decoration:underline}
.ch-nav{display:flex;gap:.4rem;flex-shrink:0}
.ch-nav a{font-size:12px;font-weight:600;padding:6px 13px;border:1px solid var(--bd);border-radius:var(--r-pill);color:var(--tx2);display:flex;align-items:center;gap:5px;transition:background .15s,border-color .15s;white-space:nowrap;text-decoration:none}
.ch-nav a:hover{background:var(--bg-sb);text-decoration:none}
.ch-nav a svg{width:14px;height:14px}

/* ── Sidebar ─────────────────────────────────────────────── */
.sidebar{position:fixed;top:var(--hh);left:0;bottom:0;width:var(--sw);background:var(--bg-sb);border-right:1px solid var(--bd);overflow-y:auto;z-index:100;padding:1rem 0 3rem;transition:transform .25s}
.sidebar::-webkit-scrollbar{width:4px}
.sidebar::-webkit-scrollbar-thumb{background:var(--bd);border-radius:4px}
.sb-course{display:flex;align-items:center;gap:.6rem;font-family:var(--fn);font-weight:700;font-size:15px;line-height:1.25;color:var(--tx);text-decoration:none;padding:.1rem 1.25rem .8rem;margin-bottom:.25rem;border-bottom:1px solid var(--bd)}
.sb-course-ic{flex:none;width:30px;height:30px;display:grid;place-items:center}
.sb-course-ic svg{width:30px;height:30px;display:block}
.sb-course-mono{border-radius:8px;color:#fff;font-weight:800;font-size:15px;line-height:1;box-shadow:0 2px 6px -2px rgba(0,0,0,.4)}
.sb-course-tt{min-width:0}
.sb-label{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--tx3);padding:.75rem 1.25rem .25rem}
.ch-list{list-style:none}
.ch-list>li{border-bottom:1px solid var(--bd2)}
.ch-head{position:relative;display:flex;align-items:center;gap:.5rem;padding:.6rem 1.25rem;font-size:13px;font-weight:600;color:var(--tx2);cursor:pointer;transition:background .1s;text-decoration:none;border:none;background:none;width:100%;text-align:left;font-family:var(--fn)}
.ch-head:hover{background:var(--bg-surf);text-decoration:none}
/* Chapter roll-up rail — a thin bar down the left edge of the chapter button,
   so a COLLAPSED chapter still says whether it is finished. Same colour
   language as the per-lesson badges below it: green = every lesson's quiz
   passed, amber = every page in the chapter heard in full. The two are
   mutually exclusive in renderSidebar — green wins, because passing the
   quizzes is the stronger claim. */
.ch-head.ch-heard::before,.ch-head.ch-passed::before{content:"";position:absolute;left:0;top:5px;bottom:5px;width:3px;border-radius:0 3px 3px 0}
.ch-head.ch-heard::before{background:var(--c-warn)}
.ch-head.ch-passed::before{background:var(--c-ok)}
.ch-head.cur,.ch-head.par{color:var(--ac-dk);background:var(--ac-dim)}
.ch-arr{width:13px;height:13px;color:var(--tx3);flex-shrink:0;margin-left:auto;transition:transform .2s}
.ch-head.open .ch-arr{transform:rotate(90deg)}
.svc-list{list-style:none;display:none;border-top:1px solid var(--bd2);padding:.2rem 0 .35rem}
.svc-list.open{display:block}
.svc-list a{display:flex;align-items:center;gap:.5rem;padding:.38rem 1.2rem .38rem 1.5rem;font-size:12.5px;color:var(--tx2);transition:background .1s;line-height:1.4;text-decoration:none}
.svc-list a:hover{background:var(--bg-surf);text-decoration:none}
.svc-list a.cur{color:var(--ac-dk);background:var(--ac-dim);font-weight:600;border-radius:8px;margin:0 .45rem;padding-left:1.05rem}
.svc-n{font-size:10px;font-weight:700;color:var(--tx3);min-width:18px;text-align:center;font-family:var(--fm);flex-shrink:0}
.svc-list a.cur .svc-n{color:var(--ac)}
.sb-done{flex-shrink:0;width:18px;height:18px;border-radius:50%;background:var(--c-ok);color:#fff;font-size:11px;font-weight:700;display:inline-flex;align-items:center;justify-content:center;line-height:1}
.sb-heard{flex-shrink:0;width:18px;height:18px;border-radius:50%;background:var(--c-warn);color:#fff;display:inline-flex;align-items:center;justify-content:center;line-height:1}
/* dark theme: amber is bright → use a dark headphone glyph for contrast */
[data-theme="dark"] .sb-heard{color:#2a1d00}
.sb-lock{display:inline-flex;align-items:center;color:var(--tx3);margin-left:auto;padding-left:.4rem;flex-shrink:0;line-height:1}
.sb-lock svg{width:12px;height:12px}
.sb-free{color:var(--ac);font-size:9px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;margin-left:auto;padding-left:.4rem;flex-shrink:0;line-height:1}
.sb-done + .sb-free,.sb-heard + .sb-free{margin-left:.35rem;padding-left:0}

/* ── Main layout ─────────────────────────────────────────── */
.main{margin-left:var(--sw);padding-top:var(--hh);min-height:100vh;padding-bottom:calc(60px + env(safe-area-inset-bottom));transition:margin .25s,padding-bottom .25s}
/* Right "On this page" panel reserves a column; collapsing it widens reading. */
body.has-onpage:not(.op-hidden) .main{margin-right:var(--rw)}
.wrap{max-width:var(--cw);margin:0 auto;padding:2.5rem 3rem 6rem}

/* ── Right panel: On this page (TOC) ─────────────────────── */
.onpage{position:fixed;top:var(--hh);right:0;bottom:0;width:var(--rw);background:var(--bg);border-left:1px solid var(--bd);overflow-y:auto;z-index:90;padding:1.4rem 1.25rem 3rem;transition:transform .25s}
.onpage::-webkit-scrollbar{width:4px}
.onpage::-webkit-scrollbar-thumb{background:var(--bd);border-radius:4px}
body.op-hidden .onpage{transform:translateX(100%)}
.op-label{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--tx3);margin-bottom:.6rem}
.op-list{list-style:none;display:flex;flex-direction:column;gap:1px;border-left:1px solid var(--bd)}
.op-list a{display:block;padding:.3rem .8rem;font-size:12.5px;line-height:1.4;color:var(--tx2);border-left:2px solid transparent;margin-left:-1px;transition:color .12s,border-color .12s}
.op-list a:hover{color:var(--tx);text-decoration:none}
.op-list a.cur{color:var(--ac-dk);border-left-color:var(--ac);font-weight:600}
.op-toggle{position:fixed;top:calc(var(--hh) + 16px);right:calc(var(--rw) - 1px);z-index:110;width:18px;height:32px;background:var(--bg);border:1px solid var(--bd);border-right:none;border-radius:6px 0 0 6px;cursor:pointer;color:var(--tx3);font-size:14px;display:flex;align-items:center;justify-content:center;padding:0;transition:right .25s}
.op-toggle:hover{color:var(--tx)}
body.op-hidden .op-toggle{right:0;border-right:1px solid var(--bd);border-radius:6px 0 0 6px}
@media(max-width:1080px){.onpage,.op-toggle{display:none}body.has-onpage:not(.op-hidden) .main,body.has-onpage .main{margin-right:0}}

/* ── Current-lesson status pills (under the title) ───────── */
/* audio duration chip beside the tags */
.tag-dur{display:inline-flex;align-items:center;gap:.3rem;font-size:11px;font-family:var(--fm);color:var(--tx3);line-height:1;margin-left:.15rem}
.tag-dur svg{flex:none}

/* ── Top-bar trial CTA (non-subscribers) ─────────────────── */
.trial-cta{order:0;flex:none;font-size:12px;font-weight:700;padding:6px 14px;border-radius:var(--r-pill);background:var(--grad-brand);color:#fff;text-decoration:none;white-space:nowrap;box-shadow:var(--shadow-sm);transition:filter .15s}
.trial-cta:hover{text-decoration:none;filter:brightness(1.07)}
/* Free-course-of-the-month variant: emerald "Sign in — free this month". */
.trial-cta-free{background:#34d399;color:#04231a}

/* ── Service page header ─────────────────────────────────── */
.svc-hd{display:flex;align-items:flex-start;gap:1.25rem;margin-bottom:1.5rem}
.svc-icon{flex-shrink:0;width:60px;height:60px;background:var(--bg-surf);border:1px solid var(--bd);border-radius:14px;display:flex;align-items:center;justify-content:center;padding:10px}
.svc-icon img{width:100%;height:100%;object-fit:contain}
.svc-hd-txt{flex:1}
.svc-num{font-size:11px;font-weight:700;font-family:var(--fm);letter-spacing:.08em;text-transform:uppercase;color:var(--ac);margin-bottom:.25rem}
.svc-title{font-family:var(--fn);font-size:2.35rem;font-weight:700;color:var(--tx);line-height:1.12;letter-spacing:-.025em;margin-bottom:.6rem}
.tags{display:flex;gap:.4rem;flex-wrap:wrap;align-items:center}

/* ── Overview / intro page headers ──────────────────────── */
.eyebrow{font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--ac);margin-bottom:.5rem}
.page-title{font-family:var(--fn);font-size:clamp(2.2rem,4vw,3rem);font-weight:700;line-height:1.12;color:var(--tx);letter-spacing:-.025em;margin-bottom:.9rem}
.page-sub{font-size:18px;color:var(--tx2);max-width:660px;line-height:1.7;margin-bottom:1.5rem}
.page-meta{display:flex;gap:1rem;flex-wrap:wrap;padding-bottom:2rem;border-bottom:1px solid var(--bd);margin-bottom:2.5rem}
.meta-item{display:flex;align-items:center;gap:.4rem;font-size:13px;color:var(--tx3)}
.meta-item svg{width:14px;height:14px}

/* ── Body copy ───────────────────────────────────────────── */
/* Lesson body + in-lesson headings scale with the reading-size control
   (--reading-scale, set on <html> from Settings). TOC / sidebar / nav do NOT.

   Everything the learner READS scales, wherever it lives: lesson prose, the
   callout-box bodies (Common Confusions, Why It Matters), and the quiz —
   question text, options and the per-option explanations. A reader who needs
   bigger type needs it for the quiz too, not just the paragraphs above it.

   What deliberately does NOT scale: section headings and the boxes' uppercase
   labels (already large enough, and scaling them costs vertical space), the
   "Knowledge Check" heading, buttons and the "Why?" affordance, and figure
   titles/captions — a caption cannot grow while the diagram around it stays
   fixed without the figure falling apart. */
.body{font-size:calc(17px * var(--reading-scale));color:var(--tx)}
.body p{margin-bottom:1.1rem;line-height:1.85}
.body h2{font-family:var(--fn);font-size:calc(1.6rem * var(--reading-scale));font-weight:700;color:var(--tx);margin:2.6rem 0 1rem;letter-spacing:-.02em;line-height:1.25}
.body h3{font-size:calc(14px * var(--reading-scale));font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--tx3);margin:2rem 0 .7rem;display:flex;align-items:center;gap:.5rem}
.body h3::after{content:'';flex:1;height:1px;background:var(--bd)}
.body ul,.body ol{padding-left:1.5rem;margin-bottom:1.1rem}
.body li{margin-bottom:.45rem;line-height:1.8}
.body strong{font-weight:600}
code{font-family:var(--fm);font-size:.85em;background:var(--bg-surf);color:var(--c-err);padding:2px 6px;border-radius:4px;border:1px solid var(--bd)}

/* ── Code blocks (doc-style boxes) ───────────────────────────
   <div class="code-cap">caption</div> sits directly above its <pre class="code">.
   Syntax spans: .cmt comment · .k keyword/command · .s string · .n flag/name ·
   .nm number/shebang · .path path · .ds annotation. */
.code-cap{font-family:var(--fm);font-size:11.5px;font-weight:600;letter-spacing:.02em;color:var(--fg-subtle);
  background:var(--code-bg);border:1px solid var(--code-bd);border-bottom:none;
  border-radius:12px 12px 0 0;padding:.6rem 1.1rem .5rem;margin:1.6rem 0 0;display:block;
  position:relative;padding-left:calc(1.1rem + 48px)}
/* mac-style window dots on the caption bar — dots end at left(1.1rem)+30px+9px; pad clears them */
.code-cap::before{content:"";position:absolute;left:1.1rem;top:50%;transform:translateY(-50%);
  width:9px;height:9px;border-radius:50%;background:#ff5f57;
  box-shadow:15px 0 0 #febc2e,30px 0 0 #28c840;opacity:.85}
pre.code{font-family:var(--fm);font-size:calc(13.5px * var(--reading-scale));line-height:1.7;
  background:var(--code-bg);color:var(--code-fg);border:1px solid var(--code-bd);
  border-radius:12px;padding:1.05rem 1.25rem;margin:1.6rem 0;overflow-x:auto;white-space:pre;
  tab-size:2;-webkit-overflow-scrolling:touch;box-shadow:0 1px 2px rgba(0,0,0,.05)}
/* a pre right after its caption joins it into one box (square the shared edge) */
.code-cap + pre.code{border-radius:0 0 12px 12px;margin-top:0}
pre.code code{background:none;border:none;padding:0;color:inherit;font-size:1em}
pre.code .cmt{color:var(--code-cmt);font-style:italic}
pre.code .k{color:var(--code-k);font-weight:600}
pre.code .s{color:var(--code-s)}
pre.code .n{color:var(--code-n)}
pre.code .nm{color:var(--code-nm)}
pre.code .path{color:var(--code-path)}
pre.code .ds{color:var(--code-ds)}

/* ── Callout boxes ───────────────────────────────────────── */
.box{border-radius:10px;padding:1.1rem 1.25rem;margin:1.5rem 0;border:1px solid}
.box-hd{display:flex;align-items:center;gap:.5rem;font-size:11px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;margin-bottom:.6rem}
.box-hd svg{width:14px;height:14px;flex-shrink:0}
.box-bd{font-size:calc(15px * var(--reading-scale));line-height:1.75}
.box-bd p{margin-bottom:.6rem}
.box-bd p:last-child{margin-bottom:0}
.box-bd ul{padding-left:1.3rem}
.box-bd li{margin-bottom:.3rem}
.box-err{background:var(--c-err-bg);border-color:var(--c-err-bd)}.box-err .box-hd{color:var(--c-err)}
.box-ok{background:var(--c-ok-bg);border-color:var(--c-ok-bd)}.box-ok .box-hd{color:var(--c-ok)}
.box-warn{background:var(--c-warn-bg);border-color:var(--c-warn-bd)}.box-warn .box-hd{color:var(--c-warn)}
.box-info{background:var(--c-info-bg);border-color:var(--c-info-bd)}.box-info .box-hd{color:var(--c-info)}

/* ── Tables ──────────────────────────────────────────────── */
.tbl{width:100%;border-collapse:collapse;font-size:14px;margin:1.25rem 0}
.tbl th{background:var(--bg-surf);padding:.6rem .8rem;text-align:left;font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--tx3);border:1px solid var(--bd)}
.tbl td{padding:.6rem .8rem;border:1px solid var(--bd2);color:var(--tx);vertical-align:top;line-height:1.6}
.tbl tr:nth-child(even) td{background:var(--bg-surf)}
.tbl tr:hover td{background:var(--ac-dim)}

/* ── Comparable services ─────────────────────────────────── */
.comp-row{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin-top:2rem;padding-top:1rem;border-top:1px solid var(--bd)}
.comp-lbl{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--tx3)}
.comp-badge{font-size:13px;padding:3px 10px;border:1px solid var(--bd);border-radius:20px;color:var(--tx2);background:var(--bg-surf)}
.comp-badge strong{font-weight:600;color:var(--tx)}

/* ── Prev / Next navigation ──────────────────────────────── */
.pn{display:flex;justify-content:space-between;align-items:stretch;margin-top:4rem;padding-top:2rem;border-top:1px solid var(--bd);gap:1rem}
.pn-btn{display:flex;flex-direction:column;gap:.2rem;padding:.9rem 1.2rem;border:1px solid var(--bd);border-radius:10px;color:var(--tx);flex:1;max-width:280px;transition:background .15s;text-decoration:none}
.pn-btn:hover{background:var(--bg-sb);text-decoration:none}
.pn-btn.right{text-align:right;align-items:flex-end;margin-left:auto}
.pn-dir{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--tx3);display:flex;align-items:center;gap:.3rem}
.pn-dir svg{width:12px;height:12px}
.pn-title{font-size:15px;font-weight:600;color:var(--ac)}

/* ── Service grid (chapter overviews) ────────────────────── */
.svc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:1rem;margin:1.5rem 0}
.svc-card{border:1px solid var(--bd);border-radius:10px;padding:1.1rem 1.2rem;background:var(--bg-sb);transition:border-color .15s;text-decoration:none;display:block}
.svc-card:hover{border-color:var(--ac);text-decoration:none}
.svc-card-num{font-size:11px;font-weight:700;font-family:var(--fm);color:var(--ac);letter-spacing:.08em;text-transform:uppercase;margin-bottom:.25rem}
.svc-card-name{font-size:16px;font-weight:600;color:var(--tx);margin-bottom:.4rem}
.svc-card-desc{font-size:14px;color:var(--tx2);line-height:1.55}
.svc-card-tags{display:flex;gap:.3rem;flex-wrap:wrap;margin-top:.5rem}

/* ── Glossary ────────────────────────────────────────────── */
.gloss-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:1rem;margin:1.25rem 0}
.gloss-item{background:var(--bg-sb);border:1px solid var(--bd2);border-radius:10px;padding:.9rem 1.1rem}
.gloss-term{font-size:11px;font-weight:700;font-family:var(--fm);color:var(--ac);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.3rem}
.gloss-def{font-size:15px;color:var(--tx2);line-height:1.6}

/* ── Philosophy cards ────────────────────────────────────── */
.phil-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:1rem;margin:1.5rem 0}
.phil-card{border-left:3px solid var(--ac);background:var(--ac-dim);border-radius:0 10px 10px 0;padding:1rem 1.1rem}
.phil-title{font-size:14px;font-weight:700;color:var(--ac-dk);margin-bottom:.4rem}
.phil-body{font-size:14px;color:var(--tx2);line-height:1.6}

/* ── Chapter cards (intro page) ──────────────────────────── */
.ch-card-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:1rem;margin:1.5rem 0}
.ch-card{border:1px solid var(--bd);border-radius:10px;padding:1rem 1.1rem;background:var(--bg-sb);transition:border-color .15s}
.ch-card:hover{border-color:var(--ac)}
.ch-card-num{font-size:11px;font-weight:700;font-family:var(--fm);color:var(--ac);text-transform:uppercase;letter-spacing:.08em;margin-bottom:.25rem}
.ch-card-title{font-size:15px;font-weight:600;color:var(--tx);margin-bottom:.3rem}
.ch-card-desc{font-size:13px;color:var(--tx2);line-height:1.5}
.ch-card-icons{display:flex;flex-wrap:wrap;align-items:center;gap:.45rem;margin-top:.7rem}
.ch-card-icons img{width:24px;height:24px;display:block;object-fit:contain}

/* ── Spectrum figure (e.g. compute IaaS→serverless) ──────── */
.fig-spectrum{margin:1.75rem 0}
.fig-spectrum .fig-title{text-align:center;font-weight:700;color:var(--ac);font-size:1rem;margin-bottom:1.25rem}
.spectrum-row{display:flex;gap:.7rem;align-items:stretch}
.spectrum-card{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;text-align:center;gap:.5rem;border:1px solid var(--bd);border-radius:10px;background:var(--bg-sb);padding:1rem .75rem}
.spectrum-card img{width:42px;height:42px;object-fit:contain}
.spectrum-name{font-weight:600;color:var(--tx);font-size:.92rem;line-height:1.2}
.spectrum-desc{font-size:.78rem;font-style:italic;color:var(--tx2);line-height:1.4}
.spectrum-arrow{display:flex;align-items:center;margin:1rem .25rem .4rem}
.spectrum-arrow::before,.spectrum-arrow::after{content:"";flex:none;width:0;height:0;border-top:5px solid transparent;border-bottom:5px solid transparent}
.spectrum-arrow::before{border-right:8px solid var(--ac)}
.spectrum-arrow::after{border-left:8px solid var(--ac)}
.spectrum-arrow .ln{flex:1;height:2px;background:var(--ac);opacity:.5}
.spectrum-ends{display:flex;justify-content:space-between;font-size:.8rem;font-style:italic;color:var(--tx2)}
.spectrum-notes{display:flex;justify-content:space-between;gap:1rem;margin-top:.55rem}
.spectrum-notes span{font-size:.74rem;color:var(--tx2);max-width:42%}
.spectrum-notes span:last-child{text-align:right}
@media(max-width:640px){.spectrum-row{flex-wrap:wrap}.spectrum-card{flex:1 1 40%}}

/* ── Multi-column comparison figure (optional mini-topology) ── */
.fig-cols{display:flex;flex-wrap:wrap;gap:1rem;margin:1.75rem 0}.fig-cols>.fig-title{width:100%;flex-shrink:0;margin-bottom:0}
.fig-cols .fig-col{flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:.7rem;border:1px solid var(--bd);border-radius:10px;background:var(--bg-sb);padding:1.1rem 1rem}
.fig-col-hd{display:flex;align-items:center;gap:.55rem}
.fig-col-hd img{width:34px;height:34px;object-fit:contain;flex:none}
.fig-col-hd .nm{font-weight:600;color:var(--tx);font-size:.95rem;line-height:1.15}
.fig-col-hd .nm small{display:block;font-weight:500;color:var(--tx2);font-size:.72rem;margin-top:.1rem}
.fig-topo{display:flex;flex-direction:column;align-items:center;gap:.28rem;padding:.6rem 0;border-top:1px solid var(--bd);border-bottom:1px solid var(--bd)}
.fig-topo .row{display:flex;gap:.3rem;justify-content:center;flex-wrap:wrap}
.fig-topo .node{font-size:.66rem;font-family:var(--fm);color:var(--tx2);border:1px solid var(--bd);border-radius:6px;padding:.12rem .38rem;background:var(--bg)}
.fig-topo .conn{width:2px;height:13px;background:var(--ac);opacity:.5}
.fig-topo .store{font-size:.7rem;font-weight:600;color:var(--ac);border:1px solid var(--ac);border-radius:6px;padding:.18rem .5rem;background:var(--bg)}
.fig-col-cap{font-size:.78rem;color:var(--tx2);line-height:1.45}
.fig-col-cap strong{color:var(--tx);font-weight:600}
@media(max-width:640px){.fig-cols{flex-direction:column}}

/* ── 2D decision matrix figure ───────────────────────────── */
.fig-matrix{margin:1.75rem 0}
.fig-matrix .fig-title{text-align:center;font-weight:700;color:var(--ac);font-size:1rem;margin-bottom:1rem}
.matrix-area{display:grid;grid-template-columns:1.5rem 1fr;grid-template-rows:1fr 2.6rem;gap:.35rem;max-width:700px;margin:0 auto}
.matrix-yaxis{grid-row:1;grid-column:1;writing-mode:vertical-rl;transform:rotate(180deg);display:flex;align-items:center;justify-content:center;font-size:.72rem;font-weight:600;color:var(--tx2);letter-spacing:.03em}
.matrix-grid{grid-row:1;grid-column:2;display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,minmax(66px,1fr));border-left:2px solid var(--ac);border-bottom:2px solid var(--ac)}
.matrix-cell{border-right:1px dashed var(--bd);border-top:1px dashed var(--bd);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.3rem;padding:.4rem}
.matrix-chip{display:flex;align-items:center;gap:.32rem;font-size:.8rem;font-weight:600;color:var(--tx);white-space:nowrap}
.matrix-chip img{width:20px;height:20px;object-fit:contain;flex:none}
.matrix-xaxis{grid-row:2;grid-column:2;display:grid;grid-template-columns:repeat(3,1fr);font-size:.72rem;color:var(--tx2);text-align:center;padding-top:.3rem}
.matrix-xaxis b{display:block;color:var(--tx);font-size:.76rem}
.fig-cap{font-size:.78rem;font-style:italic;color:var(--tx2);text-align:center;margin-top:.9rem}
@media(max-width:640px){.matrix-chip{font-size:.7rem}.matrix-chip img{width:16px;height:16px}}

/* ── Layered stack figure ────────────────────────────────── */
.fig-stack{max-width:720px;margin:1.75rem auto;display:flex;flex-direction:column;gap:.5rem}
.fig-stack .fig-title{text-align:center;font-weight:700;color:var(--ac);font-size:1rem;margin-bottom:.5rem}
.stack-layer{border:1px solid var(--bd);border-radius:10px;background:var(--bg-sb);padding:.85rem 1rem}
.stack-layer-hd{display:flex;align-items:center;gap:.5rem;font-weight:600;color:var(--tx);font-size:.92rem}
.stack-layer-hd img{width:26px;height:26px;object-fit:contain;flex:none}
.stack-layer-sub{font-size:.76rem;color:var(--tx2);margin-top:.25rem}
.stack-subnets{display:flex;gap:.4rem;margin-top:.6rem}
.stack-subnet{flex:1;border:1px dashed var(--bd);border-radius:6px;padding:.35rem;text-align:center;font-size:.68rem;font-family:var(--fm);color:var(--tx2)}
.stack-row{display:flex;gap:.5rem;flex-wrap:wrap}
.stack-mini{flex:1 1 0;min-width:88px;border:1px solid var(--bd);border-radius:8px;background:var(--bg);padding:.55rem .4rem;text-align:center;display:flex;flex-direction:column;align-items:center;gap:.3rem}
.stack-mini img{width:24px;height:24px;object-fit:contain}
.stack-mini .nm{font-size:.72rem;font-weight:600;color:var(--tx);line-height:1.15}
.stack-mini .ds{font-size:.64rem;color:var(--tx2);line-height:1.25}
@media(max-width:640px){.stack-mini{flex:1 1 40%}}

/* ── Left-to-right flow figure ───────────────────────────── */
.fig-flow-wrap{margin:1.75rem 0}
.fig-flow-wrap .fig-title{text-align:center;font-weight:700;color:var(--ac);font-size:1rem;margin-bottom:1rem}
.fig-flow{display:flex;align-items:stretch;justify-content:center;flex-wrap:wrap;gap:.35rem}
.fig-flow+.fig-flow{margin-top:1.75rem}
.flow-step{flex:0 1 156px;border:1px solid var(--bd);border-radius:10px;background:var(--bg-sb);padding:.8rem .6rem;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.35rem}
.flow-step img{width:30px;height:30px;object-fit:contain}
.flow-step .nm{font-size:.82rem;font-weight:600;color:var(--tx);line-height:1.18}
.flow-step .ds{font-size:.68rem;color:var(--tx2);line-height:1.3}
.flow-arrow{display:flex;align-items:center;justify-content:center;color:var(--ac);font-size:1.2rem;font-weight:700;flex:none;padding:0 .1rem}
.flow-step.ok{border-color:#34a853}
.flow-step.fail{border-color:#ea4335}
.flow-step .badge{font-size:.62rem;font-weight:700;font-family:var(--fm)}
.flow-step.ok .badge{color:#34a853}
.flow-step.fail .badge{color:#ea4335}
@media(max-width:640px){.flow-step{flex:1 1 100%}.flow-arrow{transform:rotate(90deg);width:100%;padding:.15rem 0}}

/* ── Decision list figure (condition → service) ──────────── */
.fig-decide{max-width:700px;margin:1.75rem auto;display:flex;flex-direction:column;gap:.5rem}
.fig-decide .fig-title{text-align:center;font-weight:700;color:var(--ac);font-size:1rem;margin-bottom:.5rem}
.decide-row{display:flex;align-items:center;gap:.7rem;border:1px solid var(--bd);border-radius:8px;background:var(--bg-sb);padding:.6rem .85rem}
.decide-q{flex:1;font-size:.82rem;color:var(--tx);line-height:1.35}
.decide-arrow{color:var(--ac);font-weight:700;flex:none}
.decide-svc{display:flex;align-items:center;gap:.4rem;font-size:.82rem;font-weight:600;color:var(--tx);flex:none;min-width:142px}
.decide-svc img{width:22px;height:22px;object-fit:contain;flex:none}
@media(max-width:560px){.decide-row{flex-wrap:wrap}.decide-svc{min-width:0}}

/* ── Topology kit (regions / zones / replicas) ───────────── */
.fig-topo2{margin:1.75rem 0}
.fig-topo2 .fig-title{text-align:center;font-weight:700;color:var(--ac);font-size:1rem;margin-bottom:1rem}
.topo-frame{border:2px solid var(--ac);border-radius:12px;padding:.9rem;background:var(--bg-sb);max-width:720px;margin:0 auto}
.topo-frame-label{font-size:.72rem;font-weight:700;color:var(--ac);text-transform:uppercase;letter-spacing:.04em;margin-bottom:.6rem}
.topo-cp{border:1px solid var(--ac);border-radius:6px;padding:.35rem .5rem;background:var(--bg);font-size:.74rem;font-weight:600;color:var(--ac);text-align:center;margin-bottom:.6rem}
.topo-cols{display:flex;gap:.6rem}
.topo-zone{flex:1;min-width:0;border:1px dashed var(--bd);border-radius:8px;padding:.6rem .5rem;background:var(--bg);display:flex;flex-direction:column;gap:.4rem;align-items:center}
.topo-zone-label{font-size:.66rem;font-family:var(--fm);color:var(--tx2);text-align:center}
.topo-node{font-size:.72rem;font-weight:600;color:var(--tx);border:1px solid var(--bd);border-radius:6px;padding:.25rem .45rem;background:var(--bg-sb);display:flex;align-items:center;gap:.3rem;width:100%;justify-content:center}
.topo-node img{width:18px;height:18px;object-fit:contain;flex:none}
.topo-band{text-align:center;font-size:.72rem;font-style:italic;color:var(--tx2);margin-top:.6rem;padding-top:.55rem;border-top:1px dashed var(--bd)}
@media(max-width:560px){.topo-cols{flex-direction:column}}

/* ── Nested hierarchy figure (e.g. IAM resource tree) ────── */
.fig-tree{max-width:640px;margin:1.75rem auto}
.fig-tree .fig-title{text-align:center;font-weight:700;color:var(--ac);font-size:1rem;margin-bottom:1rem}
.tree-level{border:1px solid var(--bd);border-left:3px solid var(--ac);border-radius:8px;background:var(--bg-sb);padding:.55rem .75rem;margin-bottom:.45rem}
.tree-level .lvl{font-size:.64rem;font-family:var(--fm);color:var(--tx2);text-transform:uppercase;letter-spacing:.05em}
.tree-level .nm{font-weight:600;color:var(--tx);font-size:.88rem}
.tree-level .binding{font-size:.72rem;color:var(--ac);margin-top:.2rem;font-family:var(--fm)}
.fig-tree .d1{margin-left:1.6rem}
.fig-tree .d2{margin-left:3.2rem}
.fig-tree .d3{margin-left:4.8rem}

/* ── Trace waterfall figure ──────────────────────────────── */
.fig-waterfall{max-width:700px;margin:1.75rem auto}
.fig-waterfall .fig-title{text-align:center;font-weight:700;color:var(--ac);font-size:1rem;margin-bottom:1rem}
.wf-row{display:flex;align-items:center;gap:.6rem;margin-bottom:.4rem}
.wf-label{flex:0 0 132px;font-size:.7rem;font-family:var(--fm);color:var(--tx);text-align:right;line-height:1.2}
.wf-track{flex:1;position:relative;height:20px;background:var(--bg);border:1px solid var(--bd);border-radius:4px}
.wf-bar{position:absolute;top:-1px;height:20px;border-radius:4px;background:var(--ac)}
.wf-bar.hot{background:#ea4335}
.wf-axis{display:flex;justify-content:space-between;font-size:.64rem;font-family:var(--fm);color:var(--tx2);margin-top:.35rem;margin-left:144px}
.wf-note{font-size:.7rem;color:#ea4335;margin-left:144px;margin-top:.3rem}
.wf-b1{left:0;width:100%}
.wf-b2{left:6%;width:9%}
.wf-b3{left:16%;width:59%}
.wf-b4{left:8%;width:2%}

/* ── Prerequisites ───────────────────────────────────────── */
.prereq-box{border:1px solid var(--bd);border-radius:10px;padding:1.1rem 1.4rem;background:var(--bg-sb);margin:1rem 0 1.5rem}
.prereq-box li{font-size:16px;color:var(--tx);padding:.3rem 0;border-bottom:1px solid var(--bd2);line-height:1.6}
.prereq-box li:last-child{border-bottom:none}

/* ── Audio bar ───────────────────────────────────────────── */
/* content-box so the 52px is the control row; safe-area padding extends the
   panel BELOW it (height becomes 52px + safe-area) — otherwise border-box folds
   the safe-area into 52px, squashing controls up and leaving the tab floating. */
.audio-bar{box-sizing:content-box;position:fixed;bottom:0;left:0;right:0;height:52px;background:var(--bg);border-top:1px solid var(--bd);z-index:300;display:flex;align-items:center;transition:transform .25s;padding-bottom:env(safe-area-inset-bottom)}
/* grid 1fr auto 1fr → the play button (middle column) sits dead-centre on the bar */
.audio-bar__inner{width:100%;padding:0 1rem;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:.6rem}
.ab-col-l{display:flex;align-items:center;gap:.5rem;min-width:0}
.ab-center{display:flex;align-items:center;gap:.5rem}
.ab-col-r{display:flex;align-items:center;gap:.6rem;min-width:0;justify-content:flex-end;position:relative}
.ab-left{display:flex;flex-direction:column;justify-content:center;gap:1px;min-width:0;flex:1 1 0}
.ab-state{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--tx3);font-family:var(--fm)}
.ab-lesson{font-size:12.5px;font-weight:600;color:var(--tx2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Live player settings live in a "Player settings" popover on EVERY device,
   opened by the #ab-more button pinned to the bar's right edge. */
.ab-more{display:inline-flex;position:absolute;right:.6rem;top:50%;transform:translateY(-50%);z-index:5}
/* No hover/focus tooltips anywhere in the audio bar (belt-and-suspenders: the
   data-tip attrs are already gone from the markup, this also kills any stale one). */
#audio-bar [data-tip]:hover::after,#audio-bar [data-tip]:hover::before,
#audio-bar [data-tip]:focus-visible::after,#audio-bar [data-tip]:focus-visible::before{content:none;display:none}
.ab-settings{display:none;position:absolute;right:.6rem;bottom:calc(100% + 14px);
  flex-direction:column;align-items:stretch;gap:.55rem;min-width:230px;padding:.85rem;
  background:var(--bg);border:1px solid var(--bd);border-radius:14px;z-index:320;
  box-shadow:0 18px 44px -12px rgba(0,0,0,.45),0 4px 12px -6px rgba(0,0,0,.28)}
.audio-bar.ab-open .ab-settings{display:flex}
.ab-set-label{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--tx3);font-family:var(--fm);padding-bottom:.5rem;border-bottom:1px solid var(--bd);margin-bottom:.1rem}
.ab-settings .ab-label{justify-content:space-between;width:100%;font-size:10px}
.ab-settings .ab-label select{font-size:13px;min-height:32px}
.ab-settings .ab-check{justify-content:flex-start;width:100%;border-color:transparent;font-size:14px;padding:7px 4px;min-height:0}
.ab-settings .ab-check:hover{background:var(--bg-surf)}
.ab-keys{display:flex;flex-direction:column;gap:.4rem;padding-top:.55rem;margin-top:.15rem;border-top:1px solid var(--bd)}
.ab-keys-label{font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--tx3);font-family:var(--fm)}
.ab-key-row{display:flex;align-items:center;justify-content:space-between;gap:1rem;font-size:13px;color:var(--tx2)}
.ab-kbd{flex:none;min-width:22px;padding:2px 7px;font:600 12px/1.4 var(--fm);text-align:center;color:var(--tx);background:var(--bg-sb);border:1px solid var(--bd);border-radius:6px;box-shadow:0 1px 0 var(--bd)}
.ab-btn.ab-play-main{width:40px;height:40px;border-radius:50%;background:var(--primary);color:var(--on-primary);border:none;font-size:15px;display:inline-flex;align-items:center;justify-content:center;padding:0;box-shadow:0 4px 14px -4px color-mix(in srgb,var(--primary) 70%,transparent)}
.ab-btn.ab-play-main:hover{background:var(--primary-hover);color:var(--on-primary)}
.ab-counter{display:inline-flex;align-items:baseline;gap:.4rem;white-space:nowrap;margin-right:auto}
.ab-unit{display:none}   /* keep the compact "N / M" counter; the "sentences" word is dropped to fit + keep play centred */
.audio-bar--pending{color:var(--tx3);font-size:13px;font-style:italic}
.ab-tab{position:fixed;bottom:calc(52px + env(safe-area-inset-bottom));left:50%;transform:translateX(-50%);z-index:110;width:44px;height:16px;background:var(--bg);border:1px solid var(--bd);border-bottom:none;border-radius:5px 5px 0 0;cursor:pointer;color:var(--tx3);font-size:9px;line-height:1;display:flex;align-items:center;justify-content:center;padding:0;transition:bottom .25s}
/* Sidebar toggle tab */
.sb-toggle{position:fixed;top:calc(var(--hh) + 16px);left:calc(var(--sw) - 1px);z-index:110;width:18px;height:32px;background:var(--bg);border:1px solid var(--bd);border-left:none;border-radius:0 6px 6px 0;cursor:pointer;color:var(--tx3);font-size:14px;display:flex;align-items:center;justify-content:center;padding:0;transition:left .25s}
/* Sidebar hidden state — sidebar slides; toggle follows its right edge to left:0 */
body.sb-hidden .sidebar{transform:translateX(calc(-1 * var(--sw)))}
body.sb-hidden .sb-toggle{left:0}
/* sidebar collapsed → reclaim its width so the reading column re-centres */
body.sb-hidden .main{margin-left:0}
/* Audio bar hidden state (translateY 100% clears the bar incl. safe-area pad) */
body.bar-hidden .audio-bar{transform:translateY(100%)}
body.bar-hidden .ab-tab{bottom:0}
body.bar-hidden .main{padding-bottom:0}
/* Suppress the slide on the initial restored-hidden state (no flash on load) */
body.bar-anim-off .audio-bar,body.bar-anim-off .ab-tab{transition:none}
.ab-btn{background:none;border:none;border-radius:8px;padding:6px 9px;cursor:pointer;color:var(--tx2);font-size:15px;line-height:1;transition:background .15s,color .15s;font-family:var(--fn);display:inline-flex;align-items:center;justify-content:center}
.ab-btn:hover{background:var(--bg-surf);color:var(--tx)}
.ab-play-main:hover{color:var(--on-primary)}
.ab-btn.active{color:var(--ac);border-color:var(--ac)}
.ab-time{font-size:11px;color:var(--tx3);font-family:var(--fm);min-width:44px;text-align:center;white-space:nowrap}
.ab-label{font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;font-family:var(--fm);color:var(--tx3);display:flex;align-items:center;gap:6px;white-space:nowrap}
.ab-label select{font-size:12px;font-family:var(--fn);font-weight:600;letter-spacing:0;text-transform:none;background:var(--bg-sb);border:1px solid var(--bd);border-radius:7px;padding:4px 7px;color:var(--tx);cursor:pointer}
/* Highlight / Autoplay check toggles (word + checkbox) */
.ab-check{display:inline-flex;align-items:center;gap:6px;flex:none;background:none;border:1px solid var(--bd);border-radius:6px;padding:4px 10px;font:500 13px/1 var(--fn);color:var(--tx2);cursor:pointer;white-space:nowrap;transition:color .15s,border-color .15s,background .15s}
.ab-check:hover{background:var(--bg-surf)}
.ab-check-box{position:relative;flex:none;width:14px;height:14px;border:1.5px solid var(--bd);border-radius:3px;transition:background .15s,border-color .15s}
.ab-check.on .ab-check-box{background:var(--ac);border-color:var(--ac)}
.ab-check.on .ab-check-box::after{content:"";position:absolute;left:3.5px;top:.5px;width:4px;height:8px;border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg)}
/* Hover tooltips for audio-bar controls (bar sits at the bottom, so above) */
[data-tip]{position:relative}
[data-tip]:hover::after,[data-tip]:focus-visible::after{content:attr(data-tip);position:absolute;bottom:calc(100% + 11px);left:50%;transform:translateX(-50%);width:max-content;max-width:clamp(180px,60vw,280px);white-space:normal;text-align:left;background:var(--tip-bg);color:var(--tip-tx);border:1px solid var(--tip-bd);font:500 12.5px/1.5 var(--fn);padding:10px 13px;border-radius:11px;pointer-events:none;z-index:310;box-shadow:0 14px 36px -10px rgba(0,0,0,.32),0 3px 10px -4px rgba(0,0,0,.18);animation:tip-pop .15s ease-out}
[data-tip]:hover::before,[data-tip]:focus-visible::before{content:"";position:absolute;bottom:calc(100% + 5px);left:50%;transform:translateX(-50%);border:6px solid transparent;border-top-color:var(--tip-bg);pointer-events:none;z-index:311;animation:tip-pop .15s ease-out}
@keyframes tip-pop{from{opacity:0;transform:translate(-50%,5px)}to{opacity:1;transform:translate(-50%,0)}}
.flow-step,.tree-level,.fig-col{transition:border-color .18s,background .18s,box-shadow .18s}
.flow-step:hover,.tree-level:hover,.fig-col:hover{border-color:var(--ac);background:var(--bg-surf);box-shadow:0 10px 26px -12px rgba(0,0,0,.3)}
.flow-step[data-tip],.tree-level[data-tip]{cursor:help}
/* Figure entrance: staggered fade-in when scrolled into view (JS adds .fig-anim/.fig-in) */
@media (prefers-reduced-motion:no-preference){.fig-anim>.flow-step,.fig-anim>.flow-arrow,.fig-anim>.tree-level,.fig-anim>.fig-col{opacity:0}.fig-in>.flow-step,.fig-in>.flow-arrow,.fig-in>.tree-level,.fig-in>.fig-col{animation:fig-fade .5s ease-out forwards}.fig-in>:nth-child(2){animation-delay:.07s}.fig-in>:nth-child(3){animation-delay:.14s}.fig-in>:nth-child(4){animation-delay:.21s}.fig-in>:nth-child(5){animation-delay:.28s}.fig-in>:nth-child(6){animation-delay:.35s}.fig-in>:nth-child(7){animation-delay:.42s}.fig-in>:nth-child(8){animation-delay:.49s}.fig-in>:nth-child(9){animation-delay:.56s}.fig-in>:nth-child(10){animation-delay:.63s}.fig-in>:nth-child(11){animation-delay:.70s}.fig-in>:nth-child(12){animation-delay:.77s}}
@keyframes fig-fade{from{opacity:0}to{opacity:1}}
@media (prefers-reduced-motion:reduce){[data-tip]:hover::after,[data-tip]:hover::before,[data-tip]:focus-visible::after,[data-tip]:focus-visible::before{animation:none}.flow-step,.tree-level,.fig-col{transition:none}}

/* ── Glossary terms — first-occurrence-per-page definition bubbles ──
   shared.js wraps the first match of each glossary term in a .term-def
   span; the bubble (#term-pop, one per page) is a fixed-position floating
   element so it never clips inside the prose's overflow contexts. */
.term-def{border-bottom:1px dotted var(--ac);cursor:help;transition:color .12s,border-color .12s}
.term-def:hover,.term-def:focus-visible,.term-def.is-open{color:var(--ac);border-bottom-style:solid;outline:none}
/* Dark theme: halve the resting underline's intensity so dense pages read calmer;
   hover/focus/open still snaps to the full bright accent (light theme is left as-is). */
:root:not([data-theme="light"]) .term-def{border-bottom-color:rgba(110,139,255,.5)}
:root:not([data-theme="light"]) .term-def:hover,
:root:not([data-theme="light"]) .term-def:focus-visible,
:root:not([data-theme="light"]) .term-def.is-open{border-bottom-color:var(--ac)}
.term-pop{position:fixed;left:0;top:0;z-index:320;max-width:320px;white-space:normal;text-align:left;background:var(--tip-bg);color:var(--tip-tx);border:1px solid var(--tip-bd);border-left:3px solid var(--ac);font:500 13px/1.55 var(--fn);padding:11px 14px;border-radius:11px;box-shadow:0 14px 36px -10px rgba(0,0,0,.32),0 3px 10px -4px rgba(0,0,0,.18);pointer-events:none;opacity:0;visibility:hidden;transform:translateY(4px);transition:opacity .15s ease-out,transform .15s ease-out,visibility 0s .15s}
.term-pop.show{opacity:1;visibility:visible;transform:none;transition:opacity .15s ease-out,transform .15s ease-out}
.term-pop::after{content:"";position:absolute;top:100%;left:var(--ax,50%);transform:translateX(-50%);border:6px solid transparent;border-top-color:var(--tip-bg)}
.term-pop.below::after{top:auto;bottom:100%;border-top-color:transparent;border-bottom-color:var(--tip-bg)}
@media (prefers-reduced-motion:reduce){.term-pop{transition:none}}

/* ── Block highlight — rounded card, soft bg, full-height cyan bar ──
   padding + equal negative margin grows the card around the active
   sentence without shifting surrounding text. */
[data-b]{position:relative;border-radius:10px;transition:background .25s}
/* Highlight is painted by a ::before behind the text, NOT by padding+negative
   margin on the element. The old approach used `margin:-.3rem -1.1rem` (a
   shorthand that REPLACES all four margins), which clobbered the large top
   margin of section headings (h2 has margin-top:2.6rem) → the gap above a
   heading collapsed when it lit up. A pseudo-element bleeds the gradient out by
   `inset` without touching the element's own box, so layout never shifts —
   regardless of each element's (per-course) margins. */
[data-b].hl{position:relative;z-index:0}
[data-b].hl::before{content:'';position:absolute;inset:-.3rem -1.1rem;border-radius:10px;background:linear-gradient(90deg,color-mix(in srgb,var(--accent-cyan) 30%,transparent) 0%,color-mix(in srgb,var(--accent-cyan) 9%,transparent) 55%,transparent 100%);box-shadow:inset 4px 0 0 var(--accent-cyan);z-index:-1;pointer-events:none}
.no-hl [data-b].hl::before{display:none}

/* ── Tags ────────────────────────────────────────────────── */
.tag{font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;letter-spacing:.03em}
.t-compute{background:var(--tag-compute-bg);color:var(--tag-compute-tx)}
.t-storage{background:var(--tag-storage-bg);color:var(--tag-storage-tx)}
.t-db{background:var(--tag-db-bg);color:var(--tag-db-tx)}
.t-serverless{background:var(--tag-serverless-bg);color:var(--tag-serverless-tx)}
.t-managed{background:var(--tag-managed-bg);color:var(--tag-managed-tx)}
.t-infra{background:var(--tag-infra-bg);color:var(--tag-infra-tx)}
.t-analytics{background:var(--tag-analytics-bg);color:var(--tag-analytics-tx)}
.t-nosql{background:var(--tag-nosql-bg);color:var(--tag-nosql-tx)}

/* ── Quiz ─────────────────────────────────────────────────── */
.quiz{margin-top:2.5rem;padding-top:2rem;border-top:1px solid var(--bd)}
.quiz-hd{font-family:var(--fn);font-size:1.5rem;font-weight:700;color:var(--tx);margin:0 0 1.5rem;letter-spacing:-.02em}
.quiz-q{margin-bottom:1rem;padding:1.1rem 1.25rem;background:var(--bg-sb);border:1px solid var(--bd);border-radius:10px}
.quiz-qt{font-weight:600;font-size:calc(15px * var(--reading-scale));line-height:1.55;margin:0 0 .75rem;color:var(--tx)}
.quiz-opts{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.35rem}
.quiz-opts .quiz-opt{padding:.6rem .85rem;border-radius:7px;border:1.5px solid var(--bd);cursor:pointer;font-size:calc(15.5px * var(--reading-scale));color:var(--tx);line-height:1.55;transition:border-color .12s,background .12s,color .12s;user-select:none}
.quiz-opt:hover:not(.qd){border-color:var(--ac);background:var(--ac-dim);color:var(--tx)}
.quiz-opt.qc{border-color:var(--c-ok-bd);background:var(--c-ok-bg);color:var(--c-ok);cursor:default}
.quiz-opt.qw{border-color:var(--c-err-bd);background:var(--c-err-bg);color:var(--c-err);cursor:default}
.quiz-opt.qd{cursor:default}
/* Answer explanations: once a question is answered, each option reveals why it
   is right or wrong. Hidden before the answer so it never spoils the question.
   Green accent = correct, red = not. Desktop reveals on hover; touch devices
   (no hover) get a "Why?" pill and reveal on tap. */
.quiz-q[data-done] .quiz-opt[data-exp]{position:relative}
.quiz-q[data-done] .quiz-opt[data-exp]::after{content:attr(data-exp);position:absolute;left:0;right:0;bottom:calc(100% + 9px);white-space:normal;text-align:left;background:var(--tip-bg);color:var(--tip-tx);border:1px solid var(--tip-bd);border-left:3px solid var(--c-err);font:500 12.5px/1.55 var(--fn);font-size:calc(12.5px * var(--reading-scale));padding:11px 14px;border-radius:11px;pointer-events:none;z-index:310;box-shadow:0 14px 36px -10px rgba(0,0,0,.32),0 3px 10px -4px rgba(0,0,0,.18);opacity:0;visibility:hidden;transform:translateY(5px);transition:opacity .15s ease-out,transform .15s ease-out,visibility 0s .15s}
.quiz-q[data-done] .quiz-opt.qc[data-exp]::after{border-left-color:var(--c-ok)}
/* Desktop (hover-capable): reveal on hover or keyboard focus, no pill. */
@media (hover:hover){
  .quiz-q[data-done] .quiz-opt[data-exp]{cursor:help}
  .quiz-q[data-done] .quiz-opt[data-exp]:hover::after,.quiz-q[data-done] .quiz-opt[data-exp]:focus-visible::after{opacity:1;visibility:visible;transform:translateY(0);transition:opacity .15s ease-out,transform .15s ease-out}
}
/* Touch (no hover): a "Why?" pill, reveal on tap (focus). */
@media (hover:none){
  .quiz-q[data-done] .quiz-opt[data-exp]{padding-right:3.3rem}
  .quiz-q[data-done] .quiz-opt[data-exp]::before{content:"Why?";position:absolute;right:.6rem;top:50%;transform:translateY(-50%);font-size:10.5px;font-weight:600;letter-spacing:.02em;opacity:.62;border:1px solid currentColor;border-radius:20px;padding:1px 7px;pointer-events:none}
  .quiz-q[data-done] .quiz-opt[data-exp]:focus::after{opacity:1;visibility:visible;transform:translateY(0);transition:opacity .15s ease-out,transform .15s ease-out}
}
@media (prefers-reduced-motion:reduce){.quiz-q[data-done] .quiz-opt[data-exp]::after{transition:none}}
.quiz-summary{display:none;margin-top:1.25rem;padding:1rem 1.25rem;background:var(--bg-surf);border:1px solid var(--bd);border-radius:10px;text-align:center}
.quiz-summary.vis{display:block}
.quiz-score-txt{font-size:calc(15px * var(--reading-scale));font-weight:600;color:var(--tx);margin:0 0 .75rem}
.quiz-retry{padding:.45rem 1.2rem;border-radius:7px;border:1.5px solid var(--ac);background:transparent;color:var(--ac);cursor:pointer;font-size:13px;font-weight:600;font-family:var(--fn);transition:background .12s,color .12s}
.quiz-retry:hover{background:var(--ac);color:#fff}

/* ── Sidebar overlay backdrop ────────────────────────────── */
.sb-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:149;-webkit-tap-highlight-color:transparent}

/* ── Mobile (≤ 767px) ────────────────────────────────────── */
@media (max-width:767px){
  /* Sidebar: overlay, hidden by default via JS */
  .sidebar{z-index:150;box-shadow:4px 0 20px rgba(0,0,0,.2)}
  body:not(.sb-hidden) .sidebar{transform:none}
  body:not(.sb-hidden) .sb-overlay{display:block}

  /* Header (mobile): hamburger on the left (the fixed .sb-toggle); on the right,
     packed to the edge in order theme → user → logo (logo is order:1, last). */
  .site-header{padding-left:3.25rem;padding-right:.85rem;gap:.5rem;justify-content:flex-end}
  body.sb-hidden .site-header{padding-left:3.25rem}
  .header-brand{display:none}
  .academy-home{display:flex}   /* portal logo returns to the top-right on mobile */

  /* Toggle button: full header height, anchored left. The chevron glyph is
     hidden (font-size:0) and replaced by a hamburger icon (theme-aware via a
     CSS mask filled with currentColor), since on mobile this is THE menu button. */
  .sb-toggle{top:0;left:0;width:3rem;height:var(--hh);border-radius:0;border:none;border-right:1px solid var(--bd);font-size:0;color:var(--tx);z-index:201}
  .sb-toggle::before{content:"";width:22px;height:22px;background:currentColor;
    -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cline x1='4' y1='7' x2='20' y2='7'/%3E%3Cline x1='4' y1='12' x2='20' y2='12'/%3E%3Cline x1='4' y1='17' x2='20' y2='17'/%3E%3C/g%3E%3C/svg%3E") center/contain no-repeat;
    mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cline x1='4' y1='7' x2='20' y2='7'/%3E%3Cline x1='4' y1='12' x2='20' y2='12'/%3E%3Cline x1='4' y1='17' x2='20' y2='17'/%3E%3C/g%3E%3C/svg%3E") center/contain no-repeat}
  /* The lessons hamburger stays pinned at the top-left in BOTH states — it must
     not jump to the drawer's edge when the menu opens. */
  body.sb-hidden .sb-toggle,
  body:not(.sb-hidden) .sb-toggle{left:0;border-right:1px solid var(--bd);border-left:none}

  /* Main: full width */
  .main{margin-left:0}
  body.sb-hidden .main{margin-left:0}

  /* Hide chapter prev/next nav + breadcrumb + trial CTA in the header — the
     bottom nav, the lessons drawer (hamburger) and sidebar locks cover these. */
  .ch-nav{display:none}
  .hc{display:none}
  #trial-cta{display:none}

  /* Content */
  .wrap{padding:1.5rem 1.25rem 5rem}
  .body{font-size:calc(16px * var(--reading-scale))}
  .body h2{font-size:calc(1.5rem * var(--reading-scale));margin:1.75rem 0 .7rem}
  .svc-title{font-size:1.65rem}
  .page-title{font-size:clamp(1.6rem,6vw,2.2rem)}
  .page-sub{font-size:16px}
  .gloss-grid{grid-template-columns:1fr}
  .pn{margin-top:2rem}
  .pn-btn{padding:.7rem .85rem}

  /* Tables: horizontal scroll */
  .tbl{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch}

  /* Audio bar: keep transport + key controls; ≥44px tap targets */
  .audio-bar__inner{display:grid;grid-template-columns:1fr auto 1fr;gap:.3rem;padding:0 .5rem}
  /* settings live in the #ab-more popover on phones; keep transport + more only */
  .ab-left,.ab-counter,#ab-restart{display:none}
  .ab-col-l{gap:.25rem;justify-content:flex-end}
  .ab-col-r{gap:.35rem}
  .ab-btn{padding:0 8px;font-size:15px;min-width:44px;min-height:44px;display:inline-flex;align-items:center;justify-content:center}
  .ab-btn.ab-play-main{min-width:44px;min-height:44px}
  .ab-check{min-height:44px;padding:0 9px}
  .ab-label{font-size:0;gap:0;min-height:44px}
  .ab-label select{font-size:12px;min-height:34px}
  /* Keyboard shortcuts are irrelevant on touch devices */
  .ab-keys{display:none}

  /* Quiz */
  .quiz-q{padding:.9rem 1rem}
  /* Scoped to match the base rule above, which is .quiz-opts .quiz-opt:
     a bare .quiz-opt here would lose the cascade and quietly do nothing.
     The old 13px is deliberately gone - options are the text a student
     has to read most carefully, and a phone is where that was hardest.
     Only the padding tightens, to buy back the width. */
  .quiz-opts .quiz-opt{padding:.5rem .75rem}
}

/* ── Very small (≤ 479px) ────────────────────────────────── */
@media (max-width:479px){
  /* Hide speed/pause labels entirely — just the selects remain */
  .ab-label span{display:none}
  /* Breadcrumb: show only current page */
  .hc>a,.hc-sep{display:none}
}

/* ── Flashcards (glossary trainer; mounted on #fc-app) ───────
   One whole-course deck, FSRS-scheduled (logic in shared.js). Cards flip in
   3D, fly up on "I know" / down on "Don't know"; swipe up/down on touch.
   The audio bar runs in card mode on this page (body.fc-mode). */
.sb-cards{flex-shrink:0;color:var(--tx3)}
.ch-head.cur .sb-cards{color:var(--ac)}
/* ── Reset progress ───────────────────────────────────────
   Taking the course again. A quiet footer row under the contents, not a button
   competing with the navigation: it is used once in the life of a course, and
   it is destructive. Danger colour only on hover, so it does not shout from the
   rail every time the reader looks at the chapter list. */
.sb-foot{margin-top:.5rem;padding:.7rem 1.25rem 0;border-top:1px solid var(--bd)}
.sb-reset{display:flex;align-items:center;gap:.5rem;width:100%;padding:.45rem .5rem;margin-left:-.5rem;border:0;border-radius:6px;background:none;font:inherit;font-size:12.5px;color:var(--tx3);cursor:pointer;transition:color .15s,background .15s}
.sb-reset:hover{color:var(--c-err);background:color-mix(in srgb,var(--c-err) 10%,transparent)}
.sb-reset svg{flex:none}

/* The confirmation. A native <dialog>, so focus trapping, Escape and the
   backdrop are the browser's job rather than ours. */
/* margin:auto is what centres a modal <dialog>; the sheet's own reset zeroes
   every margin, so it has to be restored here or the dialog pins itself to
   the top-left corner. max-height keeps it scrollable on a short screen. */
.rp-dialog{width:min(420px,calc(100vw - 2rem));margin:auto;max-height:calc(100vh - 3rem);overflow-y:auto;padding:1.4rem;border:1px solid var(--bd);border-radius:14px;background:var(--bg-c,var(--bg-sb));color:var(--tx);box-shadow:0 24px 60px -20px rgba(0,0,0,.5)}
.rp-dialog::backdrop{background:rgba(0,0,0,.5)}
.rp-h{margin:0;font-family:var(--fn);font-size:19px;font-weight:700;color:var(--tx)}
.rp-sub{margin:.35rem 0 1rem;font-size:13.5px;color:var(--tx2)}
.rp-lab{margin:.9rem 0 .3rem;font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--tx3)}
.rp-list{margin:0;padding-left:1.1rem;font-size:13px;line-height:1.6;color:var(--tx2)}
.rp-list li::marker{color:var(--c-err)}
.rp-keep li::marker{color:var(--c-ok)}
.rp-check{display:flex;gap:.6rem;align-items:flex-start;margin:1.1rem 0 0;padding:.7rem .8rem;border:1px solid var(--bd);border-radius:10px;font-size:13px;color:var(--tx);cursor:pointer}
.rp-check input{margin-top:.15rem;flex:none;accent-color:var(--ac)}
.rp-check em{display:block;margin-top:.2rem;font-style:normal;font-size:11.5px;color:var(--tx3)}
.rp-warn{margin:1rem 0 0;padding:.65rem .8rem;border-radius:10px;background:color-mix(in srgb,var(--c-warn) 14%,transparent);font-size:12px;line-height:1.5;color:var(--tx2)}
/* Reassurance, not a warning: an award once earned is permanent, so this one
   is green. .rp-warn stays for the failure message. */
.rp-note{margin:1rem 0 0;padding:.65rem .8rem;border-radius:10px;background:color-mix(in srgb,var(--c-ok) 13%,transparent);font-size:12px;line-height:1.5;color:var(--tx2)}
.rp-btns{display:flex;justify-content:flex-end;gap:.6rem;margin-top:1.3rem}
.rp-btns button{padding:.6rem 1.1rem;border-radius:999px;border:1px solid var(--bd);background:none;font:inherit;font-size:13.5px;font-weight:600;color:var(--tx);cursor:pointer}
.rp-cancel:hover{background:var(--bd2)}
.rp-btns .rp-go{border-color:transparent;background:var(--c-err);color:#fff}
.rp-btns .rp-go:hover{filter:brightness(1.08)}
.rp-btns .rp-go:disabled{opacity:.7;cursor:default}

/* Sidebar: two thin vocabulary bars under the Flashcards entry.
   Green = remembered now, amber = due for review. */
.sb-fc .ch-head{padding-bottom:.35rem}
.sb-fc-bars{padding:0 1.25rem .65rem 2.55rem;cursor:default}
/* One track, segments side by side (known, then to-review); whatever is left
   showing through is the deck not seen yet. */
.sb-fc-bar{display:flex;height:3px;border-radius:2px;background:var(--bd2);overflow:hidden}
.sb-fc-bar i{display:block;height:100%;flex:0 0 auto;transition:width .35s var(--ease-out)}
.sb-fc-know{background:var(--c-ok)}
.sb-fc-rep{background:var(--c-warn)}
.fc-empty{color:var(--tx3);font-style:italic}

/* card-mode audio bar: sentence transport makes no sense per-card */
body.fc-mode #ab-prev,body.fc-mode #ab-next,body.fc-mode #ab-restart{display:none}

/* Vertically centre only the card + its controls (progress, slider, buttons,
   hint) in the space below the page header, so the trainer doesn't cling to
   the top on tall monitors. The .svc-hd header stays put at the top and the
   reading column keeps its normal width — .wrap stays a full-width block
   (only made a flex COLUMN so .body can grow and centre its content between
   the header and the audio bar). */
body.fc-mode{overscroll-behavior-y:contain}
body.fc-mode .wrap{display:flex;flex-direction:column;min-height:calc(100vh - var(--hh) - 60px);min-height:calc(100svh - var(--hh) - 60px)}
body.fc-mode .svc-hd{flex:none}
body.fc-mode .body{flex:1;display:flex;flex-direction:column;justify-content:center}

/* study view */
.fc-study{display:flex;flex-direction:column;gap:.9rem}
.fc-top{display:flex;align-items:center;gap:.9rem}
.fc-progress{flex:1;display:flex;align-items:center;gap:.7rem;min-width:0}
.fc-count{font:600 12px var(--fm);color:var(--tx3);white-space:nowrap}
.fc-ptrack{position:relative;flex:1;height:5px;border-radius:3px;background:var(--bd2);overflow:hidden}
.fc-ptrack i{position:absolute;left:0;top:0;bottom:0;border-radius:3px;transition:width .3s var(--ease-out)}
.fc-pmiss{background:var(--c-warn)}
.fc-pknow{background:var(--c-ok)}
/* Re-deal what is left of the run. A quiet control beside the progress bar,
   not a third answer button — it decides nothing about the cards. */
.fc-shuffle{flex:none;display:flex;align-items:center;gap:.4rem;padding:.3rem .6rem;border:1px solid var(--bd);border-radius:999px;background:none;font:600 11.5px var(--fn);color:var(--tx3);cursor:pointer;transition:color .15s,border-color .15s,background .15s}
.fc-shuffle:hover{color:var(--tx);border-color:var(--bd2);background:var(--bg-surf)}
.fc-shuffle svg{flex:none}

.fc-stage{display:flex;flex-direction:column;align-items:center;gap:.5rem}
/* auto-flip timeout slider (leftmost = off) */
.fc-timeout{display:flex;align-items:center;gap:.55rem;color:var(--tx3);width:100%;max-width:280px}
.fc-timeout svg{flex:none}
.fc-timeout input[type=range]{flex:1;accent-color:var(--ac);height:14px;cursor:pointer;min-width:0}
/* fixed width fits the longest label ("30 seconds" / "No timeout") so the
   slider track keeps the same length at every value */
.fc-timeout-val{flex:none;font:600 11px var(--fm);width:74px;text-align:left;white-space:nowrap}
/* The box only reserves space. svh, not vh: a mobile toolbar sliding in or out
   changes vh, and that resized the card mid-gesture — a jump, and for the
   frames it lasted a strip of page background showed where the card had been. */
.fc-cardbox{width:100%;max-width:560px;height:min(400px,52vh);height:min(400px,52svh)}
/* The drag lives in custom properties so the gesture and the fly-out keyframes
   below read the SAME numbers. Releasing a dragged card used to clear the
   inline transform first, so the card snapped back to centre for a frame and
   only then flew off from there.
   touch-action keeps the vertical drag ours: without it the browser scrolled
   the first few pixels itself, which on mobile collapses the URL bar and
   relays out the entire page under the card. */
.fc-card{position:relative;width:100%;height:100%;cursor:pointer;outline:none;touch-action:pan-x pinch-zoom;transform:translateY(var(--fc-dy,0px)) rotate(var(--fc-rot,0deg));opacity:var(--fc-op,1);transition:transform .22s var(--ease-out),opacity .22s var(--ease-out)}
/* Finger down: the card must track it exactly, with no easing in between. */
.fc-card.fc-dragging{transition:none}
.fc-card:focus-visible .fc-inner{box-shadow:0 0 0 3px color-mix(in srgb,var(--ac) 45%,transparent),var(--shadow-lg)}
.fc-inner{position:absolute;inset:0;border-radius:var(--r-xl)}
/* Each face carries its own perspective and rotation rather than sharing one
   `transform-style:preserve-3d` parent. A preserve-3d subtree has to be
   rendered as a group and re-rasterised the moment an ancestor takes a
   transform or an opacity of its own — which is precisely what a swipe does —
   and on dark, where the card sits a few RGB steps off the page, that
   re-raster reads as the background changing colour. Two independently
   rotated faces need no group at all, and flip identically. */
.fc-face{position:absolute;inset:0;display:flex;flex-direction:column;backface-visibility:hidden;-webkit-backface-visibility:hidden;border:1px solid var(--bd);border-radius:var(--r-xl);background:var(--bg-raised);box-shadow:var(--shadow-card);padding:1.6rem 1.8rem;overflow:hidden;transition:transform .45s var(--ease-out)}
.fc-front{transform:perspective(1400px) rotateY(0deg);background:linear-gradient(160deg,var(--bg-raised),color-mix(in srgb,var(--accent-blue) 5%,var(--bg-raised)))}
.fc-backside{transform:perspective(1400px) rotateY(180deg);background:linear-gradient(160deg,var(--bg-raised),color-mix(in srgb,var(--accent-violet) 6%,var(--bg-raised)))}
/* Both faces turn the same way, so they stay edge-on together and the swap is
   invisible: front 0 → 180, back 180 → 360. */
.fc-card.fc-flipped .fc-front{transform:perspective(1400px) rotateY(180deg)}
.fc-card.fc-flipped .fc-backside{transform:perspective(1400px) rotateY(360deg)}
/* auto-flip countdown line (fc-timeout setting; width animated from JS) */
.fc-tline{position:absolute;left:0;top:0;height:3px;width:100%;background:var(--grad-audio);opacity:0;border-radius:0 2px 2px 0}
.fc-fit{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;text-align:center;overflow:hidden}
.fc-word{font-weight:700;color:var(--tx);line-height:1.3;letter-spacing:-.015em;overflow-wrap:break-word;max-width:100%}
.fc-defword{font-weight:500;line-height:1.55;letter-spacing:0;text-align:left}
.fc-alias{flex:none;text-align:center;font-size:12.5px;color:var(--tx3);font-style:italic;padding-top:.4rem}

/* fly / enter animations */
@keyframes fc-fly-up{from{transform:translateY(var(--fc-dy,0px)) rotate(var(--fc-rot,0deg));opacity:var(--fc-op,1)}to{transform:translateY(-130%) rotate(5deg);opacity:0}}
@keyframes fc-fly-down{from{transform:translateY(var(--fc-dy,0px)) rotate(var(--fc-rot,0deg));opacity:var(--fc-op,1)}to{transform:translateY(130%) rotate(-5deg);opacity:0}}
@keyframes fc-enter{from{transform:scale(.92);opacity:0}to{transform:scale(1);opacity:1}}
@keyframes fc-pop{from{transform:scale(.2);opacity:0}to{transform:scale(1);opacity:1}}
/* Order matters: `animation` is a shorthand and these selectors have equal
   specificity, so the fly-out rules MUST come after the entrance one — a card
   answered before its entrance animation finished would otherwise keep
   animating fc-enter and never fly. shared.js also drops .fc-enter once it has
   played; either alone fixes it, both together make it hard to break again. */
.fc-card.fc-enter{animation:fc-enter .22s var(--ease-out)}
.fc-card.fc-fly-up{animation:fc-fly-up .32s ease-in forwards;pointer-events:none}
.fc-card.fc-fly-down{animation:fc-fly-down .32s ease-in forwards;pointer-events:none}
@media (prefers-reduced-motion:reduce){
  .fc-card.fc-fly-up,.fc-card.fc-fly-down,.fc-card.fc-enter,.fc-done-badge{animation:none}
  .fc-face,.fc-card{transition:none}
}

/* the two answer buttons — stacked, "I know" on top (least pointer travel) */
.fc-actions{display:flex;flex-direction:column;gap:.55rem;align-items:center}
.fc-btn{display:flex;flex-direction:column;align-items:center;gap:2px;width:100%;max-width:340px;font-family:var(--fn);border-radius:14px;padding:.7rem 1.2rem;cursor:pointer;transition:transform .12s,box-shadow .15s,background .15s,opacity .15s;border:1px solid}
.fc-btn:active{transform:scale(.985)}
/* "I know this" is locked once the recall timeout expires unflipped */
.fc-btn:disabled{cursor:not-allowed;opacity:.4;box-shadow:none;transform:none;filter:grayscale(.4)}
.fc-btn-t{font-size:15px;font-weight:700;display:flex;align-items:center;gap:.5rem}
.fc-btn-s{font-size:11.5px;opacity:.75}
.fc-btn-know{background:var(--c-ok-bg);border-color:var(--c-ok-bd);color:var(--c-ok)}
.fc-btn-know:hover{box-shadow:0 8px 22px -10px color-mix(in srgb,var(--c-ok) 60%,transparent)}
.fc-btn-dont{background:var(--c-warn-bg);border-color:var(--c-warn-bd);color:var(--c-warn)}
.fc-btn-dont:hover{box-shadow:0 8px 22px -10px color-mix(in srgb,var(--c-warn) 60%,transparent)}
.fc-btn-plain{background:var(--bg-sb);border-color:var(--bd);color:var(--tx2)}
.fc-btn-plain:hover{background:var(--bg-surf);color:var(--tx)}
.fc-kbd{min-width:20px;padding:1px 6px;font:600 11px/1.4 var(--fm);text-align:center;color:inherit;background:color-mix(in srgb,currentColor 12%,transparent);border:1px solid color-mix(in srgb,currentColor 35%,transparent);border-radius:5px}

/* bottom hint: flip gesture per device + a pointer to the guide */
.fc-hint{text-align:center;font-size:12px;color:var(--tx3)}
.fc-hint .fc-kbd{font-size:10px}
.fc-hint-sep{margin:0 .35rem;opacity:.6}
.fc-hint-link{color:var(--ac)}
@media (hover:none){.fc-hint-mouse{display:none}}
@media (hover:hover){.fc-hint-touch{display:none}}

/* completion view */
.fc-doneview{display:flex;flex-direction:column;align-items:center;text-align:center;gap:.6rem;padding:2.5rem 0}
.fc-done-badge{width:56px;height:56px;border-radius:50%;background:var(--c-ok);color:#fff;font-size:28px;font-weight:800;display:grid;place-items:center;animation:fc-pop .4s var(--ease-spring)}
.fc-done-hd{font-family:var(--fn);font-size:1.5rem;font-weight:700;color:var(--tx);letter-spacing:-.02em}
.fc-done-sub{font-size:14.5px;color:var(--tx2);max-width:460px;line-height:1.6}
.fc-done-acts{display:flex;flex-direction:column;gap:.55rem;align-items:center;margin-top:.9rem;width:100%}

@media (max-width:767px){
  .fc-cardbox{height:min(340px,48vh);height:min(340px,48svh)}
  .fc-face{padding:1.15rem 1.2rem}
  .fc-btn{max-width:none}
  .fc-kbd{display:none}
}

/* ── Native mode (iOS app) ───────────────────────────────────
   Set by the app on <html> before the page paints. The app draws the
   navigation and owns playback, so the site's own chrome is removed and
   the layout offsets it reserved collapse to zero. Nothing here applies
   in a browser: the class is never added there.
   ─────────────────────────────────────────────────────────── */
html.native{--sw:0px;--hh:0px}
html.native .site-header,
html.native .sidebar,
html.native .sb-toggle,
html.native .sb-overlay,
html.native .onpage,
html.native .audio-bar{display:none}
/* The reader is the whole viewport, but keep room at the foot for the
   app's own player, which floats over the bottom of the web view. */
html.native .main{margin-left:0;padding-top:0}
html.native .wrap{padding:1.5rem 1.25rem 5rem}
