/* ==========================================================================
   Nova Dojo design system v2 · "Dojo moderno" (D1)
   Plain CSS on top of Tailwind (CDN play). No build step.

   Cascade notes (important when you mix these classes with Tailwind):
   - The Tailwind CDN injects its <style> at the END of <head>, after this file
     and after page CSS. So a Tailwind utility on the same element wins over a
     component class here (e.g. class="btn btn-primary w-full" works).
   - Global element baselines (forms, tables, headings) use specificity 0,0,2
     (`body input`, `main th`): they beat Tailwind's preflight reset but lose to
     any utility class, so page templates keep full control.
   - Components read CSS custom properties: tint any of them with a belt by adding
     data-belt="blue" (or class "belt-blue") to the element or an ancestor.
   Keep the hex values in sync with base.html (tailwind.config).
   ========================================================================== */

/* ---------------------------------------------------------------- tokens */
:root {
  /* Surfaces and ink */
  --bg: #f6f4ef;            /* warm ivory page */
  --bg-sunken: #eeebe4;     /* wells, tracks */
  --paper: #ffffff;         /* cards */
  --ink: #1b1f2a;           /* main text */
  --ink-soft: #3a4050;      /* secondary text */
  --muted: #5f6573;         /* captions (AA on white and ivory) */
  --faint: #9a9890;         /* placeholders, disabled */
  --border: rgba(27, 31, 42, .08);
  --border-strong: rgba(27, 31, 42, .16);
  --line: #e6e2d9;          /* solid hairline (tracks, dividers) */
  --line-strong: #d3cec3;
  --surface: var(--paper);

  /* Brand */
  --brand-navy: #1f3a5f;
  --brand-navy-dark: #152a46;
  --brand-navy-light: #e3eaf4;
  --brand-teal: #2a9d8f;
  --brand-teal-dark: #1f7a6f;
  --brand-teal-light: #e2f4f1;
  --gold: #f5b82e;
  --gold-dark: #c98f0a;
  --gold-light: #fdf1d0;
  --gold-ink: #6b4500;

  /* Feedback */
  --ok: #16a34a;     --ok-dark: #11803a;  --ok-bg: #e3f7e9;  --ok-ink: #14532d;
  --ko: #dc2626;     --ko-dark: #a51d1d;  --ko-bg: #fde8e8;  --ko-ink: #7f1d1d;
  --warn: #d97706;   --warn-bg: #fdf3dc;  --warn-ink: #78350f;
  --info: #1f3a5f;   --info-bg: #e9eff7;  --info-ink: #1f3a5f;
  --flame: #f97316;  --flame-core: #fbbf24;

  /* Belts: fill, edge (borders, 3D shadows) */
  --belt-white: #ffffff;   --belt-white-edge: #cfc9bd;
  --belt-yellow: #facc15;  --belt-yellow-edge: #ca8a04;
  --belt-orange: #f97316;  --belt-orange-edge: #c2410c;
  --belt-green: #16a34a;   --belt-green-edge: #166534;
  --belt-blue: #2563eb;    --belt-blue-edge: #1e40af;
  --belt-purple: #7c3aed;  --belt-purple-edge: #5b21b6;
  --belt-brown: #8b5a2b;   --belt-brown-edge: #5c3a1a;
  --belt-red: #dc2626;     --belt-red-edge: #991b1b;
  --belt-black: #111827;   --belt-black-edge: #000000;

  /* Shape and depth */
  --radius-xs: .5rem;
  --radius-sm: .75rem;
  --radius: 1rem;           /* 16 px: buttons, inputs, chips containers */
  --radius-lg: 1.25rem;     /* 20 px: cards */
  --radius-xl: 1.5rem;      /* 24 px: hero panels */
  --radius-card: var(--radius-lg);
  --shadow-xs: 0 1px 2px rgba(27, 31, 42, .06);
  --shadow-sm: 0 1px 2px rgba(27, 31, 42, .06), 0 2px 6px -2px rgba(27, 31, 42, .08);
  --shadow-md: 0 1px 2px rgba(27, 31, 42, .05), 0 10px 24px -8px rgba(27, 31, 42, .14);
  --shadow-lg: 0 2px 4px rgba(27, 31, 42, .06), 0 24px 48px -16px rgba(27, 31, 42, .24);
  --ring-focus: 0 0 0 4px rgba(42, 157, 143, .22);

  /* Type */
  --font-display: "Nunito", ui-rounded, "SF Pro Rounded", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-reading: var(--font-body);
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

  /* Motion */
  --ease-out: cubic-bezier(.22, 1, .36, 1);
  --ease-spring: cubic-bezier(.34, 1.56, .64, 1);
}

/* Belt scope: sets --belt (fill), --belt-edge, --belt-ink (text on fill)
   and --belt-fill (a visible fill for bars: white belt uses warm grey). */
.belt-white,  [data-belt="white"]  { --belt: var(--belt-white);  --belt-edge: var(--belt-white-edge);  --belt-ink: #3a4050; --belt-fill: #a8a294; --belt-soft: #f3f1ec; }
.belt-yellow, [data-belt="yellow"] { --belt: var(--belt-yellow); --belt-edge: var(--belt-yellow-edge); --belt-ink: #422006; --belt-fill: var(--belt-yellow); --belt-soft: #fef9c3; }
.belt-orange, [data-belt="orange"] { --belt: var(--belt-orange); --belt-edge: var(--belt-orange-edge); --belt-ink: #ffffff; --belt-fill: var(--belt-orange); --belt-soft: #ffedd5; }
.belt-green,  [data-belt="green"]  { --belt: var(--belt-green);  --belt-edge: var(--belt-green-edge);  --belt-ink: #ffffff; --belt-fill: var(--belt-green);  --belt-soft: #dcfce7; }
.belt-blue,   [data-belt="blue"]   { --belt: var(--belt-blue);   --belt-edge: var(--belt-blue-edge);   --belt-ink: #ffffff; --belt-fill: var(--belt-blue);   --belt-soft: #dbeafe; }
.belt-purple, [data-belt="purple"] { --belt: var(--belt-purple); --belt-edge: var(--belt-purple-edge); --belt-ink: #ffffff; --belt-fill: var(--belt-purple); --belt-soft: #ede9fe; }
.belt-brown,  [data-belt="brown"]  { --belt: var(--belt-brown);  --belt-edge: var(--belt-brown-edge);  --belt-ink: #ffffff; --belt-fill: var(--belt-brown);  --belt-soft: #f3e8dc; }
.belt-red,    [data-belt="red"]    { --belt: var(--belt-red);    --belt-edge: var(--belt-red-edge);    --belt-ink: #ffffff; --belt-fill: var(--belt-red);    --belt-soft: #fee2e2; }
.belt-black,  [data-belt="black"]  { --belt: var(--belt-black);  --belt-edge: var(--belt-black-edge);  --belt-ink: #ffffff; --belt-fill: var(--belt-black);  --belt-soft: #e5e7eb; }

/* ------------------------------------------------------------------ base */
html { -webkit-text-size-adjust: 100%; text-rendering: optimizeLegibility; }
body { font-family: var(--font-body); line-height: 1.5; }
body.dojo-body {
  background-color: var(--bg);
  /* barely-there warm glow so big empty areas never look flat */
  background-image:
    radial-gradient(1200px 520px at 100% -10%, rgba(42, 157, 143, .07), transparent 60%),
    radial-gradient(900px 480px at -10% 0%, rgba(245, 184, 46, .07), transparent 60%);
  background-repeat: no-repeat;
  color: var(--ink);
}
/* Headings: Nunito, heavy, tight. 0,0,2 beats the preflight reset; utilities still win. */
h1, h2, h3, h4, h5, h6, .font-display { font-family: var(--font-display); }
body :is(h1, h2) { font-weight: 800; letter-spacing: -.01em; line-height: 1.2; }
body :is(h3, h4) { font-weight: 800; line-height: 1.3; }
::selection { background: rgba(42, 157, 143, .22); }
:focus-visible { outline: 3px solid color-mix(in srgb, var(--brand-teal) 75%, white); outline-offset: 2px; }
.tabular-nums { font-variant-numeric: tabular-nums; }
.text-ink { color: var(--ink); }
.text-muted { color: var(--muted); }
.bg-ivory { background-color: var(--bg); }
.bg-paper { background-color: var(--paper); }
.eyebrow {
  font-family: var(--font-body); font-size: .75rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--brand-teal-dark);
}
.kbd {
  display: inline-grid; place-items: center; min-width: 1.5rem; height: 1.5rem; padding: 0 .35rem;
  border: 1px solid var(--border-strong); border-bottom-width: 2px; border-radius: .4rem;
  background: var(--paper); font: 700 .75rem/1 var(--font-mono); color: var(--ink-soft);
}
.divider { height: 1px; border: 0; background: var(--border); margin-block: 1rem; }

/* ----------------------------------------------------------------- icons */
/* <svg class="icon"> from the icon() macro: inherits currentColor, 1.2em by default.
   Size it with Tailwind (w-5 h-5) or the macro's size argument. */
.icon { display: inline-block; flex-shrink: 0; width: 1.2em; height: 1.2em; vertical-align: -.22em; overflow: visible; }

/* ------------------------------------------------- global HTMX indicator */
/* htmx injects .htmx-indicator styles; these are the same rules as a fallback. */
.htmx-indicator { opacity: 0; transition: opacity 200ms ease-in; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }

.dojo-loadbar {
  position: fixed; inset: 0 0 auto 0; height: 3px; z-index: 80;
  overflow: hidden; pointer-events: none;
  background: color-mix(in srgb, var(--brand-teal) 14%, transparent);
}
.dojo-loadbar::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 45%;
  border-radius: 0 9999px 9999px 0;
  background: linear-gradient(90deg, transparent, var(--brand-teal) 35%, var(--gold) 85%, transparent);
  animation: dojo-loadbar 1.05s var(--ease-out) infinite;
}
@keyframes dojo-loadbar { from { translate: -100% 0; } to { translate: 240% 0; } }

/* -------------------------------------------------------------- navbar */
.dojo-header {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  border-bottom: 1px solid var(--border);
  -webkit-backdrop-filter: saturate(1.4) blur(14px); backdrop-filter: saturate(1.4) blur(14px);
}
.dojo-brand {
  display: inline-flex; align-items: center; gap: .6rem; flex-shrink: 0;
  font-family: var(--font-display); font-weight: 900; font-size: 1.2rem; letter-spacing: -.015em;
  color: var(--brand-navy); text-decoration: none; border-radius: .75rem;
}
.dojo-brand img { width: 32px; height: 32px; transition: transform .25s var(--ease-spring); }
.dojo-brand:hover img { transform: rotate(-8deg) scale(1.06); }
.dojo-brand__accent { color: var(--brand-teal); }

.nav-link {
  display: inline-flex; align-items: center; gap: .45rem;
  min-height: 2.5rem; padding: .45rem .8rem; border-radius: 9999px;
  font-family: var(--font-body); font-weight: 600; font-size: .875rem; line-height: 1.2;
  color: var(--ink-soft); text-decoration: none; white-space: nowrap;
  transition: background-color .15s, color .15s, box-shadow .15s;
}
.nav-link .icon { width: 1.15rem; height: 1.15rem; color: var(--muted); transition: color .15s, transform .2s var(--ease-spring); }
.nav-link:hover { background: rgba(27, 31, 42, .055); color: var(--ink); }
.nav-link:hover .icon { color: var(--brand-teal); transform: translateY(-1px); }
.nav-link.is-active, .nav-link[aria-current="page"] {
  background: var(--paper); color: var(--brand-navy);
  box-shadow: var(--shadow-sm), inset 0 0 0 1px var(--border);
}
.nav-link.is-active .icon, .nav-link[aria-current="page"] .icon { color: var(--brand-teal); }

/* Compact streak / XP counters on the right of the navbar. */
.nav-stat {
  display: inline-flex; align-items: center; gap: .3rem; height: 2.25rem; padding: 0 .7rem 0 .55rem;
  border-radius: 9999px; background: var(--paper); box-shadow: var(--shadow-xs), inset 0 0 0 1px var(--border);
  font-family: var(--font-display); font-weight: 800; font-size: .9375rem; color: var(--ink);
  font-variant-numeric: tabular-nums; white-space: nowrap; text-decoration: none;
}
.nav-stat .icon { width: 1.15rem; height: 1.15rem; }
.nav-stat--streak .icon { color: var(--flame); }
.nav-stat--streak.is-off { color: var(--faint); }
.nav-stat--streak.is-off .icon { color: var(--faint); }
.nav-stat--xp .icon { color: var(--gold-dark); }
.nav-stat small { font: 700 .6875rem/1 var(--font-body); color: var(--muted); letter-spacing: .03em; }

/* Navbar search: A10's search_box (search.css) inside .dojo-navsearch. Collapsed it is a 44 px
   icon; on focus (or while suggestions are open) it grows to the left over the nav links, so it
   never reflows the navbar. "/" focuses it (search.js). */
.dojo-navsearch { position: relative; width: 2.75rem; height: 2.75rem; flex-shrink: 0; }
.dojo-navsearch .search-box {
  position: absolute; top: 0; right: 0; z-index: 45; width: 2.75rem; padding: 0 .78rem;
  background: transparent; border-color: transparent; box-shadow: none; border-radius: 9999px; cursor: pointer;
  transition: width .25s var(--ease-out), background-color .15s, border-color .15s, box-shadow .15s;
}
.dojo-navsearch .search-box input[type="search"] { cursor: pointer; }
/* The global input baseline must not draw inside A10's search box (navbar and /search page). */
.search-box input[type="search"], .search-box input[type="search"]:focus { min-height: 0; box-shadow: none; border-radius: 0; }
.dojo-navsearch .search-box:hover { background: rgba(27, 31, 42, .055); }
.dojo-navsearch .search-box:not(:focus-within):not(.is-open) input[type="search"] {
  position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; padding: 0; border-radius: inherit; color: transparent;
}
.dojo-navsearch .search-box:not(:focus-within):not(.is-open) input[type="search"]::placeholder { color: transparent; }
.dojo-navsearch .search-box__icon { pointer-events: none; }
.dojo-navsearch .search-box:not(:focus-within):not(.is-open) .search-box__kbd { display: none; }
.dojo-navsearch .search-box:focus-within, .dojo-navsearch .search-box.is-open {
  width: min(22rem, 50vw); padding: 0 .5rem 0 .8rem; border-radius: .9rem; cursor: auto;
  background: var(--paper); border-color: var(--brand-teal); box-shadow: var(--shadow-sm), var(--ring-focus);
}
.dojo-navsearch .search-box:focus-within input[type="search"] { cursor: text; }

/* Disclosure menus (<details class="dojo-menu">): mobile panel and the avatar dropdown. */
.dojo-menu { position: relative; }
.dojo-menu > summary { list-style: none; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.dojo-menu > summary::-webkit-details-marker { display: none; }
.dojo-menu > summary::marker { content: ""; }
.dojo-iconbtn {
  display: inline-grid; place-items: center; width: 2.75rem; height: 2.75rem; border-radius: .9rem;
  color: var(--brand-navy); transition: background-color .15s;
}
.dojo-iconbtn:hover, .dojo-menu[open] > summary.dojo-iconbtn { background: rgba(27, 31, 42, .06); }
.dojo-iconbtn .icon { width: 1.5rem; height: 1.5rem; }
.dojo-usermenu > summary {
  display: inline-flex; align-items: center; gap: .35rem; height: 2.75rem; padding: 0 .4rem 0 .25rem;
  border-radius: 9999px; transition: background-color .15s;
}
.dojo-usermenu > summary:hover, .dojo-usermenu[open] > summary { background: rgba(27, 31, 42, .06); }
.dojo-usermenu > summary .icon { width: 1rem; height: 1rem; color: var(--muted); transition: rotate .2s; }
.dojo-usermenu[open] > summary .icon { rotate: 180deg; }

.dojo-dropdown {
  position: absolute; right: 0; top: calc(100% + .5rem); z-index: 50; width: 16rem;
  padding: .4rem; border-radius: var(--radius); background: var(--paper);
  box-shadow: var(--shadow-lg), 0 0 0 1px var(--border);
  animation: dojo-drop .16s var(--ease-out);
}
.dojo-dropdown__head { display: flex; align-items: center; gap: .7rem; padding: .6rem .6rem .75rem; border-bottom: 1px solid var(--border); margin-bottom: .3rem; }
.dojo-dropdown a, .dojo-dropdown button {
  display: flex; align-items: center; gap: .65rem; width: 100%; min-height: 2.5rem; padding: .5rem .65rem;
  border-radius: .7rem; font-size: .875rem; font-weight: 600; color: var(--ink-soft); text-decoration: none; text-align: left;
}
.dojo-dropdown a .icon, .dojo-dropdown button .icon { width: 1.1rem; height: 1.1rem; color: var(--muted); }
.dojo-dropdown a:hover, .dojo-dropdown button:hover { background: var(--bg); color: var(--ink); }
.dojo-dropdown a[aria-current="page"] { background: var(--brand-teal-light); color: var(--brand-teal-dark); }
.dojo-dropdown hr { border: 0; height: 1px; background: var(--border); margin: .3rem .2rem; }

.dojo-menu__panel {
  position: fixed; inset: 4rem 0 auto 0; z-index: 50; max-height: calc(100dvh - 4rem); overflow-y: auto;
  background: var(--paper); border-bottom: 1px solid var(--border);
  box-shadow: 0 24px 48px -24px rgba(27, 31, 42, .35);
  padding: .75rem 1rem 1.25rem; animation: dojo-drop .18s var(--ease-out);
}
.dojo-menu__panel .nav-link { display: flex; min-height: 3rem; padding: .75rem .9rem; border-radius: var(--radius); font-size: 1rem; }
.dojo-menu__panel .nav-link .icon { width: 1.35rem; height: 1.35rem; }
@keyframes dojo-drop { from { opacity: 0; translate: 0 -6px; } }

/* --------------------------------------------------------------- footer */
.dojo-footer { border-top: 1px solid var(--border); color: var(--muted); font-size: .8125rem; }
.dojo-footer a { color: var(--ink-soft); text-decoration: none; font-weight: 600; }
.dojo-footer a:hover { color: var(--brand-teal-dark); text-decoration: underline; text-underline-offset: 3px; }

/* ---------------------------------------------------------------- flash */
.flash {
  --flash-bg: var(--info-bg); --flash-ink: var(--info-ink); --flash-accent: var(--brand-navy);
  display: flex; align-items: flex-start; gap: .75rem;
  padding: .8rem .9rem .8rem .8rem; border-radius: var(--radius);
  background: var(--paper); color: var(--ink);
  box-shadow: var(--shadow-sm), inset 0 0 0 1px var(--border);
  font-size: .9rem; line-height: 1.45;
  animation: dojo-drop .2s var(--ease-out);
}
.flash__icon {
  display: grid; place-items: center; flex-shrink: 0; width: 2rem; height: 2rem; border-radius: .7rem;
  background: var(--flash-bg); color: var(--flash-accent);
}
.flash__icon .icon { width: 1.15rem; height: 1.15rem; }
.flash__text { min-width: 0; flex: 1; padding-top: .3rem; font-weight: 500; }
.flash__close {
  display: grid; place-items: center; flex-shrink: 0; width: 2rem; height: 2rem; border-radius: .6rem;
  color: var(--muted); transition: background-color .15s, color .15s;
}
.flash__close:hover { background: var(--bg); color: var(--ink); }
.flash__close .icon { width: 1rem; height: 1rem; }
.flash--success { --flash-bg: var(--ok-bg); --flash-accent: var(--ok-dark); }
.flash--warning { --flash-bg: var(--warn-bg); --flash-accent: var(--warn); }
.flash--error   { --flash-bg: var(--ko-bg); --flash-accent: var(--ko); }

/* --------------------------------------------------------------- avatar */
.avatar {
  --size: 32px; --avatar-bg: var(--brand-navy);
  display: inline-grid; place-items: center; flex-shrink: 0;
  width: var(--size); height: var(--size); border-radius: 9999px; overflow: hidden;
  background: var(--avatar-bg); color: #fff;
  background-image: linear-gradient(160deg, rgba(255, 255, 255, .22), rgba(255, 255, 255, 0) 55%);
  font-family: var(--font-display); font-weight: 900;
  font-size: calc(var(--size) * .44); line-height: 1;
  box-shadow: 0 0 0 2px var(--paper), 0 0 0 3px var(--border-strong);
  user-select: none;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }

/* -------------------------------------------------------------- buttons */
/* 3D buttons: a 4 px darker "lip" under the face. Hover lifts, active presses. */
.btn {
  --btn-bg: transparent; --btn-ink: inherit; --btn-edge: transparent; --btn-line: transparent; --btn-lip: 4px;
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  padding: .7rem 1.3rem; min-height: 2.75rem;
  border: 2px solid var(--btn-line); border-radius: var(--radius);
  background: var(--btn-bg); color: var(--btn-ink);
  box-shadow: 0 var(--btn-lip) 0 var(--btn-edge);
  font-family: var(--font-display); font-weight: 800; font-size: .9875rem; line-height: 1.2; letter-spacing: .01em;
  text-decoration: none; white-space: nowrap; cursor: pointer; user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform .1s ease, box-shadow .1s ease, background-color .15s, filter .15s;
}
.btn .icon { width: 1.2em; height: 1.2em; }
.btn:hover { filter: brightness(1.06) saturate(1.05); transform: translateY(-1px); box-shadow: 0 calc(var(--btn-lip) + 1px) 0 var(--btn-edge); }
.btn:active { transform: translateY(var(--btn-lip)); box-shadow: 0 0 0 var(--btn-edge); filter: brightness(.98); }
.btn:focus-visible { outline: 3px solid color-mix(in srgb, var(--brand-teal) 60%, white); outline-offset: 3px; }
.btn-primary   { --btn-bg: var(--brand-teal); --btn-ink: #fff; --btn-edge: var(--brand-teal-dark); }
.btn-navy      { --btn-bg: var(--brand-navy); --btn-ink: #fff; --btn-edge: #0f1f35; }
.btn-secondary { --btn-bg: var(--paper); --btn-ink: var(--brand-navy); --btn-edge: var(--line-strong); --btn-line: var(--line-strong); }
.btn-secondary:hover { filter: none; background: #fdfcfa; }
.btn-ghost     { --btn-ink: var(--brand-navy); --btn-lip: 0px; box-shadow: none; }
.btn-ghost:hover { background: rgba(27, 31, 42, .06); filter: none; transform: none; box-shadow: none; }
.btn-ghost:active { transform: none; box-shadow: none; background: rgba(27, 31, 42, .1); }
.btn-danger    { --btn-bg: var(--ko); --btn-ink: #fff; --btn-edge: var(--ko-dark); }
.btn-gold      { --btn-bg: var(--gold); --btn-ink: #3d2600; --btn-edge: var(--gold-dark); }
.btn-sm { --btn-lip: 3px; padding: .4rem .85rem; min-height: 2.25rem; font-size: .8438rem; border-radius: .8rem; gap: .35rem; }
.btn-lg { --btn-lip: 5px; padding: .9rem 1.7rem; min-height: 3.25rem; font-size: 1.0625rem; border-radius: 1.1rem; }
.btn-block { display: flex; width: 100%; }
.btn-icon { padding-inline: .7rem; }
.btn:disabled, .btn[aria-disabled="true"], .btn.is-disabled {
  cursor: not-allowed; filter: grayscale(.7); opacity: .5; transform: none;
  box-shadow: 0 var(--btn-lip) 0 var(--btn-edge);
}
a.btn[aria-disabled="true"], a.btn.is-disabled { pointer-events: none; }
/* Busy state while HTMX is in flight (on the button or on its form). */
.btn.htmx-request, form.htmx-request .btn[type="submit"], form.htmx-request button.btn:not([type]) { cursor: progress; }
.btn.htmx-request::after, form.htmx-request .btn[type="submit"]::after, form.htmx-request button.btn:not([type])::after {
  content: ""; width: 1em; height: 1em; border-radius: 9999px;
  border: 2px solid currentColor; border-right-color: transparent;
  animation: dojo-spin .7s linear infinite;
}
@keyframes dojo-spin { to { rotate: 360deg; } }

/* ---------------------------------------------------------------- chips */
.chip {
  --chip-bg: var(--paper); --chip-ink: var(--ink-soft); --chip-line: var(--border-strong); --chip-icon: var(--muted);
  display: inline-flex; align-items: center; gap: .35rem; max-width: 100%;
  min-height: 1.75rem; padding: .2rem .7rem; border-radius: 9999px;
  background: var(--chip-bg); color: var(--chip-ink); box-shadow: inset 0 0 0 1px var(--chip-line);
  font-size: .8125rem; font-weight: 600; line-height: 1.2; white-space: nowrap; text-decoration: none;
}
.chip .icon { width: 1rem; height: 1rem; color: var(--chip-icon); }
a.chip { transition: background-color .15s, box-shadow .15s; }
a.chip:hover { box-shadow: inset 0 0 0 1px var(--chip-icon), var(--shadow-xs); }
.chip-teal  { --chip-bg: var(--brand-teal-light); --chip-ink: var(--brand-teal-dark); --chip-line: rgba(42, 157, 143, .25); --chip-icon: var(--brand-teal); }
.chip-navy  { --chip-bg: var(--brand-navy-light); --chip-ink: var(--brand-navy); --chip-line: rgba(31, 58, 95, .18); --chip-icon: var(--brand-navy); }
.chip-gold  { --chip-bg: var(--gold-light); --chip-ink: var(--gold-ink); --chip-line: rgba(201, 143, 10, .28); --chip-icon: var(--gold-dark); }
.chip-ok    { --chip-bg: var(--ok-bg); --chip-ink: var(--ok-ink); --chip-line: rgba(22, 163, 74, .25); --chip-icon: var(--ok); }
.chip-ko    { --chip-bg: var(--ko-bg); --chip-ink: var(--ko-ink); --chip-line: rgba(220, 38, 38, .22); --chip-icon: var(--ko); }
.chip-warn  { --chip-bg: var(--warn-bg); --chip-ink: var(--warn-ink); --chip-line: rgba(217, 119, 6, .25); --chip-icon: var(--warn); }
.chip-flame { --chip-bg: #fff1e6; --chip-ink: #9a3412; --chip-line: rgba(249, 115, 22, .25); --chip-icon: var(--flame); }
.chip-solid { --chip-bg: var(--brand-navy); --chip-ink: #fff; --chip-line: transparent; --chip-icon: #fff; }
.chip[data-belt] { --chip-bg: var(--belt-soft); --chip-ink: var(--ink); --chip-line: color-mix(in srgb, var(--belt-fill) 40%, transparent); --chip-icon: var(--belt-fill); }
.chip-sm { min-height: 1.4rem; padding: .1rem .5rem; font-size: .75rem; }

/* ---------------------------------------------------------------- cards */
.dojo-card {
  position: relative; min-width: 0;
  background: var(--paper); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md), inset 0 0 0 1px var(--border);
  padding: 1.25rem;
}
@media (min-width: 640px) { .dojo-card { padding: 1.5rem; } }
.dojo-card.is-flat { box-shadow: inset 0 0 0 1px var(--border); }
.dojo-card.is-tight { padding: 1rem; }
.dojo-card.is-link { transition: transform .18s var(--ease-out), box-shadow .18s; }
.dojo-card.is-link:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg), inset 0 0 0 1px var(--border); }
.dojo-card__band {
  position: absolute; inset: 0 0 auto 0; height: 6px; border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  background: var(--belt-fill, var(--brand-teal));
}
.dojo-card__band[data-tone="navy"] { background: var(--brand-navy); }
.dojo-card__band[data-tone="gold"] { background: var(--gold); }
.dojo-card__band[data-tone="teal"] { background: var(--brand-teal); }
.dojo-card__band[data-tone="brand"] { background: linear-gradient(90deg, var(--brand-navy), var(--brand-teal) 60%, var(--gold)); }
.dojo-card__head { display: flex; align-items: flex-start; gap: .8rem; }
.dojo-card__title { font-family: var(--font-display); font-size: 1.125rem; font-weight: 800; line-height: 1.25; color: var(--brand-navy); }
.dojo-card__subtitle { margin-top: .15rem; font-size: .875rem; color: var(--muted); }
.icon-tile {
  --tile: 2.5rem; --tile-bg: var(--brand-teal-light); --tile-ink: var(--brand-teal-dark);
  display: inline-grid; place-items: center; flex-shrink: 0;
  width: var(--tile); height: var(--tile); border-radius: calc(var(--tile) * .32);
  background: var(--tile-bg); color: var(--tile-ink); font-size: calc(var(--tile) * .5); line-height: 1;
}
.icon-tile .icon { width: 55%; height: 55%; }
.icon-tile[data-tone="navy"] { --tile-bg: var(--brand-navy-light); --tile-ink: var(--brand-navy); }
.icon-tile[data-tone="gold"] { --tile-bg: var(--gold-light); --tile-ink: var(--gold-dark); }
.icon-tile[data-tone="flame"] { --tile-bg: #fff1e6; --tile-ink: var(--flame); }
.icon-tile[data-tone="ok"] { --tile-bg: var(--ok-bg); --tile-ink: var(--ok); }
.icon-tile[data-tone="ko"] { --tile-bg: var(--ko-bg); --tile-ink: var(--ko); }
.icon-tile[data-belt] { --tile-bg: var(--belt-soft); --tile-ink: var(--belt-fill); }

/* ------------------------------------------------------- stats and headers */
.stat { display: flex; align-items: center; gap: .8rem; min-width: 0; }
.stat__value { font-family: var(--font-display); font-weight: 900; font-size: 1.5rem; line-height: 1.1; color: var(--ink); font-variant-numeric: tabular-nums; }
.stat__label { font-size: .8125rem; font-weight: 600; color: var(--muted); }
.stat__hint { font-size: .75rem; color: var(--faint); }
.page-header { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 1rem; margin-bottom: 1.5rem; }
.page-header__title { font-family: var(--font-display); font-weight: 900; font-size: clamp(1.75rem, 3.2vw, 2.25rem); line-height: 1.12; letter-spacing: -.02em; color: var(--ink); }
.page-header__subtitle { margin-top: .35rem; max-width: 40rem; color: var(--muted); font-size: 1rem; }

/* ----------------------------------------------------------------- tabs */
.dojo-tabs {
  display: inline-flex; gap: .25rem; padding: .3rem; border-radius: 9999px;
  background: var(--bg-sunken); box-shadow: inset 0 1px 2px rgba(27, 31, 42, .06);
  max-width: 100%; overflow-x: auto; scrollbar-width: none;
}
.dojo-tab {
  display: inline-flex; align-items: center; gap: .4rem; min-height: 2.25rem; padding: .4rem 1rem;
  border-radius: 9999px; font-weight: 700; font-size: .875rem; color: var(--muted); text-decoration: none; white-space: nowrap;
  transition: background-color .15s, color .15s, box-shadow .15s;
}
.dojo-tab .icon { width: 1rem; height: 1rem; }
.dojo-tab:hover { color: var(--ink); }
.dojo-tab.is-active, .dojo-tab[aria-selected="true"], .dojo-tab[aria-current="page"] { background: var(--paper); color: var(--brand-navy); box-shadow: var(--shadow-sm); }

/* ---------------------------------------------------------------- forms */
/* Baseline for every text-like input, select and textarea (0,0,2: utilities win). */
body input:where(:not([type]), [type="text"], [type="email"], [type="search"], [type="number"], [type="password"], [type="url"], [type="tel"], [type="date"], [type="time"], [type="datetime-local"], [type="month"], [type="week"]),
body select, body textarea, .dojo-input {
  min-height: 2.75rem; padding: .6rem .85rem;
  border: 1.5px solid var(--line-strong); border-radius: .85rem;
  background-color: var(--paper); color: var(--ink);
  font-family: var(--font-body); font-size: .9375rem; line-height: 1.35;
  box-shadow: inset 0 1px 2px rgba(27, 31, 42, .05);
  transition: border-color .15s, box-shadow .15s, background-color .15s;
}
body textarea { min-height: 6rem; resize: vertical; }
body select, select.dojo-input {
  appearance: none; -webkit-appearance: none; padding-right: 2.5rem; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235f6573' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .8rem center; background-size: 1rem;
}
body select[multiple], body select[size] { background-image: none; padding-right: .85rem; }
body :is(input, select, textarea)::placeholder { color: var(--faint); opacity: 1; }
body input:where(:not([type]), [type="text"], [type="email"], [type="search"], [type="number"], [type="password"], [type="url"], [type="tel"], [type="date"], [type="time"], [type="datetime-local"], [type="month"], [type="week"]):where(:hover),
body select:where(:hover), body textarea:where(:hover) { border-color: color-mix(in srgb, var(--line-strong) 60%, var(--brand-navy)); }
body input:where(:not([type]), [type="text"], [type="email"], [type="search"], [type="number"], [type="password"], [type="url"], [type="tel"], [type="date"], [type="time"], [type="datetime-local"], [type="month"], [type="week"]):where(:focus),
body select:where(:focus), body textarea:where(:focus), .dojo-input:focus {
  outline: none; border-color: var(--brand-teal); box-shadow: var(--ring-focus);
}
body :is(input, select, textarea):where(:disabled) { background-color: var(--bg); color: var(--faint); cursor: not-allowed; }
body :is(input, select, textarea):where([aria-invalid="true"]) { border-color: var(--ko); }

/* Checkbox and radio: custom, 20 px, teal when checked. Hidden inputs (.sr-only/.hidden) are untouched. */
body input:where([type="checkbox"], [type="radio"]) {
  appearance: none; -webkit-appearance: none; display: inline-grid; place-content: center; flex-shrink: 0;
  width: 1.25rem; height: 1.25rem; margin: 0; vertical-align: -.25em; cursor: pointer;
  border: 2px solid var(--line-strong); border-radius: .4rem; background: var(--paper) no-repeat center / 80%;
  transition: background-color .15s, border-color .15s, box-shadow .15s;
}
body input:where([type="radio"]) { border-radius: 9999px; }
body input:where([type="checkbox"], [type="radio"]):where(:hover) { border-color: var(--brand-teal); }
body input:where([type="checkbox"], [type="radio"]):where(:focus-visible) { outline: none; box-shadow: var(--ring-focus); border-color: var(--brand-teal); }
body input:where([type="checkbox"]):where(:checked) {
  background-color: var(--brand-teal); border-color: var(--brand-teal);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E");
}
body input:where([type="checkbox"]):where(:indeterminate) {
  background-color: var(--brand-teal); border-color: var(--brand-teal);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 12h12' stroke='white' stroke-width='3.6' stroke-linecap='round'/%3E%3C/svg%3E");
}
body input:where([type="radio"]):where(:checked) { border-color: var(--brand-teal); background: var(--brand-teal); box-shadow: inset 0 0 0 3px var(--paper); }
body input:where([type="checkbox"], [type="radio"]):where(:disabled) { opacity: .5; cursor: not-allowed; }
/* Switch look: <input type="checkbox" class="dojo-switch"> */
body input.dojo-switch[type="checkbox"] {
  width: 2.6rem; height: 1.5rem; border-radius: 9999px; border: 0; background: var(--line-strong);
  background-image: none; position: relative; box-shadow: inset 0 1px 2px rgba(27, 31, 42, .15);
}
body input.dojo-switch[type="checkbox"]::before {
  content: ""; position: absolute; top: 3px; left: 3px; width: calc(1.5rem - 6px); height: calc(1.5rem - 6px);
  border-radius: 9999px; background: #fff; box-shadow: 0 1px 3px rgba(27, 31, 42, .3); transition: translate .2s var(--ease-spring);
}
body input.dojo-switch[type="checkbox"]:checked { background: var(--brand-teal); background-image: none; }
body input.dojo-switch[type="checkbox"]:checked::before { translate: 1.1rem 0; }

/* Field wrapper used by the form macros (also handy by hand). */
.dojo-field { display: grid; align-content: start; gap: .4rem; min-width: 0; }
.dojo-label { font-size: .875rem; font-weight: 700; color: var(--ink); }
.dojo-help { font-size: .8125rem; color: var(--muted); }
.dojo-error { font-size: .8125rem; font-weight: 600; color: var(--ko); }
.dojo-check {
  display: inline-flex; align-items: flex-start; gap: .65rem; cursor: pointer; min-height: 2.75rem; padding-block: .6rem;
  font-size: .9375rem; color: var(--ink);
}
.dojo-check input { margin-top: .1rem; }

/* --------------------------------------------------------------- tables */
/* Light baseline for tables inside <main> (utilities win). Full look: class="dojo-table". */
main table { font-variant-numeric: tabular-nums; }
main thead th {
  padding-block: .65rem; font-family: var(--font-body); font-size: .72rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
  border-bottom: 1.5px solid var(--line);
}
main tbody td { padding-block: .7rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
main tbody tr:last-child td { border-bottom: 0; }
main tbody tr { transition: background-color .12s; }
main tbody tr:hover { background-color: rgba(42, 157, 143, .045); }

.dojo-table-wrap {
  overflow-x: auto; border-radius: var(--radius-lg); background: var(--paper);
  box-shadow: var(--shadow-md), inset 0 0 0 1px var(--border);
}
.dojo-table { width: 100%; border-collapse: collapse; font-size: .875rem; }
.dojo-table th, .dojo-table td { padding: .75rem 1rem; text-align: left; }
.dojo-table thead th { background: #fbfaf7; position: sticky; top: 0; z-index: 1; }
.dojo-table tbody tr:nth-child(even) { background: #fcfbf8; }
.dojo-table tbody tr:hover { background: var(--brand-teal-light); }
.dojo-table .num, .dojo-table [data-num] { text-align: right; }

/* -------------------------------------------------------------- belt dot */
.belt-dot {
  --dot: .75rem;
  display: inline-block; flex-shrink: 0; vertical-align: middle;
  width: var(--dot); height: var(--dot); border-radius: 9999px;
  background: var(--belt, #a8a294);
  box-shadow: inset 0 0 0 1.5px var(--belt-edge, transparent), 0 1px 0 rgba(27, 31, 42, .08);
}
.belt-dot.lg { --dot: 1.25rem; }

.belt-badge {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .2rem .85rem .2rem .2rem; border-radius: 9999px;
  background: var(--paper); box-shadow: var(--shadow-xs), inset 0 0 0 1px var(--border);
  font-family: var(--font-display); font-weight: 800; font-size: .875rem; color: var(--ink); line-height: 1.2; white-space: nowrap;
  position: relative; overflow: hidden;
}
.belt-badge::before { /* soft belt-colored wash on the left */
  content: ""; position: absolute; inset: 0 auto 0 0; width: 2.4rem;
  background: linear-gradient(90deg, var(--belt-soft, transparent), transparent);
}
.belt-badge > * { position: relative; }
.belt-badge img { width: 28px; height: 28px; }
.belt-badge.sm { padding: 0; box-shadow: none; background: none; gap: .4rem; font-family: var(--font-body); font-size: .75rem; font-weight: 600; color: var(--ink-soft); overflow: visible; }
.belt-badge.sm::before { display: none; }
.belt-badge.sm .belt-dot { --dot: .65rem; }

/* --------------------------------------------------------- progress bar */
.progress-track {
  position: relative; height: .875rem; border-radius: 9999px;
  background: var(--bg-sunken); overflow: hidden;
  box-shadow: inset 0 1px 2px rgba(27, 31, 42, .1);
}
.progress-track.sm { height: .5rem; }
.progress-fill {
  position: relative; height: 100%; min-width: 0; border-radius: inherit;
  background: var(--belt-fill, var(--brand-teal));
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .18), rgba(255, 255, 255, 0) 60%);
  transition: width .7s var(--ease-out);
  animation: dojo-grow .9s var(--ease-out);
}
/* Duolingo-like highlight stripe on the fill */
.progress-fill::after {
  content: ""; position: absolute; left: .45rem; right: .45rem; top: 20%; height: 24%;
  border-radius: 9999px; background: rgba(255, 255, 255, .38);
}
.progress-track.sm .progress-fill::after { display: none; }
.progress-label { font-family: var(--font-display); }
@keyframes dojo-grow { from { width: 0; } }

/* -------------------------------------------------------- progress ring */
/* <div class="progress-ring" style="--percent: 40; --size: 56px"><svg viewBox="0 0 36 36">…</svg></div>
   The circle has r=15.9155, so its circumference is exactly 100 user units. */
.progress-ring {
  --percent: 0; --size: 56px;
  --ring-color: var(--belt-fill, var(--brand-teal)); --ring-track: var(--bg-sunken);
  position: relative; display: inline-grid; place-items: center; flex-shrink: 0;
  width: var(--size); height: var(--size);
}
.progress-ring > svg { width: 100%; height: 100%; rotate: -90deg; overflow: visible; }
.progress-ring .ring-track { stroke: var(--ring-track); }
.progress-ring .ring-fill {
  stroke: var(--ring-color); stroke-linecap: round;
  stroke-dasharray: var(--percent) 100;
  transition: stroke-dasharray .6s ease;
  animation: dojo-ring-in .9s var(--ease-out);
}
.progress-ring.is-empty .ring-fill { visibility: hidden; }
.progress-ring.is-done { --ring-color: var(--gold); }
.progress-ring__label {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 900; font-size: calc(var(--size) * .25); line-height: 1;
  color: var(--brand-navy); font-variant-numeric: tabular-nums;
}
.progress-ring__label img { width: 70%; height: 70%; }
.progress-ring__label .icon { width: 42%; height: 42%; }
@keyframes dojo-ring-in { from { stroke-dasharray: 0 100; } }

/* ---------------------------------------------------------------- XP pill */
.xp-pill {
  display: inline-flex; align-items: center; gap: .25rem;
  padding: .15rem .65rem .15rem .45rem; border-radius: 9999px;
  background: var(--gold-light); color: var(--gold-ink); box-shadow: inset 0 0 0 1px rgba(201, 143, 10, .3);
  font-family: var(--font-display); font-weight: 900; font-size: .8438rem; line-height: 1.45; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.xp-pill .icon { width: 1.05em; height: 1.05em; color: var(--gold-dark); }
.xp-pill.gain {
  background: var(--gold); color: #3d2600; box-shadow: 0 2px 0 var(--gold-dark);
  animation: dojo-pop .45s var(--ease-spring);
}
.xp-pill.gain .icon { color: #3d2600; }

/* ---------------------------------------------------------------- streak */
.streak {
  display: inline-flex; align-items: center; gap: .2rem;
  font-family: var(--font-display); font-weight: 900; color: #ea580c; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.streak-flame { display: inline-grid; place-items: center; transform-origin: 50% 85%; animation: dojo-flicker 1.8s ease-in-out infinite; }
.streak-flame .icon { width: 1.25em; height: 1.25em; }
.streak.is-off { color: var(--faint); }
.streak.is-off .streak-flame { filter: grayscale(1); opacity: .5; animation: none; }
@keyframes dojo-flicker {
  0%, 100% { scale: 1 1; rotate: -3deg; }
  50% { scale: 1.05 1.1; rotate: 3deg; }
}

/* ------------------------------------------------------------ path nodes */
/* .path-node.{locked|available|current|completed}; kinds .path-node--checkpoint / --exam.
   3D disc = face (radial highlight) + 6 px darker lip + soft drop shadow.
   Optional progress ring (.path-node__ring) wraps the disc. */
.path-node {
  --node-size: 4.5rem; --node-lip: 6px;
  --node-bg: #e8e4db; --node-edge: #cdc6b8; --node-ink: #a7a091;
  --ring-color: var(--brand-teal);
  position: relative;
  display: inline-flex; flex-direction: column; align-items: center; gap: .7rem;
  color: inherit; text-decoration: none; -webkit-tap-highlight-color: transparent;
}
.path-node__disc {
  position: relative; display: grid; place-items: center;
  width: var(--node-size); height: var(--node-size); border-radius: 9999px;
  background: radial-gradient(110% 90% at 50% 10%, color-mix(in srgb, var(--node-bg) 72%, white) 0%, var(--node-bg) 58%);
  color: var(--node-ink);
  box-shadow: 0 var(--node-lip) 0 var(--node-edge), 0 calc(var(--node-lip) + 8px) 16px -6px rgba(27, 31, 42, .28);
  font-family: var(--font-display); font-size: calc(var(--node-size) * .38); line-height: 1; font-weight: 900;
  transition: transform .12s ease, box-shadow .12s ease, filter .15s;
}
/* glossy highlight */
.path-node__disc::before {
  content: ""; position: absolute; top: 7%; left: 18%; width: 64%; height: 30%; border-radius: 9999px;
  background: radial-gradient(closest-side, rgba(255, 255, 255, .34), rgba(255, 255, 255, 0)); pointer-events: none;
}
.path-node__disc > .icon, .path-node__disc > svg:not(.path-node__ring) { position: relative; width: 44%; height: 44%; filter: drop-shadow(0 2px 0 rgba(0, 0, 0, .12)); }
.path-node__ring {
  position: absolute; inset: -11px; width: calc(100% + 22px); height: calc(100% + 22px);
  rotate: -90deg; overflow: visible; pointer-events: none; translate: 0 3px;
}
.path-node__ring .ring-track { stroke: rgba(27, 31, 42, .09); }
.path-node__ring .ring-fill { stroke: var(--ring-color); stroke-linecap: round; stroke-dasharray: var(--percent, 0) 100; animation: dojo-ring-in 1s var(--ease-out); }
.path-node__label {
  max-width: 10rem; text-align: center; line-height: 1.25;
  font-family: var(--font-display); font-weight: 800; font-size: .9rem; color: var(--ink);
}
.path-node__sublabel { margin-top: -.45rem; font-size: .75rem; font-weight: 500; color: var(--muted); text-align: center; max-width: 11rem; }

.path-node.locked { cursor: not-allowed; }
.path-node.locked .path-node__label { color: var(--faint); }
.path-node.locked .path-node__disc::before { opacity: .6; }
.path-node:has(.path-node__ring) .path-node__label { margin-top: .55rem; }
.path-node--exam .path-node__disc > .icon { width: 52%; height: 52%; }

.path-node.available, .path-node.current { --node-bg: var(--brand-teal); --node-edge: var(--brand-teal-dark); --node-ink: #fff; }
.path-node.completed { --node-bg: var(--gold); --node-edge: var(--gold-dark); --node-ink: #fff; --ring-color: var(--gold); }

/* current = where you are now: slightly bigger, halo pulse, ring shown. */
.path-node.current .path-node__disc { scale: 1.06; }
.path-node.current .path-node__disc::after,
.path-node.available.is-pulsing .path-node__disc::after {
  content: ""; position: absolute; inset: -16px; border-radius: inherit;
  border: 4px solid var(--ring-color); opacity: 0; pointer-events: none;
  animation: dojo-node-pulse 2.4s ease-out infinite;
}

a.path-node:hover .path-node__disc { filter: brightness(1.05) saturate(1.05); transform: translateY(-2px); box-shadow: 0 calc(var(--node-lip) + 2px) 0 var(--node-edge), 0 calc(var(--node-lip) + 12px) 20px -6px rgba(27, 31, 42, .3); }
a.path-node:active .path-node__disc { transform: translateY(var(--node-lip)); box-shadow: 0 0 0 var(--node-edge), 0 4px 8px -4px rgba(27, 31, 42, .3); }
a.path-node.locked:hover .path-node__disc { transform: none; filter: none; }
a.path-node:focus-visible { outline: none; }
a.path-node:focus-visible .path-node__disc { outline: 3px solid var(--brand-navy); outline-offset: 7px; }

.path-node--checkpoint { --node-size: 5rem; }
.path-node--checkpoint .path-node__disc { border-radius: 30%; }
.path-node--checkpoint .path-node__disc::after { border-radius: 34% !important; }
.path-node--exam { --node-size: 5.75rem; --node-lip: 7px; }
.path-node--exam:is(.available, .current) { --node-bg: var(--belt, var(--brand-navy)); --node-edge: var(--belt-edge, var(--brand-navy-dark)); --node-ink: var(--belt-ink, #fff); --ring-color: var(--belt-fill, var(--brand-navy)); }
.path-node--exam[data-belt="white"]:is(.available, .current) .path-node__disc { box-shadow: 0 var(--node-lip) 0 var(--node-edge), inset 0 0 0 2px var(--belt-edge), 0 calc(var(--node-lip) + 8px) 16px -6px rgba(27, 31, 42, .28); }

/* Speech bubble above the current node (the node makes room for it). */
.path-node:has(> .path-node__bubble) { margin-top: 2.9rem; }
.path-node__bubble {
  position: absolute; bottom: calc(100% + .75rem); left: 50%; translate: -50% 0; z-index: 2;
  padding: .4rem .85rem; border-radius: .8rem; white-space: nowrap;
  background: var(--paper); color: var(--brand-teal-dark);
  box-shadow: 0 3px 0 var(--line-strong), inset 0 0 0 2px var(--line);
  font-family: var(--font-display); font-weight: 900; font-size: .8125rem; letter-spacing: .06em; text-transform: uppercase;
  animation: dojo-bob 2.4s ease-in-out infinite;
}
.path-node__bubble::after {
  content: ""; position: absolute; top: 100%; left: 50%; translate: -50% -2px;
  border: 8px solid transparent; border-top-color: var(--paper);
  filter: drop-shadow(0 3px 0 var(--line-strong));
}
.path-node--exam .path-node__bubble { color: var(--brand-navy); }

/* Zigzag track: children shift left/right like a winding path. */
.path-track { display: flex; flex-direction: column; align-items: center; gap: 2rem; padding: 1rem 0; }
.path-track > * { --zig: 0; translate: calc(var(--zig) * var(--zig-scale, 1) * 1px) 0; }
.path-track > :nth-child(8n+2) { --zig: 44; }
.path-track > :nth-child(8n+3) { --zig: 72; }
.path-track > :nth-child(8n+4) { --zig: 44; }
.path-track > :nth-child(8n+6) { --zig: -44; }
.path-track > :nth-child(8n+7) { --zig: -72; }
.path-track > :nth-child(8n+8) { --zig: -44; }
@media (max-width: 380px) { .path-track { --zig-scale: .6; } }

@keyframes dojo-node-pulse {
  0% { opacity: .6; scale: .9; }
  70%, 100% { opacity: 0; scale: 1.18; }
}
@keyframes dojo-bob { 0%, 100% { translate: -50% 0; } 50% { translate: -50% -4px; } }

/* -------------------------------------------------------------- timer bar */
/* The bar empties as time runs out. JS sets --progress on .timer-bar:
   a unitless fraction of time LEFT, from 1 (full) to 0 (empty).
   Add .is-low (e.g. under 30 %) for the red warning state.
   CSS-only alternative: class "auto" + style="--duration: 10s" drains on its own
   (restart it by re-inserting the element). If you put your own child element
   inside, the built-in fill hides and you style the child. */
.timer-bar {
  --progress: 1; --timer-color: var(--brand-teal);
  position: relative; height: .875rem; border-radius: 9999px;
  background: var(--bg-sunken); overflow: hidden;
  box-shadow: inset 0 1px 2px rgba(27, 31, 42, .1);
}
.timer-bar::before {
  content: ""; position: absolute; inset: 0 auto 0 0;
  width: calc(var(--progress) * 100%); max-width: 100%;
  border-radius: inherit; background: var(--timer-color);
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .22), rgba(255, 255, 255, 0) 65%);
  transition: width .25s linear, background-color .3s;
}
.timer-bar:has(> *)::before { display: none; }
.timer-bar.is-low, .timer-bar[data-low="true"] { --timer-color: var(--ko); }
.timer-bar.is-low::before, .timer-bar[data-low="true"]::before { animation: dojo-blink .6s ease-in-out infinite alternate; }
.timer-bar.is-over { --progress: 0; }
.timer-bar.auto::before { width: 100%; animation: dojo-drain var(--duration, 10s) linear forwards; }
@keyframes dojo-drain {
  0% { width: 100%; background-color: var(--brand-teal); }
  65% { background-color: var(--gold); }
  80%, 100% { background-color: var(--ko); }
  100% { width: 0%; }
}
@keyframes dojo-blink { to { opacity: .55; } }

/* --------------------------------------------------------------- feedback */
/* .feedback-ok / .feedback-ko work on a panel or on an answer option. */
.feedback-ok, .feedback-ko { border-style: solid; border-width: 2px; border-radius: var(--radius); }
.feedback-ok { background: var(--ok-bg); color: var(--ok-ink); border-color: var(--ok); animation: dojo-pop .4s var(--ease-spring); }
.feedback-ko { background: var(--ko-bg); color: var(--ko-ink); border-color: var(--ko); animation: dojo-shake .45s ease-in-out; }
.feedback-panel { display: flex; gap: .9rem; align-items: flex-start; padding: 1rem 1.15rem; border-bottom-width: 4px; }
.feedback-panel__icon {
  display: grid; place-items: center; flex-shrink: 0; width: 2.5rem; height: 2.5rem; border-radius: 9999px;
  color: #fff; line-height: 1;
}
.feedback-panel__icon .icon { width: 1.35rem; height: 1.35rem; }
.feedback-panel__title { font-family: var(--font-display); font-size: 1.15rem; font-weight: 900; line-height: 1.25; }
.feedback-ok .feedback-panel__icon { background: var(--ok); box-shadow: 0 3px 0 var(--ok-dark); }
.feedback-ko .feedback-panel__icon { background: var(--ko); box-shadow: 0 3px 0 var(--ko-dark); }
@keyframes dojo-pop { 0% { scale: .92; } 60% { scale: 1.035; } 100% { scale: 1; } }
@keyframes dojo-shake {
  0%, 100% { translate: 0 0; }
  20% { translate: -7px 0; } 40% { translate: 6px 0; }
  60% { translate: -4px 0; } 80% { translate: 3px 0; }
}

/* Answer option (exercise choices). States: .is-selected / aria-pressed / checked radio,
   plus .feedback-ok / .feedback-ko after grading. */
.choice {
  display: flex; align-items: center; gap: .8rem; width: 100%;
  min-height: 3.25rem; padding: .85rem 1rem; text-align: left;
  background: var(--paper); color: var(--ink);
  border: 2px solid var(--line); border-bottom-width: 4px; border-radius: var(--radius);
  font: inherit; font-weight: 600; line-height: 1.4; cursor: pointer;
  transition: border-color .15s, background-color .15s, transform .08s;
}
.choice:hover { background: #fcfbf8; border-color: var(--line-strong); }
.choice:active { transform: translateY(2px); border-bottom-width: 2px; margin-bottom: 2px; }
.choice:focus-visible { outline: 3px solid color-mix(in srgb, var(--brand-teal) 60%, white); outline-offset: 2px; }
.choice.is-selected, .choice[aria-pressed="true"], input:checked + .choice {
  background: var(--brand-teal-light); border-color: var(--brand-teal); color: var(--brand-navy);
}
.choice.is-selected .choice__key, .choice[aria-pressed="true"] .choice__key, input:checked + .choice .choice__key { border-color: var(--brand-teal); color: var(--brand-teal-dark); background: var(--paper); }
.choice.feedback-ok, .choice.feedback-ko { border-width: 2px 2px 4px; }
.choice.feedback-ok { background: var(--ok-bg); border-color: var(--ok); color: var(--ok-ink); }
.choice.feedback-ko { background: var(--ko-bg); border-color: var(--ko); color: var(--ko-ink); }
.choice.feedback-ok .choice__key { border-color: var(--ok); color: var(--ok); }
.choice.feedback-ko .choice__key { border-color: var(--ko); color: var(--ko); }
.choice:disabled, .choice[aria-disabled="true"] { cursor: default; }
.choice__key {
  display: grid; place-items: center; flex-shrink: 0; width: 1.9rem; height: 1.9rem;
  border: 2px solid var(--line); border-radius: .55rem;
  font-family: var(--font-display); font-size: .8438rem; font-weight: 900; color: var(--muted);
}

/* ------------------------------------------------------------ lesson card */
/* Readable lesson card. Works with rendered HTML (p, ul, code, pre…);
   add .plain when the content is raw text with newlines. */
.card-pill {
  max-width: 42rem; min-width: 0; margin-inline: auto;
  padding: clamp(1.25rem, 4vw, 2.25rem);
  background: var(--paper); border-radius: var(--radius-xl);
  box-shadow: var(--shadow-md), inset 0 0 0 1px var(--border);
  font-family: var(--font-reading); font-size: 1.0625rem; line-height: 1.7; color: var(--ink);
  overflow-wrap: anywhere;
}
.card-pill.plain { white-space: pre-line; }
.card-pill > * + * { margin-top: .9em; }
.card-pill h1, .card-pill h2, .card-pill h3 { font-family: var(--font-display); color: var(--brand-navy); font-weight: 800; line-height: 1.25; }
.card-pill h1 { font-size: 1.5rem; }
.card-pill h2 { font-size: 1.3rem; }
.card-pill h3 { font-size: 1.125rem; }
.card-pill strong, .card-pill b { font-weight: 700; color: var(--brand-navy); }
.card-pill em { font-style: italic; }
.card-pill a { color: var(--brand-teal-dark); text-decoration: underline; text-underline-offset: 2px; }
.card-pill ul, .card-pill ol { padding-left: 1.4em; }
.card-pill ul { list-style: disc; }
.card-pill ol { list-style: decimal; }
.card-pill li + li { margin-top: .35em; }
.card-pill li::marker { color: var(--brand-teal); font-weight: 700; }
.card-pill code {
  font-family: var(--font-mono); font-size: .88em;
  background: #f4f2ed; color: #14171f; border: 1px solid var(--line);
  padding: .08em .35em; border-radius: .4em;
}
.card-pill pre {
  font-family: var(--font-mono); font-size: .875rem; line-height: 1.55;
  background: #161a24; color: #e6e3dc; padding: 1em 1.15em; border-radius: var(--radius);
  max-width: 100%; overflow-x: auto; white-space: pre; overflow-wrap: normal;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .06);
}
.card-pill pre code { background: none; border: 0; padding: 0; color: inherit; font-size: inherit; }
.card-pill blockquote {
  border-left: 4px solid var(--brand-teal); padding: .4em .25em .4em 1em;
  color: var(--ink-soft); background: var(--brand-teal-light); border-radius: 0 .9rem .9rem 0;
}
.card-pill mark, .card-pill dfn, .card-pill .term {
  font-style: normal; font-weight: 700; color: var(--brand-navy);
  background: linear-gradient(transparent 58%, #fde7a6 58%); padding: 0 .1em;
}

/* ------------------------------------------------------------ badge icons */
.badge-icon { --size: 48px; display: inline-flex; flex-direction: column; align-items: center; gap: .4rem; margin: 0; }
.badge-icon__img { position: relative; display: block; width: var(--size); height: var(--size); transition: transform .25s var(--ease-spring); }
.badge-icon:not(.is-locked):hover .badge-icon__img { transform: rotate(-6deg) scale(1.08); }
.badge-icon__img img { width: 100%; height: 100%; filter: drop-shadow(0 3px 4px rgba(27, 31, 42, .18)); }
.badge-icon figcaption { max-width: 6.5rem; text-align: center; font-size: .75rem; font-weight: 700; line-height: 1.2; color: var(--ink-soft); }
.badge-icon.is-locked img { filter: grayscale(1); opacity: .32; }
.badge-icon.is-locked figcaption { color: var(--faint); }
.badge-icon__lock {
  position: absolute; right: -2px; bottom: -2px; display: grid; place-items: center;
  width: 40%; height: 40%; min-width: 16px; min-height: 16px; border-radius: 9999px;
  background: #6b6f7a; color: #fff; box-shadow: 0 0 0 2px var(--paper);
}
.badge-icon__lock .icon, .badge-icon__lock svg { width: 58%; height: 58%; }

/* ------------------------------------------------------------ empty state */
.empty-state { padding: 2.75rem 1.5rem; text-align: center; }
.empty-state__art {
  display: inline-grid; place-items: center; width: 5.5rem; height: 5.5rem; border-radius: 1.75rem;
  background: radial-gradient(circle at 30% 25%, #fff, var(--brand-teal-light) 70%);
  color: var(--brand-teal-dark); box-shadow: var(--shadow-sm), inset 0 0 0 1px rgba(42, 157, 143, .18);
  animation: dojo-bob-y 3.2s ease-in-out infinite;
}
.empty-state__art .icon { width: 2.6rem; height: 2.6rem; }
.empty-state__art.is-illustration { width: auto; height: auto; background: none; box-shadow: none; border-radius: 0; }
.empty-state__art.is-illustration img { width: 9rem; height: auto; max-height: 9rem; }
.empty-state__emoji { display: inline-block; font-size: 2.75rem; line-height: 1; }
.empty-state__title { margin-top: 1rem; font-family: var(--font-display); font-size: 1.2rem; font-weight: 900; color: var(--ink); }
.empty-state__text { margin: .35rem auto 0; max-width: 28rem; color: var(--muted); }
@keyframes dojo-bob-y { 0%, 100% { translate: 0 0; } 50% { translate: 0 -5px; } }

/* ------------------------------------------------------------------ toast */
.dojo-toast {
  pointer-events: auto; max-width: 28rem;
  padding: .75rem 1.05rem; border-radius: var(--radius);
  background: var(--ink); color: #fff; font-weight: 600; font-size: .875rem;
  box-shadow: var(--shadow-lg);
  animation: dojo-toast-in .22s var(--ease-out);
}
@keyframes dojo-toast-in { from { opacity: 0; translate: 0 8px; } }

/* --------------------------------------------------------- reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  /* Keep the information, drop the motion. */
  .path-node.current .path-node__disc::after, .path-node.available.is-pulsing .path-node__disc::after { animation: none !important; opacity: .4; scale: 1; }
  .dojo-loadbar::before { animation: none !important; width: 100%; opacity: .7; }
  .btn.htmx-request::after, form.htmx-request .btn::after { animation: none !important; border-right-color: currentColor; opacity: .6; }
  .btn:hover, a.path-node:hover .path-node__disc { transform: none; }
  /* The quiz timer is information, not decoration: it keeps draining. */
  .timer-bar.auto::before { animation-duration: var(--duration, 10s) !important; }
  .timer-bar.is-low::before, .timer-bar[data-low="true"]::before { animation: none !important; }
}

/* ------------------------------------------------------------------ print */
@media print {
  .dojo-header, .dojo-footer, #toasts, .dojo-loadbar { display: none !important; }
  body.dojo-body { background: #fff; }
}
