@font-face {
  font-family: 'DM Sans';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url(./fonts/dm-sans-italic-400-700-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'DM Sans';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url(./fonts/dm-sans-italic-400-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(./fonts/dm-sans-normal-400-700-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(./fonts/dm-sans-normal-400-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 700 800;
  font-display: swap;
  src: url(./fonts/manrope-normal-700-800-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 700 800;
  font-display: swap;
  src: url(./fonts/manrope-normal-700-800-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==========================================================================
   MathUniverse — stylesheet
   Design tokens and component geometry are ported from the reference design so
   the visual language matches. Fonts are self-hosted (see source/fonts.css);
   nothing here makes a third-party request.
   ========================================================================== */

/* --- 1. Tokens ----------------------------------------------------------- */

:root {
  --accent: #7956e9;
  --accent-strong: #6b48dd;
  --accent-soft: #eeebfb;
  --accent-tint: #f2ecfc;
  --accent-tint-line: #e1d6f3;

  --ink: #242633;
  --ink-soft: #454453;
  --ink-mid: #626779;
  --muted: #9295a4;
  --muted-soft: #a0a2af;
  --muted-strong: #737789;

  --bg: #f7f8fa;
  --surface: #fcfcfe;
  --card: #ffffff;
  --card-soft: #fbfaff;
  --line: #e9eaf0;
  --line-soft: #f0eff4;
  --line-card: #e5e7ee;

  --green-ink: #294b40;
  --green-mid: #487c67;
  --green-body: #6b7c73;
  --green-line: #d6e5dc;
  --green-line-soft: #e4ece6;
  --green-tint: #dcece3;
  --green-soft: #f4faf7;

  --amber-ink: #9c8c73;
  --amber-tint: #fff9ee;
  --amber-line: #f1e7d6;

  --level-ink: #559780;
  --level-bg: #e8f2ed;

  --rg-node-bg: #ffffff;
  --rg-pending-line: #d5d8e3;
  --rg-done-bg: var(--accent-soft);
  --rg-done-line: var(--accent);
  --rg-learning-bg: #fdf0d8;
  --rg-learning-line: #b07510;
  --rg-skip-bg: #fbeef1;
  --rg-skip-line: #a9647c;
  --rg-skip-ink: #8d4b60;
  --rg-edge-ink: #c9cbd8;
  --rg-edge-done: #a892f0;
  --rg-group-bg: #fbfbfd;
  --rg-group-line: #e5e7ee;

  --radius-card: 14px;
  --radius-panel: 12px;
  --radius-control: 7px;

  /* 268px rather than 244: the Materi tree now indents two tiers, and the
     longest topik title ("Bangun ruang: volume & permukaan") needs the room.
     The sub-topik rail is fixed-width, so this is the only lever. */
  --sidebar-w: 268px;
  --topbar-h: 66px;
  --pad-x: 30px;

  --font-body: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-brand: "Manrope", "DM Sans", -apple-system, BlinkMacSystemFont, sans-serif;

  color-scheme: light;
}

:root[data-theme="dark"] {
  --accent: #c2a7ff;
  --accent-strong: #b394f7;
  --accent-soft: #463b5e;
  --accent-tint: #332d47;
  --accent-tint-line: #53445f;

  --ink: #e8e5ef;
  --ink-soft: #e2dfec;
  --ink-mid: #c3bfd2;
  --muted: #b1aec1;
  --muted-soft: #9d99ad;
  --muted-strong: #b9b5c8;

  --bg: #22232d;
  --surface: #2b2c38;
  --card: #2b2c38;
  --card-soft: #303040;
  --line: #42404f;
  --line-soft: #3a3947;
  --line-card: #45434f;

  --green-ink: #d4e9df;
  --green-mid: #9fc9b6;
  --green-body: #b6cbbc;
  --green-line: #4b6257;
  --green-line-soft: #455a50;
  --green-tint: #35473f;
  --green-soft: #2f3b36;

  --amber-ink: #d8c39c;
  --amber-tint: #3a3428;
  --amber-line: #564c38;

  --level-ink: #8fd0b4;
  --level-bg: #2f443a;

  --rg-node-bg: var(--card);
  --rg-pending-line: #4a4859;
  --rg-done-bg: #3a3352;
  --rg-done-line: #c2a7ff;
  --rg-learning-bg: #3a3428;
  --rg-learning-line: #d8b06a;
  --rg-skip-bg: #3a2e35;
  --rg-skip-line: #c08a9c;
  --rg-skip-ink: #d9a8b7;
  --rg-edge-ink: #4a4859;
  --rg-edge-done: #7a6ba8;
  /* Darker than the card, not lighter: a node has to stand out from the group
     it sits in, and in this theme the cards are already the light surface. */
  --rg-group-bg: #1f2029;
  --rg-group-line: #3a3947;
  color-scheme: dark;
}

/* --- 2. Base ------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  /* The sidebar's sub-topik links are the site's first in-page anchors, and a
     jump that teleports loses the connection between the link and the block it
     points at. Turned back off under `prefers-reduced-motion` below. */
  scroll-behavior: smooth;
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink);
  background: var(--bg);
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.4px;
  line-height: 1.3;
}

p {
  margin: 0;
}

ul,
ol {
  margin: 0;
  padding: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

img,
svg {
  display: block;
  max-width: 100%;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--accent);
  color: #fff;
  padding: 10px 16px;
  border-radius: 0 0 var(--radius-control) 0;
  font-size: 12px;
}

.skip-link:focus {
  left: 0;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* --- 3. Shell ------------------------------------------------------------ */

.app-shell {
  display: flex;
  min-height: 100vh;
}

.workspace {
  width: calc(100% - var(--sidebar-w));
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.page {
  padding: 0 var(--pad-x) 8px;
  max-width: 1180px;
  width: 100%;
}

/* --- 4. Sidebar ---------------------------------------------------------- */

.sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  background: var(--surface);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  height: 100vh;
  position: sticky;
  top: 0;
  padding: 29px 17px 0;
  z-index: 30;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-brand);
  font-weight: 800;
  font-size: 21px;
  letter-spacing: -0.9px;
  padding-left: 7px;
}

.brand-name {
  white-space: nowrap;
}

.brand-mark {
  background: var(--accent);
  color: #fff;
  width: 33px;
  height: 34px;
  border-radius: 10px;
  display: grid;
  place-items: center;
  flex-shrink: 0;
}

.brand-mark svg {
  width: 19px;
  height: 19px;
}

.brand-dot {
  color: #8660ed;
}

.sidebar-intro {
  font-size: 10px;
  color: var(--muted-soft);
  padding: 12px 7px 27px;
  line-height: 1.7;
}

.sidebar-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  padding-bottom: 16px;
}

.main-nav {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding-bottom: 25px;
}

.main-nav a {
  display: flex;
  gap: 12px;
  align-items: center;
  text-align: left;
  padding: 12px 13px;
  border-radius: var(--radius-control);
  color: var(--muted-strong);
  font-size: 12px;
  font-weight: 500;
}

.main-nav a svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.main-nav a:hover {
  background: #f1eff9;
}

.main-nav a.active {
  background: var(--accent-soft);
  color: #7956de;
}

:root[data-theme="dark"] .main-nav a:hover {
  background: #3d364e;
  color: #e0cdff;
}

:root[data-theme="dark"] .main-nav a.active {
  background: var(--accent-soft);
  color: #e0cdff;
  border: 1px solid #75608e;
}

.library-heading {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 9px;
  letter-spacing: 1px;
  font-weight: 650;
  color: var(--muted);
  padding: 0 10px 14px;
}

.library-heading > span:last-child {
  background: var(--line-soft);
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 9px;
  letter-spacing: 0;
}

/* --- 4b. Materi tree: tingkatan > topik > sub-topik ---------------------- */

/* The Materi block is three tiers deep, so the styling has to make the tiers
   legible without a legend. The hierarchy is carried by three different
   devices, deliberately, because any one of them alone is easy to miss:
   a card per tingkatan, a badge per card, and a rail per sub-topik list.

   Colour choice notes, all measured rather than eyeballed:
   `--muted` (#9295a4) is only about 2.6:1 on the tinted card and 3.0:1 on
   white, so it is fine for a decorative ring but not for text. Every label in
   this tree therefore uses `--ink-mid` (4.9:1 on the tint, 5.5:1 on the
   surface) or darker. The active topik uses `--accent-strong` rather than the
   `--accent` used elsewhere in the nav, because `--accent` on `--accent-soft`
   measures 4.27:1 and `--accent-strong` measures 4.98:1. */

.side-library {
  display: block;
}

.side-level {
  /* Every tingkatan gets a panel, not only the active one. With no panel the
     five levels read as one flat list on any page that is not a lesson — the
     home page, Rumus, Latihan, Progres — because the badge alone is too quiet a
     divider. The active level then sits *on top* of this as a tinted card. */
  background: #f7f6fb;
  border: 1px solid #eeecf5;
  border-radius: var(--radius-panel);
  padding: 4px;
  margin-bottom: 9px;
  transition: background 160ms ease, border-color 160ms ease;
}

:root[data-theme="dark"] .side-level {
  background: var(--card-soft);
  border-color: var(--line-soft);
}

/* The card behind the tingkatan you are currently reading. Without it the
   tree reads as one flat list of 20 links and the tiers disappear. */
.side-level[data-active-level="true"] {
  background: var(--accent-tint);
  border-color: var(--accent-tint-line);
}

.side-level-toggle {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 7px 6px 5px;
  border-radius: 9px;
  text-align: left;
  transition: background 140ms ease;
}

.side-level-toggle:hover {
  background: rgba(121, 86, 233, 0.08);
}

:root[data-theme="dark"] .side-level-toggle:hover {
  background: rgba(194, 167, 255, 0.1);
}

.side-level-num {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border-radius: 7px;
  font-size: 9.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.2px;
  background: var(--line-soft);
  color: var(--muted-strong);
  transition: background 160ms ease, color 160ms ease;
}

.side-level[data-active-level="true"] .side-level-num {
  background: var(--accent);
  /* White clears 4.9:1 on the light accent. In dark the accent is a pale
     lilac, where white drops to 1.5:1, so the badge flips to a dark ink. */
  color: #fff;
}

:root[data-theme="dark"] .side-level[data-active-level="true"] .side-level-num {
  color: #241d38;
}

.side-level-title {
  flex: 1;
  min-width: 0;
  font-size: 11.5px;
  font-weight: 650;
  line-height: 1.35;
  letter-spacing: -0.1px;
  color: var(--ink-soft);
}

.side-level[data-active-level="true"] .side-level-title {
  color: var(--ink);
}

.side-level-chevron {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  color: var(--muted-strong);
  transition: transform 180ms ease;
}

.side-level-chevron-icon {
  width: 14px;
  height: 14px;
}

.side-level[data-collapsed="true"] .side-level-chevron {
  transform: rotate(-90deg);
}

.side-level-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  /* 4px card padding + 6px button padding + the 22px badge + the 9px gap. */
  padding: 0 6px 2px 37px;
}

.side-level-count {
  flex-shrink: 0;
  font-size: 8.5px;
  font-weight: 600;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--ink-mid);
}

.side-level-progress {
  flex: 1;
  min-width: 0;
  height: 3px;
  border: 0;
  border-radius: 999px;
  background: rgba(121, 86, 233, 0.18);
  overflow: hidden;
  appearance: none;
  -webkit-appearance: none;
}

:root[data-theme="dark"] .side-level-progress {
  background: rgba(194, 167, 255, 0.18);
}

.side-level-progress::-webkit-progress-bar {
  background: transparent;
  border-radius: 999px;
}

.side-level-progress::-webkit-progress-value {
  background: var(--accent);
  border-radius: 999px;
  transition: width 200ms ease;
}

.side-level-progress::-moz-progress-bar {
  background: var(--accent);
  border-radius: 999px;
}

.side-topics {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 1px 0 2px;
}

.side-level[data-collapsed="true"] .side-topics {
  display: none;
}

.side-topic-item {
  list-style: none;
}

.side-topic {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 8px;
  border-radius: 8px;
  font-size: 11px;
  line-height: 1.45;
  color: var(--ink-mid);
  transition: background 140ms ease, color 140ms ease;
}

.side-topic:hover {
  /* Not `#f1eff9` like the rest of the sidebar: the hover state also has to be
     visible on the active tingkatan's tinted card, and against #f2ecfc that
     value is indistinguishable. This one reads on both surfaces. */
  background: #ece7f9;
  color: var(--ink-soft);
}

.side-topic.is-active {
  /* `--accent-soft` is only a hair off `--accent-tint`, the card behind it, so
     on the light theme the active row looked like every other row. This is a
     measured step darker: `--accent-strong` on it is 4.58:1, where `--accent`
     on `--accent-soft` was 4.27:1. The dark theme has no such problem, because
     there `--accent-soft` is well clear of `--accent-tint`. */
  background: #e6e1f7;
  color: var(--accent-strong);
  font-weight: 600;
}

:root[data-theme="dark"] .side-topic:hover {
  background: #3d364e;
  color: #e0cdff;
}

:root[data-theme="dark"] .side-topic.is-active {
  background: var(--accent-soft);
  color: #e0cdff;
}

.side-topic-marker {
  flex-shrink: 0;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  border: 1.5px solid var(--muted-strong);
  background: transparent;
  transition: background 140ms ease, border-color 140ms ease, box-shadow 140ms ease;
}

.side-topic.is-active .side-topic-marker {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(121, 86, 233, 0.18);
}

.side-topic.is-done .side-topic-marker {
  background: var(--level-ink);
  border-color: var(--level-ink);
}

:root[data-theme="dark"] .side-topic.is-active .side-topic-marker {
  box-shadow: 0 0 0 3px rgba(194, 167, 255, 0.2);
}

.side-topic-label {
  flex: 1;
  min-width: 0;
}

.side-topic-done {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 13px;
  height: 13px;
  color: var(--level-ink);
  opacity: 0;
  transition: opacity 160ms ease;
}

.side-topic-done svg {
  width: 13px;
  height: 13px;
}

.side-topic.is-done .side-topic-done {
  opacity: 1;
}

/* Tier three. The rail is hung off the list's left border and each link grows
   a short tick back to it, which is what makes the sub-topik read as
   belonging to the topik above rather than to the tingkatan as a whole. The
   12px inset lines the rail up under the centre of the marker dot. */
.side-subtopics {
  list-style: none;
  display: flex;
  flex-direction: column;
  margin: 1px 0 4px 12px;
  padding: 0 0 0 12px;
  border-left: 1px solid var(--accent-tint-line);
}

.side-subtopic {
  position: relative;
  display: block;
  padding: 5px 8px;
  border-radius: 6px;
  font-size: 10px;
  line-height: 1.45;
  color: var(--ink-mid);
  transition: color 140ms ease, background 140ms ease;
}

.side-subtopic::before {
  content: "";
  position: absolute;
  left: -12px;
  top: 50%;
  width: 9px;
  height: 1px;
  background: var(--accent-tint-line);
}

.side-subtopic:hover {
  /* Same reasoning as `.side-topic:hover`: this list only ever appears inside the
     tinted active card, so the site-wide #f1eff9 would be a no-op here. */
  background: #ece7f9;
  color: var(--ink-soft);
}

:root[data-theme="dark"] .side-subtopic:hover {
  background: #3d364e;
  color: #e0cdff;
}

.app-theme-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
  width: 100%;
  padding: 12px 10px;
  margin: 0 0 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  text-align: left;
  background: #f5f2fb;
  color: #735990;
  min-height: 60px;
}

:root[data-theme="dark"] .app-theme-toggle {
  background: #363044;
  border-color: #53445f;
  color: #dcc9f3;
}

.app-theme-toggle > span:nth-child(2) {
  flex: 1;
  min-width: 0;
}

.app-theme-toggle strong {
  display: block;
  font-size: 12px;
  font-weight: 600;
}

.app-theme-toggle small {
  display: block;
  font-size: 9px;
  margin-top: 4px;
  color: #777184;
}

:root[data-theme="dark"] .app-theme-toggle small {
  color: #bfb2cf;
}

.app-theme-toggle .theme-icon {
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  flex-shrink: 0;
}

.app-theme-toggle .theme-icon svg {
  width: 17px;
  height: 17px;
}

.theme-switch-track {
  width: 28px;
  height: 15px;
  border-radius: 20px;
  background: #d6d2e4;
  flex-shrink: 0;
  position: relative;
  transition: background 0.18s ease;
}

.theme-switch-track > span {
  position: absolute;
  left: 2px;
  top: 2px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: #fff;
  transition: transform 0.18s ease;
}

.app-theme-toggle[aria-pressed="true"] .theme-switch-track {
  background: #a18ad9;
}

.app-theme-toggle[aria-pressed="true"] .theme-switch-track > span {
  transform: translateX(13px);
}

.icon-toggle {
  width: 34px;
  height: 34px;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-control);
  color: var(--ink-mid);
}

.icon-toggle svg {
  width: 16px;
  height: 16px;
}

.icon-toggle .icon-moon,
.icon-toggle .icon-sun {
  display: none;
}

:root[data-theme="dark"] .icon-toggle .icon-moon {
  display: block;
}

:root:not([data-theme="dark"]) .icon-toggle .icon-sun {
  display: block;
}

.sidebar-foot {
  margin: 0 -17px;
  padding: 18px 19px;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 10px;
  flex-shrink: 0;
}

.sidebar-foot strong {
  font-size: 12px;
  font-weight: 600;
  display: block;
}

.sidebar-foot small {
  font-size: 8px;
  display: block;
  margin-top: 4px;
  color: var(--muted-soft);
}

.sidebar-foot svg {
  margin-left: auto;
  color: var(--muted-soft);
  width: 16px;
  height: 16px;
}

/* --- 5. Topbar ----------------------------------------------------------- */

.topbar {
  height: var(--topbar-h);
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 0 var(--pad-x);
  background: var(--card);
  position: sticky;
  top: 0;
  z-index: 20;
}

.breadcrumb {
  display: flex;
  align-items: center;
  gap: 11px;
  color: var(--muted);
  font-size: 11px;
  min-width: 0;
}

.breadcrumb a:hover {
  color: var(--accent);
}

.breadcrumb strong {
  font-weight: 500;
  color: var(--ink-mid);
}

.breadcrumb svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  color: var(--muted-soft);
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: 20px;
  font-size: 10px;
  color: var(--muted);
  flex-shrink: 0;
}

.topbar-actions a,
.topbar-actions button {
  display: flex;
  gap: 5px;
  align-items: center;
}

.topbar-actions a:hover,
.topbar-actions button:hover {
  color: var(--accent);
}

.topbar-actions svg {
  width: 16px;
  height: 16px;
}

.menu-toggle {
  display: none;
  width: 34px;
  height: 34px;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-control);
  color: var(--ink-mid);
}

.menu-toggle svg {
  width: 17px;
  height: 17px;
}

.nav-scrim {
  display: none;
}

/* --- 6. Page heading / hero --------------------------------------------- */

.page-heading {
  padding: 34px 0 27px;
}

.page-heading h1 {
  font-size: 35px;
  line-height: 1.17;
  letter-spacing: -1.2px;
  font-weight: 800;
}

.page-heading p {
  margin-top: 13px;
  font-size: 13px;
  line-height: 1.85;
  color: var(--muted-strong);
  max-width: 720px;
}

.eyebrow {
  font-size: 8px;
  font-weight: 650;
  letter-spacing: 1.7px;
  color: var(--muted-soft);
  margin-bottom: 11px;
  display: block;
}

.eyebrow-tags {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.eyebrow-tags > span {
  font-size: 9px;
  letter-spacing: 0;
  font-weight: 500;
  background: var(--level-bg);
  color: var(--green-mid);
  padding: 4px 8px;
  border-radius: 20px;
}

.section-kicker {
  display: block;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.5px;
  color: #786791;
  margin-bottom: 6px;
}

:root[data-theme="dark"] .section-kicker {
  color: #b9a6d8;
}

/* --- 7. Panels ---------------------------------------------------------- */

.learning-intro {
  display: flex;
  align-items: center;
  gap: 20px;
  margin: 0 0 36px;
  padding: 25px;
  background: var(--accent-tint);
  border: 1px solid var(--accent-tint-line);
  border-radius: var(--radius-panel);
}

.learning-intro > div {
  flex: 1;
  min-width: 190px;
}

.learning-intro h2 {
  font-size: 17px;
  color: var(--ink-soft);
  margin-bottom: 8px;
}

:root[data-theme="dark"] .learning-intro h2 {
  color: var(--ink);
}

.learning-intro p {
  font-size: 13px;
  line-height: 1.8;
  color: var(--muted-strong);
  max-width: 720px;
}

:root[data-theme="dark"] .learning-intro p {
  color: var(--muted);
}

.learning-intro .primary-button {
  margin-left: auto;
  flex-shrink: 0;
}

.learning-intro .intro-icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--card);
  display: grid;
  place-items: center;
  color: var(--accent);
  flex-shrink: 0;
}

.learning-intro .intro-icon svg {
  width: 21px;
  height: 21px;
}

.progress-summary {
  display: flex;
  gap: 20px;
  align-items: center;
  border: 1px solid var(--accent-tint-line);
  border-radius: var(--radius-panel);
  background: var(--accent-tint);
  padding: 25px;
  margin: 28px 0;
  color: #8d6cd4;
}

:root[data-theme="dark"] .progress-summary {
  color: var(--accent);
}

.progress-summary > div {
  flex: 1;
  min-width: 0;
}

.progress-summary strong {
  color: #635079;
  font-size: 13px;
  display: block;
}

:root[data-theme="dark"] .progress-summary strong {
  color: var(--ink);
}

.progress-summary p {
  font-size: 10px;
  color: #9d8aac;
  margin-top: 5px;
}

:root[data-theme="dark"] .progress-summary p {
  color: var(--muted);
}

.progress-summary b {
  font-size: 16px;
  display: block;
  margin-bottom: 2px;
}

.progress-bar {
  appearance: none;
  border: 0;
  width: 180px;
  height: 7px;
  border-radius: 10px;
  overflow: hidden;
  background: rgba(121, 86, 233, 0.18);
  flex-shrink: 0;
}

.progress-bar::-webkit-progress-bar {
  background: rgba(121, 86, 233, 0.18);
  border-radius: 10px;
}

.progress-bar::-webkit-progress-value {
  background: #9271df;
  border-radius: 10px;
}

.progress-bar::-moz-progress-bar {
  background: #9271df;
  border-radius: 10px;
}

/* --- 8. Path groups / phases -------------------------------------------- */

.path-group {
  margin: 30px 0;
  scroll-margin-top: 84px;
}

.path-group h2 {
  font-size: 21px;
  margin-top: 3px;
  color: var(--ink-soft);
}

.stage-heading {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  margin-bottom: 17px;
}

.stage-heading > div {
  min-width: 0;
  flex: 1;
}

.stage-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 10px;
}

.stage-meta .count {
  font-size: 11px;
  color: var(--muted);
}

.concept-number {
  border-radius: 5px;
  background: #f3f0fb;
  color: #a591cb;
  width: 29px;
  height: 29px;
  min-width: 29px;
  display: grid;
  place-items: center;
  font-size: 10px;
  font-weight: 600;
  flex-shrink: 0;
}

:root[data-theme="dark"] .concept-number {
  background: var(--accent-soft);
  color: var(--accent);
}

.phase-pill {
  font-size: 8px;
  letter-spacing: 0.7px;
  color: #a092b7;
  background: #f1edf7;
  padding: 6px 8px;
  border-radius: 4px;
  white-space: nowrap;
}

:root[data-theme="dark"] .phase-pill {
  background: var(--accent-soft);
  color: var(--accent);
}

.phase-pill.live {
  color: #5b9c83;
  background: #e9f5ed;
}

:root[data-theme="dark"] .phase-pill.live {
  color: #8fd0b4;
  background: #2f443a;
}

.lead {
  font-size: 13px;
  line-height: 1.85;
  color: var(--muted-strong);
  max-width: 760px;
  margin-bottom: 22px;
}

/* --- 9. Lesson cards ---------------------------------------------------- */

.lesson-cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.lesson-card {
  border: 1px solid var(--line-card);
  border-radius: var(--radius-card);
  background: var(--card);
  text-align: left;
  padding: 23px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  color: var(--accent);
  transition: border-color 0.18s, box-shadow 0.18s, transform 0.18s;
}

.lesson-card:hover {
  border-color: #c6b2ef;
  box-shadow: 0 5px 15px #8064b808;
  transform: translateY(-1px);
}

.lesson-card .card-icon {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
}

.lesson-card .card-icon svg {
  width: 19px;
  height: 19px;
}

.lesson-card h3 {
  font-size: 15px;
  color: var(--ink-soft);
  margin-top: 20px;
  margin-bottom: 10px;
}

.lesson-card p {
  font-size: 11px;
  color: var(--muted);
  line-height: 1.8;
  flex: 1;
}

.card-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  width: 100%;
  font-size: 10px;
  border-top: 1px solid var(--line-soft);
  padding-top: 15px;
  margin-top: 20px;
  color: var(--muted);
}

.card-bottom .go {
  display: flex;
  align-items: center;
  gap: 5px;
  color: var(--accent);
  font-weight: 500;
}

.card-bottom .go svg {
  width: 13px;
  height: 13px;
}

.lesson-meta {
  font-size: 11px;
  color: var(--muted);
}

.level {
  font-size: 9px;
  font-weight: 500;
  color: var(--level-ink);
  background: var(--level-bg);
  padding: 5px 8px;
  border-radius: 5px;
  white-space: nowrap;
}

/* --- 10. Interstitial --------------------------------------------------- */

.path-pause {
  margin: 30px 0;
  padding: 25px;
  border-radius: var(--radius-panel);
  background: var(--amber-tint);
  border: 1px solid var(--amber-line);
}

.path-pause h3 {
  font-size: 17px;
  color: #514535;
  margin: 6px 0 10px;
}

:root[data-theme="dark"] .path-pause h3 {
  color: #deceb5;
}

.path-pause > p {
  font-size: 13px;
  line-height: 1.85;
  color: var(--amber-ink);
  max-width: 760px;
}

.path-pause .recall {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--amber-line);
  font-size: 12px;
  line-height: 1.75;
  color: var(--amber-ink);
}

.path-pause .recall svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin-top: 1px;
}

.path-pause .recall strong {
  display: block;
  font-size: 9px;
  letter-spacing: 1.2px;
  font-weight: 700;
  text-transform: uppercase;
  margin-bottom: 5px;
  opacity: 0.85;
}

.path-pause .back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 18px;
  font-size: 11px;
  font-weight: 500;
  color: #8a7355;
}

:root[data-theme="dark"] .path-pause .back-link {
  color: #d8c39c;
}

.path-pause .back-link:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.path-pause .back-link svg {
  width: 14px;
  height: 14px;
}

/* --- 11. Latihan (green section) ---------------------------------------- */

.recipe-section {
  margin: 44px 0 30px;
  padding-top: 34px;
  border-top: 1px solid var(--line);
}

.recipe-header {
  display: flex;
  gap: 18px;
  align-items: flex-start;
}

.recipe-header .path-kicker {
  color: var(--green-mid);
}

.recipe-header h2 {
  font-size: 27px;
  letter-spacing: -0.6px;
  color: var(--green-ink);
  margin: 8px 0 12px;
}

.recipe-header p {
  color: #5a766c;
  line-height: 1.9;
  max-width: 700px;
  font-size: 13px;
}

:root[data-theme="dark"] .recipe-header p {
  color: var(--green-body);
}

.recipe-invitation {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 24px 0;
  padding: 17px 0;
  border-top: 1px solid var(--green-line);
  border-bottom: 1px solid var(--green-line);
  color: #4b7564;
}

:root[data-theme="dark"] .recipe-invitation {
  color: var(--green-mid);
}

.recipe-invitation p {
  line-height: 1.8;
  font-size: 12px;
}

.recipe-invitation > svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
}

.recipe-invitation > span {
  margin-left: auto;
  flex-shrink: 0;
  font-size: 10px;
  background: var(--green-tint);
  border-radius: 20px;
  padding: 8px 11px;
  color: #4b7564;
}

:root[data-theme="dark"] .recipe-invitation > span {
  color: var(--green-ink);
}

.recipe-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.recipe-card {
  text-align: left;
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--green-line);
  border-radius: 16px;
  padding: 23px;
  transition: border-color 0.18s, box-shadow 0.18s, transform 0.18s;
}

.recipe-card:hover {
  border-color: #80ad99;
  box-shadow: 0 5px 18px #335b4710;
  transform: translateY(-1px);
}

.recipe-card-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
}

.recipe-card-top > span:last-child {
  display: flex;
  align-items: center;
  gap: 5px;
  color: var(--green-body);
  font-size: 10px;
}

.recipe-card-top svg {
  width: 14px;
  height: 14px;
}

.recipe-card h3 {
  font-size: 17px;
  color: #345547;
  margin: 19px 0 10px;
}

:root[data-theme="dark"] .recipe-card h3 {
  color: var(--green-ink);
}

.recipe-card p {
  font-size: 13px;
  line-height: 1.85;
  color: var(--green-body);
}

.recipe-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 16px;
}

.recipe-tags span {
  font-size: 9px;
  color: #5b7c6d;
  background: var(--green-soft);
  border: 1px solid var(--green-line-soft);
  padding: 4px 8px;
  border-radius: 20px;
}

:root[data-theme="dark"] .recipe-tags span {
  color: var(--green-mid);
}

.recipe-card-action {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-top: 1px solid var(--green-line-soft);
  padding-top: 16px;
  margin-top: auto;
  color: #40785f;
  font-size: 12px;
  font-weight: 600;
}

:root[data-theme="dark"] .recipe-card-action {
  color: #c0e1cf;
}

.recipe-card-action svg {
  width: 14px;
  height: 14px;
}

.recipe-footer-note {
  margin-top: 24px;
  font-size: 12px;
  line-height: 1.8;
  color: var(--green-body);
}

/* --- 12. Formula cards -------------------------------------------------- */

.handbook-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 28px 0 21px;
  gap: 15px;
  flex-wrap: wrap;
}

.handbook-notice {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 11px;
  line-height: 1.9;
  color: var(--amber-ink);
  background: var(--amber-tint);
  border: 1px solid var(--amber-line);
  padding: 14px 18px;
  border-radius: 8px;
  margin-bottom: 24px;
}

.handbook-notice svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  margin-top: 2px;
}

/* Multi-column rather than a grid: the formula groups differ a lot in length,
   and a two-column grid would stretch every short card to match the tallest in
   its row, leaving large empty gaps. */
.handbook-grid {
  display: block;
  columns: 2;
  column-gap: 20px;
}

.syntax-card {
  background: var(--card);
  border: 1px solid var(--line-card);
  border-radius: 11px;
  padding: 24px;
  min-width: 0;
  scroll-margin-top: 84px;
  break-inside: avoid;
  margin-bottom: 20px;
}

.syntax-card-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  font-size: 9px;
  margin-bottom: 18px;
}

.syntax-card-top > span {
  color: #b09ec9;
  font-size: 8px;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-weight: 650;
}

:root[data-theme="dark"] .syntax-card-top > span {
  color: var(--accent);
}

.syntax-card-top > small {
  font-size: 8px;
  padding: 4px 6px;
  border-radius: 4px;
  color: #9c9cac;
  background: #f4f4f8;
}

:root[data-theme="dark"] .syntax-card-top > small {
  background: var(--accent-soft);
  color: var(--accent);
}

.syntax-card h2 {
  font-size: 18px;
  margin-bottom: 8px;
  letter-spacing: -0.4px;
}

.syntax-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 16px;
}

.syntax-list li {
  padding: 14px 16px;
  border-radius: 8px;
  background: var(--card-soft);
  border: 1px solid var(--line-soft);
}

.syntax-list .syntax-label {
  font-size: 10px;
  color: var(--muted);
  display: block;
  margin-bottom: 7px;
}

.syntax-list .syntax-expr {
  font-size: 14px;
  color: #725989;
  line-height: 1.6;
  overflow-wrap: anywhere;
}

:root[data-theme="dark"] .syntax-list .syntax-expr {
  color: #d2bbec;
}

.syntax-list .syntax-note {
  font-size: 10px;
  color: var(--muted);
  margin-top: 7px;
  line-height: 1.7;
}

/* --- 13. Lesson page ---------------------------------------------------- */

.concept-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  padding-top: 30px;
}

.concept-heading {
  display: flex;
  align-items: center;
  gap: 13px;
  min-width: 0;
}

.concept-heading h1 {
  font-size: 26px;
  letter-spacing: -0.7px;
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.concept-header-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 9px;
  margin-left: auto;
  flex-shrink: 0;
}

.concept-intro {
  padding-top: 16px;
  color: var(--muted-strong);
  font-size: 14px;
  line-height: 1.85;
  max-width: 760px;
}

:root[data-theme="dark"] .concept-intro {
  color: var(--muted);
}

.lesson-section {
  margin-top: 34px;
}

.lesson-section > h2 {
  font-size: 17px;
  margin-bottom: 16px;
  display: flex;
  align-items: center;
  gap: 10px;
}

.lesson-section > h2 .section-icon {
  width: 24px;
  height: 24px;
  border-radius: 6px;
  background: var(--accent-soft);
  color: var(--accent);
  display: grid;
  place-items: center;
  flex-shrink: 0;
}

.lesson-section > h2 .section-icon svg {
  width: 14px;
  height: 14px;
}

.concept-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.concept-block {
  border: 1px solid var(--line-card);
  border-radius: var(--radius-panel);
  background: var(--card);
  padding: 22px;
  /* The sidebar's sub-topik links point at these blocks, so a jump has to
     clear the sticky topbar instead of burying the heading under it. */
  scroll-margin-top: 84px;
}

.concept-block h3 {
  font-size: 14px;
  margin-bottom: 9px;
  color: var(--ink-soft);
}

.concept-block p {
  font-size: 13px;
  line-height: 1.9;
  color: var(--muted-strong);
}

:root[data-theme="dark"] .concept-block p {
  color: var(--muted);
}

.formula-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.formula-card {
  border: 1px solid var(--line-card);
  border-radius: var(--radius-panel);
  background: var(--card);
  padding: 20px;
}

.formula-card .formula-label {
  font-size: 10px;
  color: var(--muted);
  display: block;
  margin-bottom: 10px;
}

.formula-card .formula-expr {
  font-size: 16px;
  line-height: 1.6;
  color: #725989;
  overflow-wrap: anywhere;
}

:root[data-theme="dark"] .formula-card .formula-expr {
  color: #d2bbec;
}

.formula-card .formula-note {
  font-size: 10px;
  color: var(--muted);
  margin-top: 10px;
  line-height: 1.7;
}

.example-card {
  border: 1px solid var(--accent-tint-line);
  border-radius: var(--radius-panel);
  background: var(--accent-tint);
  padding: 24px;
}

:root[data-theme="dark"] .example-card {
  background: var(--accent-tint);
}

.example-card h3 {
  font-size: 15px;
  color: var(--ink-soft);
  margin-bottom: 12px;
}

:root[data-theme="dark"] .example-card h3 {
  color: var(--ink);
}

.example-problem {
  font-size: 13px;
  line-height: 1.9;
  color: var(--muted-strong);
  padding-bottom: 16px;
  border-bottom: 1px solid var(--accent-tint-line);
}

:root[data-theme="dark"] .example-problem {
  color: var(--muted);
}

.example-steps {
  list-style: none;
  counter-reset: step;
  margin-top: 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.example-steps li {
  counter-increment: step;
  display: flex;
  gap: 12px;
  font-size: 13px;
  line-height: 1.85;
  color: var(--muted-strong);
}

:root[data-theme="dark"] .example-steps li {
  color: var(--muted);
}

.example-steps li::before {
  content: counter(step);
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--card);
  color: var(--accent);
  font-size: 10px;
  font-weight: 600;
  display: grid;
  place-items: center;
  margin-top: 3px;
}

.example-answer {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--accent-tint-line);
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}

.example-answer span {
  font-size: 9px;
  letter-spacing: 1.2px;
  font-weight: 700;
  color: #9d8aac;
  text-transform: uppercase;
}

.example-answer strong {
  font-size: 17px;
  color: #635079;
  font-weight: 700;
}

:root[data-theme="dark"] .example-answer strong {
  color: var(--accent);
}

.points-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 11px;
}

.points-list li {
  display: flex;
  gap: 11px;
  font-size: 13px;
  line-height: 1.85;
  color: var(--muted-strong);
}

:root[data-theme="dark"] .points-list li {
  color: var(--muted);
}

.points-list svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  margin-top: 4px;
  color: var(--level-ink);
}

/* Practice ---------------------------------------------------------------- */

.practice {
  border: 1px solid var(--line-card);
  border-radius: var(--radius-panel);
  background: var(--card);
  padding: 24px;
}

.practice-q {
  font-size: 14px;
  line-height: 1.8;
  color: var(--ink-soft);
  margin-bottom: 18px;
}

.practice-options {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.option {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 11px;
  text-align: left;
  border: 1px solid var(--line-card);
  border-radius: 8px;
  background: var(--card-soft);
  padding: 13px 15px;
  font-size: 13px;
  color: var(--muted-strong);
  transition: border-color 0.15s, background 0.15s;
}

.option:hover:not(:disabled) {
  border-color: #c6b2ef;
  background: var(--accent-soft);
}

.option:disabled {
  cursor: default;
}

.option-key {
  width: 22px;
  height: 22px;
  border-radius: 5px;
  background: var(--line-soft);
  color: var(--muted);
  font-size: 10px;
  font-weight: 600;
  display: grid;
  place-items: center;
  flex-shrink: 0;
}

.option.correct {
  border-color: #80ad99;
  background: var(--green-soft);
  color: var(--green-ink);
}

.option.correct .option-key {
  background: var(--green-tint);
  color: var(--green-ink);
}

.option.wrong {
  border-color: #d9a3a3;
  background: #fdf3f3;
  color: #8a4b4b;
}

.option.wrong .option-key {
  background: #f7dede;
  color: #8a4b4b;
}

:root[data-theme="dark"] .option.correct {
  color: var(--green-ink);
}

:root[data-theme="dark"] .option.wrong {
  border-color: #6d4a4a;
  background: #3b2f2f;
  color: #e3b6b6;
}

:root[data-theme="dark"] .option.wrong .option-key {
  background: #4d3838;
  color: #e3b6b6;
}

.practice-feedback {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--line-soft);
  font-size: 13px;
  line-height: 1.85;
  color: var(--muted-strong);
}

:root[data-theme="dark"] .practice-feedback {
  color: var(--muted);
}

.practice-feedback strong {
  color: var(--level-ink);
  display: block;
  margin-bottom: 6px;
  font-size: 11px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
}

.practice-feedback[hidden] {
  display: none;
}

/* Pagination ------------------------------------------------------------- */

.lesson-pagination {
  display: flex;
  gap: 14px;
  margin-top: 34px;
  padding-top: 26px;
  border-top: 1px solid var(--line);
}

.lesson-pagination a {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-panel);
  background: var(--card);
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 7px;
  transition: border-color 0.18s, box-shadow 0.18s;
}

.lesson-pagination a:hover {
  border-color: #c6b2ef;
  box-shadow: 0 5px 15px #8064b808;
}

.lesson-pagination a.next {
  text-align: right;
  align-items: flex-end;
}

.lesson-pagination .dir {
  font-size: 9px;
  letter-spacing: 1.2px;
  font-weight: 700;
  color: var(--muted-soft);
  text-transform: uppercase;
  display: flex;
  align-items: center;
  gap: 6px;
}

.lesson-pagination .dir svg {
  width: 13px;
  height: 13px;
}

.lesson-pagination strong {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}

.lesson-pagination .spacer {
  flex: 1;
}

/* --- 14. Progress page -------------------------------------------------- */

.progress-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 30px;
}

.stat-card {
  border: 1px solid var(--line-card);
  border-radius: var(--radius-panel);
  background: var(--card);
  padding: 22px;
}

.stat-card b {
  font-size: 27px;
  letter-spacing: -1px;
  display: block;
  color: var(--accent);
}

.stat-card span {
  font-size: 11px;
  color: var(--muted);
  margin-top: 7px;
  display: block;
}

.progress-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.progress-table th,
.progress-table td {
  text-align: left;
  padding: 13px 14px;
  border-bottom: 1px solid var(--line-soft);
}

.progress-table th {
  font-size: 9px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--muted-soft);
  font-weight: 700;
}

.progress-table td {
  color: var(--muted-strong);
}

.progress-table tr:last-child td {
  border-bottom: 0;
}

.progress-table a:hover {
  color: var(--accent);
}

.status {
  font-size: 9px;
  padding: 5px 8px;
  border-radius: 5px;
  white-space: nowrap;
  color: var(--muted);
  background: var(--line-soft);
}

.status.done {
  color: var(--level-ink);
  background: var(--level-bg);
}

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-panel);
  background: var(--card);
}

.table-wrap .progress-table {
  min-width: 560px;
}

.progress-table .group-row {
  background: var(--card-soft);
}

.progress-table .group-row td {
  padding: 14px 16px 11px;
}

.progress-table .group-row .section-kicker {
  margin-bottom: 0;
}

.progress-table td:first-child {
  width: 46px;
}

.row-summary {
  font-size: 11px;
  color: var(--muted);
  line-height: 1.7;
  margin-top: 5px;
  max-width: 520px;
}

.count {
  font-size: 11px;
  color: var(--muted);
}

.syntax-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--accent);
}

.syntax-link:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.syntax-link svg {
  width: 13px;
  height: 13px;
}

.related-list {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.related-link {
  display: flex;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--line-card);
  border-radius: 10px;
  background: var(--card);
  padding: 15px 17px;
  font-size: 12px;
  color: var(--muted-strong);
  transition: border-color 0.18s;
}

.related-link:hover {
  border-color: #c6b2ef;
  color: var(--accent);
}

.related-link svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  color: var(--accent);
}

.insight-card {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  border: 1px solid var(--accent-tint-line);
  border-radius: var(--radius-panel);
  background: var(--accent-tint);
  padding: 22px;
  margin-bottom: 16px;
}

.insight-card > svg {
  width: 19px;
  height: 19px;
  flex-shrink: 0;
  color: var(--accent);
  margin-top: 2px;
}

.insight-card strong {
  display: block;
  font-size: 9px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: #9d8aac;
  margin-bottom: 8px;
}

:root[data-theme="dark"] .insight-card strong {
  color: var(--muted);
}

.insight-card p {
  font-size: 13px;
  line-height: 1.9;
  color: var(--muted-strong);
}

:root[data-theme="dark"] .insight-card p {
  color: var(--muted);
}

/* --- 15. Buttons -------------------------------------------------------- */

.primary-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-control);
  padding: 10px 14px;
  background: var(--card);
  font-size: 11px;
  font-weight: 500;
  white-space: nowrap;
  color: var(--ink-soft);
}

.primary-button.accent {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}

.primary-button.accent:hover {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
}

/* White on the dark theme's accent is 1.5:1 — the accent there is a pale lilac,
   not a saturated violet. The same fix the sidebar's level badge uses: flip the
   text to near-black, which clears 7:1 on the same fill. This is the button on
   the roadmap capstone and in the map's detail panel, both of which shipped
   white-on-lilac until now. */
:root[data-theme="dark"] .primary-button.accent {
  color: #241d38;
}

:root[data-theme="dark"] .primary-button.accent:hover {
  background: #d3bcff;
  border-color: #d3bcff;
}

.primary-button svg {
  width: 14px;
  height: 14px;
}

.done-toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-control);
  background: var(--card);
  padding: 8px 11px;
  font-size: 11px;
  color: var(--muted-strong);
  transition: border-color 0.15s, color 0.15s;
}

.done-toggle:hover {
  border-color: #c6b2ef;
  color: var(--accent);
}

.done-toggle svg {
  width: 14px;
  height: 14px;
}

.done-toggle[aria-pressed="true"] {
  background: var(--level-bg);
  border-color: var(--level-bg);
  color: var(--level-ink);
}

/* --- 16. Footer --------------------------------------------------------- */

.workspace-footer {
  margin: 22px var(--pad-x) 26px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  font-size: 9px;
  color: var(--muted-soft);
}

.workspace-footer > span:first-child {
  display: flex;
  gap: 6px;
  align-items: center;
}

.workspace-footer svg {
  width: 13px;
  height: 13px;
}

/* --- 17. Maths typography ----------------------------------------------- */

.frac {
  display: inline-flex;
  flex-direction: column;
  vertical-align: middle;
  text-align: center;
  line-height: 1.1;
  font-size: 0.86em;
  margin: 0 0.18em;
  position: relative;
  top: -0.08em;
}

.frac-n {
  padding: 0 0.3em 0.09em;
  border-bottom: 1px solid currentColor;
}

.frac-d {
  padding: 0.09em 0.3em 0;
}

.rad {
  white-space: nowrap;
}

.rad-body {
  border-top: 1px solid currentColor;
  padding: 0 0.12em;
  margin-left: -0.05em;
}

.var,
.lesson-body i,
.formula-expr i,
.syntax-expr i,
.example-card i {
  font-style: italic;
}

.xbar {
  position: relative;
}

.xbar::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -0.36em;
  height: 1px;
  background: currentColor;
}

sub,
sup {
  font-size: 0.68em;
  line-height: 0;
}

/* --- 17a. Peta jalur belajar: the graph -------------------------------- */

/* The other reading of the same curriculum, drawn as a graph above the rail
   in 17b. Everything here is layout for nodes whose coordinates arrive from
   public/assets/roadmap.css, which tools/build.py generates out of
   source/roadmap.py — so a node's position is never written in two places.
   The rail below keeps the sub-topik links; this keeps the prerequisites. */

/* The map is a graph, not a list: five cluster boxes, twenty lesson nodes and
   the prerequisite edges between them, laid out the way roadmap.sh draws a
   roadmap. Node and group positions are not here — they come from
   `public/assets/roadmap.css`, which the build generates from source/roadmap.py.
   Nothing in this block positions anything.

   The canvas is scaled by the reader, so every length inside it is in canvas
   units: text does not reflow when the map is zoomed, it only gets bigger. */

.rg-section {
  margin: 28px 0 8px;
}

.rg-head {
  max-width: 660px;
}

.rg-head h2 {
  font-size: 21px;
  color: var(--ink-soft);
  margin: 4px 0 9px;
}

.rg-lead {
  font-size: 13px;
  line-height: 1.85;
  color: var(--muted-strong);
  margin: 0 0 8px;
}

.rg-hint {
  font-size: 12px;
  line-height: 1.8;
  color: var(--ink-mid);
  margin: 0;
}

/* --- toolbar --- */

.rg-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 20px;
  margin: 18px 0 0;
  padding: 12px 14px;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-panel);
  background: var(--surface);
}

.rg-progress {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* A ring rather than the site's bar: it has to sit inside a toolbar row, and a
   bar there would either be too short to read or too wide to fit. The fill is
   a conic gradient driven by `--rg-progress`, which app.js sets. */
.rg-ring {
  position: relative;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  background: conic-gradient(
    var(--accent) calc(var(--rg-progress, 0) * 1%),
    var(--line) 0
  );
}

.rg-ring::after {
  content: "";
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  background: var(--surface);
}

.rg-ring-value {
  position: relative;
  font-size: 9px;
  font-weight: 600;
  color: var(--ink-mid);
  letter-spacing: -0.2px;
}

.rg-progress-text {
  font-size: 11px;
  color: var(--muted-strong);
}

.rg-progress-text strong {
  color: var(--ink);
  font-weight: 600;
}

.rg-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 11px;
  color: var(--muted-strong);
}

.rg-legend li {
  display: flex;
  align-items: center;
  gap: 6px;
}

.rg-dot {
  width: 9px;
  height: 9px;
  border-radius: 3px;
  border: 1.5px solid var(--rg-pending-line);
  background: var(--rg-node-bg);
  flex-shrink: 0;
}

.rg-dot--done {
  background: var(--rg-done-bg);
  border-color: var(--rg-done-line);
}

.rg-dot--learning {
  background: var(--rg-learning-bg);
  border-color: var(--rg-learning-line);
}

.rg-dot--skip {
  background: var(--rg-skip-bg);
  border-color: var(--rg-skip-line);
}

.rg-tools {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-left: auto;
}

.rg-search {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 6px 10px;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-control);
  background: var(--card);
  color: var(--muted);
}

.rg-search:focus-within {
  border-color: var(--accent);
  color: var(--accent);
}

.rg-search input {
  border: 0;
  background: none;
  font: inherit;
  font-size: 12px;
  color: var(--ink);
  width: 150px;
  min-width: 0;
  padding: 0;
}

.rg-search input:focus {
  outline: none;
}

.rg-zoom {
  display: flex;
  align-items: center;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-control);
  background: var(--card);
  overflow: hidden;
}

.rg-zoom button {
  display: grid;
  place-items: center;
  width: 32px;
  height: 30px;
  border: 0;
  border-left: 1px solid var(--line-soft);
  background: none;
  color: var(--muted-strong);
  cursor: pointer;
  font: inherit;
  font-size: 10px;
  font-weight: 600;
}

.rg-zoom button:first-child {
  border-left: 0;
}

.rg-zoom button:hover {
  background: var(--accent-tint);
  color: var(--accent-strong);
}

.rg-zoom button[data-rg-zoom="reset"] {
  width: 46px;
}

.rg-status {
  margin: 8px 0 0;
  min-height: 15px;
  font-size: 11px;
  color: var(--muted-strong);
}

/* --- the map --- */

.rg-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 312px;
  gap: 16px;
  margin-top: 10px;
  align-items: start;
}

/* The panel is a grid column, so it would hold its 312px even while closed and
   leave a third of the map's width empty. Collapsing the column when the panel
   is hidden gives the map the full width at rest; opening a node narrows it
   again, which costs a scrollbar rather than a reflow. */
.rg-shell:has([data-rg-panel][hidden]) {
  grid-template-columns: minmax(0, 1fr);
}

.rg-viewport {
  position: relative;
  overflow: auto;
  max-height: min(78vh, 820px);
  border: 1px solid var(--line-card);
  border-radius: var(--radius-panel);
  background: var(--bg);
  overscroll-behavior: contain;
  cursor: grab;
  /* The document sets `scroll-behavior: smooth` for anchor jumps. Dragging the
     map has to move it now, not glide there, so it is switched back off here. */
  scroll-behavior: auto;
}

.rg-viewport.is-panning {
  cursor: grabbing;
  user-select: none;
}

.rg-viewport:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.rg-zoom-layer {
  width: max-content;
  min-width: 100%;
  padding: 8px;
}

.rg-canvas {
  position: relative;
  transform-origin: 0 0;
}

.rg-groups,
.rg-edges,
.rg-node {
  position: absolute;
}

.rg-groups {
  inset: 0;
  z-index: 1;
}

.rg-edges {
  left: 0;
  top: 0;
  z-index: 2;
  pointer-events: none;
}

.rg-node {
  z-index: 3;
}

.rg-group {
  position: absolute;
  border: 1px solid var(--rg-group-line);
  border-radius: var(--radius-card);
  background: var(--rg-group-bg);
  pointer-events: none;
}

.rg-group-head {
  position: absolute;
  left: 14px;
  top: 12px;
  right: 14px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.rg-group-num {
  width: 20px;
  height: 20px;
  border-radius: 6px;
  display: grid;
  place-items: center;
  font-size: 9px;
  font-weight: 600;
  background: var(--accent-soft);
  color: var(--accent-strong);
  flex-shrink: 0;
}

/* `--accent-strong` is 5.0:1 on `--accent-soft` in the light theme but 4.2:1 in
   the dark one, where the accent softens towards the text rather than away from
   it. The plain accent is 5.0:1 there. */
:root[data-theme="dark"] .rg-group-num {
  color: var(--accent);
}

.rg-group-title {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--ink-mid);
}

.rg-group-count {
  margin-left: auto;
  font-size: 10px;
  color: var(--muted-strong);
}

.rg-node {
  position: absolute;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  padding: 11px 26px 11px 12px;
  border: 1.5px solid var(--rg-pending-line);
  border-radius: 11px;
  background: var(--rg-node-bg);
  color: var(--ink);
  text-decoration: none;
  overflow: hidden;
}

.rg-node-title {
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.1px;
  /* Two lines fit the box; a third would be clipped by the node's own
     `overflow: hidden` without saying so, so it is clamped where the layout can
     be measured. `tools/shot.mjs --roadmap` asserts nothing is clamped. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.rg-node-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 10px;
  color: var(--muted-strong);
}

.rg-node-num {
  font-weight: 600;
  color: var(--accent-strong);
}

.rg-node-state {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The four state marks are drawn rather than iconified: a check from two
   borders, a dot, a dash. Twenty nodes would otherwise carry eighty inline SVG
   icons, and `currentColor` would not follow the state's own ink. */
.rg-node-mark {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1.5px solid var(--rg-pending-line);
  background: var(--rg-node-bg);
  display: grid;
  place-items: center;
  color: var(--muted);
}

.rg-node[data-state="done"] {
  border-color: var(--rg-done-line);
  background: var(--rg-done-bg);
}

.rg-node[data-state="done"] .rg-node-mark {
  border-color: var(--rg-done-line);
  background: var(--rg-done-line);
  color: var(--rg-node-bg);
}

.rg-node[data-state="done"] .rg-node-mark::after {
  content: "";
  width: 4px;
  height: 8px;
  border: 2px solid currentColor;
  border-top: 0;
  border-left: 0;
  transform: translateY(-1px) rotate(45deg);
}

.rg-node[data-state="learning"] {
  border-color: var(--rg-learning-line);
  background: var(--rg-learning-bg);
}

.rg-node[data-state="learning"] .rg-node-mark {
  border-color: var(--rg-learning-line);
  background: var(--rg-learning-bg);
  color: var(--rg-learning-line);
}

.rg-node[data-state="learning"] .rg-node-mark::after {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}

.rg-node[data-state="skip"] {
  border-color: var(--rg-skip-line);
  background: var(--rg-skip-bg);
}

.rg-node[data-state="skip"] .rg-node-mark {
  border-color: var(--rg-skip-line);
  background: var(--rg-skip-bg);
  color: var(--rg-skip-line);
}

.rg-node[data-state="skip"] .rg-node-mark::after {
  content: "";
  width: 8px;
  height: 2px;
  border-radius: 1px;
  background: currentColor;
}

.rg-node:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(36, 38, 51, 0.1);
}

.rg-node:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Two rings, not one: a single accent outline disappears against a done node,
   which is already accent-coloured. */
.rg-node[aria-current="true"] {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent);
}

.rg-node.is-dim {
  opacity: 0.26;
}

.rg-node.is-hit {
  box-shadow: 0 0 0 2px var(--accent);
}

.rg-group.is-dim {
  opacity: 0.45;
}

.rg-node-cap {
  display: grid;
  place-items: center;
  gap: 2px;
  padding: 6px 10px;
  border-radius: 999px;
  border: 1.5px dashed var(--rg-pending-line);
  background: var(--surface);
  text-align: center;
}

.rg-node-cap .rg-node-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
  -webkit-line-clamp: 1;
}

.rg-node-cap .rg-node-meta {
  font-size: 10px;
  color: var(--muted-strong);
}

.rg-node-cap--finish {
  border-style: solid;
  border-color: var(--accent);
  background: var(--accent-soft);
}

.rg-edge {
  fill: none;
  stroke: var(--rg-edge-ink);
  stroke-width: 1.6;
  stroke-linecap: round;
  marker-end: url(#rg-arrow);
}

.rg-edge.is-done {
  stroke: var(--rg-edge-done);
  marker-end: url(#rg-arrow-done);
}

/* The frontier: the edge whose source is finished and whose target is not. */
.rg-edge.is-next {
  stroke: var(--accent);
  stroke-dasharray: 4 5;
  marker-end: url(#rg-arrow-done);
}

/* --- detail panel --- */

.rg-panel {
  border: 1px solid var(--line-card);
  border-radius: var(--radius-panel);
  background: var(--card);
  padding: 16px;
  max-height: min(78vh, 820px);
  overflow: auto;
}

.rg-panel-head {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.rg-panel-head > div {
  min-width: 0;
  flex: 1;
}

.rg-panel-kicker {
  font-size: 9px;
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: var(--muted-strong);
}

.rg-panel h3 {
  font-size: 16px;
  letter-spacing: -0.3px;
  margin: 4px 0 0;
  color: var(--ink);
}

.rg-panel-close {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-control);
  background: none;
  color: var(--muted-strong);
  cursor: pointer;
}

.rg-panel-close:hover {
  border-color: var(--accent);
  color: var(--accent-strong);
}

.rg-panel-summary {
  font-size: 12px;
  line-height: 1.75;
  color: var(--muted-strong);
  margin: 10px 0 0;
}

.rg-panel-meta {
  display: flex;
  gap: 16px;
  margin: 12px 0 0;
  padding: 10px 0;
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
}

.rg-panel-meta dt {
  font-size: 9px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--muted);
}

.rg-panel-meta dd {
  margin: 3px 0 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
}

.rg-panel-block {
  margin-top: 14px;
}

.rg-panel-label {
  font-size: 9px;
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: var(--muted);
}

.rg-panel-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: grid;
  gap: 7px;
}

.rg-panel-list a {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-soft);
  text-decoration: none;
}

.rg-panel-list a::before {
  content: "";
  width: 5px;
  height: 5px;
  margin-top: 6px;
  border-radius: 50%;
  background: var(--accent);
  flex-shrink: 0;
}

.rg-panel-list a:hover {
  color: var(--accent-strong);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.rg-state-buttons {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin-top: 8px;
}

.rg-state-button {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 7px 9px;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-control);
  background: var(--card);
  font: inherit;
  font-size: 11px;
  color: var(--ink-soft);
  cursor: pointer;
  text-align: left;
}

.rg-state-button svg {
  flex-shrink: 0;
  color: var(--muted);
}

.rg-state-button:hover {
  border-color: var(--accent);
  color: var(--accent-strong);
}

.rg-state-button:hover svg {
  color: var(--accent-strong);
}

.rg-state-button[aria-pressed="true"] {
  font-weight: 600;
  color: var(--ink);
}

.rg-state-button[data-rg-state="done"][aria-pressed="true"] {
  background: var(--rg-done-bg);
  border-color: var(--rg-done-line);
}

.rg-state-button[data-rg-state="learning"][aria-pressed="true"] {
  background: var(--rg-learning-bg);
  border-color: var(--rg-learning-line);
}

.rg-state-button[data-rg-state="skip"][aria-pressed="true"] {
  background: var(--rg-skip-bg);
  border-color: var(--rg-skip-line);
  color: var(--rg-skip-ink);
}

.rg-state-button[data-rg-state="none"][aria-pressed="true"] {
  background: var(--line-soft);
  border-color: var(--line-card);
}

.rg-panel-open {
  width: 100%;
  justify-content: center;
  margin-top: 16px;
}

/* The map carries its own breakpoints instead of adding to section 18: what
   changes below 1180px is the shape of this one component, not of the page. */
@media (max-width: 1180px) {
  .rg-shell {
    grid-template-columns: minmax(0, 1fr);
  }

  /* There is no room for a side column beside the map, and a panel sitting
     under a 74vh viewport would open off screen, so it floats instead. */
  .rg-panel {
    position: fixed;
    right: 16px;
    bottom: 16px;
    z-index: 40;
    width: min(360px, calc(100vw - 32px));
    max-height: 68vh;
    box-shadow: 0 18px 40px rgba(20, 18, 40, 0.26);
  }
}

@media (max-width: 640px) {
  .rg-panel {
    left: 12px;
    right: 12px;
    bottom: 12px;
    width: auto;
    max-height: 62vh;
  }

  .rg-tools {
    width: 100%;
    margin-left: 0;
  }

  .rg-search {
    flex: 1;
  }

  .rg-search input {
    width: 100%;
  }

  .rg-viewport {
    max-height: 66vh;
  }
}

/* --- the bridge to the reading-order list --- */

.path-list-head {
  max-width: 660px;
  margin: 34px 0 22px;
  padding-top: 24px;
  border-top: 1px solid var(--line);
}

.path-list-head h2 {
  font-size: 21px;
  color: var(--ink-soft);
  margin: 4px 0 8px;
}

.path-list-head p {
  font-size: 13px;
  line-height: 1.85;
  color: var(--muted-strong);
  margin: 0;
}


/* --- 17b. Roadmap ------------------------------------------------------- */

/* A roadmap.sh-shaped page: a vertical rail per tahap, one node per materi, and
   a connector between tahap. All of the geometry is pseudo-elements hung off
   the node's own box rather than an SVG, so a node that grows — a title that
   wraps, a sub-topik list that opens — keeps its dot and its stub attached. */

.rm-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 18px;
  padding: 12px 16px;
  margin: 0 0 20px;
  background: var(--card);
  border: 1px solid var(--line-card);
  border-radius: var(--radius-card);
  font-size: 12px;
  color: var(--ink-mid);
  /* The topbar is sticky at 0 with z-index 20, so this parks underneath it
     instead of sliding behind. */
  position: sticky;
  top: var(--topbar-h);
  z-index: 10;
}

.rm-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.rm-key {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 2px solid var(--line-card);
  background: var(--card-soft);
  flex: none;
}

.rm-key-done {
  background: var(--green-mid);
  border-color: var(--green-mid);
}

.rm-legend-total {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-left: auto;
  color: var(--ink-soft);
}

.rm-map {
  list-style: none;
  margin: 0;
  padding: 0;
}

.rm-stage {
  position: relative;
  background: var(--card);
  border: 1px solid var(--line-card);
  border-radius: var(--radius-card);
  padding: 20px 22px 22px;
  margin-bottom: 32px;
}

/* The connector lives in the gap, so the two tahap stay siblings. */
.rm-stage + .rm-stage::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -32px;
  width: 2px;
  height: 24px;
  margin-left: -1px;
  background: var(--line);
}

.rm-stage + .rm-stage::after {
  content: "";
  position: absolute;
  left: 50%;
  top: -10px;
  margin-left: -5px;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 6px solid var(--line);
}

.rm-stage-head {
  display: flex;
  align-items: flex-start;
  gap: 14px;
}

.rm-stage-num {
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: 11px;
  background: var(--accent-tint);
  border: 1px solid var(--accent-tint-line);
  color: var(--accent-strong);
  font-family: var(--font-brand);
  font-weight: 700;
  font-size: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.rm-stage-title {
  flex: 1 1 auto;
  min-width: 0;
}

.rm-stage-title h2 {
  margin: 2px 0 0;
  font-size: 19px;
}

.rm-stage > .lead {
  margin: 12px 0 0;
}

/* The rail. One per tahap, drawn once, with every node hanging off it. */
.rm-nodes {
  list-style: none;
  margin: 18px 0 0;
  padding: 0 0 0 34px;
  position: relative;
}

.rm-nodes::before {
  content: "";
  position: absolute;
  left: 9px;
  top: 14px;
  bottom: 14px;
  width: 2px;
  border-radius: 2px;
  /* Not `--line`. Measured: a 2px #e9eaf0 line on a white card is a contrast
     ratio of about 1.1:1, which photographs as "there is no rail here" even
     though the geometry probe finds it. The accent tint is the next step up in
     both themes and ties the rail to the rest of the page. */
  background: var(--accent-tint-line);
}

.rm-node {
  position: relative;
  padding-bottom: 12px;
}

.rm-node:last-child {
  padding-bottom: 0;
}

/* Dot centred on the rail, and the stub from the rail out to the card. The
   rail sits at x=10 inside .rm-nodes, which is 34px of padding, so it is at
   -24 relative to the node: a 12px dot starts at -30, and a 24px stub at -24
   reaches the card's left edge exactly. Verified against the live DOM rather
   than by eye. */
.rm-node::before {
  content: "";
  position: absolute;
  left: -30px;
  top: 21px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--card);
  border: 2px solid var(--accent-tint-line);
}

.rm-node::after {
  content: "";
  position: absolute;
  left: -24px;
  top: 26px;
  width: 24px;
  height: 2px;
  background: var(--accent-tint-line);
}

.rm-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  background: var(--card-soft);
  border: 1px solid var(--line-card);
  border-radius: var(--radius-panel);
  color: inherit;
  text-decoration: none;
  transition: border-color 140ms ease, background-color 140ms ease;
}

.rm-card:hover {
  border-color: var(--accent-tint-line);
  background: var(--accent-tint);
}

.rm-card-icon {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--accent-soft);
  color: var(--accent-strong);
}

.rm-card-icon svg {
  width: 18px;
  height: 18px;
}

.rm-card-body {
  flex: 1 1 auto;
  min-width: 0;
}

.rm-card-title {
  display: block;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
}

.rm-card-meta {
  display: block;
  margin-top: 2px;
  font-size: 11.5px;
  color: var(--muted-strong);
}

.rm-card-state {
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--green-tint);
  color: var(--green-ink);
  opacity: 0;
  transition: opacity 140ms ease;
}

.rm-card-state svg {
  width: 13px;
  height: 13px;
}

.rm-node.is-done .rm-card {
  background: var(--green-soft);
  border-color: var(--green-line-soft);
}

.rm-node.is-done::before {
  background: var(--green-mid);
  border-color: var(--green-mid);
}

.rm-node.is-done .rm-card-state {
  opacity: 1;
}

.rm-subs {
  margin: 7px 0 0 4px;
  font-size: 12px;
}

.rm-subs > summary {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 2px 0;
  color: var(--muted-strong);
  font-size: 11.5px;
  list-style: none;
}

.rm-subs > summary::-webkit-details-marker {
  display: none;
}

.rm-subs > summary::before {
  content: "";
  width: 6px;
  height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 140ms ease;
}

.rm-subs[open] > summary::before {
  transform: rotate(45deg);
}

.rm-subs > summary:hover {
  color: var(--accent-strong);
}

.rm-subs ul {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin: 7px 0 2px;
  padding: 0 0 0 13px;
  border-left: 1px solid var(--line);
}

.rm-subs li a {
  color: var(--ink-mid);
  text-decoration: none;
}

.rm-subs li a:hover {
  color: var(--accent-strong);
  text-decoration: underline;
}

.rm-capstone {
  margin-top: 2px;
  padding: 22px;
  border-radius: var(--radius-card);
  background: var(--green-soft);
  border: 1px solid var(--green-line);
}

.rm-capstone h2 {
  margin: 4px 0 6px;
  font-size: 19px;
}

.rm-capstone p {
  margin: 0 0 15px;
  color: var(--green-body);
  font-size: 13.5px;
  max-width: 62ch;
}

.rm-total-progress,
.rm-stage-progress {
  border: 0;
  border-radius: 99px;
  background: var(--line);
  appearance: none;
  -webkit-appearance: none;
}

.rm-total-progress {
  width: 150px;
  height: 7px;
}

.rm-stage-progress {
  flex: none;
  width: 110px;
  height: 7px;
  margin-top: 12px;
}

.rm-total-progress::-webkit-progress-bar,
.rm-stage-progress::-webkit-progress-bar {
  background: var(--line);
  border-radius: 99px;
}

.rm-total-progress::-webkit-progress-value {
  background: var(--accent);
  border-radius: 99px;
}

.rm-stage-progress::-webkit-progress-value {
  background: var(--green-mid);
  border-radius: 99px;
}

.rm-total-progress::-moz-progress-bar {
  background: var(--accent);
  border-radius: 99px;
}

.rm-stage-progress::-moz-progress-bar {
  background: var(--green-mid);
  border-radius: 99px;
}

/* Narrow screens: the rail is the first thing to go, because at 320px the
   34px of indent it costs is a tenth of the column and the cards are already
   full-width targets. */
@media (max-width: 700px) {
  .rm-nodes {
    padding-left: 0;
  }

  .rm-nodes::before,
  .rm-node::before,
  .rm-node::after {
    display: none;
  }

  .rm-stage {
    padding: 17px 16px 18px;
  }

  .rm-stage-head {
    flex-wrap: wrap;
  }

  .rm-stage-progress {
    width: 100%;
    margin-top: 10px;
  }

  .rm-legend-total {
    margin-left: 0;
  }
}

/* --- 18. Responsive ----------------------------------------------------- */

@media (max-width: 1100px) {
  .lesson-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .progress-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 900px) {
  :root {
    --pad-x: 20px;
  }

  .sidebar {
    position: fixed;
    left: 0;
    top: 0;
    transform: translateX(-100%);
    transition: transform 0.22s ease;
    box-shadow: 0 0 40px rgba(20, 18, 40, 0.18);
  }

  .sidebar.mobile-open {
    transform: translateX(0);
  }

  .workspace {
    width: 100%;
  }

  .menu-toggle {
    display: flex;
  }

  .nav-scrim {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(24, 22, 40, 0.35);
    z-index: 25;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.22s ease;
  }

  .nav-scrim.visible {
    opacity: 1;
    pointer-events: auto;
  }

  .recipe-grid,
  .formula-grid {
    grid-template-columns: 1fr;
  }

  .handbook-grid {
    columns: 1;
  }

  .crumb-trail {
    display: none;
  }

  .lesson-pagination {
    flex-direction: column;
  }

  .lesson-pagination .spacer {
    display: none;
  }
}

@media (max-width: 640px) {
  .lesson-cards,
  .progress-grid,
  .practice-options {
    grid-template-columns: 1fr;
  }

  .page-heading h1 {
    font-size: 27px;
    letter-spacing: -0.8px;
  }

  .concept-heading h1 {
    font-size: 21px;
  }

  .recipe-header h2 {
    font-size: 22px;
  }

  .learning-intro,
  .progress-summary {
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
  }

  .learning-intro .primary-button {
    margin-left: 0;
  }

  .progress-bar {
    width: 100%;
  }

  .concept-header {
    flex-direction: column;
    align-items: flex-start;
  }

  .concept-header-meta {
    align-items: flex-start;
    margin-left: 0;
  }

  .workspace-footer {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }

  .path-group h2 {
    font-size: 18px;
  }
}

/* --- 19. Motion / print ------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }

  /* `transition-duration` does not cover `scroll-behavior`, so the anchor jump
     from the sidebar has to be turned off by name. */
  html {
    scroll-behavior: auto;
  }
}

@media print {
  .sidebar,
  .topbar,
  .lesson-pagination,
  .menu-toggle,
  .nav-scrim {
    display: none;
  }

  .workspace {
    width: 100%;
  }

  body {
    background: #fff;
  }
}

/* ==========================================================================
   MathUniverse — visualisations
   A step-through player for the lesson scenes. Everything is driven by one
   attribute (`data-step`) on the figure, so an animation is an attribute write
   rather than a re-render, and no inline style is ever needed.

   Loaded after style.css and concatenated into the same served file.
   ========================================================================== */

/* --- 1. Figure shell ----------------------------------------------------- */

.viz {
  margin: 0;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-card);
  background: var(--card);
  overflow: hidden;
}

.viz-head {
  padding: 22px 24px 0;
}

.viz-kicker {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: #786791;
  margin-bottom: 8px;
}

:root[data-theme="dark"] .viz-kicker {
  color: #b9a6d8;
}

.viz-head h3 {
  font-size: 15px;
  color: var(--ink-soft);
  margin-bottom: 8px;
}

:root[data-theme="dark"] .viz-head h3 {
  color: var(--ink);
}

.viz-lede {
  font-size: 12.5px;
  line-height: 1.85;
  color: var(--muted-strong);
  max-width: 62ch;
}

:root[data-theme="dark"] .viz-lede {
  color: var(--muted);
}

/* --- 2. Stage ------------------------------------------------------------ */

.viz-stage {
  margin: 18px 24px 0;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-panel);
  background: var(--bg);
  padding: 12px;
  min-height: 180px;
  display: flex;
  align-items: center;
  justify-content: center;
}

:root[data-theme="dark"] .viz-stage {
  background: #262733;
}

.vz-svg {
  display: block;
  width: 100%;
  height: auto;
  max-height: 420px;
}

/* --- 3. Step rail -------------------------------------------------------- */

.viz-steps {
  list-style: none;
  margin: 16px 24px 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.viz-step {
  display: block;
  width: 100%;
  text-align: left;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  background: none;
  padding: 9px 11px;
  font: inherit;
  color: var(--muted-strong);
  display: flex;
  gap: 11px;
  align-items: flex-start;
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}

:root[data-theme="dark"] .viz-step {
  color: var(--muted);
}

.viz-step:hover {
  background: var(--card-soft);
}

.viz-step:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.viz-step-num {
  flex-shrink: 0;
  width: 21px;
  height: 21px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--line-card);
  color: var(--muted);
  font-size: 10px;
  font-weight: 600;
  display: grid;
  place-items: center;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}

:root[data-theme="dark"] .viz-step-num {
  background: #303040;
}

.viz-step-text {
  font-size: 12.5px;
  line-height: 1.8;
}

.viz-step[aria-current="step"] {
  background: var(--accent-tint);
  border-color: var(--accent-tint-line);
  color: var(--ink);
}

.viz-step[aria-current="step"] .viz-step-num {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.viz-step[data-passed="true"] .viz-step-num {
  color: var(--accent);
  border-color: var(--accent-tint-line);
}

/* --- 4. Controls --------------------------------------------------------- */

.viz-bar {
  margin: 18px 24px 0;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

/* A native <progress>, not a styled div: the fill has to be set from script,
   and `style=""` is unavailable under this CSP. */
.viz-progress {
  flex: 1;
  min-width: 90px;
  height: 3px;
  border: none;
  border-radius: 2px;
  background: var(--line);
  appearance: none;
  -webkit-appearance: none;
  overflow: hidden;
}

.viz-progress::-webkit-progress-bar {
  background: var(--line);
  border-radius: 2px;
}

.viz-progress::-webkit-progress-value {
  background: var(--accent);
  border-radius: 2px;
  transition: width 0.4s ease;
}

.viz-progress::-moz-progress-bar {
  background: var(--accent);
  border-radius: 2px;
}

.viz-controls {
  display: flex;
  align-items: center;
  gap: 7px;
}

.viz-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: 1px solid var(--line-card);
  border-radius: var(--radius-control);
  background: var(--card);
  padding: 7px 11px;
  font: inherit;
  font-size: 11px;
  color: var(--muted-strong);
  transition: border-color 0.15s, color 0.15s;
}

.viz-btn:hover {
  border-color: #c6b2ef;
  color: var(--accent);
}

.viz-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.viz-btn svg {
  width: 14px;
  height: 14px;
}

.viz-btn-icon {
  padding: 7px;
}

.viz-btn[aria-pressed="true"] {
  background: var(--accent-tint);
  border-color: var(--accent-tint-line);
  color: var(--accent);
}

.viz-btn:disabled {
  opacity: 0.42;
  cursor: default;
}

.viz-btn:disabled:hover {
  border-color: var(--line-card);
  color: var(--muted-strong);
}

/* Play and pause share one button; which icon shows follows `aria-pressed`. */
.viz-btn .icon-play,
.viz-btn .icon-pause {
  display: inline-flex;
  align-items: center;
}

.viz-btn .icon-pause {
  display: none;
}

.viz-btn[aria-pressed="true"] .icon-play {
  display: none;
}

.viz-btn[aria-pressed="true"] .icon-pause {
  display: inline-flex;
}

.viz-count {
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-width: 34px;
  text-align: right;
}

.viz-count b {
  color: var(--ink-soft);
  font-weight: 600;
}

.viz-caption {
  padding: 14px 24px 20px;
  font-size: 11.5px;
  line-height: 1.8;
  color: var(--muted);
}

/* --- 5. Step visibility --------------------------------------------------
   One rule per step. `data-at` carries an explicit list (ranges are expanded
   at build time), so `[data-at~="k"]` is the only matching logic needed.
   Elements that persist across steps simply list every step they belong to and
   therefore never re-trigger their transition.
   ------------------------------------------------------------------------ */

.viz-stage [data-at] {
  opacity: 0;
  transition: opacity 0.45s ease, stroke-dashoffset 1s ease;
}

.viz[data-step="1"] .viz-stage [data-at~="1"],
.viz[data-step="2"] .viz-stage [data-at~="2"],
.viz[data-step="3"] .viz-stage [data-at~="3"],
.viz[data-step="4"] .viz-stage [data-at~="4"],
.viz[data-step="5"] .viz-stage [data-at~="5"],
.viz[data-step="6"] .viz-stage [data-at~="6"],
.viz[data-step="7"] .viz-stage [data-at~="7"],
.viz[data-step="8"] .viz-stage [data-at~="8"],
.viz[data-step="9"] .viz-stage [data-at~="9"],
.viz[data-step="10"] .viz-stage [data-at~="10"] {
  opacity: 1;
  stroke-dashoffset: 0;
}

/* A curve draws itself on. `pathLength="1"` normalises the geometry, so the
   dash maths works without measuring the path at runtime. The attribute is
   emitted by `graph()` in vizparts.py; every curve in the build goes through
   there. It is load-bearing, not decorative: without it these two declarations
   turn the curve into a dotted ribbon and the animation into a no-op. */
.vz-curve {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1.1s ease, opacity 0.4s ease;
}

/* --- 6. Scene primitives -------------------------------------------------
   Colour lives here, geometry lives in the markup. Every closed shape gets an
   explicit fill: SVG's default fill is black, and a missing class is a black
   blob rather than a silent no-op.
   ------------------------------------------------------------------------ */

.vz-svg text {
  font-family: var(--font-body);
  font-variant-numeric: tabular-nums;
}

.vz-lbl {
  font-size: 11px;
  fill: var(--muted);
}

.vz-lbl-strong {
  font-size: 11px;
  fill: var(--ink-mid);
  font-weight: 600;
}

/* A label sitting on top of a filled shape rather than on the page background.

   `vz-lbl-strong` is `--ink-mid`, which looks reasonable until you measure it
   against the fills it lands on: #626779 on #7956e9 (light) and #c3bfd2 on
   #c2a7ff (dark) are both about 1.5:1, so a bar label reads as a smudge instead
   of a word. The obvious fix, a theme-flipping white, does not work either,
   because the fills are mid-tone in light and light in dark.

   A fixed near-black clears 5:1 against every one of them, in both themes, so
   no theme rule is needed. If a fill is ever darkened to the point where this
   stops holding, measure again rather than swapping in a variable. */
.vz-lbl-on-fill {
  font-size: 11px;
  fill: #1c1b24;
  font-weight: 700;
}

.vz-eq {
  font-size: 14px;
  fill: var(--ink);
  font-weight: 600;
}

.vz-eq-lg {
  font-size: 18px;
  fill: var(--accent);
  font-weight: 700;
}

.vz-note {
  font-size: 10px;
  fill: var(--muted);
}

.vz-tag {
  font-size: 10px;
  fill: var(--accent);
  font-weight: 600;
}

.vz-axis {
  stroke: var(--line-card);
  stroke-width: 1.5;
}

.vz-grid {
  stroke: var(--line-soft);
  stroke-width: 1;
}

.vz-ink {
  stroke: var(--ink-mid);
  stroke-width: 1.8;
}

.vz-ink-thin {
  stroke: var(--muted);
  stroke-width: 1.3;
}

.vz-accent {
  stroke: var(--accent);
  stroke-width: 2.4;
}

.vz-accent-thin {
  stroke: var(--accent);
  stroke-width: 1.6;
}

.vz-muted {
  stroke: var(--muted);
  stroke-width: 1.6;
}

.vz-dashed {
  stroke-dasharray: 5 4;
}

.vz-fill-card {
  fill: var(--card);
}

.vz-fill-bg {
  fill: var(--bg);
}

.vz-fill-accent {
  fill: var(--accent);
}

.vz-fill-accent-soft {
  fill: var(--accent-soft);
}

.vz-fill-tint {
  fill: var(--accent-tint);
}

.vz-fill-line {
  fill: var(--line);
}

.vz-fill-muted {
  fill: var(--muted);
}

.vz-fill-ink {
  fill: var(--ink-mid);
}

.vz-fill-green {
  fill: var(--green-mid);
}

.vz-fill-green-soft {
  fill: var(--green-tint);
}

.vz-fill-amber {
  fill: var(--amber-tint);
}

.vz-stroke-green {
  stroke: var(--green-mid);
  stroke-width: 2.4;
}

.vz-stroke-amber {
  stroke: var(--amber-ink);
  stroke-width: 2.4;
}

.vz-stroke-line {
  stroke: var(--line-card);
}

.vz-hatch-line {
  stroke: var(--accent);
  stroke-width: 1.4;
  opacity: 0.35;
}

/* Scene-specific shapes. Each closed shape names its fill explicitly, because
   SVG's default is black and a missing class is a black blob rather than a
   silent no-op. */

.vz-dot-solid {
  fill: var(--accent);
  stroke: none;
}

.vz-dot-open {
  fill: var(--bg);
  stroke: var(--accent);
  stroke-width: 2.4;
}

:root[data-theme="dark"] .vz-dot-open {
  fill: #262733;
}

.vz-dot-ghost {
  fill: var(--muted);
  stroke: none;
}

.vz-band {
  fill: var(--accent);
  fill-opacity: 0.13;
}

.vz-band-green {
  fill: var(--green-mid);
  fill-opacity: 0.18;
}

.vz-node {
  fill: var(--card);
  stroke: var(--ink-mid);
  stroke-width: 1.6;
}

.vz-node-accent {
  fill: var(--accent);
  stroke: var(--accent);
}

.vz-node-soft {
  fill: var(--accent-soft);
  stroke: var(--accent);
  stroke-width: 1.6;
}

.vz-tok {
  fill: var(--card);
  stroke: var(--ink-mid);
  stroke-width: 1.4;
}

.vz-tok-x {
  fill: var(--accent-soft);
  stroke: var(--accent);
  stroke-width: 1.4;
}

.vz-tok-unit {
  fill: var(--green-tint);
  stroke: var(--green-mid);
  stroke-width: 1.4;
}

.vz-tok-gone {
  fill: none;
  stroke: var(--line-card);
  stroke-width: 1.4;
  stroke-dasharray: 3 3;
}

.vz-shape {
  fill: var(--accent-tint);
  stroke: var(--accent);
  stroke-width: 1.8;
}

.vz-shape-alt {
  fill: var(--green-tint);
  stroke: var(--green-mid);
  stroke-width: 1.8;
}

.vz-shape-ghost {
  fill: var(--line-soft);
  stroke: var(--muted);
  stroke-width: 1.4;
  stroke-dasharray: 5 4;
}

.vz-shape-line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.8;
}

.vz-guide {
  stroke: var(--muted);
  stroke-width: 1.4;
  stroke-dasharray: 5 4;
}

.vz-angle {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2.2;
}

.vz-angle-alt {
  fill: none;
  stroke: var(--green-mid);
  stroke-width: 2.2;
}

.vz-pan {
  fill: var(--card);
  stroke: var(--ink-mid);
  stroke-width: 1.6;
}

.vz-bar {
  fill: var(--accent);
  fill-opacity: 0.85;
}

.vz-bar-alt {
  fill: var(--green-mid);
  fill-opacity: 0.85;
}

.vz-line-ref {
  stroke: var(--green-mid);
  stroke-width: 2;
  stroke-dasharray: 6 4;
}

.vz-cell {
  fill: var(--card);
  stroke: var(--line-card);
  stroke-width: 1;
}

.vz-cell-on {
  fill: var(--accent);
  fill-opacity: 0.85;
  stroke: var(--accent);
  stroke-width: 1;
}

.vz-cell-win {
  fill: var(--green-mid);
  fill-opacity: 0.9;
  stroke: var(--green-mid);
  stroke-width: 1;
}

.vz-wedge {
  fill: var(--accent);
  fill-opacity: 0.82;
  stroke: var(--card);
  stroke-width: 1.5;
}

.vz-wedge-alt {
  fill: var(--green-mid);
  fill-opacity: 0.82;
  stroke: var(--card);
  stroke-width: 1.5;
}

.vz-wedge-off {
  fill: var(--line);
  stroke: var(--card);
  stroke-width: 1.5;
}

.vz-bracket {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.6;
}

.vz-bracket-alt {
  fill: none;
  stroke: var(--green-mid);
  stroke-width: 1.6;
}

/* --- 7. HTML scene parts (step-calc) ------------------------------------- */

.vz-calc {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.vz-row {
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  padding: 10px 12px;
}

.vz-row-expr {
  font-size: 15px;
  line-height: 1.7;
  color: var(--ink-soft);
  flex: 1;
  min-width: 0;
  overflow-wrap: anywhere;
}

.vz-row-note {
  font-size: 11px;
  color: var(--muted);
  flex-shrink: 0;
}

.vz-row[data-tone="focus"] {
  background: var(--accent-tint);
  border-color: var(--accent-tint-line);
}

.vz-row[data-tone="focus"] .vz-row-expr {
  color: var(--accent);
  font-weight: 600;
}

.vz-row[data-tone="result"] {
  background: var(--green-soft);
  border-color: var(--green-line);
}

.vz-row[data-tone="result"] .vz-row-expr {
  color: var(--green-ink);
  font-weight: 700;
}

.vz-row[data-tone="wrong"] .vz-row-expr {
  color: var(--muted);
  text-decoration: line-through;
  text-decoration-color: var(--muted-soft);
}

.vz-hl {
  background: var(--accent-soft);
  color: var(--accent);
  border-radius: 4px;
  padding: 1px 5px;
  font-weight: 600;
}

.vz-hl-green {
  background: var(--green-tint);
  color: var(--green-ink);
  border-radius: 4px;
  padding: 1px 5px;
  font-weight: 600;
}

.vz-lane {
  border: 1px dashed var(--line-card);
  border-radius: var(--radius-panel);
  padding: 12px;
}

.vz-lane-title {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}

.vz-lane[data-lane="wrong"] {
  border-color: var(--line-card);
  opacity: 0.75;
}

/* --- 8. Staggered reveal for the worked example --------------------------
   The example card already exists; this only adds motion, no new markup.

   The hiding rule is scoped to `.js`, which `theme-init.js` puts on <html>
   before the body is parsed. Without scripting the steps must stay visible, and
   an unscoped `opacity: 0` would erase the worked solution entirely.
   ------------------------------------------------------------------------ */

.js .reveal > li {
  opacity: 0;
  transform: translateY(8px);
}

.reveal.is-in > li {
  opacity: 1;
  transform: none;
  transition: opacity 0.5s ease, transform 0.5s ease;
}

.reveal.is-in > li:nth-child(1) { transition-delay: 0.04s; }
.reveal.is-in > li:nth-child(2) { transition-delay: 0.12s; }
.reveal.is-in > li:nth-child(3) { transition-delay: 0.2s; }
.reveal.is-in > li:nth-child(4) { transition-delay: 0.28s; }
.reveal.is-in > li:nth-child(5) { transition-delay: 0.36s; }
.reveal.is-in > li:nth-child(6) { transition-delay: 0.44s; }
.reveal.is-in > li:nth-child(7) { transition-delay: 0.52s; }
.reveal.is-in > li:nth-child(8) { transition-delay: 0.6s; }

/* --- 9. Narrow screens ---------------------------------------------------
   Below ~640px a 640-wide scene is scaled to about half, which puts 11px
   labels near 5px. Rather than shrink the type below legibility, the stage
   becomes a contained horizontal scroller with a floor on the drawing width.
   The page itself still never overflows.
   ------------------------------------------------------------------------ */

@media (max-width: 900px) {
  .viz-head,
  .viz-bar,
  .viz-caption {
    padding-left: 18px;
    padding-right: 18px;
  }

  .viz-steps {
    margin-left: 18px;
    margin-right: 18px;
  }

  .viz-stage {
    margin-left: 18px;
    margin-right: 18px;
    padding: 10px;
  }
}

@media (max-width: 640px) {
  .viz-stage {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    justify-content: flex-start;
    -webkit-overflow-scrolling: touch;
  }

  .vz-svg {
    min-width: 470px;
  }

  .viz-bar {
    gap: 10px;
  }

  .viz-progress {
    order: 3;
    flex-basis: 100%;
  }
}

/* --- 10. Reduced motion --------------------------------------------------
   The scenes still work: every step is reachable, it just arrives instantly.
   ------------------------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .viz-stage [data-at],
  .viz-step,
  .viz-step-num,
  .viz-progress span,
  .reveal > li {
    transition: none;
  }

  .vz-curve {
    stroke-dashoffset: 0;
  }

  .reveal > li {
    opacity: 1;
    transform: none;
  }
}
