/* DEPLOY-TEST-1 */
/* ===== FOUNDATION & SHELL ===== */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');

/* ---------------------------------------------------------------------------
   1) TOKENS
--------------------------------------------------------------------------- */
:root {
  /* Brand — indigo/blue base (light mode). Dark mode flips primary to orange. */
  --color-primary:        #4F46E5;
  --color-primary-hover:  #4338CA;
  --color-secondary:      #7C3AED;

  /* Orange scale + signature gradient (from landing.css).
     Used as ACCENT touches in light mode (dashboard, streaks); becomes the
     primary brand in dark mode. */
  --orange:               #F97316;
  --orange-2:             #EA580C;
  --orange-3:             #FB923C;
  --grad:                 linear-gradient(135deg,#FB923C 0%,#F97316 46%,#EA580C 100%);
  --grad-text:            linear-gradient(120deg,#FB923C 0%,#F97316 55%,#EA580C 100%);

  /* Soft brand tints — for active states, hover fills, subtle chips. */
  --orange-tint:          #FFF4EC;
  --orange-tint-2:        #FFE7D4;
  --indigo-tint:          #EEF0FE;
  --indigo-tint-2:        #E0E2FB;

  /* Surfaces */
  --color-canvas:         #F8FAFC;
  --color-surface:        #FFFFFF;

  /* Text */
  --color-text:           #111827;
  --color-body:           #374151;
  --color-muted:          #6B7280;

  /* Lines */
  --color-border:         #E5E7EB;
  --color-divider:        #F1F5F9;

  /* Status (fg / bg) */
  --color-success:        #059669;
  --color-success-bg:     #ECFDF5;
  --color-warning:        #D97706;
  --color-warning-bg:     #FFFBEB;
  --color-danger:         #DC2626;
  --color-danger-bg:      #FEF2F2;
  --color-neutral:        #6B7280;
  --color-neutral-bg:     #F3F4F6;

  /* Accuracy thresholds (reuse for all % badges/bars) */
  --color-acc-high:       var(--color-success);   /* >=70%  */
  --color-acc-mid:        var(--color-warning);    /* 50–69% */
  --color-acc-low:        var(--color-danger);     /* <50%   */
  --color-acc-none:       var(--color-neutral);    /* Sin datos */

  /* Typography */
  --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

  /* Radius — landing scale (--r1..--r5 = 10→30px) */
  --r1: 10px;
  --r2: 14px;
  --r3: 18px;
  --r4: 24px;
  --r5: 30px;
  --radius-input:  var(--r1);   /* 10px */
  --radius-card:   var(--r2);   /* 14px */
  --radius-pill:   9999px;

  /* Shadows (soft, layered, never glossy) — premium depth. */
  --shadow-card:   0 1px 2px rgba(16, 24, 40, .06), 0 1px 1px rgba(16, 24, 40, .03);
  --shadow-pop:    0 10px 30px -12px rgba(16, 24, 40, .18), 0 4px 10px -6px rgba(16, 24, 40, .10);
  --shadow-hover:  0 18px 40px -18px rgba(16, 24, 40, .22), 0 6px 16px -10px rgba(16, 24, 40, .12);
  --shadow-orange: 0 14px 30px -10px rgba(234, 88, 12, .34);
  --shadow-primary:0 10px 24px -10px rgba(79, 70, 229, .45);

  /* Spacing — 4px grid */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;

  /* Shell */
  --sidebar-width: 240px;
  --sidebar-rail-width: 68px;
  --content-max:   1180px;
  --content-max-wide: 1480px;   /* wide layouts (planner) + rail-mode reclaim */

  /* Focus ring — indigo (light). Dark mode overrides to orange. */
  --ring: 0 0 0 3px rgba(79, 70, 229, .35);

  /* ---- Short-name aliases ----------------------------------------------
     Existing inline styles + JS across the app use short token names.
     Map them onto the foundation tokens so nothing references an
     undefined variable. Prefer the --color-* names in new code. */
  --primary:        var(--color-primary);
  --primary-hover:  var(--color-primary-hover);
  --secondary:      var(--color-secondary);
  --bg:             var(--color-canvas);
  --surface:        var(--color-surface);
  --text:           var(--color-text);
  --body:           var(--color-body);
  --muted:          var(--color-muted);
  --border:         var(--color-border);
  --border-color:   var(--color-border);
  --divider:        var(--color-divider);
  --success:        var(--color-success);
  --warning:        var(--color-warning);
  --danger:         var(--color-danger);
}

/* ---------------------------------------------------------------------------
   1b) DARK THEME — token overrides
   Toggled by `body.dark` (set by Metodium.toggleDarkMode / OS preference in
   app.js). Because the short-name aliases resolve --color-* with var() at use
   time, overriding the --color-* tokens here re-themes the whole app.
   Dark mode is the ORANGE brand: primary + focus ring go orange; surfaces go
   to the landing's dark inks. Accuracy colors stay FUNCTIONAL (green/amber/red
   keep their meaning) — just brightened for contrast on dark.
--------------------------------------------------------------------------- */
body.dark {
  /* Brand — orange is the primary in dark mode */
  --color-primary:        #F97316;
  --color-primary-hover:  #FB923C;
  --color-secondary:      #6366F1;   /* indigo, brightened for dark */

  /* Surfaces — landing dark inks */
  --color-canvas:         #0B0E14;
  --color-surface:        #141A26;

  /* Text */
  --color-text:           #F1F5F9;
  --color-body:           #CBD5E1;
  --color-muted:          #94A3B8;

  /* Lines */
  --color-border:         #263042;
  --color-divider:        #1E2636;

  /* Status — brightened fg for dark; translucent tint backgrounds */
  --color-success:        #34D399;
  --color-success-bg:     rgba(5, 150, 105, .16);
  --color-warning:        #FBBF24;
  --color-warning-bg:     rgba(217, 119, 6, .16);
  --color-danger:         #F87171;
  --color-danger-bg:      rgba(220, 38, 38, .16);
  --color-neutral:        #94A3B8;
  --color-neutral-bg:     rgba(148, 163, 184, .14);

  /* Accuracy thresholds still map to the (brightened) functional colors */
  --color-acc-high:       var(--color-success);
  --color-acc-mid:        var(--color-warning);
  --color-acc-low:        var(--color-danger);
  --color-acc-none:       var(--color-neutral);

  /* Shadows — deeper on dark */
  --shadow-card:   0 1px 2px rgba(0, 0, 0, .40);
  --shadow-pop:    0 12px 32px -10px rgba(0, 0, 0, .60), 0 4px 12px -6px rgba(0, 0, 0, .40);
  --shadow-hover:  0 20px 44px -18px rgba(0, 0, 0, .66), 0 8px 18px -10px rgba(0, 0, 0, .44);
  --shadow-primary:0 10px 24px -10px rgba(249, 115, 22, .50);

  /* Focus ring — orange, a touch stronger on dark */
  --ring: 0 0 0 3px rgba(249, 115, 22, .45);

  color-scheme: dark;
}

/* ---------------------------------------------------------------------------
   2) RESET & BASE
--------------------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

* { margin: 0; }

/* The hidden attribute must always win, even over a class that sets display
   (flex/grid). JS across the app toggles visibility via [hidden]. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font-sans);
  color: var(--color-body);
  background: var(--color-canvas);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6 {
  color: var(--color-text);
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: -.02em;
}

h1 { font-size: 1.5rem; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.0625rem; }

p { color: var(--color-body); }

a {
  color: var(--color-primary);
  text-decoration: none;
  transition: color .15s ease;
}
a:hover { color: var(--color-primary-hover); }

/* Text selection — subtle orange brand accent (ties the app to the landing). */
::selection { background: var(--orange-tint-2); color: var(--orange-2); }
body.dark ::selection { background: rgba(249, 115, 22, .32); color: #FED7AA; }

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

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

button { cursor: pointer; }

ul, ol { list-style: none; padding: 0; }

:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-radius: var(--radius-input);
}

/* ---------------------------------------------------------------------------
   2b) BRAND UTILITIES  (shared with the Metodium landing — reuse for eyebrows,
   section leads and the occasional gradient display word)
--------------------------------------------------------------------------- */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--color-primary);
}
.eyebrow::before {
  content: "";
  width: 18px;
  height: 2px;
  border-radius: 2px;
  background: var(--grad);
}
.eyebrow--center { justify-content: center; }

.lead {
  font-size: 1.075rem;
  line-height: 1.6;
  color: var(--color-muted);
  max-width: 60ch;
}

/* Gradient display word (orange brand accent). Use sparingly on a headline. */
.gt {
  background: var(--grad-text);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

/* ---------------------------------------------------------------------------
   3) APP SHELL — SIDEBAR  (hooks from header.php)
--------------------------------------------------------------------------- */
.sidebar {
  position: fixed;
  inset: 0 auto 0 0;               /* top:0 right:auto bottom:0 left:0 */
  width: var(--sidebar-width);
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border-right: 1px solid var(--color-border);
  padding: var(--space-5) var(--space-4);
  z-index: 50;
  transition: width .2s ease;
}

/* Logo (anchor) */
.sidebar__logo {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-2);
  color: var(--color-text);
  /* Button reset — the logo doubles as the light/dark toggle. */
  width: 100%;
  background: none;
  border: 0;
  font: inherit;
  cursor: pointer;
}
.sidebar__logo:hover { color: var(--color-text); opacity: .85; }
.sidebar__logo-name {
  height: 36px;
  width: auto;
  object-fit: contain;
}
/* Theme logo swap: blue accents in light mode, orange in dark mode. */
.sidebar__logo-name--dark { display: none; }
body.dark .sidebar__logo-name--light { display: none; }
body.dark .sidebar__logo-name--dark  { display: block; }

/* User strip */
.sidebar__user {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-5);
  padding: var(--space-3);
  background: var(--color-divider);
  border-radius: var(--radius-card);
}
.sidebar__avatar {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  color: #fff;
  font-weight: 600;
  font-size: .8125rem;
  flex: 0 0 auto;
}
.sidebar__userinfo {
  display: flex;
  flex-direction: column;
  min-width: 0;            /* allow children to truncate */
}
.sidebar__username {
  font-weight: 600;
  font-size: .875rem;
  color: var(--color-text);
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sidebar__userrole {
  font-size: .75rem;
  font-weight: 400;
  color: var(--color-muted);
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Nav lists */
.sidebar__nav {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-top: var(--space-6);
}
.sidebar__bottom {
  margin-top: auto;
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-divider);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* Links */
.sidebar__link {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-input);
  color: var(--color-body);
  font-weight: 500;
  font-size: .9375rem;
  transition: background-color .12s ease, color .12s ease;
}
.sidebar__link:hover {
  background: var(--color-divider);
  color: var(--color-text);
}
.sidebar__link.is-active {
  background: rgba(79, 70, 229, .08);
  color: var(--color-primary);
}
/* Dark mode: the active nav pill tracks the orange primary (its text +
   accent bar already flip via var(--color-primary)). */
body.dark .sidebar__link.is-active { background: rgba(249, 115, 22, .12); }
.sidebar__link.is-active::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 60%;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
}
.sidebar__link-icon {
  display: inline-grid;
  place-items: center;
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  color: currentColor;
}
.sidebar__link-icon svg { width: 18px; height: 18px; }

/* The sidebar collapse/expand toggle was relocated to the top-left app toolbar
   (ROADMAP N23) — see .app-toolbar / .app-menu below. */

/* ---------------------------------------------------------------------------
   3b) APP SHELL — MAIN CONTENT
--------------------------------------------------------------------------- */
.main-content {
  margin-left: var(--sidebar-width);
  min-height: 100vh;
  background: var(--color-canvas);
  padding: var(--space-8) var(--space-6);
  transition: margin-left .2s ease;
}
.main-content > * {
  max-width: var(--content-max-wide);
  margin-inline: auto;
}
/* The planner is a full-width workspace (wide hero + calendar) — it uses ALL the
   available width, even with the sidebar expanded. */
.main-content > .planner-page { max-width: none; }

/* ---------------------------------------------------------------------------
   3c) APP SHELL — MOBILE (hamburger + overlay), under 1024px
   Icon swap (.icon-open/.icon-close) is driven by inline styles in header.php
   JS; CSS only sets the resting state.
--------------------------------------------------------------------------- */
.hamburger {
  display: none;
  position: fixed;
  top: var(--space-4);
  left: var(--space-4);
  z-index: 60;
  width: 40px;
  height: 40px;
  align-items: center;
  justify-content: center;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  box-shadow: var(--shadow-card);
  color: var(--color-text);
}
.hamburger .icon-open  { display: inline-flex; }
.hamburger .icon-close { display: none; }   /* JS overrides via inline style */

/* Light/dark theme toggle (ROADMAP N21). The button now lives in the sidebar
   toolbar (ROADMAP N23) styled as an .app-toolbar__btn; only the icon-swap logic
   remains here. The icon shows the CURRENT theme: sun in light mode, moon in dark. */
.theme-toggle__icon { display: inline-flex; }
.theme-toggle__icon--moon { display: none; }                    /* light mode → show sun */
body.dark .theme-toggle__icon--sun  { display: none; }
body.dark .theme-toggle__icon--moon { display: inline-flex; }   /* dark mode → show moon */

/* ---------------------------------------------------------------------------
   App toolbar (ROADMAP N23)
   A desktop-only row of icon buttons at the TOP of the sidebar (part of it, above
   the logo): ☰ menu, collapse, global search, browser back/forward. The ☰ opens a
   pop-out dropdown menu below it (each category cascades a flyout to the right on
   hover). All colours use :root tokens so dark mode adapts automatically.
--------------------------------------------------------------------------- */
.app-toolbar {
  display: none;                 /* desktop-only — shown in the media query below */
  align-self: stretch;           /* span the full width of the sidebar */
  align-items: center;
  justify-content: space-between;/* spread the buttons evenly across the bar */
  gap: 2px;
  margin-top: calc(-1 * var(--space-3));   /* pull the thin bar up toward the top edge */
  margin-bottom: var(--space-2);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-divider);   /* thin line under the bar */
  /* No pill background/border — the row blends flush into the sidebar top. */
}
.app-toolbar__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 28px;
  padding: 0;
  border: none;
  border-radius: var(--radius-input);
  background: transparent;
  color: var(--color-muted);
  cursor: pointer;
  transition: background-color .12s ease, color .12s ease;
}
.app-toolbar__btn:hover,
.app-toolbar__btn[aria-expanded="true"] {
  background: var(--color-divider);
  color: var(--color-text);
}
.app-toolbar__btn:focus-visible { outline: none; box-shadow: var(--ring); }
.app-toolbar__ico { display: inline-flex; }
.app-toolbar__ico svg { width: 18px; height: 18px; }
.app-toolbar__sep {
  width: 1px;
  height: 20px;
  margin: 0 2px;
  background: var(--color-border);
}
.app-toolbar__menuwrap { position: relative; display: inline-flex; }

/* ☰ pop-out dropdown menu — opens on CLICK of the ☰ button (JS toggles .is-open),
   floating below it. Each category cascades a flyout to the RIGHT on hover. */
.app-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 190px;
  padding: var(--space-1);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  display: none;
  z-index: 70;                   /* above the sidebar's own content */
}
.app-menu.is-open { display: block; }

.app-menu__cats { list-style: none; margin: 0; padding: 0; }
.app-menu__cat { position: relative; list-style: none; }
.app-menu__catbtn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: none;
  background: transparent;
  color: var(--color-text);
  font: inherit;
  font-size: .875rem;
  text-align: left;
  cursor: default;
  border-radius: var(--radius-input);
  white-space: nowrap;
}
.app-menu__cat:hover > .app-menu__catbtn,
.app-menu__cat:focus-within > .app-menu__catbtn { background: var(--color-divider); }
.app-menu__chev { display: inline-flex; color: var(--color-muted); }
.app-menu__chev svg { width: 16px; height: 16px; }

/* Flyout — a sub-menu popover cascading to the right on hover. */
.app-menu__flyout {
  position: absolute;
  top: calc(-1 * var(--space-1));
  left: 100%;
  min-width: 210px;
  margin: 0;
  padding: var(--space-1);
  list-style: none;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  display: none;
}
.app-menu__cat:hover > .app-menu__flyout,
.app-menu__cat:focus-within > .app-menu__flyout { display: block; }

.app-menu__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: none;
  background: transparent;
  color: var(--color-text);
  font: inherit;
  font-size: .875rem;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  border-radius: var(--radius-input);
  white-space: nowrap;
}
.app-menu__item:hover,
.app-menu__item:focus-visible { background: var(--color-divider); outline: none; }
.app-menu__label { color: inherit; }
.app-menu__sh { color: var(--color-muted); font-size: .75rem; }
.app-menu__sep {
  height: 1px;
  margin: var(--space-1) var(--space-2);
  background: var(--color-border);
  list-style: none;
}

@media (min-width: 1025px) {
  .app-toolbar { display: flex; }
  /* Collapsed rail: the row can't fit the narrow rail, so show ONLY the collapse
     button (lets the user expand again), centered. Full toolbar returns on expand. */
  body.is-nav-rail .app-toolbar { align-self: center; justify-content: center; border-bottom: none; }
  body.is-nav-rail .app-toolbar > *:not(#sidebarToggle) { display: none; }
}

/* ---------------------------------------------------------------------------
   Global search palette (ROADMAP N22)
   The search trigger button now lives in the top-left app toolbar (ROADMAP N23,
   .app-toolbar below); this section styles only the ⌘K dropdown palette it opens
   (searching temas via api/content/search.php + page actions). Colours use :root
   tokens so dark mode adapts automatically (like .theme-toggle).
--------------------------------------------------------------------------- */
.search-palette {
  position: fixed;
  inset: 0;
  z-index: 1400;             /* above tour (1000) + modals (≤1300) */
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 12vh var(--space-4) var(--space-4);
}
.search-palette__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(17, 24, 39, .4);
}
.search-palette__panel {
  position: relative;
  width: 100%;
  max-width: 560px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
}
.search-palette__inputwrap {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-divider);
}
.search-palette__inputicon { display: inline-flex; flex: 0 0 auto; color: var(--color-muted); }
.search-palette__input {
  flex: 1 1 auto;
  border: none;
  background: transparent;
  font-size: 1rem;
  color: var(--color-text);
  padding: var(--space-1) 0;
}
.search-palette__input:focus { outline: none; }
.search-palette__input::placeholder { color: var(--color-muted); }
.search-palette__esc {
  flex: 0 0 auto;
  font-size: .68rem;
  color: var(--color-muted);
  background: var(--color-divider);
  border-radius: var(--radius-input);
  padding: 2px 6px;
}
.search-palette__results {
  list-style: none;
  margin: 0;
  padding: var(--space-2);
  max-height: 56vh;
  overflow-y: auto;
}
.search-palette__group {
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--color-muted);
  padding: var(--space-2) var(--space-2) var(--space-1);
}
.search-palette__item {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-2);
  border-radius: var(--radius-input);
  cursor: pointer;
}
.search-palette__item.is-active { background: var(--color-divider); }
.search-palette__item-main { color: var(--color-text); font-weight: 500; }
.search-palette__item-sub {
  margin-left: auto;
  max-width: 45%;
  color: var(--color-muted);
  font-size: .82rem;
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.search-palette__empty {
  padding: var(--space-3) var(--space-2);
  color: var(--color-muted);
  text-align: center;
}
@media (max-width: 1024px) {
  .search-palette { padding-top: 8vh; }
}

/* ---------------------------------------------------------------------------
   Aesthetic expandable search (ROADMAP N24)
   Fixed top-right on every page. A collapsed 40px circle expands to an input bar.
   Basic + consistent in both themes (de-glow, 2026-07-11): the awake bar gets a
   plain primary-accent border + --shadow-pop in light AND dark — no animated ring,
   no neon glow. The results panel below shows click-ranked options with category
   badges. All colours use :root tokens.
--------------------------------------------------------------------------- */
.qsearch {
  position: fixed;
  top: var(--space-4);
  right: var(--space-4);
  z-index: 44;                    /* below the mobile sidebar overlay (45) + modals */
  display: flex;
  align-items: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-card);
  transition: width .5s cubic-bezier(.22, 1, .36, 1), box-shadow .35s ease, border-color .2s ease;
}
.qsearch.is-awake {
  width: min(360px, calc(100vw - 2 * var(--space-4)));
  border-color: var(--color-primary);
  box-shadow: var(--shadow-pop);
}
.qsearch__icon-btn {
  flex: 0 0 auto;
  width: 38px; height: 38px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border: none; background: transparent;
  color: var(--color-muted);
  cursor: pointer;
  border-radius: var(--radius-pill);
}
.qsearch__icon-btn:hover { color: var(--color-primary); }
.qsearch__icon-btn:focus-visible { outline: none; box-shadow: var(--ring); }
.qsearch__icon { display: inline-flex; }
.qsearch__input {
  flex: 1 1 auto;
  min-width: 0;
  height: 38px;
  border: none; background: transparent; outline: none;
  color: var(--color-text);
  font: inherit; font-size: .9rem;
  padding: 0 var(--space-3) 0 2px;
  opacity: 0;
  transition: opacity .25s ease .12s;
}
.qsearch.is-awake .qsearch__input { opacity: 1; }
.qsearch__input::placeholder { color: var(--color-muted); }

/* Results panel */
.qsearch__panel {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  width: min(360px, calc(100vw - 2 * var(--space-4)));
  max-height: 62vh;
  overflow-y: auto;
  padding: var(--space-1);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
}
.qsearch__group {
  font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--color-muted);
  padding: var(--space-2) var(--space-3) var(--space-1);
}
.qsearch__item {
  display: flex; align-items: center; gap: var(--space-3);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: none; background: transparent;
  border-radius: var(--radius-input);
  text-align: left; font: inherit; cursor: pointer;
}
.qsearch__item:hover,
.qsearch__item.is-active { background: var(--color-divider); outline: none; }
.qsearch__item-main { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.qsearch__item-label { color: var(--color-text); font-size: .875rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.qsearch__item-sub { color: var(--color-muted); font-size: .75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.qsearch__badge {
  flex: 0 0 auto;
  font-size: .64rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  padding: 2px 7px; border-radius: var(--radius-pill);
  background: var(--color-divider); color: var(--color-muted);
}
.qsearch__badge--tema    { color: var(--color-acc-high); }
.qsearch__badge--seccion { color: var(--color-primary); }
.qsearch__badge--accion  { color: var(--color-acc-mid); }
.qsearch__empty { padding: var(--space-3); color: var(--color-muted); font-size: .8125rem; }

.sidebar-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(17, 24, 39, .4);
  z-index: 45;
}
.sidebar-overlay.is-open { display: block; }

@media (max-width: 1024px) {
  .hamburger { display: inline-flex; }

  .sidebar {
    transform: translateX(-100%);
    transition: transform .2s ease;
    box-shadow: var(--shadow-pop);
  }
  .sidebar.is-open { transform: translateX(0); }

  .main-content {
    margin-left: 0;
    padding-top: calc(var(--space-8) + 40px);
  }
}

/* ---------------------------------------------------------------------------
   3d) APP SHELL — ICON-RAIL MODE (ROADMAP #6)
   When body.is-nav-rail is set (study.php toggles it on node focus), the global
   sidebar collapses to an icon-only rail: labels/logo/userinfo hidden, icons
   centered, and .main-content reclaims the freed width. Scoped to desktop only
   (min-width:1025px) so it never fights the mobile drawer (≤1024px), which uses
   transform/translateX with margin-left:0.
--------------------------------------------------------------------------- */
@media (min-width: 1025px) {
  body.is-nav-rail .sidebar {
    width: var(--sidebar-rail-width);
    padding-left: var(--space-2);
    padding-right: var(--space-2);
  }
  body.is-nav-rail .sidebar__logo-name,
  body.is-nav-rail .sidebar__userinfo,
  body.is-nav-rail .sidebar__link-label {
    display: none;
  }
  /* Center the remaining glyphs in the narrow rail. */
  body.is-nav-rail .sidebar__user {
    justify-content: center;
    padding-left: var(--space-2);
    padding-right: var(--space-2);
  }
  body.is-nav-rail .sidebar__link {
    justify-content: center;
    gap: 0;
  }
  body.is-nav-rail .main-content {
    margin-left: var(--sidebar-rail-width);
  }

  /* ROADMAP #7 — reclaim the freed width. The .main-content > * cap
     (--content-max, centered) otherwise leaves the rail's reclaimed space as an
     empty gutter. Drop the cap ONLY inside an open subject (tree + reader); the
     two-level asignaturas grid keeps its comfortable max-width. */
  body.is-nav-rail .study-wrap:has(> .subject-view:not([hidden])) {
    max-width: none;
  }

  /* Collapsing the sidebar to the rail reclaims the freed width for EVERY page —
     content goes edge-to-edge instead of leaving the freed space as an empty gutter. */
  body.is-nav-rail .main-content > * { max-width: none; }
}

/* ---------------------------------------------------------------------------
   4) SHARED COMPONENTS
--------------------------------------------------------------------------- */

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font-size: .9375rem;
  font-weight: 600;
  line-height: 1.25;
  white-space: nowrap;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease,
              box-shadow .2s ease, transform .15s ease;
}
.btn:disabled { opacity: .55; cursor: not-allowed; box-shadow: none; transform: none; }
.btn:active { transform: translateY(0); }

.btn-primary { background: var(--color-primary); color: #fff; box-shadow: var(--shadow-primary); }
.btn-primary:hover { background: var(--color-primary-hover); color: #fff; transform: translateY(-1px); }
.btn-primary:disabled:hover { transform: none; }

.btn-secondary {
  background: var(--color-surface);
  border-color: var(--color-border);
  color: var(--color-text);
  box-shadow: var(--shadow-card);
}
.btn-secondary:hover {
  background: var(--color-surface);
  border-color: var(--color-primary);
  color: var(--color-text);
  transform: translateY(-1px);
  box-shadow: var(--shadow-pop);
}

.btn-ghost { background: transparent; color: var(--color-body); }
.btn-ghost:hover { background: var(--color-divider); color: var(--color-text); }

.btn-sm { padding: var(--space-1) var(--space-4); font-size: .8125rem; }
.btn-block { display: flex; width: 100%; }

/* Card + subcomponents (card-header / card-title / card-body used across pages) */
.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--space-6);
  transition: box-shadow .2s ease, transform .15s ease, border-color .15s ease;
}
/* Opt-in: clickable cards lift on hover (add alongside .card on interactive tiles). */
.card--interactive { cursor: pointer; }
.card--interactive:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-hover);
}
.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.card-title {
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--color-text);
}
.card-body { color: var(--color-body); }

/* Badges (soft tinted pills) */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: .75rem;
  font-weight: 600;
  line-height: 1.4;
}
.badge-success { color: var(--color-success); background: var(--color-success-bg); }
.badge-warning { color: var(--color-warning); background: var(--color-warning-bg); }
.badge-danger  { color: var(--color-danger);  background: var(--color-danger-bg);  }
.badge-neutral { color: var(--color-neutral); background: var(--color-neutral-bg); }

/* Status dots (status-dot--{status}; status set by study.php JS) */
.status-dot {
  display: inline-grid;
  place-items: center;
  width: 9px;
  height: 9px;
  border-radius: var(--radius-pill);
  background: var(--color-neutral);
  color: #fff;
  flex: 0 0 auto;
  transition: width .12s ease, height .12s ease, background-color .12s ease;
}
.status-dot--pending     { background: var(--color-neutral); }
.status-dot--in_progress { background: var(--color-primary); }
/* Done: a filled green check (set inline by study.php's dotHtml). */
.status-dot--done {
  width: 17px;
  height: 17px;
  background: var(--color-success);
  box-shadow: 0 1px 2px rgba(0,0,0,.12);
}
.status-dot--done svg { display: block; }

/* Dopamine pop when a tema is freshly marked done (class added by study.php JS,
   removed after it runs). Springy scale + a radiating ring + the check springing
   in. Disabled under reduced-motion. */
@keyframes dotPop {
  0%   { transform: scale(.35); }
  45%  { transform: scale(1.45); }
  70%  { transform: scale(.88); }
  100% { transform: scale(1); }
}
@keyframes dotRing {
  0%   { box-shadow: 0 0 0 0 rgba(5,150,105,.55); }
  100% { box-shadow: 0 0 0 14px rgba(5,150,105,0); }
}
@keyframes checkSpring {
  0%   { opacity: 0; transform: scale(.2) rotate(-12deg); }
  60%  { opacity: 1; transform: scale(1.15) rotate(0deg); }
  100% { transform: scale(1) rotate(0deg); }
}
.status-dot--pop {
  animation: dotPop .55s cubic-bezier(.34,1.56,.64,1) both,
             dotRing .6s ease-out both;
}
.status-dot--pop svg { animation: checkSpring .5s cubic-bezier(.34,1.56,.64,1) both; }
@media (prefers-reduced-motion: reduce) {
  .status-dot--pop,
  .status-dot--pop svg { animation: none; }
}

/* Utility */
.text-muted { color: var(--color-muted); }

/* Form inputs */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="search"],
select,
textarea {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  color: var(--color-text);
  transition: border-color .12s ease, box-shadow .12s ease;
}
input::placeholder,
textarea::placeholder { color: var(--color-muted); }

input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
input[type="search"]:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: var(--ring);
}

/* Toast — built by app.js: #toast-container > .toast.<type> with
   .toast__icon / .toast__body (.toast__title + .toast__message) / .toast__close.
   Exit state adds .removing. Types: success | error | warning | info. */
#toast-container {
  position: fixed;
  top: var(--space-5);
  right: var(--space-5);
  z-index: 100;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: 360px;
}
.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-neutral);
  border-radius: var(--radius-input);
  box-shadow: var(--shadow-pop);
  color: var(--color-text);
  animation: toast-in .2s ease;
}
.toast.removing { animation: toast-out .2s ease forwards; }

.toast__icon { width: 18px; height: 18px; flex: 0 0 auto; margin-top: 1px; }
.toast__body { flex: 1 1 auto; min-width: 0; }
.toast__title { font-size: .875rem; font-weight: 600; color: var(--color-text); }
.toast__message { font-size: .8125rem; color: var(--color-body); }
.toast__close {
  flex: 0 0 auto;
  background: none;
  border: 0;
  font-size: 1.125rem;
  line-height: 1;
  color: var(--color-muted);
  padding: 0 var(--space-1);
}
.toast__close:hover { color: var(--color-text); }

.toast.success { border-left-color: var(--color-success); }
.toast.success .toast__icon { color: var(--color-success); }
.toast.error   { border-left-color: var(--color-danger); }
.toast.error   .toast__icon { color: var(--color-danger); }
.toast.warning { border-left-color: var(--color-warning); }
.toast.warning .toast__icon { color: var(--color-warning); }
.toast.info    { border-left-color: var(--color-primary); }
.toast.info    .toast__icon { color: var(--color-primary); }

@keyframes toast-in {
  from { opacity: 0; transform: translateX(12px); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes toast-out {
  from { opacity: 1; transform: translateX(0); }
  to   { opacity: 0; transform: translateX(12px); }
}

/* ---------------------------------------------------------------------------
   5) SHARED SYLLABUS TREE (used by Estudiar AND Tests — built by JS)
   Hooks: .tree(.tree--root) .tree__item .tree__children .tree__row(.is-selected
   .is-done) .tree__chevron(.tree__chevron--leaf) .tree__status(button)
   .tree__check(tests) .tree__name .tree__src .tree__prov + .tree-wrap.
   JS sets row padding-left inline for depth — do NOT override it.
--------------------------------------------------------------------------- */
.tree-wrap {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--space-2);
  overflow: auto;
}

.tree,
.tree__children { display: flex; flex-direction: column; }
.tree__item { display: flex; flex-direction: column; }

/* Row */
.tree__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 36px;
  padding-top: var(--space-1);
  padding-bottom: var(--space-1);
  padding-right: var(--space-3);          /* left padding set inline by JS */
  border-radius: var(--radius-input);
  color: var(--color-body);
  cursor: pointer;
  transition: background-color .1s ease;
}
.tree__row:hover { background: var(--color-divider); }
.tree__row.is-selected {
  background: rgba(79, 70, 229, .08);
  color: var(--color-primary);
}
.tree__row.is-done .tree__name { color: var(--color-muted); }
.tree__row:focus-visible { outline: none; box-shadow: var(--ring); }

/* Chevron (button-like toggle) */
.tree__chevron {
  display: inline-grid;
  place-items: center;
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  background: none;
  border: 0;
  color: var(--color-muted);
  border-radius: var(--radius-input);
  cursor: pointer;
}
.tree__chevron svg { display: block; }
.tree__chevron:hover { background: var(--color-border); color: var(--color-text); }
.tree__chevron--leaf { visibility: hidden; cursor: default; }  /* keep alignment */

/* Expand / collapse — driven by aria-expanded on the .tree__item.
   The caret SVG points right; rotating the button 90° makes it point down. */
.tree__chevron { transition: transform .18s cubic-bezier(.4,0,.2,1), background-color .1s ease, color .1s ease; }
.tree__item[aria-expanded="true"]  > .tree__row .tree__chevron { transform: rotate(90deg); }
.tree__item[aria-expanded="false"] > .tree__children { display: none; }

/* Status toggle button (Estudiar) — cycles pending/in_progress/done */
.tree__status {
  display: inline-grid;
  place-items: center;
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
  background: none;
  border: 0;
  border-radius: var(--radius-pill);
  cursor: pointer;
}
.tree__status:hover { background: var(--color-divider); }

/* Check toggle (Tests) — square selector */
.tree__check {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
  cursor: pointer;
}
.tree__check.is-checked,
.tree__check[aria-checked="true"] {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
}

/* N33 — a node the plan locks from individual selection (too deep). Shows a 🔒 where the
   checkbox would be; clicking it opens the upgrade pop-up. The name is muted to read as
   non-interactive, but the chevron still expands so the subtree stays browsable. */
.tree__lock {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  font-size: .75rem;
  line-height: 1;
  cursor: pointer;
  opacity: .6;
}
.tree__lock:hover,
.tree__lock:focus-visible { opacity: 1; outline: none; }
.tree__row--locked .tree__name { color: var(--color-muted); }

/* Labels */
.tree__name { font-size: .9375rem; font-weight: 500; color: inherit; }
.tree__src  { font-size: .75rem; color: var(--color-muted); font-weight: 400; margin-left: var(--space-1); }
.tree__prov { font-size: .75rem; color: var(--color-warning); font-weight: 500; margin-left: auto; }

/* N33 — upgrade pop-up (locked node → "elige artículos concretos"). Centered modal,
   :root tokens, hidden-attr visibility (matches the other modals). */
body.upgrade-open { overflow: hidden; }
.upgrade-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
}
.upgrade-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(16, 24, 40, .55);
}
.upgrade-modal__panel {
  position: relative;
  width: min(420px, 94vw);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  padding: var(--space-6) var(--space-5) var(--space-5);
  text-align: center;
}
.upgrade-modal__x {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  border: 0;
  background: none;
  color: var(--color-muted);
  font-size: 1rem;
  cursor: pointer;
  padding: var(--space-1);
  line-height: 1;
}
.upgrade-modal__x:hover { color: var(--color-text); }
.upgrade-modal__icon { font-size: 2rem; margin-bottom: var(--space-2); }
.upgrade-modal__title { margin: 0 0 var(--space-2); font-size: 1.0625rem; color: var(--color-text); }
.upgrade-modal__msg { margin: 0 0 var(--space-4); font-size: .875rem; line-height: 1.55; color: var(--color-body); }
.upgrade-modal__actions { display: flex; gap: var(--space-2); justify-content: center; flex-wrap: wrap; }

/* ===== DASHBOARD ===== */
/* Scoped to .dash-page so this block never collides with other pages. */

.dash-page {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

/* --- Page head: eyebrow (oposición, caps) · h1 · meta line --------------- */
.dash-head { display: flex; flex-direction: column; gap: var(--space-1); }
.dash-head__eyebrow {
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--color-primary);
}
.dash-head h1 { font-size: 1.9375rem; line-height: 1.12; letter-spacing: -.025em; font-weight: 800; }
.dash-head__meta {
  font-size: .9375rem;
  color: var(--color-muted);
  max-width: 70ch;
}

/* --- Gamification (ROADMAP #17): streak + objetivo + logros, and Tu día -- */
/* Tu día card row (full width; streak now lives in the rollup grid). */
.dash-gami { display: block; }
.tudia-meta { font-size: .8125rem; color: var(--color-muted); font-variant-numeric: tabular-nums; }

/* Streak as a 4th rollup stat box that expands (hover / tap) into the week
   activity row + logros. `.rollup-cards` is display:contents so the 3 tree-stat
   cards and the streak card share one grid. */
.rollup-cards { display: contents; }
.stat-card--streak { position: relative; cursor: pointer; overflow: visible; }
.stat-card--streak:hover { transform: none; box-shadow: var(--shadow-card); }
.stat-card--streak:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.gami-streak__unit { font-size: 1.25rem; font-weight: 700; color: var(--color-muted); }
.stat-card--streak.is-pending .stat-card__icon--amber { filter: grayscale(.35); opacity: .9; }
.stat-card--streak.is-pending .stat-card__sub { color: var(--color-warning); font-weight: 600; }

/* The expanding panel under the streak box. */
.streak-pop {
  position: absolute;
  top: 100%;
  right: 0;
  left: auto;
  z-index: 30;
  margin-top: var(--space-2);
  padding: var(--space-4);
  min-width: 280px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity .14s ease, transform .14s ease, visibility .14s ease;
  pointer-events: none;
}
.stat-card--streak:hover .streak-pop,
.stat-card--streak:focus-within .streak-pop,
.stat-card--streak.is-open .streak-pop {
  opacity: 1;
  visibility: visible;
  transform: none;
  pointer-events: auto;
}
.streak-pop .gami-week { margin: 0 0 var(--space-4); }

/* This-week activity row (L M X J V S D). */
.gami-week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--space-2);
  margin: var(--space-5) 0;
}
.gami-daycol { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.gami-day__lbl { font-size: .7rem; font-weight: 700; letter-spacing: .04em; color: var(--color-muted); }
.gami-day {
  width: 100%;
  max-width: 40px;
  aspect-ratio: 1 / 1;
  border-radius: 9px;
  display: grid;
  place-items: center;
  background: var(--color-divider);
  color: #fff;
  transition: transform .15s ease;
}
.gami-day svg { width: 15px; height: 15px; }
.gami-day--done   { background: var(--grad); box-shadow: var(--shadow-orange); }
.gami-day--done:hover { transform: translateY(-1px); }
.gami-day--today  { background: transparent; border: 2px dashed var(--orange-3); color: var(--orange-2); }
.gami-day__dot    { width: 6px; height: 6px; border-radius: 50%; background: var(--orange-2); }
.gami-day--future, .gami-day--miss { background: var(--color-divider); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .015); }
/* Break marker (N52): a past day with no activity — where the streak was broken. */
.gami-day--break { background: var(--color-danger-bg); color: var(--color-danger); box-shadow: none; }

/* Logros recientes — badge circles. */
.gami-logros__head {
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--color-muted);
  margin-bottom: var(--space-3);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.gami-logros__row { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.gami-logro {
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 1.25rem;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
}
.gami-logro--earned { border-color: var(--color-warning); background: var(--color-warning-bg); }
.gami-logro--locked { opacity: .5; filter: grayscale(.6); }

/* Today's minutes objetivo bar. */
.tudia-goal { margin-bottom: var(--space-4); }
.tudia-goal__top {
  display: flex;
  justify-content: space-between;
  font-size: .8125rem;
  color: var(--color-muted);
  margin-bottom: var(--space-2);
}
.tudia-goal__val { color: var(--color-text); font-weight: 600; font-variant-numeric: tabular-nums; }
.tudia-goal__bar {
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--color-divider);
  overflow: hidden;
}
.tudia-goal__fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--grad);
  transition: width .3s ease;
}

/* ── Dashboard top row: 2×2 stat grid (left) + big streak box (right) ─────── */
.dash-top {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
  gap: var(--space-5);
  align-items: stretch;
  margin-bottom: var(--space-5);
}
.dash-top__stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-5);
}
.streak-box {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  justify-content: space-between;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--space-6);
}
.streak-box__head {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}
.streak-box__flame {
  flex: 0 0 auto;
  width: 52px;
  height: 52px;
  border-radius: var(--radius-card);
  display: grid;
  place-items: center;
  font-size: 1.6rem;
  background: rgba(249, 115, 22, .12);
}
.streak-box__headmain { flex: 1 1 auto; min-width: 0; }
.streak-box__num {
  font-size: 2.2rem;
  font-weight: 800;
  letter-spacing: -.02em;
  line-height: 1;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}
.streak-box__sub { margin-top: 4px; font-size: .8125rem; color: var(--color-muted); }
.streak-box.is-pending .streak-box__sub { color: var(--orange-2); font-weight: 600; }
.streak-box__record {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}
.streak-box__record-lbl { font-size: .8125rem; color: var(--color-muted); }
.streak-box__record-val {
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}
.streak-box .gami-week { margin: 0; }
.streak-box__foot {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding-top: var(--space-5);
  border-top: 1px solid var(--color-divider);
}
.streak-box__goal { margin-bottom: 0; }

/* Stack the dashboard top row on narrow screens. */
@media (max-width: 900px) {
  .dash-top { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .dash-top__stats { grid-template-columns: 1fr; }
}

/* Today's task list. */
.tudia-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.tudia-task {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: 10px;
  transition: background .13s ease;
}
.tudia-task:hover { background: var(--color-canvas); }
.tudia-task__check {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  border: 1.5px solid var(--color-border);
  border-radius: 50%;
  font-size: .7rem;
  line-height: 1;
  color: var(--color-success);
  background: transparent;
  padding: 0;
  font-family: inherit;
  -webkit-appearance: none;
  appearance: none;
}
.tudia-task__check--btn { cursor: pointer; transition: border-color .12s ease, background .12s ease; }
/* N8 fix (2026-07-08): this class now only decorates the shared .opocheck__box input
   (dashboard.php "Tu día") for its cursor/JS hook — the old green :hover border/background
   below fought the opocheck grey→primary hover/check styling (border-color set here always
   wins over opocheck's currentColor approach), so it's dropped. Kept :disabled/:focus-visible,
   which don't clash. */
.tudia-task__check--btn:disabled { opacity: .5; cursor: default; }
.tudia-task__check--btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.tudia-task--done .tudia-task__check {
  border-color: var(--color-success);
  background: var(--color-success-bg);
}
.tudia-task__kind { flex: 0 0 auto; }
.tudia-task__name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: .9375rem;
  color: var(--color-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tudia-task--done .tudia-task__name { color: var(--color-muted); text-decoration: line-through; }
.tudia-cta { margin-top: var(--space-4); }
.tudia-rest { color: var(--color-muted); font-size: .9375rem; margin: 0; }
.tudia-empty { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-3); }
.tudia-empty p { color: var(--color-muted); font-size: .9375rem; margin: 0; }

/* On small screens the streak panel expands inline (no hover) to avoid an
   off-screen absolute popover; it reveals only when tapped (.is-open). */
@media (max-width: 768px) {
  .streak-pop {
    position: static;
    min-width: 0;
    margin-top: var(--space-3);
    padding: 0;
    border: none;
    box-shadow: none;
    background: transparent;
  }
  .stat-card--streak:hover .streak-pop,
  .stat-card--streak:focus-within .streak-pop { opacity: 0; visibility: hidden; transform: none; pointer-events: none; }
  .stat-card--streak.is-open .streak-pop { opacity: 1; visibility: visible; pointer-events: auto; }
}

/* Loading / empty states */
.dash-state {
  color: var(--color-muted);
  font-size: .9375rem;
  padding: var(--space-4) var(--space-1);
}

/* ── Shared empty-state component (ROADMAP #22) ─────────────────────────────
   One consistent "nothing here yet" block: emoji icon + title + hint + an
   optional CTA (reuses .btn). Used app-wide for PRIMARY empty states only —
   never loading placeholders, inline errors or toasts. Token-driven, so it
   tracks the theme (indigo light / orange dark) in both modes. */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-2);
  padding: var(--space-6) var(--space-4);
  color: var(--color-muted);
}
.empty-state__icon { font-size: 2rem; line-height: 1; opacity: .9; }
.empty-state__title {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--color-text);
}
.empty-state__hint {
  margin: 0;
  max-width: 36ch;
  font-size: .9rem;
  line-height: 1.5;
  color: var(--color-muted);
}
.empty-state__hint a { color: var(--color-primary); }
.empty-state .btn { margin-top: var(--space-2); }

/* --- Oposición rollup: one card, 4-up stat grid + sub line -------------- */
.dash-page .rollup-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-6);
}
.dash-page .rollup-stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.dash-page .rollup-stat .num {
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}
.dash-page .rollup-stat .lbl {
  font-size: .8125rem;
  color: var(--color-muted);
}
.dash-page .rollup-sub {
  margin-top: calc(-1 * var(--space-6));   /* tighten under the stat grid */
  font-size: .8125rem;
  color: var(--color-muted);
}

/* --- Rollup stat cards (icon + big number + caption) -------------------- */
.dash-page .stat-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-5);
}
.stat-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  transition: transform .2s cubic-bezier(.22, 1, .36, 1), box-shadow .2s ease, border-color .2s ease;
}
/* Read-only summary cards: lift gently on hover (not clickable). */
.stat-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-pop); border-color: var(--color-border-strong, var(--color-border)); }
.stat-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.stat-card__label { font-size: .8125rem; font-weight: 500; color: var(--color-muted); }
.stat-card__icon {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  flex: 0 0 auto;
}
.stat-card__icon--indigo { background: rgba(79, 70, 229, .1);  color: #4F46E5; }
.stat-card__icon--green  { background: var(--color-success-bg); color: var(--color-success); }
.stat-card__icon--amber  { background: var(--color-warning-bg); color: var(--color-warning); }
.stat-card__icon--violet { background: rgba(124, 58, 237, .1); color: var(--color-secondary); }
.stat-card__icon--orange { background: rgba(249, 115, 22, .12); color: var(--orange-2); }
.stat-card__num {
  font-size: 2.25rem;
  font-weight: 800;
  letter-spacing: -.035em;
  line-height: 1.05;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
}
.stat-card__sub { font-size: .8125rem; color: var(--color-muted); }
/* Orange progress bar inside a stat card (e.g. Precisión global). */
.stat-card__bar {
  height: 8px;
  margin-top: var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-divider);
  overflow: hidden;
}
.stat-card__barfill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--grad);
  transition: width .3s ease;
}
/* Skeleton placeholder shown before stats load */
.dash-page .skeleton-num {
  display: inline-block;
  width: 2.5ch;
  height: 1.5rem;
  border-radius: var(--radius-input);
  background: var(--color-divider);
  animation: dash-skeleton 1.2s ease-in-out infinite;
}
@keyframes dash-skeleton {
  0%, 100% { opacity: 1; }
  50%      { opacity: .45; }
}

/* --- Section title above the subject cards ------------------------------ */
.dash-section-title {
  font-size: 1.125rem;
  font-weight: 700;
  letter-spacing: -.015em;
  color: var(--color-text);
  margin-bottom: calc(-1 * var(--space-4));  /* tighten to the grid below */
}

/* --- Subject cards (responsive grid) ----------------------------------- */
.subj-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: var(--space-5);
}
.subj-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: transform .16s ease, box-shadow .2s ease, border-color .16s ease;
}
/* Clickable subject cards (link to study.php): lift on hover. */
.subj-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-hover); border-color: var(--color-border); }
.subj-card:hover .subj-card__title { color: var(--color-primary); }
.subj-card:focus-visible { outline: none; box-shadow: var(--ring); }

.subj-card__head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.subj-card__title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--color-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.subj-card__prov { flex: 0 0 auto; }   /* provisional badge (uses .badge) */

/* Last-studied label, pinned to the top-right of the card head. */
.subj-card__last {
  flex: 0 0 auto;
  margin-left: auto;
  white-space: nowrap;
  font-size: .75rem;
  color: var(--color-muted);
  font-variant-numeric: tabular-nums;
}
.subj-card__last--none { font-style: italic; opacity: .8; }

/* Progress (Estudiado) */
.subj-progress { display: flex; flex-direction: column; gap: var(--space-2); }
.subj-progress__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-size: .8125rem;
  color: var(--color-muted);
}
.subj-progress__pct {
  font-weight: 700;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}
.subj-progress__bar {
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--color-divider);
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .02);
}
.subj-progress__fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--color-primary);   /* default before threshold modifier */
  transition: width .3s ease;
}
/* Fill color follows the accuracy threshold (set by dashboard.php JS) */
.subj-progress__fill--high { background: var(--color-acc-high); }
.subj-progress__fill--mid  { background: var(--color-acc-mid); }
.subj-progress__fill--low  { background: var(--color-acc-low); }
.subj-progress__fill--none { background: var(--color-acc-none); }

/* Stats row: N en banco · acierto pill · N por repasar */
.subj-stats {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  font-size: .8125rem;
  color: var(--color-body);
}
.subj-stat-num strong {
  font-weight: 700;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}
.subj-stat-sep { color: var(--color-border); }

/* CTAs */
.subj-cta {
  display: flex;
  gap: var(--space-2);
  margin-top: auto;
  padding-top: var(--space-1);
}
.subj-cta .btn { flex: 1 1 0; }

/* --- Responsive ---------------------------------------------------------- */
@media (max-width: 900px) {
  .dash-page .stat-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 768px) {
  .dash-page .rollup-grid { grid-template-columns: repeat(2, 1fr); row-gap: var(--space-5); }
  .subj-grid { grid-template-columns: 1fr; }
}

/* ===== PERFIL ===== */
/* The account page: a read-only overview (identity + stat cards + Ajustes
   summary) followed by the editable oposición / account forms. Reuses the
   global .stat-card / .badge / foundation tokens; all rules are pf-* scoped. */

.pf-page {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  max-width: 880px;
  margin-inline: 0;            /* left-align the settings column */
}

/* --- Page head: eyebrow (caps) · h1 ------------------------------------- */
.pf-header { display: flex; flex-direction: column; gap: var(--space-1); }
.pf-header__eyebrow {
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--color-primary);
}
.pf-header__title { font-size: 1.9375rem; line-height: 1.12; letter-spacing: -.025em; font-weight: 800; }

/* --- Identity card (avatar + name/email/role) -------------------------- */
.pf-identity {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--space-6);
  transition: transform .2s cubic-bezier(.22, 1, .36, 1), box-shadow .2s ease, border-color .2s ease;
}
.pf-identity:hover { transform: translateY(-2px); box-shadow: var(--shadow-hover); }
.pf-identity__avatar {
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  border-radius: var(--radius-pill);
  display: grid;
  place-items: center;
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--color-primary);
  background: rgba(79, 70, 229, .1);
}
.pf-identity__info {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}
.pf-identity__name {
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--color-text);
}
.pf-identity__email {
  font-size: .875rem;
  color: var(--color-muted);
  overflow: hidden;
  text-overflow: ellipsis;
}
.pf-identity__role {
  align-self: flex-start;
  margin-top: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: .75rem;
  font-weight: 600;
  color: var(--color-primary);
  background: rgba(79, 70, 229, .1);
}

/* --- Overview stat cards (2×2 grid; reuses global .stat-card) ----------- */
.pf-stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-5);
}

/* --- Ajustes summary (read-only rows) ---------------------------------- */
.pf-summary {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--space-6) var(--space-6) var(--space-2);
  transition: transform .2s cubic-bezier(.22, 1, .36, 1), box-shadow .2s ease, border-color .2s ease;
}
.pf-summary:hover { transform: translateY(-2px); box-shadow: var(--shadow-hover); }
.pf-summary__title {
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -.012em;
  margin-bottom: var(--space-2);
}
.pf-summary__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-top: 1px solid var(--color-divider);
}
.pf-summary__label { font-size: .875rem; color: var(--color-muted); }
.pf-summary__value {
  font-size: .875rem;
  font-weight: 600;
  color: var(--color-text);
  text-align: right;
}
/* Not-set-yet placeholders (no oposición / no exam date) read as intentional
   muted text instead of a stark full-strength "—" / "Sin fecha". */
.pf-summary__value--empty { color: var(--color-muted); font-weight: 500; }
.pf-stats .stat-card__num--empty { color: var(--color-muted); font-weight: 700; letter-spacing: -.02em; }

/* --- Logros (achievements) panel — N41 --------------------------------- */
.pf-logros {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--space-6);
  margin-top: var(--space-5);
}
.pf-logros__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.pf-logros__title {
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -.012em;
}
.pf-logros__count {
  font-size: .8125rem;
  font-weight: 600;
  color: var(--color-muted);
  font-variant-numeric: tabular-nums;
}
.pf-logros__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--space-3);
}
.pf-logros__loading,
.pf-logros__empty {
  grid-column: 1 / -1;
  font-size: .875rem;
  color: var(--color-muted);
  padding: var(--space-3) 0;
}
.pf-logro {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
}
.pf-logro__icon {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 1.25rem;
  border: 1px solid var(--color-border);
  background: var(--color-divider);
}
.pf-logro__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pf-logro__name {
  font-size: .9rem;
  font-weight: 600;
  color: var(--color-text);
}
.pf-logro__desc {
  font-size: .8125rem;
  color: var(--color-muted);
  line-height: 1.35;
}
.pf-logro__meta {
  font-size: .75rem;
  font-weight: 600;
  color: var(--color-muted);
  margin-top: 2px;
}
.pf-logro--earned {
  border-color: var(--color-warning);
  background: var(--color-warning-bg);
}
.pf-logro--earned .pf-logro__icon {
  border-color: var(--color-warning);
  background: var(--color-surface);
}
.pf-logro--earned .pf-logro__meta { color: var(--color-warning); }
.pf-logro--locked { opacity: .72; }
.pf-logro--locked .pf-logro__icon { filter: grayscale(.6); opacity: .8; }

/* Admin: inline checkbox toggle (Logros setting, N41). */
.admin-switch {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
}
.admin-switch input { width: auto; margin: 0; cursor: pointer; }

/* --- Section divider before the editable forms ------------------------- */
.pf-edit-title {
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -.015em;
  margin-top: var(--space-4);
  padding-top: var(--space-5);
  border-top: 1px solid var(--color-border);
}

/* --- Editable sections (oposición + account) --------------------------- */
.pf-section {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.pf-section__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--color-divider);
}
.pf-section__icon {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-input);
  display: grid;
  place-items: center;
  font-size: 1.0625rem;
}
.pf-section__icon--indigo { background: rgba(79, 70, 229, .1);  color: var(--color-primary); }
.pf-section__icon--slate  { background: var(--color-neutral-bg); color: var(--color-body); }
.pf-section__icon--rose   { background: var(--color-danger-bg);  color: var(--color-danger); }
.pf-section__title { font-size: 1.0625rem; font-weight: 700; letter-spacing: -.012em; }
.pf-section__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-6);
}

/* --- Rows, labels, inputs ---------------------------------------------- */
.pf-row { display: flex; flex-direction: column; gap: var(--space-2); }
.pf-label {
  font-size: .875rem;
  font-weight: 600;
  color: var(--color-body);
}
.pf-input {
  width: 100%;
  font: inherit;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  padding: var(--space-3) var(--space-4);
  transition: border-color .14s ease, box-shadow .14s ease;
}
.pf-input::placeholder { color: var(--color-muted); }
.pf-input:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: var(--ring);
}
.pf-hint { font-size: .8125rem; color: var(--color-muted); }

/* --- Oposición search + dropdown --------------------------------------- */
.pf-search-wrap { position: relative; }
.pf-dropdown {
  position: absolute;
  top: calc(100% + var(--space-1));
  left: 0;
  right: 0;
  z-index: 20;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  box-shadow: var(--shadow-pop);
  max-height: 280px;
  overflow-y: auto;
  display: none;
}
.pf-dropdown.is-open { display: block; }
.pf-dropdown__item {
  padding: var(--space-3) var(--space-4);
  cursor: pointer;
  border-bottom: 1px solid var(--color-divider);
}
.pf-dropdown__item:last-child { border-bottom: none; }
.pf-dropdown__item:hover,
.pf-dropdown__item:focus {
  background: var(--color-divider);
  outline: none;
}
.pf-dropdown__name { font-size: .9375rem; font-weight: 600; color: var(--color-text); }
.pf-dropdown__meta { font-size: .8125rem; color: var(--color-muted); }
.pf-dropdown__empty { padding: var(--space-4); font-size: .875rem; color: var(--color-muted); }

/* --- Selected-oposición badge (shown after pick) ----------------------- */
.pf-badge {
  display: none;
  align-items: center;
  gap: var(--space-2);
  align-self: flex-start;
  padding: var(--space-1) var(--space-1) var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  font-size: .875rem;
  font-weight: 600;
  color: var(--color-primary);
  background: rgba(79, 70, 229, .1);
}
.pf-badge.is-visible { display: inline-flex; }
.pf-badge__clear {
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border: none;
  border-radius: var(--radius-pill);
  font-size: .75rem;
  line-height: 1;
  cursor: pointer;
  color: var(--color-primary);
  background: rgba(79, 70, 229, .14);
}
.pf-badge__clear:hover { background: rgba(79, 70, 229, .24); }

/* --- Days-until-exam pill ---------------------------------------------- */
.pf-days-pill {
  display: none;
  align-items: center;
  gap: var(--space-2);
  align-self: flex-start;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  font-size: .8125rem;
  font-weight: 600;
  color: var(--color-secondary);
  background: rgba(124, 58, 237, .1);
}
.pf-days-pill.is-visible { display: inline-flex; }

/* --- Save row, button, spinner, error ---------------------------------- */
.pf-save-row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
}
.pf-save-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font: inherit;
  font-weight: 600;
  color: #fff;
  background: var(--color-primary);
  border: none;
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-primary);
  padding: var(--space-3) var(--space-5);
  cursor: pointer;
  transition: background .14s ease, transform .16s cubic-bezier(.22, 1, .36, 1), box-shadow .16s ease;
}
.pf-save-btn:hover { background: var(--color-primary-hover); transform: translateY(-1px); box-shadow: var(--shadow-hover); }
.pf-save-btn:focus-visible { outline: none; box-shadow: var(--ring); }
.pf-save-btn:disabled { opacity: .65; cursor: default; box-shadow: none; transform: none; }
.pf-spinner {
  display: none;
  width: 14px;
  height: 14px;
  border: 2px solid rgba(255, 255, 255, .45);
  border-top-color: #fff;
  border-radius: var(--radius-pill);
  animation: pf-spin .7s linear infinite;
}
@keyframes pf-spin { to { transform: rotate(360deg); } }
.pf-error {
  font-size: .875rem;
  color: var(--color-danger);
  display: none;
}
.pf-error.is-visible { display: inline; }

/* --- Danger zone (account deletion) ------------------------------------- */
.pf-section--danger {
  border-color: var(--color-danger);
  background: var(--color-danger-bg);
}
.pf-section--danger .pf-section__title { color: var(--color-danger); }
.pf-danger-note {
  font-size: .875rem;
  color: var(--color-body);
  margin-bottom: var(--space-4);
}
.pf-delete-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font: inherit;
  font-weight: 600;
  color: #fff;
  background: var(--color-danger);
  border: none;
  border-radius: var(--radius-input);
  padding: var(--space-3) var(--space-5);
  cursor: pointer;
  transition: background .14s ease;
}
.pf-delete-btn:hover { background: #B91C1C; }
.pf-delete-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--color-danger-bg), 0 0 0 4px var(--color-danger); }
.pf-delete-btn:disabled { opacity: .65; cursor: default; }

/* --- Accent consistency: dark mode tracks the orange primary ------------ */
/* The indigo tints above pair with var(--color-primary) foregrounds, which
   already go orange in dark mode; retint their backgrounds so background and
   foreground both track orange. Light mode keeps indigo (the light primary);
   the días-pill keeps the indigo secondary; danger + accuracy colors are
   functional and left untouched. */
body.dark .pf-identity__avatar,
body.dark .pf-identity__role,
body.dark .pf-section__icon--indigo,
body.dark .pf-badge { background: rgba(249, 115, 22, .14); }
body.dark .pf-badge__clear { background: rgba(249, 115, 22, .22); }
body.dark .pf-badge__clear:hover { background: rgba(249, 115, 22, .32); }
body.dark .pf-days-pill { background: rgba(99, 102, 241, .16); }
/* Overview stat icons (profile-scoped so the shared dashboard cards are untouched):
   the "Temas estudiados" icon is a PRIMARY accent (indigo in light) → flip to orange
   in dark like every other primary tint; the "Días hasta el examen" icon is the
   SECONDARY accent, whose foreground token goes indigo in dark, so retint its
   background to match (violet in light, indigo in dark — pairs with the días-pill). */
body.dark .pf-stats .stat-card__icon--indigo { background: rgba(249, 115, 22, .14); color: var(--orange-2); }
body.dark .pf-stats .stat-card__icon--violet { background: rgba(99, 102, 241, .16); }

/* --- Responsive --------------------------------------------------------- */
@media (max-width: 640px) {
  .pf-stats { grid-template-columns: 1fr; }
  .pf-identity { flex-direction: column; align-items: flex-start; text-align: left; }
}

/* ===== ESTUDIAR ===== */
/* Scoped to .study-wrap. Reuses foundation tokens, .btn, .badge and the shared
   .tree widget; only adds Estudiar-specific rules. */

.study-wrap {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

/* --- Header ------------------------------------------------------------- */
.study-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
}
.study-eyebrow {
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--color-primary);
}
.study-title { font-size: 1.9375rem; line-height: 1.12; letter-spacing: -.025em; font-weight: 800; margin-top: 2px; }
.study-subtitle { font-size: .9375rem; color: var(--color-muted); margin-top: var(--space-1); }

/* --- Two-column board: tree (main) + reader (side) ---------------------- */
/* ROADMAP #7 — three grid tracks: tree | drag-splitter | reader. The middle
   track replaces the old gap (24px) so the default spacing is unchanged; it
   carries the resize handle. Once the user drags, JS adds .is-resized and sets
   --study-tree-w (px): the tree becomes that fixed width and the reader absorbs
   the rest (1fr). */
.study-board {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--study-resizer-w, 24px) 340px;
  align-items: start;
}
.study-board.is-resized {
  grid-template-columns: var(--study-tree-w, 1fr) var(--study-resizer-w, 24px) minmax(320px, 1fr);
}
/* When the reader is closed, reclaim its column (and hide the splitter). The
   :has() rule outranks .is-resized, so a closed reader always collapses to one
   column even after a manual resize. */
.study-board:has(.reader-card.is-closed) { grid-template-columns: 1fr; }
.study-board:has(.reader-card.is-closed)   .study-board__resizer,
.study-board:has(.reader-card.is-modal)    .study-board__resizer,
.study-board:has(.reader-card.is-fullscreen) .study-board__resizer { display: none; }

/* ROADMAP N7 — clean import/review screen: while treeProposal is visible,
   study.php toggles body.is-importing (syncImportMode()). Hide the reader box
   + the surrounding hint copy so the review is just the tree + save, and let
   the tree/proposal editor reclaim the freed width — same collapse pattern as
   the "reader closed" rule above. */
body.is-importing .study-board { grid-template-columns: 1fr; }
body.is-importing .study-board__resizer,
body.is-importing .study-board__side { display: none; }
body.is-importing .study-subtitle,
body.is-importing .subjects-card__hint,
body.is-importing #buildStatus { display: none; }

/* ROADMAP N10 — an empty asignatura (no temas yet) has nothing to read, so hide
   the reader box + resizer and let the tree/add-content builder reclaim the full
   width. study.php toggles body.is-empty-subject in enterSubject()/showGrid();
   cleared automatically once the subject gains content. Same collapse pattern as
   is-importing above. */
body.is-empty-subject .study-board,
/* also beat a persisted .is-resized grid (specificity), else --study-tree-w keeps
   the lone main column narrow instead of full width. */
body.is-empty-subject .study-board.is-resized { grid-template-columns: 1fr; }
body.is-empty-subject .study-board__resizer,
body.is-empty-subject .study-board__side { display: none; }

.study-board__main {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
  /* Establish an inline-size container so the tree text can scale with the
     box width (clamp + cqi below) — covers both drag-resize and full-width. */
  container-type: inline-size;
  container-name: studytree;
}
.study-board__side { position: sticky; top: var(--space-6); }

/* Drag handle between tree and reader. Full-height grab strip with a centered
   hairline that thickens/colours on hover, focus and during a drag. */
.study-board__resizer {
  align-self: stretch;
  position: relative;
  min-height: 60px;
  cursor: col-resize;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}
.study-board__resizer::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  transform: translateX(-50%);
  background: var(--color-border);
  border-radius: 2px;
  transition: width .1s ease, background-color .1s ease;
}
.study-board__resizer:hover::before,
.study-board__resizer:focus-visible::before,
.study-board__resizer.is-dragging::before {
  width: 3px;
  background: var(--color-primary);
}
.study-board__resizer:focus-visible { outline: none; }

/* Tree text scales with the tree box width (ROADMAP #7). cqi = 1% of the
   .study-board__main inline size, so narrowing the box (drag) shrinks the font
   and widening it (full-width rail) grows it, bounded by the clamp. */
.study-board__main .tree__name { font-size: clamp(.8125rem, .69rem + .92cqi, 1rem);
  /* N26(a): long asignatura/block/tema names (e.g. from a freshly imported PDF) used to
     wrap and overflow their row — clip to one line with an ellipsis instead. min-width:0
     lets the flex item shrink; the row already sets nameEl.title so the full name shows
     on hover. */
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.study-board__main .tree__src  { font-size: clamp(.6875rem, .60rem + .55cqi, .8125rem); }

/* --- Subjects container (no card chrome; each subject is its own card) -- */
.subjects-card { display: flex; flex-direction: column; gap: var(--space-3); }
.subjects-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}
.subjects-card__title { font-size: .8125rem; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--color-muted); }
.subjects-card__hint  { font-size: .8125rem; color: var(--color-muted); }

/* Inline create row */
.subject-create { display: flex; gap: var(--space-2); align-items: center; }
.subject-create__input { flex: 1 1 auto; }

/* Neutralise the shared tree-wrap card look on this page only. */
.study-board .tree-wrap {
  background: transparent;
  border: 0;
  box-shadow: none;
  padding: 0;
  border-radius: 0;
  overflow: visible;
}
.study-board .tree--root { gap: var(--space-3); }

/* Each top-level subject = a white card that expands to hold its sub-tree. */
.study-board .tree--root > .tree__item {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  transition: box-shadow .12s ease, border-color .12s ease;
}
.study-board .tree--root > .tree__item:hover { box-shadow: var(--shadow-pop); }
.study-board .tree--root > .tree__item > .tree__children { padding: 0 var(--space-2) var(--space-2); }

/* Big subject row */
.tree__row--subject {
  gap: var(--space-3);
  min-height: 64px;
  padding-top: var(--space-4);
  padding-bottom: var(--space-4);
  padding-right: var(--space-5);
  border-radius: 0;
}
.tree__row--subject:hover { background: transparent; }   /* the card hovers, not the row */
.tree__row--subject.is-selected { background: rgba(79, 70, 229, .06); }
.tree__row--subject .tree__status { display: none; }     /* status dot hidden on subjects */
.tree__row--subject .tree__chevron { order: 9; color: var(--color-muted); }
.tree__row--subject .tree__name { font-size: 1rem; font-weight: 600; color: var(--color-text); }

.subject-row__icon {
  order: 1;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  flex: 0 0 auto;
  border-radius: var(--radius-input);
  background: var(--color-divider);
  color: var(--color-muted);
}
.subject-row__main {
  order: 2;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.subject-row__bar {
  height: 6px;
  width: 100%;
  max-width: 560px;
  border-radius: var(--radius-pill);
  background: var(--color-divider);
  overflow: hidden;
}
.subject-row__fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  transition: width .3s ease;
}
.subject-row__count {
  order: 7;
  flex: 0 0 auto;
  font-size: .8125rem;
  color: var(--color-muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* "Estudiar" play control — hidden until the node is in the in-progress
   (review) state. Sits on the right of the row. */
.study-board .tree__play {
  display: none;
  order: 8;
  margin-left: auto;
  width: 26px;
  height: 26px;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  color: #fff;
}
.study-board .tree__play svg { display: block; }
.study-board .tree__play:hover { background: var(--color-primary-hover); }

/* Show ▶ where it's actionable: hover, the selected row, an in-progress node,
   or the row of the running session (where it becomes ⏹). */
.study-board .tree__row:hover .tree__play,
.study-board .tree__row.is-selected .tree__play,
.study-board .tree__item[data-status="in_progress"] > .tree__row .tree__play,
.study-board .tree__row.is-studying .tree__play { display: inline-flex; }

/* Faint tint for the in-progress (review) state. */
.study-board .tree__item[data-status="in_progress"] > .tree__row { background: rgba(79, 70, 229, .045); }

/* Active session row → pause/resume control (indigo, stronger tint). */
.study-board .tree__row.is-studying { background: rgba(79, 70, 229, .09); }

/* Dark mode: the primary is orange, so these primary-tinted row states track it
   too (light indigo untouched). Grouped here for the study tree + reader chrome. */
body.dark .study-board .tree__item[data-status="in_progress"] > .tree__row { background: rgba(249, 115, 22, .06); }
body.dark .study-board .tree__row.is-studying { background: rgba(249, 115, 22, .12); }
body.dark .tree__row--subject.is-selected { background: rgba(249, 115, 22, .08); }
body.dark .study-board .tree__item--block:has(> .tree__row.is-selected) { background: rgba(249, 115, 22, .10); }

/* Edit (pencil) control on mother nodes — calm, revealed on hover/focus like the
   play control. Sits at the far right, after the ▶ button. Opens edit mode. */
.study-board .tree__actions {
  order: 9;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: var(--space-1);
  opacity: 0;
  pointer-events: none;
  transition: opacity .12s ease;
}
.study-board .tree__row:hover .tree__actions,
.study-board .tree__row.is-selected .tree__actions,
.study-board .tree__row:focus-within .tree__actions {
  opacity: 1;
  pointer-events: auto;
}
.study-board .tree__action {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
  border: 0;
  background: none;
  border-radius: var(--radius-input);
  color: var(--color-muted);
  cursor: pointer;
}
.study-board .tree__action svg { display: block; }
.study-board .tree__action:hover { background: var(--color-divider); color: var(--color-text); }

/* Temario edit mode — builder-style editable forest (reuses .proposal-* rows). */
.study-board .tree-editor { display: flex; flex-direction: column; gap: var(--space-3); }
/* Sticky Guardar/Cancelar bar — ONE bar only (no top duplicate), shared pattern
   with the import/proposal review's .proposal-save below. position:sticky pins it
   to the bottom of the viewport while a long tree scrolls (same technique as
   .study-board__side's sticky top), so saving never requires scrolling all the
   way down. Rober's call, 2026-07-07. */
/* N11 (2026-07-08, Rober): buttons-only, no full-width strip. Dropped the
   background fill + border-top so only the two buttons float; right-aligned. The
   .btn's own surfaces keep them legible as the tree scrolls behind (transparent
   container, so bleed-through in the gap is accepted per Rober's call). */
.study-board .tree-editor__foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-1);
  padding: var(--space-3) 0;
  position: sticky;
  bottom: 0;
  z-index: 5;
}
.study-board .tree-editor__addbar { display: flex; }
.study-board .tree-editor__roothead { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.study-board .tree-editor__roothead .proposal-name-input { flex: 1 1 12rem; }

/* Same sticky treatment for the import/proposal review footer (.proposal-save is
   also reused by the transient loading/error states — harmless there, those are
   short). Keeps both tree-edit flows (editing existing temario vs. reviewing a
   new import) visually identical. */
.study-board .proposal-save {
  position: sticky;
  bottom: 0;
  z-index: 5;
  justify-content: flex-end;
  padding: var(--space-3) 0;
  /* Lift the Guardar árbol / Cancelar buttons above the fixed bottom-right timer
     (.tw: bottom 24px, 42px tall) so they never clip it. Width-independent, so it
     also holds on narrow screens where a right-inset couldn't. */
  padding-bottom: 5rem;
  margin-top: var(--space-2);
}

/* N11 follow-up (2026-07-08, Rober): with the full-width strip gone, the ghost
   "Cancelar" had no surface behind it and read as plain text. Give ghost buttons
   inside the two save bars a .btn-secondary-style surface so they read as buttons
   on the transparent bar (mirrors .btn-secondary; specificity (0,3,0) wins). */
.study-board .tree-editor__foot .btn-ghost,
.study-board .proposal-save .btn-ghost {
  background: var(--color-surface);
  border-color: var(--color-border);
  color: var(--color-text);
  box-shadow: var(--shadow-card);
}
.study-board .tree-editor__foot .btn-ghost:hover,
.study-board .proposal-save .btn-ghost:hover {
  background: var(--color-surface);
  border-color: var(--color-primary);
  color: var(--color-text);
  transform: translateY(-1px);
  box-shadow: var(--shadow-pop);
}

/* Timer panel finish button spans the panel width. */
.mini-timer__finish { width: 100%; }

/* Empty / no-content + loading states (study page).
   Base = centered, generous, muted — covers the plain "Cargando…" strings.
   A state that carries a __title is a REAL empty state → give it a subtle
   surface card (via :has(), already used elsewhere in this file) so it reads
   as intentional rather than stray text. Both themes via tokens; scoped to
   .subjects-state, so the JS-rendered markup/classes are untouched. */
.subjects-state {
  color: var(--color-muted);
  font-size: .9375rem;
  line-height: 1.5;
  text-align: center;
  max-width: 34rem;
  margin-left: auto;
  margin-right: auto;
  padding: var(--space-6) var(--space-4);
}
/* Standing alone in the subjects grid, span every column so it centers on the
   full width instead of being trapped in the first 320px auto-fill track. */
.subj-grid > .subjects-state { grid-column: 1 / -1; }
/* Real empty state (has a heading) → intentional surface card. */
.subjects-state:has(.subjects-state__title) {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  padding: var(--space-8) var(--space-5);
}
.subjects-state__title {
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--color-text);
  margin-bottom: var(--space-2);
}
.subjects-state__actions { display: flex; justify-content: center; gap: var(--space-2); margin-top: var(--space-4); }

/* --- Functional PDF dropzone ------------------------------------------- */
.pdf-dropzone {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-5);
  border: 1.5px dashed var(--color-border);
  border-radius: var(--radius-card);
  background: var(--color-surface);
  cursor: pointer;
  transition: border-color .12s ease, background-color .12s ease;
}
.pdf-dropzone:hover,
.pdf-dropzone:focus-visible { border-color: var(--color-primary); background: rgba(79, 70, 229, .03); outline: none; }
.pdf-dropzone.is-dragover { border-color: var(--color-primary); background: rgba(79, 70, 229, .07); }
body.dark .pdf-dropzone:hover,
body.dark .pdf-dropzone:focus-visible { background: rgba(249, 115, 22, .05); }
body.dark .pdf-dropzone.is-dragover { background: rgba(249, 115, 22, .09); }
.pdf-dropzone.is-busy { opacity: .6; pointer-events: none; }
.pdf-dropzone.is-disabled { opacity: .5; pointer-events: none; }
.pdf-dropzone__icon {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  flex: 0 0 auto;
  border-radius: var(--radius-pill);
  background: var(--color-divider);
  color: var(--color-primary);
  font-size: 1.5rem;
  line-height: 1;
}
.pdf-dropzone__text { display: flex; flex-direction: column; gap: 2px; }
.pdf-dropzone__title { font-weight: 600; color: var(--color-text); }
.pdf-dropzone__hint  { font-size: .8125rem; color: var(--color-muted); }

/* --- Reader: docked panel ⇄ floating modal ----------------------------- */
.reader-card {
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  max-height: calc(100vh - var(--space-8) * 2);
  overflow: hidden;
}
.reader-card.is-closed { display: none; }

.reader-card__head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-divider);
}
.reader-card__title { font-size: .875rem; font-weight: 600; color: var(--color-text); }
.reader-card__node  { font-size: .75rem; color: var(--color-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.reader-card__actions { margin-left: auto; display: flex; gap: var(--space-1); flex: 0 0 auto; }
.reader-card__btn {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 0;
  background: none;
  border-radius: var(--radius-input);
  color: var(--color-muted);
  font-size: .9375rem;
}
.reader-card__btn:hover { background: var(--color-divider); color: var(--color-text); }
.reader-card__body { padding: var(--space-4); overflow: auto; display: flex; flex-direction: column; min-height: 0; }

/* Floating window + full-screen + backdrop.
   The reader lives inside .study-board__side, which is position:sticky and so
   creates a stacking context that would trap the card *below* the fixed
   backdrop. While floating, drop the side out of sticky so the fixed card
   escapes to the root stacking context and sits above the backdrop. */
.study-board:has(.reader-card.is-modal) .study-board__side,
.study-board:has(.reader-card.is-fullscreen) .study-board__side {
  position: static;
}

.reader-card.is-modal,
.reader-card.is-fullscreen {
  position: fixed;
  z-index: 200;          /* above the backdrop (150) */
  box-shadow: var(--shadow-pop);
}
.reader-card.is-modal {
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(880px, 92vw);
  max-height: 86vh;
}
.reader-card.is-fullscreen {
  inset: var(--space-4);
  width: auto;
  max-height: none;
  transform: none;
}
/* NATIVE fullscreen (⛶ now uses the Fullscreen API when available; is-fullscreen
   stays as the shared styling hook). As the fullscreen element the card owns the
   whole screen: no inset gap or rounded corners (the top layer paints black behind
   anything it doesn't cover) and an explicit opaque background. Kept as two rules —
   an unknown pseudo-class would invalidate a combined selector list. */
.reader-card.is-fullscreen:fullscreen {
  inset: 0;
  border-radius: 0;
  background: var(--color-surface);
}
.reader-card.is-fullscreen:-webkit-full-screen {
  inset: 0;
  border-radius: 0;
  background: var(--color-surface);
}
/* Fullscreen polish: a reading-room look. Text content is capped to the same book
   column the PDF pages fit to (PDF_FIT_MAX_FS in study.php) and centered; the PDF
   canvas keeps its full-bleed muted background with the white pages centered on it,
   and gets roomier vertical padding. */
.reader-card.is-fullscreen .reader-card__head { padding: var(--space-3) var(--space-6); }
.reader-card.is-fullscreen .reader-card__body { position: relative; padding: var(--space-3) var(--space-6) var(--space-5); }
.reader-card.is-fullscreen .reader-state,
.reader-card.is-fullscreen .reader-body:not(.is-pdf) {
  width: 100%;
  max-width: 1100px;
  margin-left: auto;
  margin-right: auto;
}
.reader-card.is-fullscreen .reader-body.is-pdf .reader-pdf { padding: var(--space-6) 0; }

/* reader-float: transparent wrapper around Hacer test + A−/A+. In normal modes it is
   display:contents (zero layout impact — the children flow exactly as before). In
   fullscreen it becomes a compact pill FLOATING top-right over the document, so the
   chrome stops eating a full-width row of the reading space. Hidden entirely when
   every child is hidden (no empty capsule). */
.reader-float { display: contents; }
.reader-card.is-fullscreen .reader-float {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  position: absolute;
  top: var(--space-2);
  right: var(--space-4);
  z-index: 30;
  padding: var(--space-1) var(--space-2);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-card);
}
.reader-card.is-fullscreen .reader-float:not(:has(> :not([hidden]))) { display: none; }
.reader-card.is-fullscreen .reader-float .reader-gen   { margin: 0; flex-direction: row; }
.reader-card.is-fullscreen .reader-float .reader-tools { margin: 0; }
.reader-card.is-fullscreen .reader-float .reader-gen .btn-block { width: auto; white-space: nowrap; }

/* Auto-hiding chrome in fullscreen: the header (title + window controls) and the
   floating Hacer-test / zoom pill fade out once the pointer goes idle — JS toggles
   .is-chrome-hidden on mousemove, like a video player — so nothing sits over the text
   while reading. The float is absolute (no layout impact) so it just fades; the header
   also COLLAPSES its vertical box and the PDF grows into the reclaimed space, leaving no
   blank bar so it's truly fullscreen. Only VERTICAL space changes (max-height / vertical
   padding / scroll-area height) — horizontal padding + width are untouched, so the PDF
   fit-to-width scale (and the rendered pages) never recompute. */
.reader-card.is-fullscreen .reader-card__head {
  overflow: hidden;
  max-height: 5rem;                                   /* base so the collapse animates */
  transition: opacity .25s ease, max-height .25s ease, padding .25s ease;
}
.reader-card.is-fullscreen .reader-float { transition: opacity .25s ease; }
.reader-card.is-fullscreen.is-chrome-hidden .reader-float { opacity: 0; pointer-events: none; }
.reader-card.is-fullscreen.is-chrome-hidden .reader-card__head {
  opacity: 0;
  pointer-events: none;
  max-height: 0;
  padding-top: 0;
  padding-bottom: 0;
}
.reader-card.is-fullscreen.is-chrome-hidden .reader-card__body { padding-top: 0; }
.reader-card.is-fullscreen.is-chrome-hidden .reader-body.is-pdf .reader-pdf {
  height: calc(100vh - var(--space-5));               /* fill the reclaimed header space */
}

.reader-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(17, 24, 39, .35);   /* dims what's behind, a bit */
  z-index: 150;                         /* below the floating reader (200) */
}

/* Reader tools / state / body / children (moved from inline <style>) */
.reader-tools { display: flex; align-items: center; gap: var(--space-1); margin-bottom: var(--space-2); }
.reader-tools__btn {
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  border-radius: var(--radius-input);
  padding: 2px var(--space-2);
  font-size: .85rem;
  line-height: 1.45;
}
.reader-tools__btn:hover:not(:disabled) { background: rgba(79, 70, 229, .08); }
.reader-tools__btn[aria-pressed="true"] { background: rgba(79, 70, 229, .12); border-color: var(--color-primary); }
.reader-tools__btn:disabled { opacity: .45; cursor: default; }
body.dark .reader-tools__btn:hover:not(:disabled) { background: rgba(249, 115, 22, .10); }
body.dark .reader-tools__btn[aria-pressed="true"] { background: rgba(249, 115, 22, .16); }
.reader-tools__sep { width: 1px; height: 1.1rem; background: var(--color-border); margin: 0 var(--space-1); }

.reader-state { color: var(--color-muted); font-size: .92rem; padding: var(--space-1) 0; }

.reader-children { margin: var(--space-2) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.reader-children__item {
  display: block;
  width: 100%;
  text-align: left;
  font-size: .9rem;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  border-radius: var(--radius-input);
  padding: var(--space-2) var(--space-3);
}
.reader-children__item:hover { background: rgba(79, 70, 229, .06); }
body.dark .reader-children__item:hover { background: rgba(249, 115, 22, .08); }

.reader-body {
  flex: 1 1 auto;
  overflow: auto;
  margin: 0 auto;
  padding: var(--space-1);
  font-size: var(--reader-fs, 1rem);
  line-height: 1.75;
  color: var(--color-text);
}
.reader-body.is-narrow { max-width: 42rem; }
.reader-body p { margin: 0 0 1rem; white-space: pre-wrap; }
.reader-body p:last-child { margin-bottom: 0; }

/* Real-PDF mode (ROADMAP #13): bodyEl holds a single .reader-pdf scroll container
   rendered by pdf.js (a canvas + a selectable text layer per page), so we own the page
   DOM for the annotation layer. No is-narrow cap; .reader-pdf scrolls internally. */
.reader-body.is-pdf {
  max-width: none;
  /* The reader body is a flex item with `margin: 0 auto`; in a flex COLUMN those auto
     side-margins shrink it to its content. In PDF mode force full-width (no centering)
     so the page container truly fills the box. */
  width: 100%;
  align-self: stretch;
  margin: 0;
  padding: 0;
  overflow: hidden;
}
.reader-pdf {
  position: relative;            /* page placeholders anchor their offsetTop to this */
  width: 100%;
  height: 60vh;                  /* docked default — definite height so it scrolls */
  overflow: auto;
  background: var(--color-canvas);
  border-radius: var(--radius-input);
  padding: var(--space-3) 0;
}
.reader-card.is-modal     .reader-pdf { height: 74vh; }
.reader-card.is-fullscreen .reader-pdf { height: calc(100vh - var(--space-8) * 3); }
.reader-pdf__page {
  position: relative;            /* canvas + textLayer stack inside */
  margin: 0 auto var(--space-3);
  background: var(--color-surface);
  box-shadow: var(--shadow-card);
  border-radius: 2px;
  overflow: hidden;
}
.reader-pdf__page:last-child { margin-bottom: 0; }
.reader-pdf__canvas { display: block; }
/* pdf.js text layer: transparent, absolutely-positioned spans over the canvas so the
   user can select/copy text (and, in ROADMAP #13, highlight it). Standard pdf.js CSS. */
.reader-pdf .textLayer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  line-height: 1;
  opacity: 1;
  z-index: 2;
  text-align: initial;
  forced-color-adjust: none;
}
.reader-pdf .textLayer span,
.reader-pdf .textLayer br {
  color: transparent;
  position: absolute;
  white-space: pre;
  cursor: text;
  transform-origin: 0 0;
}
/* Keep selected glyphs transparent: the text-layer spans mirror the canvas glyphs at
   `color:transparent`, but a `::selection` rule that sets only `background` lets Chrome
   repaint them in the default selection foreground → the offset spans show over the canvas
   glyphs = doubled / struck-through text (N50, the selection-path twin of N29). Pinning the
   colour (and -webkit-text-fill-color, which wins on WebKit/Blink) keeps them invisible so
   only the selection tint shows over the crisp canvas text. Selection tint is blue in light
   theme, orange in dark (body.dark override below) to match each theme's UI. */
.reader-pdf .textLayer ::selection {
  background: rgba(59, 130, 246, .28);   /* light theme: normal blue selection */
  color: transparent;
  -webkit-text-fill-color: transparent;
}
/* Dark theme keeps the warm orange selection to match the rest of the dark UI. */
body.dark .reader-pdf .textLayer ::selection {
  background: rgba(249, 115, 22, .32);
  color: transparent;
  -webkit-text-fill-color: transparent;
}
/* Smooth multi-line selection (standard pdf.js "endOfContent" recipe): a sentinel div
   sits after the glyph spans, collapsed below the page (top:100%). While the pointer is
   down (.selecting, toggled in study.php), it expands to cover the whole layer, giving
   the selection's end anchor one stable hit target instead of hopping span→span — which
   is what made dragging across many lines flicker and stutter. */
.reader-pdf .textLayer .endOfContent {
  display: block;
  position: absolute;
  inset: 100% 0 0;
  z-index: -1;
  cursor: default;
  -webkit-user-select: none;
  user-select: none;
}
.reader-pdf .textLayer.selecting .endOfContent { inset: 0; }
.reader-pdf__loading {
  margin: var(--space-6) auto;
  font-size: .8125rem;
  color: var(--color-muted);
}

/* ROADMAP #13 Phase 2 — persistent highlights + comments.
   The overlay sits above the transparent text layer (z 2) so highlights are visible
   and clickable; the overlay itself is click-through (pointer-events:none) so empty
   areas still select text, and only the highlight rects capture clicks (edit/delete).
   Fills are a PLAIN translucent colour (no mix-blend-mode). N29 fix (2026-07-11): the
   previous `mix-blend-mode: multiply` forced Chrome to read back the backdrop, which
   faintly painted pdf.js's normally-transparent text layer offset over the canvas glyphs
   → the highlighted text appeared DOUBLED. A plain alpha tint never re-composites the
   backdrop, so the text can't ghost; alphas are tuned to keep the glyphs readable. */
.reader-pdf__annots {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
}
.reader-annot {
  position: absolute;
  pointer-events: auto;
  cursor: pointer;
  border-radius: 2px;
  transition: filter .12s ease;
}
.reader-annot:hover { filter: brightness(.93); }
.reader-annot--yellow { background: rgba(255, 235, 59, .45); }
.reader-annot--green  { background: rgba(52, 211, 153, .42); }
.reader-annot--red    { background: rgba(248, 113, 113, .42); }
.reader-annot.has-note { box-shadow: inset 0 0 0 1px rgba(17, 24, 39, .22); }
/* Clickable link layer (ROADMAP N50): a PDF's index/TOC + in-text cross-references carry
   Link annotations rendered as positioned hotspots over the text layer. The layer is
   click-through so only the hotspots are interactive (text selection elsewhere is
   unaffected); sits above the highlight layer so a link under a highlight still works. */
.reader-pdf__links {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
}
.reader-pdf__link {
  position: absolute;
  display: block;
  pointer-events: auto;
  cursor: pointer;
  border-radius: 2px;
  text-decoration: none;
}
.reader-pdf__link:hover { background: rgba(79, 70, 229, .16); }   /* --color-primary tint */
.reader-annot__note-dot {
  position: absolute;
  top: -4px; right: -4px;
  width: 9px; height: 9px;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  box-shadow: 0 0 0 2px var(--color-surface);
  pointer-events: none;
}

/* Highlight popover: color picker on create; color + note + delete on edit. Fixed to
   the viewport so the reader's internal overflow can't clip it in any window state. */
.reader-annot-pop {
  position: fixed;
  z-index: 1200;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  width: 248px;
  max-width: calc(100vw - var(--space-4));
}
.reader-annot-pop[hidden] { display: none !important; }
.reader-annot-pop__swatches { display: flex; gap: var(--space-2); align-items: center; }
.reader-annot-pop__swatch {
  width: 26px; height: 26px;
  border-radius: var(--radius-pill);
  border: 2px solid transparent;
  cursor: pointer;
  padding: 0;
}
.reader-annot-pop__swatch:focus-visible { outline: none; box-shadow: var(--ring); }
.reader-annot-pop__swatch.is-active { border-color: var(--color-text); }
.reader-annot-pop__swatch--yellow { background: rgba(250, 204, 21, .9); }
.reader-annot-pop__swatch--green  { background: rgba(74, 222, 128, .9); }
.reader-annot-pop__swatch--red    { background: rgba(248, 113, 113, .9); }
.reader-annot-pop__note {
  width: 100%;
  min-height: 56px;
  resize: vertical;
  font: inherit;
  font-size: .8125rem;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-canvas);
  color: var(--color-text);
}
.reader-annot-pop__row { display: flex; gap: var(--space-2); justify-content: space-between; align-items: center; }

/* --- PDF / tree-builder cards ------------------------------------------ */
.pdf-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}
.pdf-card__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-divider);
}
.pdf-card__title { font-size: 1rem; font-weight: 600; color: var(--color-text); }
.pdf-card__node  { margin-left: auto; font-size: .8125rem; color: var(--color-muted); }
.pdf-card__body  { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-4); }

.pdf-drop { display: flex; flex-direction: column; gap: var(--space-2); align-items: flex-start; }
.pdf-drop__label {
  display: inline-flex;
  align-items: center;
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  font-weight: 600;
  font-size: .875rem;
  color: var(--color-text);
  cursor: pointer;
}
.pdf-drop__label:hover { background: var(--color-divider); }
.pdf-drop__hint { font-size: .8125rem; color: var(--color-muted); }
.pdf-file { font-size: .8125rem; color: var(--color-muted); }

.pdf-status, .build-status, .sa-progress, .sa-status, .inbox-q__sug {
  font-size: .875rem;
  color: var(--color-body);
}
.pdf-disclaimer {
  font-size: .8125rem;
  color: var(--color-warning);
  background: var(--color-warning-bg);
  border-radius: var(--radius-input);
  padding: var(--space-2) var(--space-3);
}
.pdf-staged { font-size: .8125rem; color: var(--color-muted); }
.pdf-build { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.pdf-build__hint { flex-basis: 100%; font-size: .8125rem; color: var(--color-muted); }

/* Extracted chunk preview */
.chunk-list { display: flex; flex-direction: column; gap: var(--space-2); max-height: 280px; overflow: auto; }
.chunk-card { border: 1px solid var(--color-border); border-radius: var(--radius-input); padding: var(--space-3); }
.chunk-card__top { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); }
.chunk-card__title { font-weight: 600; font-size: .875rem; color: var(--color-text); }
.chunk-card__meta { font-size: .75rem; color: var(--color-muted); }
.chunk-card__preview { margin-top: var(--space-1); font-size: .8125rem; color: var(--color-muted); white-space: pre-wrap; max-height: 4.5em; overflow: hidden; }

/* Editable proposed tree */
.tree-proposal { display: flex; flex-direction: column; gap: var(--space-2); }
.proposal-head { font-weight: 600; color: var(--color-text); }
.proposal-meta { font-size: .8125rem; color: var(--color-muted); }
.proposal-warning {
  font-size: .8125rem;
  color: var(--color-warning);
  background: var(--color-warning-bg);
  border-radius: var(--radius-input);
  padding: var(--space-2) var(--space-3);
}
/* Import errors read in the theme primary (blue/orange), never red — the step
   stays recoverable (Reintentar keeps the same file). Overrides the amber
   .proposal-warning it sits alongside. */
.proposal-error {
  color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 8%, transparent);
}
.proposal-note { font-size: .8125rem; color: var(--color-muted); }
.proposal-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
}
.proposal-row--edit { border-color: var(--color-primary); box-shadow: var(--ring); }
.proposal-name { flex: 1 1 auto; min-width: 0; font-size: .9375rem; color: var(--color-text); }
.proposal-name-input { flex: 1 1 auto; min-width: 0; }
/* N18: expand/collapse toggle for the editable tree (lazy-rendered branches).
   Leaves keep an invisible spacer so their rows stay aligned with parents. */
.proposal-toggle {
  flex: 0 0 auto;
  width: 1.25rem;
  height: 1.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  color: var(--color-body);
  font-size: .7rem;
  line-height: 1;
  border-radius: var(--radius-input);
}
.proposal-toggle:hover { background: var(--color-divider); color: var(--color-text); }
.proposal-toggle--leaf { visibility: hidden; cursor: default; }
.proposal-btn {
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-body);
  border-radius: var(--radius-input);
  padding: 2px var(--space-2);
  font-size: .8125rem;
}
.proposal-btn:hover { background: var(--color-divider); }
.proposal-btn--danger { color: var(--color-danger); border-color: var(--color-danger); }
.proposal-btn--danger:hover { background: var(--color-danger-bg); }
/* Icon-only proposal button (e.g. the trash delete) — center the inline SVG. */
.proposal-btn--icon {
  display: inline-grid;
  place-items: center;
  padding: 4px;
  line-height: 0;
}
.proposal-btn--icon svg { display: block; }
.proposal-save { font-size: .8125rem; color: var(--color-success); display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.proposal-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }

/* ROADMAP #10: PDF import → editable tree loading state (calm skeleton + spinner). */
.proposal-loading { display: flex; flex-direction: column; gap: var(--space-3); }
.proposal-loading__head {
  display: flex; align-items: center; gap: var(--space-2);
  font-size: .875rem; color: var(--color-body);
}
.proposal-loading__msg { min-width: 0; }
.proposal-spinner {
  flex: none;
  width: 18px; height: 18px;
  border: 2px solid var(--color-divider);
  border-top-color: var(--color-primary);
  border-radius: var(--radius-pill);
  animation: proposalSpin .7s linear infinite;
}
.proposal-skel { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.proposal-skel__row {
  height: 14px;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--color-divider) 0%, var(--color-border) 50%, var(--color-divider) 100%);
  background-size: 200% 100%;
  animation: proposalShimmer 1.4s ease-in-out infinite;
}
.proposal-skel__row--in { margin-left: var(--space-6); }
@keyframes proposalSpin { to { transform: rotate(360deg); } }
@keyframes proposalShimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .proposal-spinner, .proposal-skel__row { animation: none; }
}

/* --- Subject actions (bank / exam) ------------------------------------- */
.sa-provisional {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  font-size: .8125rem;
  color: var(--color-warning);
  background: var(--color-warning-bg);
  border-radius: var(--radius-input);
  padding: var(--space-3);
}
.sa-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* «Generar más preguntas» inside the «Banco de la selección» card */
.bank-gen {
  margin-top: var(--space-4);
}
.bank-gen__status {
  margin-top: var(--space-2);
  font-size: .8125rem;
  color: var(--color-muted);
}

/* --- Inbox (sin clasificar) -------------------------------------------- */
.inbox-review { display: flex; flex-direction: column; gap: var(--space-3); }
.inbox-review__head { font-size: .85rem; color: var(--color-muted); }
.inbox-review__foot { display: flex; gap: var(--space-2); margin-top: var(--space-1); }
.inbox-q {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
}
.inbox-q__chk,
.inbox-q__keep {
  font-size: .8rem;
  white-space: nowrap;
  display: flex;
  align-items: flex-start;
  gap: var(--space-1);
  color: var(--color-muted);
}
.inbox-q__body { flex: 1; min-width: 0; }
.inbox-q__text { font-weight: 600; color: var(--color-text); margin: 0 0 var(--space-1); }
.inbox-q__opts { margin: 0 0 var(--space-2) 1.1rem; padding: 0; font-size: .85rem; color: var(--color-muted); }
.inbox-q__sug { color: var(--color-primary); margin: 0 0 var(--space-1); }
.inbox-q__sel { font-size: .85rem; display: block; }
.inbox-q__node { max-width: 100%; }

/* --- Docked timer ------------------------------------------------------- */
/* Bottom-right dock. column-reverse keeps the clock circle at the bottom and
   opens the panel upward above it. */
.mini-timer {
  position: fixed;
  right: var(--space-6);
  bottom: var(--space-6);
  z-index: 120;
  display: flex;
  flex-direction: column-reverse;
  align-items: flex-end;
  gap: var(--space-3);
}
/* Collapsed face = a status pill (auto-stopwatch) + inline pause/discard buttons. */
.mini-timer__bar {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 4px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-pop);
}
.mini-timer__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 40px;
  padding: 0 var(--space-3);
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--color-primary);
  font: inherit;
  font-size: .85rem;
  font-weight: 600;
  cursor: pointer;
  transition: background .15s ease;
}
.mini-timer__toggle:hover { background: var(--color-divider); }
.mini-timer__toggle[aria-expanded="true"] { background: var(--color-divider); }
.mini-timer__toggle-label { display: none; }
.mini-timer__status { color: var(--color-body); }
.mini-timer__bar.is-study  .mini-timer__status { color: var(--color-text); }
.mini-timer__bar.is-paused .mini-timer__status { color: var(--color-muted); }
.mini-timer__time { font-variant-numeric: tabular-nums; color: var(--color-primary); }
.mini-timer__bar.is-paused .mini-timer__time { color: var(--color-muted); }
.mini-timer__time[hidden], .mini-timer__clock[hidden], .mini-timer__dot[hidden] { display: none !important; }
.mini-timer__dot {
  width: 8px; height: 8px; flex: 0 0 auto; border-radius: 50%;
  background: var(--color-muted);
}
.mini-timer__bar.is-study .mini-timer__dot {
  background: var(--color-acc-high);
  animation: activity-pulse 1.6s ease-in-out infinite;
}
.mini-timer__bar.is-paused .mini-timer__dot { background: var(--color-muted); animation: none; }
.mini-timer__trackbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; flex: 0 0 auto; padding: 0;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--color-muted);
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.mini-timer__trackbtn:hover { background: var(--color-divider); color: var(--color-text); }
#miniTrackDiscard:hover { background: var(--color-acc-low-bg, var(--color-divider)); color: var(--color-acc-low); }
.mini-timer__trackbtn[hidden] { display: none !important; }

/* Centered round play / pause control. */
.mini-timer__primary {
  display: inline-grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border: 0;
  border-radius: 50%;
  background: var(--color-primary);
  color: #fff;
  box-shadow: var(--shadow-card);
  transition: background-color .12s ease, transform .06s ease;
}
.mini-timer__primary:hover { background: var(--color-primary-hover); }
.mini-timer__primary:active { transform: scale(.94); }
.mini-timer__subcontrols { display: flex; justify-content: center; gap: var(--space-2); }
.mini-timer__panel {
  width: 280px;
  padding: var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.mini-timer__tabs { display: flex; gap: var(--space-1); padding: var(--space-1); background: var(--color-divider); border-radius: var(--radius-input); }
.mini-timer__tab {
  flex: 1 1 0;
  border: 0;
  background: none;
  border-radius: calc(var(--radius-input) - 2px);
  padding: var(--space-1) var(--space-2);
  font-size: .8125rem;
  font-weight: 600;
  color: var(--color-muted);
}
.mini-timer__tab.is-active { background: var(--color-surface); color: var(--color-primary); box-shadow: var(--shadow-card); }
.mini-timer__subject { font-size: .8125rem; color: var(--color-muted); text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mini-timer__phase {
  align-self: center;
  font-size: .75rem;
  font-weight: 600;
  padding: 2px var(--space-3);
  border-radius: var(--radius-pill);
}
.mini-timer__phase.pom-work  { color: var(--color-primary); background: rgba(79, 70, 229, .1); }
.mini-timer__phase.pom-break { color: var(--color-success); background: var(--color-success-bg); }
.mini-timer__display { font-size: 2.25rem; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--color-text); text-align: center; }
.mini-timer__cycle { font-size: .75rem; color: var(--color-muted); text-align: center; }
.mini-timer__controls { display: flex; flex-wrap: wrap; gap: var(--space-2); justify-content: center; }

/* Pause prompt dialog */
.study-dialog-backdrop {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: grid;
  place-items: center;
  background: rgba(17, 24, 39, .35);
  padding: var(--space-4);
}
.study-dialog {
  position: relative;
  width: min(340px, 92vw);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  padding: var(--space-6);
  text-align: center;
}
.study-dialog__close {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 0;
  background: none;
  border-radius: var(--radius-input);
  color: var(--color-muted);
  font-size: .9375rem;
  line-height: 1;
}
.study-dialog__close:hover { background: var(--color-divider); color: var(--color-text); }
/* Destructive action: hover red. */
.study-dialog__danger:hover { background: var(--color-danger-bg); color: var(--color-danger); }
.study-dialog__title { font-size: 1.0625rem; font-weight: 600; color: var(--color-text); }
.study-dialog__text { font-size: .875rem; color: var(--color-muted); margin-top: var(--space-1); }
.study-dialog__actions { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-5); }
.study-dialog__actions .btn { width: 100%; }
.mini-timer__steppers { display: flex; flex-direction: column; gap: var(--space-2); }
.mini-timer__note { font-size: .75rem; color: var(--color-muted); text-align: center; }

/* Stepper */
.stepper { display: flex; align-items: center; gap: var(--space-2); }
.stepper__label { flex: 1 1 auto; font-size: .8125rem; color: var(--color-body); }
.stepper__btn {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  border-radius: var(--radius-input);
  color: var(--color-text);
  font-size: .75rem;
}
.stepper__btn:hover { background: var(--color-divider); }
.stepper__val { min-width: 2ch; text-align: center; font-weight: 600; font-variant-numeric: tabular-nums; }
.stepper__unit { font-size: .75rem; color: var(--color-muted); }

/* --- Subjects grid landing (Estudiar level 1) --------------------------- */
/* The Estudiar landing is a responsive grid of subject boxes — richer than the
   dashboard .subj-card. Clicking a box opens that subject's workspace below
   (level 2) and resumes at the node last studied. View switching is done with
   the `hidden` attribute on #studyGrid / #subjectView — never a forced display.
   Boxes reuse .card + .subj-card (chrome, hover-scale, .subj-progress);
   .asig-* adds the meta line, the ⋮ options menu and the workspace bar. */
.study-grid { display: flex; flex-direction: column; gap: var(--space-5); }
.study-grid .subject-create { margin-bottom: var(--space-1); }

/* The clickable box. Behaves like a link (role="link" + JS); the shared
   .subj-card:hover gives it the scale-up affordance. position:relative anchors
   the ⋮ options menu. */
.asig-card { gap: var(--space-3); cursor: pointer; position: relative; text-align: center; }
.asig-card:focus-visible { outline: none; box-shadow: var(--ring); }
/* Keep the card steady (don't scale) while its options menu is open. */
.asig-card.is-menu-open:hover { transform: none; box-shadow: var(--shadow-card); }

/* The "+ Nueva asignatura" box: same footprint as a subject card, but a dashed,
   muted placeholder with a big plus. It's a <button>, so reset its chrome and
   center its contents. Sits as the last item in the grid. */
.asig-card--add {
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  width: 100%;
  min-height: 100%;
  font: inherit;
  background: none;
  border: 1px dashed var(--color-border);
  color: var(--color-muted);
  transition: transform .14s ease, box-shadow .14s ease,
              border-color .14s ease, color .14s ease;
}
.asig-card--add:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
  box-shadow: var(--shadow-pop);
}
.asig-card--add:focus-visible { outline: none; box-shadow: var(--ring); }

/* Big, clean circular plus badge. */
.asig-card__add-icon {
  display: inline-grid;
  place-items: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--color-divider);
  color: var(--color-muted);
  transition: background .14s ease, color .14s ease;
}
.asig-card__add-icon svg { display: block; }
.asig-card--add:hover .asig-card__add-icon {
  background: var(--color-primary);
  color: #fff;
}
.asig-card__add-label { font-size: .9375rem; font-weight: 600; letter-spacing: .01em; }

/* Centered, minimal box. The title centers (capped so it clears the corner ⋮),
   while the ⋮ button sits absolutely in the top-right. */
.asig-card .subj-card__head { justify-content: center; }
.asig-card .subj-card__title { flex: 0 1 auto; min-width: 0; max-width: calc(100% - 56px); }
.asig-menu__btn {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  display: inline-grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 0;
  background: none;
  border-radius: var(--radius-input);
  color: var(--color-muted);
  cursor: pointer;
}
.asig-menu__btn:hover { background: var(--color-divider); color: var(--color-text); }
.asig-menu__btn:focus-visible { outline: none; box-shadow: var(--ring); }

/* Dropdown menu: rename / delete. */
.asig-menu {
  position: absolute;
  top: 52px;
  right: var(--space-5);
  z-index: 20;
  min-width: 168px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-1);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
}
.asig-menu__item {
  width: 100%;
  text-align: left;
  padding: var(--space-2) var(--space-3);
  border: 0;
  background: none;
  border-radius: var(--radius-input);
  font-size: .875rem;
  color: var(--color-text);
  cursor: pointer;
}
.asig-menu__item:hover { background: var(--color-divider); }
.asig-menu__item:focus-visible { outline: none; box-shadow: var(--ring); }
.asig-menu__item--danger { color: var(--color-danger); }
.asig-menu__item--danger:hover { background: var(--color-danger-bg); }

/* Meta line: X/Y temas · tiempo estudiado · último estudio + source chip. */
.asig-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
  font-size: .8125rem;
  color: var(--color-muted);
}
.asig-meta__item { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
.asig-meta__item strong { color: var(--color-body); font-weight: 600; font-variant-numeric: tabular-nums; }
.asig-meta__sep { color: var(--color-border); }
.asig-meta__chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-divider);
  color: var(--color-body);
  font-size: .75rem;
  font-weight: 600;
}

/* Centered meta line, pinned to the card foot so uneven boxes align. */
.asig-card .asig-meta { margin-top: auto; justify-content: center; }

/* --- Subject workspace (Estudiar level 2): back bar -------------------- */
/* #subjectView wraps the existing board + PDF/bank/inbox cards so the whole
   workspace toggles as one. Restore the study-wrap inter-card spacing inside. */
.subject-view { display: flex; flex-direction: column; gap: var(--space-6); }
.subject-view__bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.study-back { flex: 0 0 auto; }
.subject-view__name {
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--color-text);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- Responsive --------------------------------------------------------- */
@media (max-width: 1024px) {
  .study-board,
  .study-board.is-resized { grid-template-columns: 1fr; }
  .study-board:has(.reader-card.is-closed) { grid-template-columns: 1fr; }
  .study-board__resizer { display: none; }          /* no split on the stacked mobile layout */
  .study-board__side { position: static; }
  .reader-card { max-height: 70vh; }
}
@media (max-width: 540px) {
  .mini-timer { right: var(--space-3); bottom: var(--space-3); }
  .mini-timer__panel { width: calc(100vw - var(--space-6)); }
}

/* ===== TESTS ===== */
/* Scoped to .tests-page. Reuses foundation tokens + shared components
   (.card / .btn / .badge / .tree). Only adds Tests-specific rules.
   Hooks mirror tests.php (S22) exactly — never rename. */

.tests-page {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

/* --- Page head: eyebrow + h1 + lead paragraph (matches .dash-head) ------- */
.tests-head { display: flex; flex-direction: column; gap: var(--space-1); }
/* Scoped with .tests-page to outrank `.tests-head p` (which also matches this <p>). */
.tests-page .tests-head__eyebrow {
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--color-primary);   /* indigo (light) / orange (dark) — theme-driven */
  max-width: none;
}
.tests-head h1 {
  font-size: 1.9375rem;
  line-height: 1.12;
  letter-spacing: -.025em;
  font-weight: 800;
}
.tests-head p {
  font-size: .9375rem;
  color: var(--color-muted);
  max-width: 70ch;
}

/* --- Page layout: picker (left) + bank/config column (right) ------------- */
/* The right column sets its own inline flex/gap in tests.php — keep it. */
.tests-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: var(--space-6);
  align-items: start;
}

/* Tighter, more confident section titles (mirrors .dash-section-title). */
.tests-page .card-title { font-weight: 700; letter-spacing: -.012em; }

/* --- Loading / empty states -------------------------------------------- */
.tests-page .tests-state,
.tests-page .tests-empty {
  color: var(--color-muted);
  font-size: .9375rem;
  line-height: 1.5;
}
.tests-page .tests-state { padding: var(--space-4) var(--space-2); }
.tests-page .tests-empty { padding: var(--space-2) 0; }

/* --- Branch picker ------------------------------------------------------ */
.picker-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  width: 100%;
}
.picker-clear {
  flex: 0 0 auto;
  padding: var(--space-1) var(--space-2);
  border: 0;
  background: none;
  border-radius: var(--radius-input);
  font-size: .8125rem;
  font-weight: 500;
  color: var(--color-primary);
  cursor: pointer;
  transition: background-color .1s ease, color .1s ease;
}
.picker-clear:hover:not(:disabled) { background: var(--color-divider); color: var(--color-primary-hover); }
.picker-clear:disabled { color: var(--color-muted); cursor: not-allowed; }

.picker-hint {
  font-size: .8125rem;
  color: var(--color-muted);
  line-height: 1.5;
}

/* Keep a tall syllabus tree scrollable inside the card. */
.tests-page #treeWrap { max-height: 60vh; overflow: auto; }

/* Selection highlight — tests.php toggles .is-checked on the ROW
   (foundation only ships .is-selected). Page-scoped so the shared tree
   is untouched on other pages. */
.tests-page .tree__row.is-checked {
  background: rgba(79, 70, 229, .08);
  color: var(--color-primary);
}
/* Dark mode: track the orange primary instead of staying indigo. */
body.dark .tests-page .tree__row.is-checked { background: rgba(249, 115, 22, .12); }
.tests-page .tree__row.is-checked .tree__name { font-weight: 600; }

/* The checkbox here is a NATIVE <input type=checkbox> (not the div-toggle the
   foundation .tree__check assumes). Revert the box styling and use the native
   control with an indigo accent so the checked state actually shows. */
.tests-page .tree__check {
  display: inline-block;
  place-items: initial;
  width: 16px;
  height: 16px;
  border: 0;
  border-radius: 0;
  background: none;
  accent-color: var(--color-primary);
  cursor: pointer;
}

/* --- Bank-depth panel --------------------------------------------------- */
.tests-page .bank-total {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}
.tests-page .bank-total .num {
  font-size: 1.75rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}
.tests-page .bank-total .lbl { font-size: .875rem; color: var(--color-muted); }

.tests-page .bank-line {
  margin-top: var(--space-3);
  font-size: .875rem;
  color: var(--color-body);
}
.tests-page .bank-line + div { margin-top: var(--space-3); }

/* Difficulty mix = a row of soft badge pills (not a bar). */
.bank-diffmix {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

/* Per-branch breakdown list. */
.bank-rows {
  display: flex;
  flex-direction: column;
  margin-top: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  overflow: hidden;
}
.bank-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  font-size: .875rem;
}
.bank-row + .bank-row { border-top: 1px solid var(--color-divider); }
.bank-row__name {
  min-width: 0;
  color: var(--color-text);
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bank-row__stats {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}
.bank-note {
  margin-top: var(--space-3);
  font-size: .8125rem;
  line-height: 1.5;
  color: var(--color-muted);
}

/* --- Exam / review config ---------------------------------------------- */
.tests-page .form-group { margin-bottom: var(--space-4); }
.tests-page .form-group label {
  display: block;
  margin-bottom: var(--space-2);
  font-size: .8125rem;
  font-weight: 600;
  color: var(--color-body);
}
.cfg-actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-2);
}
.cfg-notice {
  margin-top: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-input);
  font-size: .8125rem;
  line-height: 1.5;
  background: var(--color-neutral-bg);
  color: var(--color-body);
  border: 1px solid var(--color-border);
}
.cfg-notice.is-error {
  background: var(--color-danger-bg);
  color: var(--color-danger);
  border-color: var(--color-danger);
}

/* Live question-generation progress bar (Montar examen). Mirrors the PDF-upload bar
   (.pdf-upload__bar/__fill) so the two feel like one product: a divider track with a
   primary fill that grows as questions are banked, plus an indeterminate sweep while the
   first batch assembles. Shown/hidden via the `hidden` attribute (per the hard rules). */
.gen-progress {
  margin-top: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.gen-progress__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
}
.gen-progress__label {
  font-size: .875rem;
  color: var(--color-body);
}
.gen-progress__count {
  flex: 0 0 auto;
  font-size: 1.05rem;
  font-weight: 800;
  color: var(--color-primary);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}
.gen-progress__bar {
  position: relative;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--color-divider);
  overflow: hidden;
}
.gen-progress__fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 0;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  transition: width .12s linear;   /* tracks the fine per-tick counter updates smoothly */
}
.gen-progress.is-indeterminate .gen-progress__fill {
  width: 35%;
  animation: genProgSweep 1.15s ease-in-out infinite;
}
@keyframes genProgSweep {
  0%   { left: -35%; }
  100% { left: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .gen-progress.is-indeterminate .gen-progress__fill { animation: none; left: 0; width: 35%; }
}

/* Segmented test-mode selector (Montar examen → Normal / Estudio). The .is-selected
   class is toggled in JS so we don't depend on :has(). Selectors are scoped with
   .tests-page and an extra class to outrank `.tests-page .form-group label` (the
   option chips are <label>s and would otherwise inherit display:block + margins). */
.tests-page .mode-seg { display: flex; gap: var(--space-2); }
.tests-page .mode-seg .mode-seg__opt {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  cursor: pointer;
  transition: border-color .12s ease, background-color .12s ease, box-shadow .12s ease;
}
.tests-page .mode-seg .mode-seg__opt:hover { border-color: var(--color-primary); }
.tests-page .mode-seg .mode-seg__opt.is-selected {
  border-color: var(--color-primary);
  background: rgba(79, 70, 229, .06);
  box-shadow: inset 0 0 0 1px var(--color-primary);
}
/* Dark mode: orange primary tint on the chosen chip, not the light indigo. */
body.dark .tests-page .mode-seg .mode-seg__opt.is-selected { background: rgba(249, 115, 22, .12); }
.tests-page .mode-seg .mode-seg__opt:focus-within { box-shadow: var(--ring); }
.mode-seg__opt input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.mode-seg__txt { font-size: .875rem; font-weight: 500; color: var(--color-text); }
.mode-seg__hint {
  margin-top: var(--space-2);
  font-size: .8125rem;
  line-height: 1.4;
  color: var(--color-muted);
}

/* Inline spinner shown on the CTAs while assembling. */
.inline-spin {
  display: inline-block;
  width: 14px;
  height: 14px;
  vertical-align: -2px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: var(--radius-pill);
  opacity: .9;
  animation: tests-spin .6s linear infinite;
}
@keyframes tests-spin { to { transform: rotate(360deg); } }

/* --- Attempt history ---------------------------------------------------- */
.hist-list { display: flex; flex-direction: column; }

.hist-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-2);
  border-radius: var(--radius-input);
  color: inherit;
  text-decoration: none;
  transition: background-color .1s ease;
}
.hist-row + .hist-row { border-top: 1px solid var(--color-divider); }
.hist-row:hover { background: var(--color-canvas); }
.hist-row:hover .hist-row__title { color: var(--color-primary); }
.hist-row:hover .hist-row__score { background: var(--color-surface); }
.hist-row:focus-visible { outline: none; box-shadow: var(--ring); }

.hist-row__main { min-width: 0; }
/* Asignatura chips under an attempt's title (ROADMAP N25). */
.hist-row__subjects {
  margin-top: var(--space-1);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  min-width: 0;
}
.hist-row__title {
  font-size: .9375rem;
  font-weight: 600;
  color: var(--color-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hist-row__meta {
  margin-top: var(--space-1);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-1);
  font-size: .8125rem;
  color: var(--color-muted);
}

/* Score = a neutral correct/total pill (the JS prints "N / M" or "—"). */
.hist-row__score {
  flex: 0 0 auto;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  background: var(--color-neutral-bg);
  color: var(--color-body);
  font-size: .8125rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.hist-pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
  font-size: .8125rem;
  color: var(--color-muted);
}

/* --- Responsive --------------------------------------------------------- */
@media (max-width: 900px) {
  .tests-grid { grid-template-columns: 1fr; }
}

/* ===== HACER TEST (test-taking) ===== */
/* Scoped to .test-take. Reuses foundation tokens + .card / .btn. Hooks mirror
   test_take.php (tt-*) exactly — never rename. A centered reading column with
   one card per question and selectable option rows. */

.test-take {
  max-width: 720px;
  margin: 0 auto;
}
.test-take #takeStatus {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

/* Head: title + question count. */
.tt-header { display: flex; flex-direction: column; gap: var(--space-1); }
.tt-header h1 { font-size: 1.625rem; line-height: 1.18; letter-spacing: -.02em; font-weight: 700; color: var(--color-text); }
.tt-meta { font-size: .875rem; color: var(--color-muted); }

/* N45 — smart exam title. Applied to the take/results <h1> (adds .exam-title); the inner
   markup is built by Metodium.examTitleHtml from the API `scope`. Keeps the h1's font from
   .tt-header h1 / .tr-header h1 and just lays out the subject name + excluded ✕ chips
   (whole-minus-a-couple) or the "+N" partial suffix. */
.exam-title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); }
.exam-title__subject { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); }
.exam-title__icon { font-size: .9em; }
.exam-title__part { color: var(--color-muted); font-weight: 600; }
.exam-title__more { color: var(--color-muted); font-weight: 600; }
.exam-title__sep { color: var(--color-divider); font-weight: 400; }
.exam-title__excluded { display: inline-flex; flex-wrap: wrap; gap: var(--space-1); }
.exam-title__chip {
  display: inline-flex; align-items: center; gap: 2px;
  font-size: .8rem; font-weight: 600; line-height: 1.4; letter-spacing: 0;
  padding: 1px var(--space-2);
  border-radius: var(--radius-pill);
  color: var(--color-danger); background: var(--color-danger-bg);
  white-space: nowrap;
}

/* Simulacro countdown (exam_sim). Floats fixed at the top-right of the viewport so
   it stays visible while the user scrolls through the questions — it owns the corner
   the global .qsearch is suppressed from on the take page. Turns red in the last minute. */
.tt-timer {
  position: fixed;
  top: var(--space-4);
  right: var(--space-4);
  z-index: 44;                    /* mirrors .qsearch: below the mobile overlay (45) + modals */
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-warning);
  border-radius: var(--radius-pill);
  background: var(--color-warning-bg);
  box-shadow: var(--shadow-pop);
}
.tt-timer__label {
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--color-warning);
}
.tt-timer__clock {
  font-size: 1.25rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--color-warning);
}
.tt-timer--low {
  border-color: var(--color-danger);
  background: var(--color-danger-bg);
}
.tt-timer--low .tt-timer__label,
.tt-timer--low .tt-timer__clock { color: var(--color-danger); }

/* The form is a flex column of question cards. */
#takeForm { display: flex; flex-direction: column; gap: var(--space-4); }

/* Question card (already .card → chrome). */
.tt-question { display: flex; flex-direction: column; gap: var(--space-3); }
.tt-question__num {
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--color-muted);
}
.tt-question__text {
  font-size: 1.0625rem;
  line-height: 1.5;
  font-weight: 500;
  color: var(--color-text);
}

/* Selectable option rows with a custom indigo radio dot. */
.tt-option {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  cursor: pointer;
  transition: border-color .12s ease, background-color .12s ease, box-shadow .12s ease;
}
.tt-option:hover { border-color: var(--color-primary); background: rgba(79, 70, 229, .03); }
.tt-option--selected {
  border-color: var(--color-primary);
  background: rgba(79, 70, 229, .06);
  box-shadow: inset 0 0 0 1px var(--color-primary);
}
/* Dark mode: track the orange primary instead of a faint indigo tint. */
body.dark .tt-option:hover     { background: rgba(249, 115, 22, .07); }
body.dark .tt-option--selected { background: rgba(249, 115, 22, .12); }
.tt-option input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  position: relative;
  width: 20px;
  height: 20px;
  margin: 0;
  border: 2px solid var(--color-border);
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: border-color .12s ease;
}
.tt-option input[type="radio"]:checked { border-color: var(--color-primary); }
.tt-option input[type="radio"]:checked::after {
  content: "";
  position: absolute;
  inset: 3px;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
}
.tt-option input[type="radio"]:focus-visible { outline: none; box-shadow: var(--ring); }
.tt-option__letter {
  flex: 0 0 auto;
  min-width: 1.25em;
  font-size: .9375rem;
  font-weight: 600;
  color: var(--color-muted);
}
.tt-option--selected .tt-option__letter { color: var(--color-primary); }
.tt-option__text { font-size: .9375rem; line-height: 1.45; color: var(--color-body); }
.tt-option--selected .tt-option__text { color: var(--color-text); font-weight: 500; }

/* Submit row. */
.tt-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding-top: var(--space-1);
}
.tt-actions .btn { flex: 0 0 auto; min-width: 220px; }
.tt-unanswered { font-size: .875rem; font-weight: 600; color: var(--color-warning); }

/* ===== Modo estudio (test_take.php) ===== */
/* Two columns: scrollable question list (left) + a sticky panel (right) showing the
   source PDF of the ACTIVE question, rendered with the SAME pdf.js reader as study.php
   (canvas + selectable text layer — reuses the .reader-pdf/.textLayer styles above;
   pdf.js worker is already CSP-allowlisted). Falls back to the single column when no
   question has a stored PDF. The wider container is opt-in via .test-take--study. */
.test-take--study { max-width: 1180px; }
.tt-study {
  display: grid;
  /* questions | drag-handle | pdf. The PDF track defaults to a fraction; the N27
     drag-resizer rewrites --tt-pdf-basis to a px width. The handle track carries the
     inter-column spacing (grid gap is 0 so the handle owns the gutter). */
  grid-template-columns: minmax(0, 1fr) var(--space-5) var(--tt-pdf-basis, minmax(0, 1.05fr));
  gap: 0;
  align-items: start;
}
.tt-study__questions { min-width: 0; }
.tt-study__questions #takeForm { display: flex; flex-direction: column; gap: var(--space-4); }

/* N27: drag handle between the question column and the PDF panel (desktop only). */
.tt-study__resizer {
  align-self: stretch;
  position: relative;
  cursor: col-resize;
  touch-action: none;
}
.tt-study__resizer::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 50%;
  width: 2px;
  transform: translateX(-50%);
  background: var(--color-border);
  border-radius: var(--radius-pill);
  transition: background .12s ease, width .12s ease;
}
.tt-study__resizer:hover::before,
.tt-study__resizer:focus-visible::before { background: var(--color-primary); width: 3px; }
.tt-study__resizer:focus-visible { outline: none; }
/* While dragging: forbid text selection + let the pointer glide over the PDF text. */
body.is-tt-resizing { cursor: col-resize; user-select: none; }
body.is-tt-resizing .textLayer { pointer-events: none; }

.tt-study__pdf {
  position: sticky;
  top: var(--space-5);
  height: calc(100vh - var(--space-8) * 2);
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.tt-study__pdf-head {
  flex: 0 0 auto;
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.tt-study__pdf-tools { display: flex; gap: var(--space-2); }
.tt-study__pdf-tools[hidden] { display: none; }
.tt-study__zoom {
  min-width: 34px;
  padding: 4px 8px;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--color-text);
  background: var(--color-canvas);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  cursor: pointer;
}
.tt-study__zoom:hover:not(:disabled) { background: var(--color-surface); border-color: var(--color-primary); }
.tt-study__zoom:disabled { opacity: .45; cursor: default; }
.tt-study__pdf-label {
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--color-muted);
}
.tt-study__pdf-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.tt-study__pdf-empty {
  margin: auto;
  padding: var(--space-6);
  font-size: .875rem;
  color: var(--color-muted);
  text-align: center;
}
/* The pdf.js scroll container fills the panel body (the shared .reader-pdf sets a
   viewport-relative default height for the study.php reader; here it fills the flex box). */
.tt-study__pdf-body .reader-pdf {
  flex: 1 1 auto;
  height: auto;
  min-height: 0;
}

/* N27: fullscreen the PDF panel. Native :fullscreen already fills the screen; the
   .is-fullscreen class is the shared hook that also drives the CSS viewport-fill
   fallback when the Fullscreen API is unavailable/denied. */
.tt-study__pdf.is-fullscreen,
.tt-study__pdf:fullscreen {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  z-index: 1000;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/* Active question = the one whose PDF is shown (study mode) OR, since N2
   (2026-07-07), the one nearest the viewport centre in exam/simulacro mode too —
   same assisted-scroll highlight, no PDF panel. Scoped to #takeForm (always the
   take-page form id) instead of .tt-study so it applies in both layouts. */
#takeForm .tt-question { cursor: pointer; scroll-margin-top: var(--space-5); }
#takeForm .tt-question--active {
  border-color: var(--color-primary);
  box-shadow: inset 0 0 0 2px var(--color-primary);
}
#takeForm .tt-question:focus-visible { outline: none; box-shadow: var(--ring); }

@media (max-width: 900px) {
  .test-take--study { max-width: 720px; }
  .tt-study { grid-template-columns: 1fr; }
  .tt-study__resizer { display: none; }   /* N27: stacked on mobile, no resize */
  .tt-study__pdf { position: static; height: auto; order: -1; }
  /* Stacked: the PDF sits above the questions with a definite height so it scrolls
     internally (no scroll-sync on mobile — the JS skips the assisted scroll there). */
  .tt-study__pdf-body .reader-pdf { height: 55vh; flex: 0 0 auto; }
}

/* ===== REVISIÓN DEL TEST (solution sheet) ===== */
/* Scoped to .test-results. Reuses foundation tokens + .card / .btn and the
   accuracy palette (acc-high/mid/low). Hooks mirror test_results.php (tr-*)
   exactly — never rename. Per-question right/wrong highlighting + explanation. */

.test-results {
  max-width: 720px;
  margin: 0 auto;
}
.test-results #resultsStatus {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

/* Score band. */
.tr-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  text-align: center;
  padding: var(--space-6);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
}
.tr-header h1 { font-size: 1.375rem; line-height: 1.22; letter-spacing: -.02em; font-weight: 700; color: var(--color-text); }
.tr-score {
  font-size: 2.75rem;
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -.03em;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}
.tr-score__pct { font-size: 1rem; font-weight: 600; color: var(--color-muted); }
.tr-header__meta { margin-top: var(--space-1); font-size: .8125rem; color: var(--color-muted); }
/* Tint the score by performance (>=70 green, 50–69 amber, <50 red). */
.tr-header--high .tr-score, .tr-header--high .tr-score__pct { color: var(--color-acc-high); }
.tr-header--mid  .tr-score, .tr-header--mid  .tr-score__pct { color: var(--color-acc-mid); }
.tr-header--low  .tr-score, .tr-header--low  .tr-score__pct { color: var(--color-acc-low); }

/* Simulacro breakdown chips: correct / wrong / blank counts under the net score. */
.tr-breakdown {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}
.tr-chip {
  display: inline-flex;
  align-items: center;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  font-size: .8125rem;
  font-weight: 600;
  border: 1px solid var(--color-border);
}
.tr-chip--ok    { color: var(--color-success); background: var(--color-success-bg); border-color: var(--color-success-bg); }
.tr-chip--bad   { color: var(--color-danger);  background: var(--color-danger-bg);  border-color: var(--color-danger-bg); }
.tr-chip--blank { color: var(--color-muted);   background: var(--color-surface); }

/* Question block. N5 (2026-07-08, Rober's call): fully flat — no border/shadow/
   background, just spacing — so it blends with the page instead of sitting in a
   boxed card. `.card` still supplies the padding (kept, for internal rhythm); this
   overrides just its box styling. Options (.tr-option) keep their own borders. */
.tr-question {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  background: none;
  border: none;
  box-shadow: none;
}
.tr-question__num {
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--color-muted);
}
.tr-question__num--ok  { color: var(--color-success); }
.tr-question__num--bad { color: var(--color-danger); }
.tr-question__text {
  font-size: 1.0625rem;
  line-height: 1.5;
  font-weight: 500;
  color: var(--color-text);
}
.tr-unanswered { font-size: .875rem; font-weight: 500; color: var(--color-warning); }

/* Option rows: neutral, with correct/wrong highlighting + a tag. */
.tr-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  font-size: .9375rem;
  color: var(--color-body);
}
.tr-option__content {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}
.tr-option__letter {
  flex: 0 0 auto;
  min-width: 1.25em;
  font-weight: 600;
  color: var(--color-muted);
}
.tr-option--correct .tr-option__letter,
.tr-option--wrong .tr-option__letter { color: inherit; }
.tr-option__text { min-width: 0; line-height: 1.45; }
.tr-option--correct {
  border-color: var(--color-acc-high);
  background: var(--color-success-bg);
  color: var(--color-text);
}
.tr-option--wrong {
  border-color: var(--color-acc-low);
  background: var(--color-danger-bg);
  color: var(--color-text);
}
.tr-tag {
  flex: 0 0 auto;
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: .6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  white-space: nowrap;
}
.tr-tag--correct { background: var(--color-success); color: #fff; }
.tr-tag--wrong   { background: var(--color-danger);  color: #fff; }

/* Explanation block. */
.tr-expl {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-input);
  border-left: 3px solid var(--color-border);
  background: var(--color-neutral-bg);
  font-size: .875rem;
  line-height: 1.55;
  color: var(--color-body);
}
.tr-expl__label { font-weight: 600; color: var(--color-text); }
.tr-expl u { text-decoration-color: var(--color-primary); text-underline-offset: 2px; }

/* N30 — a clickable explanation (has a source PDF + stored quote): opens the source
   popup with the passage highlighted. Retheme in place; the base .tr-expl look is kept. */
.tr-expl--clickable {
  cursor: pointer;
  transition: border-color .12s ease, background-color .12s ease;
}
.tr-expl--clickable:hover,
.tr-expl--clickable:focus-visible {
  border-left-color: var(--color-primary);
  background: var(--color-primary-soft, var(--color-neutral-bg));
  outline: none;
}
.tr-expl--clickable:focus-visible { box-shadow: var(--ring); }
.tr-expl__cta {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-left: var(--space-2);
  padding: 1px var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-primary);
  font-size: .75rem;
  font-weight: 600;
  white-space: nowrap;
  vertical-align: baseline;
}
.tr-expl--clickable:hover .tr-expl__cta { border-color: var(--color-primary); }

/* N30 — centered source-PDF popup (pdf.js). Reuses the .reader-pdf render styles inside
   .tr-pdf-modal__body; the highlight is a transient .tr-pdf-hl (not a saved annotation). */
body.tr-pdf-open { overflow: hidden; }
.tr-pdf-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
}
.tr-pdf-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(16, 24, 40, .55);
}
.tr-pdf-modal__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(880px, 96vw);
  height: min(88vh, 1000px);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
}
.tr-pdf-modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
}
.tr-pdf-modal__title {
  font-weight: 600;
  font-size: .9375rem;
  color: var(--color-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tr-pdf-modal__tools { display: flex; align-items: center; gap: var(--space-1); flex: none; }
.tr-pdf-modal__zoom,
.tr-pdf-modal__close {
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-body);
  border-radius: var(--radius-input);
  padding: 4px 10px;
  font-size: .875rem;
  cursor: pointer;
  line-height: 1.2;
}
.tr-pdf-modal__zoom:hover,
.tr-pdf-modal__close:hover { border-color: var(--color-primary); color: var(--color-primary); }
.tr-pdf-modal__zoom:disabled { opacity: .45; cursor: default; }
.tr-pdf-modal__close { font-size: 1rem; }
.tr-pdf-modal__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  background: var(--color-neutral-bg);
  padding: var(--space-3);
}
.tr-pdf-modal__body .reader-pdf { height: 100%; }
.tr-pdf-modal__msg {
  margin: var(--space-6) auto;
  text-align: center;
  font-size: .8125rem;
  color: var(--color-muted);
}
/* Transient highlight over the quote's text-layer spans. Plain translucent fill (no
   mix-blend-mode — N29 lesson: multiply forces a backdrop read-back that ghosts the
   text layer). Sits in the .reader-pdf__annots overlay above the transparent text. */
.tr-pdf-hl {
  position: absolute;
  background: rgba(249, 235, 59, .45);
  border-radius: 2px;
  pointer-events: none;
}

/* Per-question 👍/👎 — faint until chosen, no color fills. */
.tr-qvote {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding-top: var(--space-1);
}
.tr-qvote__hint { font-size: .8125rem; color: var(--color-muted); }
.tr-qvote__btn {
  border: 0;
  background: none;
  padding: 2px var(--space-1);
  font-size: 1rem;
  line-height: 1;
  border-radius: var(--radius-input);
  cursor: pointer;
  opacity: .4;
  filter: grayscale(1);
  transition: opacity .12s ease, filter .12s ease, background-color .12s ease;
}
.tr-qvote__btn:hover { opacity: .85; filter: grayscale(.3); background: var(--color-divider); }
.tr-qvote__btn.is-active { opacity: 1; filter: none; }
.tr-qvote__btn:focus-visible { outline: none; box-shadow: var(--ring); }

/* Per-test rating gate (the page's "continue"). */
.tr-rate {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  text-align: center;
}
.tr-rate__prompt { font-size: 1rem; font-weight: 600; color: var(--color-text); }
.tr-rate__buttons { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-3); }
.tr-rate__btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  font-size: .9375rem;
  font-weight: 500;
  color: var(--color-body);
  cursor: pointer;
  transition: transform .14s ease, border-color .12s ease, background-color .12s ease, color .12s ease, box-shadow .14s ease;
}
.tr-rate__btn:hover { transform: translateY(-1px); border-color: var(--color-primary); color: var(--color-text); box-shadow: var(--shadow-hover); }
.tr-rate__btn:focus-visible { outline: none; box-shadow: var(--ring); }
.tr-rate__btn:disabled { cursor: default; opacity: .7; }
.tr-rate__emoji { font-size: 1.05rem; line-height: 1; }
.tr-rate__btn--up.is-active   { border-color: var(--color-acc-high); background: var(--color-success-bg); color: var(--color-text); }
.tr-rate__btn--down.is-active { border-color: var(--color-acc-low);  background: var(--color-danger-bg);  color: var(--color-text); }
.tr-rate__note { max-width: 48ch; font-size: .8125rem; color: var(--color-muted); }

/* --- Responsive --------------------------------------------------------- */
@media (max-width: 540px) {
  .tt-actions .btn { flex: 1 1 auto; min-width: 0; width: 100%; }
  .tr-option { flex-wrap: wrap; }
}

/* ===== GENERAR TEST (modal desde el lector) ===== */
/* The reader's "Generar test" button + a node-picker modal: a simplified,
   pre-checked tree of the selected tema's subtree. Reuses tokens + .btn.
   Hooks mirror study.php (reader-gen / genmodal-*) exactly — never rename. */

/* Button at the top of the reader pane. */
.reader-gen { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-3); }

/* N28: brand-accent the reader's "Hacer test" CTA so it reads as the primary
   reader action instead of a plain grey outline. Gradient fill + white text/icon
   + orange shadow; keeps the .btn/.btn-block layout (full-width, or the width:auto
   floating pill in fullscreen) and the clipboard icon. ID-scoped so it overrides
   .btn-secondary without renaming the JS-relied-on class/ID. */
#readerGenTest {
  background: var(--grad);
  border-color: transparent;
  color: #fff;
  box-shadow: var(--shadow-orange);
}
#readerGenTest:hover {
  background: var(--grad);
  border-color: transparent;
  color: #fff;
  filter: brightness(1.04);
  transform: translateY(-1px);
  box-shadow: var(--shadow-orange);
}
#readerGenTest:active { filter: brightness(.98); transform: translateY(0); }
#readerGenTest:disabled,
#readerGenTest:disabled:hover { filter: none; transform: none; box-shadow: none; }
#readerGenTest svg { stroke: #fff; }

/* Backdrop + centered dialog (above the docked timer). */
.genmodal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: grid;
  place-items: center;
  padding: var(--space-4);
  background: rgba(17, 24, 39, .4);
}
.genmodal {
  display: flex;
  flex-direction: column;
  width: min(540px, 96vw);
  max-height: 88vh;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
}

/* Head */
.genmodal__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--color-divider);
}
.genmodal__eyebrow {
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--color-muted);
}
.genmodal__title {
  margin-top: 2px;
  font-size: 1.125rem;
  line-height: 1.3;
  color: var(--color-text);
}
.genmodal__close {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: 0;
  background: none;
  border-radius: var(--radius-input);
  color: var(--color-muted);
  font-size: 1rem;
  cursor: pointer;
}
.genmodal__close:hover { background: var(--color-divider); color: var(--color-text); }

/* Body (scrolls) */
.genmodal__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-5) var(--space-6);
  overflow: auto;
}

/* Config: questions + difficulty */
.genmodal__config {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}
.genmodal__field { display: flex; flex-direction: column; gap: var(--space-2); }
.genmodal__field-label { font-size: .8125rem; font-weight: 600; color: var(--color-body); }
.genmodal__field input,
.genmodal__field select {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
  font-size: .9375rem;
  color: var(--color-text);
}
.genmodal__field input:focus,
.genmodal__field select:focus { outline: none; box-shadow: var(--ring); border-color: var(--color-primary); }

/* Temas picker */
.genmodal__temas { display: flex; flex-direction: column; gap: var(--space-2); }
.genmodal__temas-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.genmodal__temas-title { font-size: .8125rem; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--color-muted); }
.genmodal__all {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: .8125rem;
  color: var(--color-body);
  cursor: pointer;
}
.genmodal__all input { accent-color: var(--color-primary); width: 16px; height: 16px; cursor: pointer; }

.genmodal__tree {
  max-height: 320px;
  overflow: auto;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
}
.genmodal__loading { font-size: .875rem; color: var(--color-muted); padding: var(--space-3); }
.genmodal__list { list-style: none; display: flex; flex-direction: column; gap: 1px; }
.genmodal__list .genmodal__list { padding-left: var(--space-5); }
.genmodal__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-input);
  cursor: pointer;
}
.genmodal__row:hover { background: var(--color-divider); }
.genmodal__row input[type="checkbox"] {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  accent-color: var(--color-primary);
  cursor: pointer;
}
.genmodal__name { font-size: .875rem; line-height: 1.4; color: var(--color-text); }
.genmodal__row--root .genmodal__name { font-weight: 600; }

/* Foot */
.genmodal__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--color-divider);
  background: var(--color-surface);
}
.genmodal__note { font-size: .8125rem; color: var(--color-muted); min-width: 0; }
.genmodal__note.is-error { color: var(--color-danger); }
.genmodal__actions { display: flex; gap: var(--space-2); margin-left: auto; }

/* ── Examen de referencia / estilo (ROADMAP #16) ─────────────────────────────
   Personal modal (study.php) + admin shared card (admin.php). Mirrors the
   .genmodal modal tokens; the candidate-list/-item/-opt classes are shared by
   both surfaces. */
.examref-open { flex: 0 0 auto; }

.examref-backdrop {
  position: fixed;
  inset: 0;
  /* Above the fullscreen reader (1200). The JS also portals this modal to <body> so the
     fixed backdrop is viewport-relative and covers the WHOLE screen (incl. the sidebar). */
  z-index: 1300;
  display: grid;
  place-items: center;
  padding: var(--space-4);
  background: rgba(17, 24, 39, .4);
}
.examref {
  display: flex;
  flex-direction: column;
  width: min(620px, 96vw);
  max-height: 88vh;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
}
.examref__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--color-divider);
}
.examref__eyebrow {
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--color-muted);
}
.examref__title { margin-top: 2px; font-size: 1.125rem; line-height: 1.3; color: var(--color-text); }
.examref__close {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: 0;
  background: none;
  border-radius: var(--radius-input);
  color: var(--color-muted);
  font-size: 1rem;
  cursor: pointer;
}
.examref__close:hover { background: var(--color-divider); color: var(--color-text); }
.examref__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-6);
  overflow: auto;
}
.examref__intro { font-size: .875rem; color: var(--color-body); line-height: 1.5; }
.examref__shared-note {
  font-size: .8125rem;
  color: var(--color-body);
  background: var(--color-warning-bg);
  border-radius: var(--radius-input);
  padding: var(--space-2) var(--space-3);
}

/* "Ver examen (PDF)" link(s) — view the stored reference PDF (migration 025) */
.examref__view { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.examref__view-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: .8125rem;
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: none;
  padding: 4px var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
}
.examref__view-link:hover { background: var(--color-divider); text-decoration: underline; }

/* Upload zone (drop target) */
.examref__upload {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-5);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-input);
  text-align: center;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}
.examref__upload.is-drag { border-color: var(--color-primary); background: var(--color-canvas); }
.examref__upload-icon { font-size: 1.25rem; color: var(--color-muted); }
.examref__upload-text { font-size: .875rem; color: var(--color-body); }
.examref__link {
  border: 0;
  background: none;
  padding: 0;
  color: var(--color-primary);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  text-decoration: underline;
}
.examref__status { font-size: .8125rem; color: var(--color-muted); }

/* Candidate list (shared by personal + admin) */
.examref__list { display: flex; flex-direction: column; gap: var(--space-3); }
.examref__empty { font-size: .875rem; color: var(--color-muted); }
.examref-item {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-canvas);
}
.examref-item__head { display: flex; align-items: center; justify-content: space-between; }
.examref-item__num {
  font-size: .75rem;
  font-weight: 600;
  color: var(--color-muted);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.examref-item__del {
  border: 0;
  background: none;
  color: var(--color-muted);
  font-size: .9375rem;
  line-height: 1;
  cursor: pointer;
  border-radius: var(--radius-input);
  padding: 2px 6px;
}
.examref-item__del:hover { color: var(--color-danger); background: var(--color-danger-bg); }
.examref-item__stem {
  width: 100%;
  resize: vertical;
  font: inherit;
  font-size: .875rem;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
  color: var(--color-text);
}
.examref-item__opts { display: flex; flex-direction: column; gap: var(--space-1); }
.examref-opt { display: flex; align-items: center; gap: var(--space-2); }
.examref-opt input[type="radio"] { flex: 0 0 auto; }
.examref-opt__text {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-size: .8125rem;
  padding: 4px var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
  color: var(--color-text);
}
.examref__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--color-divider);
}
.examref__note { font-size: .8125rem; color: var(--color-muted); min-width: 0; }
.examref__note.is-error { color: var(--color-danger); }
.examref__actions { display: flex; gap: var(--space-2); margin-left: auto; }

/* Admin shared variant (admin.php card) */
.examref-admin { display: flex; flex-direction: column; gap: var(--space-4); }
.examref-admin__bar { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: flex-end; }
.examref-admin__field { display: flex; flex-direction: column; gap: var(--space-1); }
.examref-admin__label { font-size: .8125rem; font-weight: 600; color: var(--color-text); }
.examref-admin__select {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: .875rem;
  min-width: 220px;
}
.examref-admin__upload { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.examref-admin__status { font-size: .8125rem; color: var(--color-muted); }
.examref-admin__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
}

@media (max-width: 480px) {
  .genmodal__config { grid-template-columns: 1fr; }
}

/* ===== TEMARIO: asignatura sin "mother node" + añadir contenido ===== */
/* Inside an asignatura its own row is hidden and its temas are promoted to the
   top level (we're already on that asignatura's page). A persistent "add
   content" card — same height as a collapsed tema — lets the user drop a PDF or
   create temas manually. Hooks mirror study.php — never rename. */

/* Hide the asignatura's own row; promote its temas up one indent level. */
.study-board .tree__item.is-temario-root > .tree__row { display: none; }
.study-board .tree__item.is-temario-root > .tree__children {
  margin-left: -1.15rem;       /* cancel one depth level of indentation */
  padding-top: var(--space-2);
}

/* In a subject the subject's own item is just a container (its row is hidden via
   is-temario-root); drop its card chrome so each top-level child stands alone as
   its own box rather than being grouped inside one big card. */
.study-board .tree--root > .tree__item.is-temario-root {
  background: transparent;
  border: 0;
  box-shadow: none;
  overflow: visible;
}
.study-board .tree--root > .tree__item.is-temario-root:hover { box-shadow: none; }

/* Temario blocks: every top-level node renders as its own boxed card (a manually
   created tema or a PDF imported as a block). */
.study-board .tree__item--block {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  background: var(--color-surface);
  box-shadow: var(--shadow-card);
  margin: var(--space-3) 0;
  padding: var(--space-1) var(--space-2) var(--space-2);
}
.study-board .tree__item--block > .tree__row {
  padding-left: var(--space-2) !important;   /* header hugs the box edge */
}
.study-board .tree__item--block > .tree__row .tree__name {
  font-size: 1rem;
  font-weight: 600;
  color: var(--color-text);
}
.study-board .tree__item--block > .tree__children {
  margin-left: 0;                            /* indent children from the box, not the tree */
  padding-top: var(--space-1);
}
/* Hover / selected highlight fills the whole box, not just the inner header row. */
.study-board .tree__item--block { transition: background .12s ease, box-shadow .12s ease, border-color .12s ease; }
.study-board .tree__item--block:hover { background: var(--color-divider); }
.study-board .tree__item--block:has(> .tree__row.is-selected) { background: rgba(79, 70, 229, .08); }
.study-board .tree__item--block > .tree__row:hover,
.study-board .tree__item--block > .tree__row.is-selected { background: transparent; }

/* Add-content card: a collapsed-tema-sized dashed dropzone + manual link. */
.temario-add { display: flex; flex-direction: column; gap: var(--space-2); }
/* Drop zone (Signal 1: it answers back). Big, inviting target; border+glow+copy
   swap on dragover. Primary tints via color-mix so they follow the theme
   (indigo in light, orange in dark) with no per-theme overrides. */
.temario-add__zone {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-height: 210px;
  padding: var(--space-8) var(--space-5);
  border: 1.5px dashed var(--color-border);
  border-radius: var(--radius-card);
  background: var(--color-surface);
  cursor: pointer;
  text-align: center;
  transition: border-color .14s ease, background-color .14s ease, box-shadow .14s ease;
}
/* Animated dashed border (marching ants). The static CSS border shows at rest;
   while dragging or uploading, it goes transparent and this SVG draws flowing
   dashes that march clockwise around the box. */
.temario-add__ants {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
  opacity: 0;
  transition: opacity .15s ease;
}
.temario-add__ants rect {
  x: 1px;
  y: 1px;
  width: calc(100% - 2px);
  height: calc(100% - 2px);
  rx: var(--radius-card);
  ry: var(--radius-card);
  fill: none;
  stroke: var(--color-primary);
  stroke-width: 1.5;
  stroke-dasharray: 10 8;
  vector-effect: non-scaling-stroke;
}
.temario-add__zone.is-dragover,
.temario-add__zone.has-upload { border-color: transparent; }
.temario-add__zone.is-dragover .temario-add__ants,
.temario-add__zone.has-upload  .temario-add__ants { opacity: 1; }
.temario-add__zone.is-dragover .temario-add__ants rect,
.temario-add__zone.has-upload  .temario-add__ants rect { animation: temarioAnts .5s linear infinite; }
@keyframes temarioAnts { to { stroke-dashoffset: -18; } }
/* Once the structure is ready (card is-done), stop marching — steady dashes while
   the user reviews the proposed tree below. */
.temario-add__zone:has(.pdf-upload.is-done) .temario-add__ants rect { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .temario-add__ants rect { animation: none !important; }
}
/* While a file is staged, the idle prompt gives way to the upload card, centered
   inside the box; the card itself goes borderless/transparent so it reads as
   "loading in the center of the box" (the reference look). */
.temario-add__zone.has-upload .temario-add__icon,
.temario-add__zone.has-upload .temario-add__copy { display: none; }
.temario-add__zone .pdf-upload {
  width: min(100%, 460px);
  background: transparent;
  border: none;
  box-shadow: none;
  padding: 0;
}
/* Placeholder file-icon thumb is hidden during upload; the real page-1 thumbnail
   (has-img) appears once rendered, so early progress is a clean name + % + bar. */
.temario-add__zone .pdf-upload__thumb:not(.has-img) { display: none; }
.temario-add__zone:hover,
.temario-add__zone:focus-visible {
  border-color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 4%, var(--color-surface));
  outline: none;
}
.temario-add__zone.is-dragover {
  /* border goes transparent (rule above) so the animated dashes read cleanly */
  background:
    radial-gradient(ellipse at center, color-mix(in srgb, var(--color-primary) 14%, transparent), transparent 68%),
    color-mix(in srgb, var(--color-primary) 6%, var(--color-surface));
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-primary) 15%, transparent), var(--shadow-pop);
}
.temario-add__zone.has-upload {
  background:
    radial-gradient(ellipse at center, color-mix(in srgb, var(--color-primary) 8%, transparent), transparent 70%),
    var(--color-surface);
}
.temario-add__icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--color-primary) 10%, transparent);
  color: var(--color-primary);
  transition: transform .14s ease;
}
.temario-add__icon svg { width: 28px; height: 28px; display: block; }
.temario-add__zone.is-dragover .temario-add__icon { transform: translateY(-3px) scale(1.06); }
.temario-add__copy { display: flex; flex-direction: column; align-items: center; gap: var(--space-1); min-width: 0; }
.temario-add__title { font-size: 1.0625rem; font-weight: 700; color: var(--color-text); }
.temario-add__t-drop { display: none; color: var(--color-primary); }
.temario-add__zone.is-dragover .temario-add__t-idle { display: none; }
.temario-add__zone.is-dragover .temario-add__t-drop { display: inline; }
.temario-add__text { font-size: .8125rem; color: var(--color-muted); line-height: 1.4; }
.temario-add__hint { font-size: .75rem; color: var(--color-muted); opacity: .85; }
.temario-add__link {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: underline;
  cursor: pointer;
}
.temario-add__link:hover { color: var(--color-primary-hover); }

/* Upload card (Signals 2 + 4: honest progress + preview proof). Shows the staged
   PDF's page-1 thumbnail, name, type, size, page count, a real progress bar, and
   Reemplazar / Quitar / Volver a intentar. All feedback in the theme primary
   (never red) — a failed step stays recoverable in place. */
.pdf-upload {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  background: var(--color-surface);
  box-shadow: var(--shadow-card);
}
.pdf-upload__row { display: flex; align-items: center; gap: var(--space-3); }
.pdf-upload__thumb {
  flex: 0 0 auto;
  width: 52px;
  height: 66px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-input);
  background: color-mix(in srgb, var(--color-primary) 8%, var(--color-surface));
  border: 1px solid var(--color-border);
  color: var(--color-primary);
  overflow: hidden;
}
.pdf-upload__thumb-ico { width: 24px; height: 24px; }
.pdf-upload__thumb.has-img .pdf-upload__thumb-ico { display: none; }
.pdf-upload__canvas { width: 100%; height: 100%; object-fit: cover; display: block; }
.pdf-upload__info { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.pdf-upload__namerow { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.pdf-upload__name {
  font-weight: 600;
  font-size: .875rem;
  color: var(--color-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.pdf-upload__type {
  flex: 0 0 auto;
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 12%, transparent);
  border-radius: var(--radius-pill);
  padding: 1px var(--space-2);
}
.pdf-upload__check {
  display: none;
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  place-items: center;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--color-primary) 15%, transparent);
  color: var(--color-primary);
}
.pdf-upload__check svg { width: 12px; height: 12px; display: block; }
.pdf-upload.is-done .pdf-upload__check { display: inline-grid; }
.pdf-upload__meta { font-size: .75rem; color: var(--color-muted); }
.pdf-upload__pct {
  flex: 0 0 auto;
  font-size: 1.05rem;
  font-weight: 800;
  color: var(--color-primary);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}
.pdf-upload__bar {
  position: relative;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--color-divider);
  overflow: hidden;
}
.pdf-upload__fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 0%;
  border-radius: inherit;
  background: var(--color-primary);
  transition: width .25s ease;
}
.pdf-upload.is-indeterminate .pdf-upload__fill {
  width: 35%;
  animation: pdfUpSweep 1.15s ease-in-out infinite;
}
@keyframes pdfUpSweep {
  0%   { left: -35%; }
  100% { left: 100%; }
}
.pdf-upload.is-done .pdf-upload__bar { background: color-mix(in srgb, var(--color-primary) 18%, transparent); }
.pdf-upload.is-done .pdf-upload__fill { width: 100%; }
.pdf-upload.is-error .pdf-upload__fill {
  width: 100%;
  background: color-mix(in srgb, var(--color-primary) 45%, var(--color-muted));
}
.pdf-upload .pdf-status { font-size: .8125rem; color: var(--color-muted); }
.pdf-upload.is-done .pdf-status { color: var(--color-primary); font-weight: 600; }
.pdf-upload.is-error .pdf-status { color: var(--color-primary); }
.pdf-upload__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
@media (prefers-reduced-motion: reduce) {
  .pdf-upload.is-indeterminate .pdf-upload__fill { animation: none; left: 0; width: 35%; }
}
.temario-create {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  width: 100%;
}
/* PDF→árbol engine output, stacked under the dropzone. Empty (all children
   hidden) it collapses to nothing; it fills in as the PDF is processed. */
.temario-add__process { display: flex; flex-direction: column; gap: var(--space-3); }

/* No-index choice: surfaced when a dropped PDF has no navigable index. */
.pdf-noindex { display: flex; flex-direction: column; gap: var(--space-2); flex-basis: 100%; }
.pdf-noindex__msg { font-size: .8125rem; line-height: 1.5; color: var(--color-muted); }
.pdf-noindex__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* ===== BANCO DE PREGUNTAS (browser) ===== */
/* Collapsible tree of the asignatura's banked questions; expand a node to its
   table. Hooks mirror study.php (bank-*, bankq*) exactly — never rename. */
.bank-toolbar { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-3); }
.bank-tree { display: flex; flex-direction: column; gap: 2px; }

/* Merged bank box: #subjectActions (acciones, ámbito tema) + #bankBrowser
   (árbol, ámbito asignatura) now share one .pdf-card body. Each region used to
   inherit column spacing from .pdf-card__body — restore it here, and draw a
   hairline divider between them only when the actions region is visible. */
.bank-actions,
.bank-browser { display: flex; flex-direction: column; gap: var(--space-4); }
.bank-actions__node { font-size: .8125rem; color: var(--color-muted); }
.bank-actions__node:empty { display: none; }
.bank-actions:not([hidden]) + .bank-browser {
  margin-top: var(--space-2);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}

.bank-node { display: flex; flex-direction: column; }
.bank-node__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-input);
  cursor: pointer;
}
.bank-node__row:hover { background: var(--color-divider); }
.bank-node__row:focus-visible { outline: none; box-shadow: var(--ring); }
.bank-node__chev { flex: 0 0 auto; font-size: .75rem; color: var(--color-muted); transition: transform .12s ease; }
.bank-node.is-open > .bank-node__row > .bank-node__chev { transform: rotate(90deg); }
.bank-node__name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: .9375rem;
  font-weight: 500;
  color: var(--color-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bank-node__count { flex: 0 0 auto; font-size: .8125rem; color: var(--color-muted); font-variant-numeric: tabular-nums; }
.bank-node__wrong { flex: 0 0 auto; font-size: .75rem; font-weight: 600; color: var(--color-danger); }
.bank-node__review {
  flex: 0 0 auto;
  padding: 2px var(--space-2);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  border-radius: var(--radius-pill);
  font-size: .75rem;
  color: var(--color-body);
  cursor: pointer;
}
.bank-node__review:hover { border-color: var(--color-danger); color: var(--color-danger); }
.bank-node__body { display: flex; flex-direction: column; gap: 2px; padding-left: var(--space-4); }
/* Inbox mother node: roomier body (status + actions + review list, not a Q table). */
.bank-node--inbox .bank-node__body { gap: var(--space-3); padding: var(--space-2) 0 var(--space-3) var(--space-4); }
.bank-node__table { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-2) 0; }

/* One banked question */
.bankq {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
  transition: border-color .12s ease, box-shadow .12s ease;
}
.bankq:hover { border-color: var(--color-border-strong, var(--color-border)); box-shadow: var(--shadow-card); }
.bankq__main { min-width: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.bankq__q { font-size: .875rem; line-height: 1.45; color: var(--color-text); }
.bankq__a { font-size: .8125rem; color: var(--color-body); }
.bankq__a-label { color: var(--color-success); font-weight: 600; }
.bankq__meta { flex: 0 0 auto; display: flex; align-items: center; gap: var(--space-2); }
.bankq__stat {
  white-space: nowrap;
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: .6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
}
.bankq__stat--wrong   { background: var(--color-danger-bg);  color: var(--color-danger); }
.bankq__stat--correct { background: var(--color-success-bg); color: var(--color-success); }
.bankq__stat--unseen  { background: var(--color-neutral-bg); color: var(--color-muted); }
.bankq__del {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border: 0;
  background: none;
  border-radius: var(--radius-input);
  color: var(--color-muted);
  cursor: pointer;
}
.bankq__del:hover { background: var(--color-danger-bg); color: var(--color-danger); }

/* ===== AUTH (LOGIN & REGISTER) ===== */
/* Requires: <body class="auth-page"> on login.php and register.php */

body.auth-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  padding: var(--space-8) var(--space-4);
}

.login-shell,
.reg-shell {
  width: 100%;
  padding: var(--space-6);
}
.login-shell { max-width: 26.25rem; }  /* 420px */
.reg-shell   { max-width: 27.5rem;  }  /* 440px */

/* ---------------------------------------------------------------------
   Brand
------------------------------------------------------------------------ */
.login-brand,
.reg-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.625rem;                        /* 10px */
  margin-bottom: var(--space-8);
  text-decoration: none;
}

.login-brand__name,
.reg-brand__name {
  height: 44px;
  width: auto;
  object-fit: contain;
}

/* ---------------------------------------------------------------------
   Card
------------------------------------------------------------------------ */
.login-card,
.reg-card {
  background: var(--surface);
  border: 0.0625rem solid var(--border);              /* 1px */
  border-radius: calc(var(--radius-card) + 0.25rem);  /* +4px */
  padding: var(--space-8);
  box-shadow: var(--shadow-pop);
}

.login-card__heading,
.reg-card__heading {
  font-size: 1.375rem;
  font-weight: 700;
  color: var(--text);
  margin-bottom: var(--space-1);
}

.login-card__sub,
.reg-card__sub {
  font-size: 0.875rem;
  color: var(--muted);
  margin-bottom: 1.75rem;
}

/* ---------------------------------------------------------------------
   Alerts (general error banner)
------------------------------------------------------------------------ */
.login-alert,
.reg-alert {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  background: var(--color-danger-bg);
  border: 0.0625rem solid rgba(220, 38, 38, .25);   /* 1px */
  border-radius: var(--radius-input);
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-5);
  font-size: 0.875rem;
  color: var(--danger);
}
.login-alert svg,
.reg-alert svg {
  flex-shrink: 0;
  margin-top: 0.0625rem;                /* 1px */
}

/* ---------------------------------------------------------------------
   Form fields
------------------------------------------------------------------------ */
.login-field + .login-field,
.reg-field + .reg-field {
  margin-top: var(--space-4);
}

.login-label,
.reg-label {
  display: block;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 0.375rem;
  letter-spacing: 0.01em;
}

/* Password label + "forgot?" link on one row (login.php) */
.login-label-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}
.login-label-row .login-label {
  margin-bottom: 0.375rem;
}
.login-forgot {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: none;
}
.login-forgot:hover {
  text-decoration: underline;
}

/* Neutral confirmation note (forgot_password.php success state) */
.login-note {
  background: var(--color-success-bg);
  border: 0.0625rem solid rgba(5, 150, 105, .25);   /* 1px, success tint */
  border-radius: var(--radius-input);
  padding: var(--space-3) var(--space-4);
  font-size: 0.875rem;
  color: var(--text);
  line-height: 1.5;
}

.login-input,
.reg-input {
  display: block;
  width: 100%;
  padding: 0.625rem 0.875rem;
  font-size: 0.9375rem;
  font-family: inherit;
  color: var(--text);
  background: var(--bg);
  border: 0.09375rem solid var(--border);  /* 1.5px */
  border-radius: var(--radius-input);
  outline: none;
  -webkit-appearance: none;
  transition: border-color 140ms ease, box-shadow 140ms ease;
}
.login-input::placeholder,
.reg-input::placeholder {
  color: var(--muted);
  opacity: 1;
}
.login-input:focus,
.reg-input:focus {
  border-color: var(--primary);
  box-shadow: var(--ring);
}

/* Per-field error state (register only) */
.reg-input--error {
  border-color: var(--danger);
}
.reg-input--error:focus {
  border-color: var(--danger);
  box-shadow: 0 0 0 0.1875rem rgba(220, 38, 38, .25);  /* 3px spread */
}

.reg-field-error {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.8125rem;
  color: var(--danger);
}

.reg-hint {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.8125rem;
  color: var(--muted);
}

/* ---------------------------------------------------------------------
   Submit button
------------------------------------------------------------------------ */
.login-submit,
.reg-submit {
  display: block;
  width: 100%;
  margin-top: var(--space-6);
  padding: var(--space-3) var(--space-4);
  font-size: 0.9375rem;
  font-weight: 600;
  font-family: inherit;
  color: #fff;
  background: var(--primary);
  border: none;
  border-radius: var(--radius-input);
  letter-spacing: 0.01em;
  cursor: pointer;
  transition: background 140ms ease, transform 80ms ease;
}
.login-submit:hover,
.reg-submit:hover { background: var(--primary-hover); }
.login-submit:active,
.reg-submit:active { transform: translateY(0.0625rem); }   /* 1px */
.login-submit:focus-visible,
.reg-submit:focus-visible {
  outline: 0.125rem solid var(--primary-hover);   /* 2px */
  outline-offset: 0.1875rem;                      /* 3px */
  box-shadow: var(--ring);
}

/* ---------------------------------------------------------------------
   Footer link
------------------------------------------------------------------------ */
.login-footer,
.reg-footer {
  text-align: center;
  margin-top: var(--space-5);
  font-size: 0.8125rem;
  color: var(--muted);
}
.login-footer a,
.reg-footer a {
  color: var(--primary);
  text-decoration: none;
  font-weight: 600;
}
.login-footer a:hover,
.reg-footer a:hover { text-decoration: underline; }

/* ---------------------------------------------------------------------
   Responsive — tighten card on very small screens
------------------------------------------------------------------------ */
@media (max-width: 25em) {   /* ~400px, em used intentionally in media queries */
  .login-shell,
  .reg-shell { padding: var(--space-4); }
  .login-card,
  .reg-card  { padding: var(--space-6); }
}

/* ===== AUTH — SLIDING DOUBLE-SLIDER (login.php + register.php) =====
   Requires <body class="auth-page auth-page--split auth-page--login|--register">
   and the shared includes/auth_render.php markup (#authSlider holds BOTH forms).
   The gradient overlay slides across to swap Sign in and Create account. Brand
   palette: blue to violet to orange on near-black, white text. Scoped so
   forgot/reset/verify (plain .auth-page) stay untouched. Progressive: the switch
   controls are real links, so with JS off they navigate normally.
   NOTE: never write a class glob with a slash right after a star inside these
   comments — that sequence would close the comment early and drop the next rule. */

body.auth-page--split {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  min-height: 100vh;
  color: #E5E9F2;
  /* Metodium dark-section palette: near-black ink, orange primary glow + indigo
     secondary glow (mirrors the landing .cta-band). */
  background:
    radial-gradient(1100px 640px at 6% -14%, rgba(249, 115, 22, .26), transparent 58%),
    radial-gradient(1000px 660px at 104% 112%, rgba(99, 102, 241, .20), transparent 55%),
    #0B0E14;
}

/* ---- Slider shell ---- */
.auth-slider {
  position: relative;
  width: 100%;
  max-width: 60rem;
  min-height: 42rem;
  background: #141A26;
  border: 1px solid rgba(255, 255, 255, .06);
  border-radius: var(--r4);
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .70), inset 0 1px 0 rgba(255, 255, 255, .04);
  overflow: hidden;
  animation: authCardIn .6s cubic-bezier(.22, 1, .36, 1) both;
}
@keyframes authCardIn {
  from { opacity: 0; transform: translateY(18px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* ---- Sliding form panes ---- */
.auth-pane {
  position: absolute;
  top: 0;
  left: 0;
  width: 50%;
  height: 100%;
  display: flex;
  align-items: center;
  overflow-y: auto;
  scrollbar-width: none;            /* Firefox — hide the bar, keep scrollability */
  padding: clamp(1.25rem, 1.8vw, 1.6rem) clamp(var(--space-6), 3.2vw, 3rem);
  transition: transform .8s cubic-bezier(.77, 0, .18, 1),
              opacity .5s ease, filter .5s ease;
}
.auth-pane::-webkit-scrollbar { width: 0; height: 0; }   /* Chrome/Safari — hide the bar */
.auth-pane--login    { z-index: 2; }
.auth-pane--register { z-index: 1; opacity: 0; filter: blur(6px); }
.auth-slider.is-register .auth-pane--login    { transform: translateX(100%); opacity: 0; filter: blur(6px); z-index: 1; }
.auth-slider.is-register .auth-pane--register { transform: translateX(100%); opacity: 1; filter: blur(0); z-index: 5; }

.auth-form-inner {
  width: 100%;
  max-width: 25rem;
  margin: 0 auto;
  animation: authFormIn .7s .08s cubic-bezier(.22, 1, .36, 1) both;
}
@keyframes authFormIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
.auth-logo { display: inline-flex; margin-bottom: var(--space-3); }
.auth-logo img { height: 27px; width: auto; }
.auth-eyebrow { margin-bottom: var(--space-1); }
.auth-title { font-size: 1.5rem; line-height: 1.15; color: #F4F6FB; margin-bottom: var(--space-1); }
.auth-sub { font-size: .925rem; color: #9BA6BC; margin-bottom: var(--space-3); }

.auth-switch { display: none; margin-top: var(--space-5); font-size: .875rem; color: #9BA6BC; }
.auth-switch a { color: #FDBA74; font-weight: 600; }
.auth-switch a:hover { color: #FB923C; }

/* Re-skin the shared field classes for the dark panel */
body.auth-page--split .login-label,
body.auth-page--split .reg-label { color: #C7D0E0; }
body.auth-page--split .login-input,
body.auth-page--split .reg-input {
  background: rgba(255, 255, 255, .04);
  border: 1.5px solid rgba(255, 255, 255, .10);
  color: #F1F4FA;
  border-radius: var(--r1);
  padding: .625rem .9rem;
}
/* Tighter vertical rhythm on the split screen so the register form fits with
   no scrollbar (the plain forgot/reset pages keep the roomier default). */
body.auth-page--split .login-field + .login-field,
body.auth-page--split .reg-field + .reg-field { margin-top: .625rem; }
body.auth-page--split .reg-label,
body.auth-page--split .login-label { margin-bottom: .25rem; }
/* Compact error rows so even an all-fields-invalid submit still fits (no scroll). */
body.auth-page--split .reg-field-error { margin-top: .2rem; font-size: .78rem; line-height: 1.3; }
body.auth-page--split .login-input::placeholder,
body.auth-page--split .reg-input::placeholder { color: #6B7688; }
body.auth-page--split .login-input:focus,
body.auth-page--split .reg-input:focus {
  border-color: #F97316;
  box-shadow: 0 0 0 3px rgba(249, 115, 22, .28);
  background: rgba(255, 255, 255, .06);
}
/* Keep browser autofill dark instead of the default pale-yellow fill. */
body.auth-page--split .login-input:-webkit-autofill,
body.auth-page--split .reg-input:-webkit-autofill,
body.auth-page--split .login-input:-webkit-autofill:focus,
body.auth-page--split .reg-input:-webkit-autofill:focus {
  -webkit-text-fill-color: #F1F4FA;
  -webkit-box-shadow: 0 0 0 100px #1B2230 inset;
  caret-color: #F1F4FA;
  transition: background-color 9999s ease-out 0s;
}
body.auth-page--split .login-forgot { color: #FDBA74; }
body.auth-page--split .login-forgot:hover { color: #FB923C; }
body.auth-page--split .reg-hint { color: #7C879B; }
body.auth-page--split .reg-consent { color: #9BA6BC; }
body.auth-page--split .reg-consent a { color: #FDBA74; font-weight: 600; }
body.auth-page--split .reg-field-error { color: #FCA5A5; }

/* Icon-in-field: a leading glyph inside each input for a cleaner, pro finish.
   Scoped to the split auth screen only, so the plain forgot/reset pages that reuse
   the login and reg field classes stay untouched. */
body.auth-page--split .auth-input-wrap { position: relative; }
body.auth-page--split .auth-input-wrap > .login-input,
body.auth-page--split .auth-input-wrap > .reg-input { padding-left: 2.65rem; }
body.auth-page--split .auth-ico {
  position: absolute;
  left: .9rem;
  top: 50%;
  transform: translateY(-50%);
  width: 18px;
  height: 18px;
  color: #6B7688;
  pointer-events: none;
  transition: color .2s ease;
}
body.auth-page--split .auth-input-wrap:focus-within .auth-ico { color: #FB923C; }
/* nudge the error-state icon red so it reads with the border */
body.auth-page--split .auth-input-wrap > .reg-input--error ~ .auth-ico,
body.auth-page--split .auth-input-wrap:has(.reg-input--error) .auth-ico { color: #FCA5A5; }

/* Alerts on dark */
body.auth-page--split .login-alert,
body.auth-page--split .reg-alert {
  background: rgba(220, 38, 38, .14);
  border-color: rgba(248, 113, 113, .35);
  color: #FCA5A5;
}

/* Gradient pill CTA (indigo→violet brand) */
body.auth-page--split .login-submit,
body.auth-page--split .reg-submit {
  border-radius: var(--radius-pill);
  border: none;
  background: linear-gradient(135deg, #FB923C 0%, #F97316 46%, #EA580C 100%);
  box-shadow: 0 14px 30px -10px rgba(234, 88, 12, .44);
  transition: transform .15s ease, box-shadow .2s ease, filter .2s ease;
}
body.auth-page--split .login-submit:hover,
body.auth-page--split .reg-submit:hover {
  background: linear-gradient(135deg, #FB923C 0%, #F97316 46%, #EA580C 100%);
  transform: translateY(-1px);
  filter: brightness(1.04);
  box-shadow: 0 18px 34px -12px rgba(234, 88, 12, .52);
}
body.auth-page--split .login-submit:active,
body.auth-page--split .reg-submit:active { transform: translateY(0); }

/* ---- Sliding gradient overlay ---- */
.auth-overlay-wrap {
  position: absolute;
  top: 0;
  left: 50%;
  width: 50%;
  height: 100%;
  overflow: hidden;
  z-index: 100;
  /* Signature diagonal edge — the gradient panel's inner edge is angled, not a
     straight vertical seam. clip-path animates alongside the slide so the slant
     flips sides. Slider bg (#141A26) sits behind the exposed wedge → reads as a
     clean diagonal seam between the dark form and the gradient. */
  clip-path: polygon(8% 0, 100% 0, 100% 100%, 0 100%);
  transition: transform .8s cubic-bezier(.77, 0, .18, 1),
              clip-path .8s cubic-bezier(.77, 0, .18, 1);
}
.auth-slider.is-register .auth-overlay-wrap {
  transform: translateX(-100%);
  clip-path: polygon(0 0, 92% 0, 100% 100%, 0 100%);
}

.auth-overlay-inner {
  position: relative;
  left: -100%;
  width: 200%;
  height: 100%;
  color: #fff;
  background: linear-gradient(155deg, #FFFFFF 0%, #FFF7F0 38%, #FFEAD9 72%, #FFDCBE 100%);
  transform: translateX(0);
  transition: transform .8s cubic-bezier(.77, 0, .18, 1);
}
.auth-slider.is-register .auth-overlay-inner { transform: translateX(50%); }

/* Highlight + orange brand glow layered over the gradient */
.auth-overlay__glow {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    /* soft warm depth on the light panel: a gentle orange bloom pooled low-right,
       a clean white lift top-left — keeps it airy and premium, not a flat block. */
    radial-gradient(640px 480px at 88% 104%, rgba(249, 115, 22, .22), transparent 60%),
    radial-gradient(420px 300px at 84% 88%, rgba(234, 88, 12, .12), transparent 62%),
    radial-gradient(460px 340px at 14% 6%, rgba(255, 255, 255, .85), transparent 62%);
}

.auth-overlay-panel {
  position: absolute;
  top: 0;
  height: 100%;
  width: 50%;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: clamp(var(--space-6), 3vw, 3rem);
  transition: transform .8s cubic-bezier(.77, 0, .18, 1);
}
.auth-overlay-panel--to-register { right: 0; transform: translateX(0); }
.auth-overlay-panel--to-login    { left: 0;  transform: translateX(-18%); }
.auth-slider.is-register .auth-overlay-panel--to-register { transform: translateX(18%); }
.auth-slider.is-register .auth-overlay-panel--to-login    { transform: translateX(0); }

.auth-overlay__title {
  color: #141A26;
  font-size: 1.7rem;
  line-height: 1.15;
  letter-spacing: -.02em;
  font-weight: 800;
  margin-bottom: var(--space-3);
}
.auth-overlay__text { color: #7A6A5B; max-width: 21rem; line-height: 1.6; margin-bottom: var(--space-6); }
/* Solid brand CTA on the light panel — punchy orange pill that pops (not a ghost). */
.auth-ghost-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: .85rem 1.8rem;
  border-radius: var(--radius-pill);
  border: none;
  color: #fff;
  font-weight: 600;
  background: linear-gradient(135deg, #FB923C 0%, #F97316 46%, #EA580C 100%);
  box-shadow: 0 14px 30px -10px rgba(234, 88, 12, .45);
  transition: box-shadow .2s ease, transform .15s ease, filter .2s ease;
}
.auth-ghost-btn:hover {
  color: #fff;
  transform: translateY(-1px);
  filter: brightness(1.04);
  box-shadow: 0 18px 34px -12px rgba(234, 88, 12, .55);
}

.auth-legal {
  text-align: center;
  margin: var(--space-3) auto 0;
  font-size: .8125rem;
  color: #6B7688;
}
.auth-legal a { color: #8A93A6; }
.auth-legal a:hover { color: #B9C0CE; }

/* ---- Responsive: below the slider width, stack to a single visible pane ---- */
@media (max-width: 56em) {   /* ~896px */
  .auth-slider { min-height: 0; max-width: 30rem; }
  .auth-overlay-wrap { display: none; }
  .auth-pane {
    position: static;
    width: 100%;
    height: auto;
    opacity: 1;
    transform: none;
    overflow: visible;
  }
  .auth-pane--register { display: none; }
  .auth-slider.is-register .auth-pane--login { display: none; }
  .auth-slider.is-register .auth-pane--register { display: flex; transform: none; opacity: 1; }
  .auth-switch { display: block; }
}
@media (prefers-reduced-motion: reduce) {
  .auth-slider, .auth-form-inner { animation: none; }
  .auth-pane, .auth-overlay-wrap, .auth-overlay-inner, .auth-overlay-panel { transition: none; }
}

/* ===== ONBOARDING (2-STEP WIZARD) ===== */
/* Requires: <body class="onboarding">. Standalone page (no app shell). A single
   centered card with a 2-step progress bar. Reuses foundation tokens; matches
   the AUTH visual language. */

body.onboarding {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: var(--color-canvas);
  padding: var(--space-8) var(--space-4);
}

/* --- Brand (top-left, like the auth brand but lockup at the page head) --- */
.ob-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.625rem;
  margin-bottom: var(--space-8);
  text-decoration: none;
}
.ob-brand__name {
  height: 44px;
  width: auto;
  object-fit: contain;
}

/* --- Shell: constrains the card width --------------------------------- */
.ob-shell {
  width: 100%;
  max-width: 34rem;   /* ~544px */
}

/* --- Progress bar + step labels --------------------------------------- */
.ob-progress { margin-bottom: var(--space-5); }
.ob-progress__labels {
  display: flex;
  justify-content: space-between;
  margin-bottom: var(--space-2);
}
.ob-progress__step {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-muted);
  transition: color 140ms ease;
}
.ob-progress__step.is-active { color: var(--color-primary); }
.ob-progress__step.is-done   { color: var(--color-success); }
.ob-progress__bar {
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--color-divider);
  overflow: hidden;
}
.ob-progress__fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  transition: width 280ms ease;
}

/* --- Card -------------------------------------------------------------- */
.ob-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: calc(var(--radius-card) + 0.25rem);
  box-shadow: var(--shadow-pop);
  padding: var(--space-8);
}

/* Steps: only the active step is shown. */
.ob-step { display: none; }
.ob-step.is-active {
  display: block;
  animation: ob-fade 240ms ease;
}
@keyframes ob-fade {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

.ob-card__eyebrow {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-muted);
  margin-bottom: var(--space-2);
}
.ob-card__title {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.25;
  color: var(--color-text);
  margin-bottom: var(--space-2);
}
.ob-card__sub {
  font-size: 0.9375rem;
  color: var(--color-muted);
  margin-bottom: var(--space-6);
}

/* --- Field ------------------------------------------------------------- */
.ob-field { display: flex; flex-direction: column; gap: var(--space-2); }
.ob-label {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-text);
  letter-spacing: 0.01em;
}

.ob-search-input,
.ob-date-input {
  width: 100%;
  padding: 0.625rem 0.875rem;
  font-size: 0.9375rem;
  font-family: inherit;
  color: var(--color-text);
  background: var(--color-canvas);
  border: 0.09375rem solid var(--color-border);   /* 1.5px */
  border-radius: var(--radius-input);
  outline: none;
  -webkit-appearance: none;
  transition: border-color 140ms ease, box-shadow 140ms ease;
}
.ob-search-input::placeholder { color: var(--color-muted); opacity: 1; }
.ob-search-input:focus,
.ob-date-input:focus {
  border-color: var(--color-primary);
  box-shadow: var(--ring);
}
.ob-date-input { max-width: 16rem; }

/* --- Search dropdown --------------------------------------------------- */
.ob-search-wrap { position: relative; }
.ob-dropdown {
  position: absolute;
  top: calc(100% + var(--space-1));
  left: 0;
  right: 0;
  z-index: 20;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  box-shadow: var(--shadow-pop);
  max-height: 17.5rem;
  overflow-y: auto;
  display: none;
}
.ob-dropdown.is-open { display: block; }
.ob-dropdown__item {
  padding: var(--space-3) var(--space-4);
  cursor: pointer;
  border-bottom: 1px solid var(--color-divider);
}
.ob-dropdown__item:last-child { border-bottom: none; }
.ob-dropdown__item:hover,
.ob-dropdown__item:focus {
  background: var(--color-divider);
  outline: none;
}
.ob-dropdown__name { font-size: 0.9375rem; font-weight: 600; color: var(--color-text); }
.ob-dropdown__meta { font-size: 0.8125rem; color: var(--color-muted); }
.ob-dropdown__empty { padding: var(--space-4); font-size: 0.875rem; color: var(--color-muted); }
.ob-dropdown__item--custom { border-top: 1px solid var(--color-divider); }
.ob-dropdown__item--custom .ob-dropdown__name { color: var(--color-primary); }

/* --- Selected-oposición badge ----------------------------------------- */
.ob-selected-badge {
  display: none;
  align-items: center;
  gap: var(--space-2);
  align-self: flex-start;
  padding: var(--space-1) var(--space-1) var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-primary);
  background: rgba(79, 70, 229, .1);
}
.ob-selected-badge.is-visible { display: inline-flex; }
.ob-selected-badge__clear {
  display: grid;
  place-items: center;
  width: 1.25rem;
  height: 1.25rem;
  border: none;
  border-radius: var(--radius-pill);
  font-size: 0.75rem;
  line-height: 1;
  cursor: pointer;
  color: var(--color-primary);
  background: rgba(79, 70, 229, .14);
}
.ob-selected-badge__clear:hover { background: rgba(79, 70, 229, .24); }
/* Dark mode: the selected-oposición badge tracks the orange primary. */
body.dark .ob-selected-badge { background: rgba(249, 115, 22, .14); }
body.dark .ob-selected-badge__clear { background: rgba(249, 115, 22, .22); }
body.dark .ob-selected-badge__clear:hover { background: rgba(249, 115, 22, .32); }

/* --- Days-until-exam pill --------------------------------------------- */
.ob-days-pill {
  display: none;
  align-items: center;
  gap: var(--space-2);
  align-self: flex-start;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-secondary);
  background: rgba(124, 58, 237, .1);
}
/* Dark mode: pairs with the indigo secondary text (secondary flips violet→indigo). */
body.dark .ob-days-pill { background: rgba(99, 102, 241, .14); }
.ob-days-pill.is-visible { display: inline-flex; }

.ob-hint { font-size: 0.8125rem; color: var(--color-muted); }

/* --- Error ------------------------------------------------------------- */
.ob-error {
  display: none;
  margin-top: var(--space-4);
  font-size: 0.875rem;
  color: var(--color-danger);
  background: var(--color-danger-bg);
  border: 1px solid rgba(220, 38, 38, .25);
  border-radius: var(--radius-input);
  padding: var(--space-3) var(--space-4);
}
.ob-error.is-visible { display: block; }

/* --- Actions + buttons ------------------------------------------------- */
.ob-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-top: var(--space-8);
}
.ob-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font: inherit;
  font-weight: 600;
  border: none;
  border-radius: var(--radius-input);
  padding: var(--space-3) var(--space-6);
  cursor: pointer;
  transition: background 140ms ease, transform 80ms ease, opacity 140ms ease;
}
.ob-btn:focus-visible { outline: none; box-shadow: var(--ring); }
.ob-btn:active { transform: translateY(0.0625rem); }
.ob-btn--primary { color: #fff; background: var(--color-primary); }
.ob-btn--primary:hover { background: var(--color-primary-hover); }
.ob-btn--primary:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
.ob-btn--ghost { color: var(--color-body); background: transparent; }
.ob-btn--ghost:hover { background: var(--color-divider); color: var(--color-text); }

/* --- Button spinner (injected by setLoading) -------------------------- */
.spinner {
  display: inline-block;
  width: 0.875rem;
  height: 0.875rem;
  border: 2px solid rgba(255, 255, 255, .45);
  border-top-color: #fff;
  border-radius: var(--radius-pill);
  animation: ob-spin 0.7s linear infinite;
}
@keyframes ob-spin { to { transform: rotate(360deg); } }

/* --- Responsive -------------------------------------------------------- */
@media (max-width: 32em) {
  .ob-card { padding: var(--space-6); }
  .ob-card__title { font-size: 1.3125rem; }
  .ob-actions { flex-direction: column-reverse; }
  .ob-btn { width: 100%; }
}

/* ============================================================================
   Metodium BRANDED-DARK WRAPPER (body.brand-dark) — N20
   Keeps the signup to verify to onboarding journey on the Metodium dark brand until
   the user reaches the dashboard (which stays the basic light theme). The
   verify pages reuse the plain .login-* auth theme and onboarding uses .ob-*;
   this block retints both to the dark palette borrowed from body.auth-page--split
   (near-black canvas, orange primary glow, indigo secondary glow, orange accents).
   Self-contained: it does NOT depend on body.dark, so a user's stored light
   preference cannot wash it out. Placed AFTER body.onboarding and the body.dark
   ob-* rules so its equal-specificity canvas + badge overrides win by source order.
   Scoped to body.brand-dark so the plain forgot and reset pages stay untouched.
   NOTE: never write a class glob with a slash right after a star inside these
   comments, or the sequence closes the comment early and drops the next rule.
   ============================================================================ */

/* Canvas — overrides body.auth-page (verify) and body.onboarding backgrounds. */
body.brand-dark {
  color: #E5E9F2;
  background:
    radial-gradient(1100px 640px at 6% -14%, rgba(249, 115, 22, .26), transparent 58%),
    radial-gradient(1000px 660px at 104% 112%, rgba(99, 102, 241, .20), transparent 55%),
    #0B0E14;
}

/* Cards + panels */
body.brand-dark .login-card,
body.brand-dark .ob-card {
  background: rgba(255, 255, 255, .03);
  border-color: rgba(255, 255, 255, .10);
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, .6);
}

/* Headings / body copy */
body.brand-dark .login-card__heading,
body.brand-dark .ob-card__title { color: #F3F6FC; }
body.brand-dark .login-card__sub,
body.brand-dark .ob-card__sub,
body.brand-dark .ob-hint,
body.brand-dark .ob-progress__step,
body.brand-dark .login-footer { color: #9BA6BC; }
body.brand-dark .login-label,
body.brand-dark .ob-label { color: #C7D0E0; }

/* Brand-orange eyebrow + active progress state */
body.brand-dark .ob-card__eyebrow { color: #FDBA74; }
body.brand-dark .ob-progress__step.is-active { color: #FB923C; }
body.brand-dark .ob-progress__step.is-done { color: #34D399; }
body.brand-dark .ob-progress__bar { background: rgba(255, 255, 255, .10); }
body.brand-dark .ob-progress__fill { background: var(--grad); }

/* Inputs */
body.brand-dark .login-input,
body.brand-dark .ob-search-input,
body.brand-dark .ob-date-input {
  background: rgba(255, 255, 255, .04);
  border-color: rgba(255, 255, 255, .10);
  color: #F1F4FA;
}
body.brand-dark .login-input::placeholder,
body.brand-dark .ob-search-input::placeholder,
body.brand-dark .ob-date-input::placeholder { color: #6B7688; opacity: 1; }
body.brand-dark .login-input:focus,
body.brand-dark .ob-search-input:focus,
body.brand-dark .ob-date-input:focus {
  border-color: #F97316;
  box-shadow: 0 0 0 3px rgba(249, 115, 22, .28);
  background: rgba(255, 255, 255, .06);
}
/* Keep browser autofill dark instead of the default pale-yellow fill. */
body.brand-dark .login-input:-webkit-autofill,
body.brand-dark .login-input:-webkit-autofill:focus {
  -webkit-text-fill-color: #F1F4FA;
  -webkit-box-shadow: 0 0 0 100px #1B2230 inset;
  caret-color: #F1F4FA;
  transition: background-color 9999s ease-out 0s;
}

/* Primary CTA — orange gradient pill (mirrors the split auth submit) */
body.brand-dark .login-submit,
body.brand-dark .ob-btn--primary {
  background: var(--grad);
  box-shadow: 0 14px 30px -10px rgba(234, 88, 12, .44);
}
body.brand-dark .login-submit:hover,
body.brand-dark .ob-btn--primary:hover {
  background: var(--grad);
  transform: translateY(-1px);
  filter: brightness(1.04);
  box-shadow: 0 18px 34px -12px rgba(234, 88, 12, .52);
}
body.brand-dark .login-submit:active,
body.brand-dark .ob-btn--primary:active { transform: translateY(0); }

/* Ghost button (onboarding "Atrás") — legible on dark */
body.brand-dark .ob-btn--ghost { color: #C7D0E0; }
body.brand-dark .ob-btn--ghost:hover { background: rgba(255, 255, 255, .06); color: #F3F6FC; }

/* Links (footer, dev-note, back-to-login) */
body.brand-dark .login-footer a,
body.brand-dark .login-card__sub a,
body.brand-dark .login-note a { color: #FDBA74; }
body.brand-dark .login-footer a:hover,
body.brand-dark .login-card__sub a:hover,
body.brand-dark .login-note a:hover { color: #FB923C; }

/* Neutral note (resend success / dev link) on dark */
body.brand-dark .login-note {
  background: rgba(255, 255, 255, .04);
  border-color: rgba(255, 255, 255, .12);
  color: #D7DEEA;
}

/* Error banners on dark (mirror the split alert) */
body.brand-dark .login-alert,
body.brand-dark .ob-error {
  background: rgba(220, 38, 38, .14);
  border-color: rgba(248, 113, 113, .35);
  color: #FCA5A5;
}

/* Search dropdown */
body.brand-dark .ob-dropdown {
  background: #151A23;
  border-color: rgba(255, 255, 255, .12);
}
body.brand-dark .ob-dropdown__item { border-bottom-color: rgba(255, 255, 255, .08); }
body.brand-dark .ob-dropdown__item:hover,
body.brand-dark .ob-dropdown__item:focus { background: rgba(255, 255, 255, .06); }
body.brand-dark .ob-dropdown__name { color: #F1F4FA; }
body.brand-dark .ob-dropdown__meta,
body.brand-dark .ob-dropdown__empty { color: #9BA6BC; }
body.brand-dark .ob-dropdown__item--custom { border-top-color: rgba(255, 255, 255, .12); }
body.brand-dark .ob-dropdown__item--custom .ob-dropdown__name { color: #FDBA74; }

/* Selected-oposición badge + days pill — orange/violet tints on dark */
body.brand-dark .ob-selected-badge {
  color: #FDBA74;
  background: rgba(249, 115, 22, .16);
}
body.brand-dark .ob-selected-badge__clear {
  color: #FDBA74;
  background: rgba(249, 115, 22, .24);
}
body.brand-dark .ob-selected-badge__clear:hover { background: rgba(249, 115, 22, .34); }
body.brand-dark .ob-days-pill {
  color: #C4B5FD;
  background: rgba(124, 58, 237, .20);
}

/* ============================================================================
   TESTS — course-first landing (global actions + asignatura grid)
   ============================================================================ */
#testsLanding { display: flex; flex-direction: column; gap: var(--space-5); }

.tests-globals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-4);
}
.tests-global {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  text-align: left;
  padding: var(--space-4) var(--space-5);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
  cursor: pointer;
  transition: transform .14s ease, box-shadow .14s ease, border-color .14s ease;
}
.tests-global:hover { transform: translateY(-3px); box-shadow: var(--shadow-hover); border-color: var(--color-border); }
.tests-global:hover .tests-global__title { color: var(--color-primary); }
.tests-global:focus-visible { outline: none; box-shadow: var(--ring); }
.tests-global__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  flex: 0 0 auto;
  border-radius: 11px;
  color: var(--color-primary);
  background: rgba(79, 70, 229, .10);
  transition: transform .14s ease;
}
.tests-global:hover .tests-global__icon { transform: scale(1.06); }
.tests-global__icon svg { width: 20px; height: 20px; }
.tests-global__icon--fallos    { color: var(--color-primary);   background: rgba(79, 70, 229, .10); }
.tests-global__icon--combinado { color: var(--color-secondary); background: rgba(124, 58, 237, .10); }
/* Dark mode: icons track the theme — primary→orange, secondary→indigo.
   Base rule sits before the modifiers so each modifier still wins for its own tile. */
body.dark .tests-global__icon            { background: rgba(249, 115, 22, .16); }
body.dark .tests-global__icon--fallos    { background: rgba(249, 115, 22, .20); }
body.dark .tests-global__icon--combinado { background: rgba(99, 102, 241, .20); }
.tests-global__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

/* Inline test icon used inside flowing text (e.g. empty-state hints). */
.test-ico-inline { vertical-align: -2px; }
.tests-global__title { font-weight: 600; color: var(--color-text); }
.tests-global__sub { font-size: .8125rem; color: var(--color-muted); }

/* Asignatura cards reuse .card + .subj-grid layout. */
.tests-course {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  text-align: left;
  cursor: pointer;
  transition: transform .14s ease, box-shadow .14s ease;
}
.tests-course:hover { transform: scale(1.02); box-shadow: var(--shadow-pop); }
.tests-course:hover .tests-course__name { color: var(--color-primary); }
.tests-course:focus-visible { outline: none; box-shadow: var(--ring); }
.tests-course__name { font-size: 1rem; font-weight: 600; color: var(--color-text); }
.tests-course__stats { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-top: auto; }
.tests-course__loading { color: var(--color-muted); }


/* =============================================================================
   PLANIFICADOR (Module 2)  — added in step P1
   Countdown header + weekly-availability setup. Reuses :root tokens and the
   shared .card / .btn / .badge components. Later steps (P2+) append below.
   ============================================================================= */

.planner-page {
  max-width: 880px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

/* ── Header: title + countdown ─────────────────────────────────────────── */
.planner-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}
.planner-head__text h1 { margin: 0 0 var(--space-1); }
.planner-head__text p { margin: 0; color: var(--color-muted); }

.planner-countdown {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 140px;
  padding: var(--space-3) var(--space-5);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}
.planner-countdown__days {
  font-size: 2.4rem;
  font-weight: 700;
  line-height: 1;
  color: var(--color-primary);
}
.planner-countdown__label {
  font-size: .85rem;
  color: var(--color-body);
  margin-top: var(--space-1);
}
.planner-countdown__weeks {
  font-size: .8rem;
  color: var(--color-muted);
  margin-top: var(--space-1);
}

/* ── No-exam-date notice ───────────────────────────────────────────────── */
.planner-notice {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  background: var(--color-warning-bg);
  border: 1px solid var(--color-warning);
  border-radius: var(--radius-card);
}
.planner-notice__icon { font-size: 1.5rem; }
.planner-notice__body { flex: 1; }
.planner-notice__body strong { color: var(--color-text); }
.planner-notice__body p { margin: var(--space-1) 0 0; color: var(--color-body); font-size: .9rem; }

/* ── Setup card: weekly availability ───────────────────────────────────── */
.planner-setup__hint { margin: 0 0 var(--space-4); color: var(--color-body); }

.planner-week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--space-3);
}
.planner-day {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
}
.planner-day__label {
  font-size: .8rem;
  font-weight: 600;
  color: var(--color-body);
}
.planner-day__input {
  width: 100%;
  max-width: 84px;
  padding: var(--space-2);
  text-align: center;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
}
.planner-day__input:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-color: var(--color-primary);
}
.planner-day__unit { font-size: .7rem; color: var(--color-muted); }

/* ── Toggles + actions ─────────────────────────────────────────────────── */
.planner-toggles {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  margin-top: var(--space-5);
}
.planner-toggle {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: .92rem;
  color: var(--color-body);
  cursor: pointer;
}
.planner-toggle input { accent-color: var(--color-primary); width: 16px; height: 16px; }

.planner-setup__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  margin-top: var(--space-6);
}
.planner-setup__total { font-size: .88rem; color: var(--color-muted); }

/* ── Collapsible availability (moved below the daily plan to declutter) ─────── */
.planner-setup > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  cursor: pointer;
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--color-text);
  list-style: none;
}
.planner-setup > summary::-webkit-details-marker { display: none; }
.planner-setup > summary::after {
  content: '';
  width: 9px;
  height: 9px;
  flex: 0 0 auto;
  margin-right: 4px;
  border-right: 2px solid var(--color-muted);
  border-bottom: 2px solid var(--color-muted);
  transform: rotate(45deg);
  transition: transform .2s ease;
}
.planner-setup[open] > summary::after { transform: rotate(-135deg); }
.planner-setup[open] > summary { margin-bottom: var(--space-5); }
.planner-setup__sub { font-size: .82rem; font-weight: 400; color: var(--color-muted); }

/* ── Responsive: stack the week on narrow screens ──────────────────────── */
@media (max-width: 640px) {
  .planner-week { grid-template-columns: repeat(4, 1fr); }
  .planner-head { flex-direction: column; align-items: flex-start; }
}

/* ── Dark mode: surfaces already follow tokens; only the warning notice
      needs a tuned background so text stays legible. ───────────────────── */
body.dark .planner-notice { background: rgba(217, 119, 6, .12); }

/* =============================================================================
   PLANIFICADOR — P2: deterministic plan (action bar + "Hoy" + week calendar)
   ============================================================================= */

.planner-plan {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

/* ── Action bar: meta + Generar / Recalcular ───────────────────────────── */
.planner-plan__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.planner-plan__meta { margin: 0; color: var(--color-muted); font-size: .9rem; }
.planner-plan__actions { display: flex; gap: var(--space-2); }

.planner-empty .card-body { color: var(--color-body); }
.planner-empty p { margin: 0; }

/* ── Hoy: today's checklist (the page's focal card) ─────────────────────── */
.planner-today {
  border-top: 1px solid var(--color-border);
}
.planner-today .card-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}
.planner-today__target { font-size: .85rem; color: var(--color-muted); white-space: nowrap; }

.planner-tasks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.planner-tasks__empty { color: var(--color-muted); padding: var(--space-2) 0; }

.planner-task {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
}
.planner-task__mark { color: var(--color-primary); font-weight: 700; width: 1em; text-align: center; }
.planner-task__name {
  flex: 1;
  min-width: 0;
  color: var(--color-text);
  font-weight: 500;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.planner-task__min  { font-size: .82rem; color: var(--color-muted); white-space: nowrap; }
.planner-task__go   { white-space: nowrap; }
/* Kept in the flex row even when done, so the card's width/height never changes
   between "to do" and "done" (reported 2026-07-08) — same technique as
   .tree__chevron--leaf above (visibility, not display, to preserve its space). */
.planner-task__go.is-invisible { visibility: hidden; pointer-events: none; }
.planner-task.is-done .planner-task__name { text-decoration: line-through; color: var(--color-muted); font-weight: 400; }
.planner-task.is-done .planner-task__mark { color: var(--color-acc-high); }

/* ── Week calendar ─────────────────────────────────────────────────────── */
.planner-cal__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}
.planner-cal__title { margin: 0; font-size: 1.05rem; }
.planner-cal__range { font-size: .85rem; color: var(--color-muted); }

.planner-cal__grid {
  display: grid;
  /* minmax(0, 1fr) — NOT 1fr (= minmax(auto,1fr)): the `auto` minimum is a cell's
     min-content, so a long non-wrapping task label would blow its column out wide and
     squeeze the others. Flooring at 0 keeps all 7 day columns exactly equal and lets
     the inner label's ellipsis engage. (N26) */
  grid-template-columns: repeat(7, minmax(0, 1fr));
  grid-auto-rows: 1fr;          /* all day cells in a row share one equal height */
  gap: var(--space-2);
  align-items: stretch;
}
.planner-cal__day {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-height: 120px;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
}
.planner-cal__day.is-today { border-color: var(--color-primary); box-shadow: var(--ring); }
.planner-cal__day.is-past  { opacity: .6; }

/* Day cells (week/month) hint they're clickable to focus into the single-day view. */
.planner-cal__grid:not(.is-day) .planner-cal__day:not(.is-outside) { cursor: pointer; }
.planner-cal__grid:not(.is-day) .planner-cal__day:not(.is-outside):hover {
  border-color: var(--color-primary);
}
/* Interactive controls inside a cell keep their own affordance. */
.planner-cal__day .planner-cal__task,
.planner-cal__day button,
.planner-cal__day a { cursor: auto; }
.planner-cal__day .planner-cal__task[draggable] { cursor: grab; }

/* Single-day view: a prominent, blue-outlined focused card flanked by two compact
   peek columns (previous / next day) — glance + one-click hop (ROADMAP #22). */
.planner-cal__grid.is-day {
  grid-template-columns: minmax(0, 1fr) minmax(0, 2.4fr) minmax(0, 1fr);
  grid-auto-rows: auto;      /* columns size to their own content, not a shared row */
  align-items: start;
}
.planner-cal__grid.is-day .planner-cal__day { cursor: default; }
.planner-cal__grid.is-day .planner-cal__day.is-focused { min-height: 180px; }
.planner-cal__day.is-focused { border-color: var(--color-primary); box-shadow: var(--ring); }
/* Cap the focused day's task list so a busy day scrolls in place instead of running
   the whole page long (the reported "day view too tall"). */
.planner-cal__grid.is-day .planner-cal__day.is-focused .planner-cal__tasks {
  max-height: 46vh;
  overflow-y: auto;
}
/* Peek columns: dimmed until hovered, clickable to focus that adjacent day. */
.planner-cal__day--peek { cursor: pointer; opacity: .78; transition: opacity .12s ease, border-color .12s ease; }
.planner-cal__day--peek:hover { opacity: 1; border-color: var(--color-primary); }
.planner-cal__peeklabel {
  display: block;
  font-size: .72rem;
  font-weight: 600;
  color: var(--color-muted);
  margin-bottom: var(--space-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.planner-cal__day-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}
.planner-cal__dow { font-size: .72rem; font-weight: 600; color: var(--color-muted); text-transform: uppercase; }
.planner-cal__dom { font-size: .95rem; font-weight: 700; color: var(--color-text); }

/* N52 streak overlay: a corner marker per day — active ✓ (studied), broken ✕ (past day
   with tasks but no activity), rest 🌙 (past day with nothing planned). Pinned right so
   it reads at a glance across the month without repainting the adherence status tints. */
.planner-cal__streak {
  margin-left: auto;
  flex: 0 0 auto;
  align-self: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  line-height: 1;
}
.planner-cal__streak svg { width: 11px; height: 11px; }
.planner-cal__streak--act  { color: var(--color-success); }
.planner-cal__streak--brk  { color: var(--color-danger); }
.planner-cal__streak--rest { font-size: .74rem; opacity: .6; }

.planner-cal__tasks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.planner-cal__task {
  font-size: .8rem;
  line-height: 1.35;
  color: var(--color-body);
  padding: 2px var(--space-1);
  border-left: 3px solid var(--color-primary);
  border-radius: 3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  background: rgba(79, 70, 229, .08);
}
.planner-cal__task.is-done { color: var(--color-muted); text-decoration: line-through; border-left-color: var(--color-acc-high); }
.planner-cal__more {
  align-self: flex-start;
  font-size: .74rem;
  font-weight: 600;
  color: var(--color-primary);
  padding: 2px var(--space-1);
  border-radius: 4px;
  cursor: pointer;
}
.planner-cal__more:hover { background: var(--color-canvas); }

/* Single-day view: calm empty state for a rest day — reads as an intentional
   placeholder (soft icon chip + roomier rhythm), matching the study-page states. */
.planner-cal__emptyday {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: 140px;
  margin: auto;
  padding: var(--space-5);
  text-align: center;
  color: var(--color-muted);
}
.planner-cal__emptyday-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px; height: 48px;
  margin-bottom: var(--space-2);
  border-radius: 50%;
  background: var(--color-canvas);
  font-size: 1.5rem;
  line-height: 1;
}
.planner-cal__emptyday-t { font-weight: 600; color: var(--color-body); }
.planner-cal__emptyday-s { font-size: .85rem; }
.planner-cal__sum  { margin-top: auto; font-size: .74rem; color: var(--color-muted); }
.planner-cal__rest { color: var(--color-muted); font-size: .85rem; }

/* ── Responsive: stack the calendar on narrow screens ──────────────────── */
@media (max-width: 640px) {
  .planner-cal__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .planner-cal__day  { min-height: auto; }
  .planner-plan__bar { flex-direction: column; align-items: stretch; }
  .planner-plan__actions { justify-content: flex-end; }
}

/* ── Dark mode tweaks — accents flip indigo→orange to match the rest of the app ── */
body.dark .planner-cal__task { background: rgba(249, 115, 22, .18); }

/* =============================================================================
   PLANIFICADOR — Phase 2: editable calendar (drag / add / delete / rest)
   Week-view today/future cells (.is-editable) become hand-editable. A hand-edited
   day (.is-locked) is protected from the scheduler and shows a 🔒.
   ============================================================================= */

.planner-cal__day.is-editable { transition: box-shadow .12s ease, border-color .12s ease; }
.planner-cal__day.is-drop {
  border-color: var(--color-primary);
  box-shadow: var(--ring);
  background: rgba(79, 70, 229, .05);
}
body.dark .planner-cal__day.is-drop { background: rgba(249, 115, 22, .07); }
/* A peek cell (day view) lit as a drop target reads at full opacity, not dimmed. */
.planner-cal__day--peek.is-drop { opacity: 1; }
.planner-cal__lock { font-size: .8rem; line-height: 1; margin-left: var(--space-1); }

/* Editable task rows: label + inline action buttons (override the base nowrap chip). */
.planner-cal__day.is-editable .planner-cal__task {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  white-space: normal;
  cursor: grab;
}
.planner-cal__day.is-editable .planner-cal__task:active { cursor: grabbing; }
.planner-cal__task.is-dragging { opacity: .45; }
.planner-cal__task-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.planner-cal__task-acts { flex: 0 0 auto; display: inline-flex; gap: 2px; opacity: 0; transition: opacity .1s ease; }
.planner-cal__task:hover .planner-cal__task-acts,
.planner-cal__task:focus-within .planner-cal__task-acts { opacity: 1; }
.planner-cal__taskbtn {
  border: 0;
  background: none;
  padding: 0 3px;
  font-size: .8rem;
  line-height: 1;
  color: var(--color-muted);
  cursor: pointer;
  border-radius: 3px;
}
.planner-cal__taskbtn:hover { color: var(--color-primary); background: rgba(79, 70, 229, .12); }
body.dark .planner-cal__taskbtn:hover { background: rgba(249, 115, 22, .16); }
.planner-cal__taskbtn[data-act="del"]:hover { color: var(--color-danger); background: var(--color-danger-bg); }

/* Per-day footer: add / rest toggle. */
.planner-cal__dayfoot {
  margin-top: auto;
  display: flex;
  gap: var(--space-1);
  padding-top: var(--space-1);
}
.planner-cal__dayact {
  flex: 1 1 auto;
  border: 1px dashed var(--color-border);
  background: var(--color-surface);
  border-radius: var(--radius-input);
  padding: 2px var(--space-1);
  font-size: .68rem;
  color: var(--color-muted);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.planner-cal__dayact:hover { border-color: var(--color-primary); color: var(--color-primary); }
.planner-cal__dayact--rest:hover { border-color: var(--color-warning); color: var(--color-warning); }
.planner-cal__day.is-locked { border-style: dashed; }
.planner-cal__day.is-locked.is-today { border-style: solid; }

/* Week/month grid: keep the per-day action footer out of the way until the cell
   is hovered/focused, so idle cells stay clean (revealed always on touch). */
.planner-cal__grid:not(.is-day) .planner-cal__dayfoot {
  opacity: 0;
  transition: opacity .12s ease;
}
.planner-cal__grid:not(.is-day) .planner-cal__day:hover .planner-cal__dayfoot,
.planner-cal__grid:not(.is-day) .planner-cal__day:focus-within .planner-cal__dayfoot {
  opacity: 1;
}
@media (hover: none) {
  .planner-cal__grid:not(.is-day) .planner-cal__dayfoot { opacity: 1; }
}

/* Move-to-day popover (drag fallback). */
.planner-movemenu {
  position: absolute;
  z-index: 1200;
  min-width: 180px;
  max-width: 240px;
  padding: var(--space-2);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.planner-movemenu__title { margin: 0 0 var(--space-1); font-size: .72rem; font-weight: 600; color: var(--color-muted); text-transform: uppercase; }
.planner-movemenu__opt {
  text-align: left;
  border: 0;
  background: none;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-input);
  font-size: .82rem;
  color: var(--color-text);
  cursor: pointer;
}
.planner-movemenu__opt:hover { background: rgba(79, 70, 229, .1); color: var(--color-primary); }
body.dark .planner-movemenu__opt:hover { background: rgba(249, 115, 22, .14); }
.planner-movemenu__empty { margin: 0; padding: var(--space-1) var(--space-2); font-size: .8rem; color: var(--color-muted); }

/* "Añadir tarea" modal (mirrors the onboarding wizard chrome). */
.planner-addt {
  position: fixed;
  inset: 0;
  z-index: 1150;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
}
.planner-addt__backdrop { position: absolute; inset: 0; background: rgba(16, 24, 40, .45); }
.planner-addt__card {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 460px;
  max-height: calc(100vh - var(--space-8));
  overflow-y: auto;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  padding: var(--space-6);
}
.planner-addt__close {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: none;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--color-muted);
  cursor: pointer;
  border-radius: var(--radius-pill);
}
.planner-addt__close:hover { background: var(--color-border); color: var(--color-text); }
.planner-addt__title { margin: 0; font-size: 1.15rem; }
.planner-addt__when { margin: var(--space-1) 0 var(--space-4); color: var(--color-muted); font-size: .9rem; text-transform: none; }
.planner-addt__when::first-letter { text-transform: uppercase; }
.planner-addt__kinds { display: flex; gap: var(--space-2); margin-bottom: var(--space-4); }
.planner-addt__kind {
  flex: 1 1 auto;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  border-radius: var(--radius-input);
  padding: var(--space-2);
  font-size: .85rem;
  color: var(--color-body);
  cursor: pointer;
}
.planner-addt__kind:hover { border-color: var(--color-primary); }
.planner-addt__kind.is-active { border-color: var(--color-primary); background: rgba(79, 70, 229, .08); color: var(--color-primary); font-weight: 600; }
body.dark .planner-addt__kind.is-active { background: rgba(249, 115, 22, .12); }
.planner-addt__label { display: block; margin-bottom: var(--space-1); font-size: .82rem; font-weight: 600; color: var(--color-body); }
.planner-addt__select {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
}
.planner-addt__hint { margin: var(--space-3) 0 0; font-size: .85rem; color: var(--color-muted); }
.planner-addt__foot { display: flex; justify-content: flex-end; gap: var(--space-2); margin-top: var(--space-5); }

@media (max-width: 640px) {
  .planner-cal__task-acts { opacity: 1; }   /* no hover on touch: always show controls */
}

/* =============================================================================
   PLANIFICADOR — P3: progress tracking (on-track badge, checkboxes, day status)
   ============================================================================= */

/* ── On-track badge (header) ───────────────────────────────────────────── */
.planner-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  align-self: flex-start;
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  font-size: .9rem;
  font-weight: 600;
  background: var(--color-surface);
}
.planner-badge__dot { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto; background: var(--color-acc-none); }
.planner-badge.is-high { border-color: var(--color-acc-high); color: var(--color-acc-high); }
.planner-badge.is-mid  { border-color: var(--color-acc-mid);  color: var(--color-acc-mid); }
.planner-badge.is-low  { border-color: var(--color-acc-low);  color: var(--color-acc-low); }
.planner-badge.is-high .planner-badge__dot { background: var(--color-acc-high); }
.planner-badge.is-mid  .planner-badge__dot { background: var(--color-acc-mid); }
.planner-badge.is-low  .planner-badge__dot { background: var(--color-acc-low); }
.planner-badge__label { color: var(--color-text); }

/* ── Task checkbox + overdue tag ───────────────────────────────────────── */
.planner-task__check {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  accent-color: var(--color-primary);
  cursor: pointer;
}
.planner-task__check:disabled { cursor: default; accent-color: var(--color-acc-high); }
.planner-task__check:focus-visible { outline: none; box-shadow: var(--ring); border-radius: 4px; }
.planner-task__when {
  font-size: .74rem;
  color: var(--color-warning);
  white-space: nowrap;
  font-weight: 600;
}

/* ── Overdue ("Pendiente de días anteriores") ──────────────────────────── */
.planner-overdue {
  margin-bottom: var(--space-4);
  padding: var(--space-3);
  border: 1px solid var(--color-warning);
  border-radius: var(--radius-input);
  background: var(--color-warning-bg);
}
.planner-overdue__title {
  margin: 0 0 var(--space-2);
  font-size: .85rem;
  font-weight: 600;
  color: var(--color-warning);
}
body.dark .planner-overdue { background: rgba(217, 119, 6, .12); }

/* ── Calendar day status colors ────────────────────────────────────────── */
.planner-cal__day.is-done    { border-color: var(--color-acc-high); }
.planner-cal__day.is-partial { border-color: var(--color-acc-mid); }
.planner-cal__day.is-missed  { border-color: var(--color-acc-low); }
.planner-cal__day.is-done    .planner-cal__dom { color: var(--color-acc-high); }
.planner-cal__day.is-missed  .planner-cal__dom { color: var(--color-acc-low); }
/* Today keeps its primary ring even when it also carries a status class. */
.planner-cal__day.is-today { border-color: var(--color-primary); }

/* =============================================================================
   PLANIFICADOR — P4: spaced review + mock exams (task icons + accent colors)
   ============================================================================= */

/* Per-kind icon in the Hoy checklist. */
.planner-task__icon { flex: 0 0 auto; width: 1.3em; text-align: center; font-size: .95rem; }

/* Accent the left edge of review / mock tasks so they read apart from study. */
.planner-task.is-review { border-left: 3px solid var(--color-secondary); }
.planner-task.is-mock   { border-left: 3px solid var(--color-warning); }

/* Calendar chips: review (violet) / mock (amber). */
.planner-cal__task.is-review {
  border-left-color: var(--color-secondary);
  background: rgba(124, 58, 237, .08);
}
.planner-cal__task.is-mock {
  border-left-color: var(--color-warning);
  background: rgba(217, 119, 6, .10);
}
body.dark .planner-cal__task.is-review { background: rgba(124, 58, 237, .20); }
body.dark .planner-cal__task.is-mock   { background: rgba(217, 119, 6, .20); }

/* =============================================================================
   PLANIFICADOR — P5: AI strategy overlay ("Estrategia" card)
   ============================================================================= */

.planner-strategy__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; }

/* Title + ritmo meta stacked on the left of the Estrategia header. */
.planner-strategy__heading { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.planner-strategy__heading .planner-plan__meta { font-size: .82rem; }
.planner-strategy__head .planner-plan__actions { flex-wrap: wrap; justify-content: flex-end; }

/* "IA" tag next to the title. */
.planner-strategy__tag {
  display: inline-block;
  margin-left: var(--space-1);
  padding: 1px 8px;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .02em;
  color: #fff;
  background: var(--color-secondary);
  border-radius: var(--radius-pill);
  vertical-align: middle;
}

.planner-strategy__summary {
  margin: 0 0 var(--space-3);
  color: var(--color-text);
  line-height: 1.5;
}

/* Lead = always-visible profile + summary; detail = collapsible phases (ROADMAP #22). */
.planner-strategy__lead .planner-strategy__summary { margin-bottom: 0; }
.planner-strategy__detail {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}

/* Bottom "Ajustes" group: availability + calendar export, tucked away. */
.planner-tools {
  margin-top: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.planner-tools__title {
  margin: 0;
  font-size: .8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--color-muted);
}

/* Phases as a vertical list with a left accent rail. */
.planner-strategy__phases { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.planner-strategy__phase {
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--color-primary);
  background: rgba(79, 70, 229, .05);
  border-radius: var(--radius-input);
}
body.dark .planner-strategy__phase { background: rgba(249, 115, 22, .13); }

.planner-strategy__phase-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; }
.planner-strategy__phase-name { font-weight: 600; color: var(--color-text); }
.planner-strategy__phase-when { font-size: .8rem; color: var(--color-muted); white-space: nowrap; }
.planner-strategy__phase-focus  { margin: var(--space-1) 0 0; color: var(--color-text); }
.planner-strategy__phase-advice { margin: var(--space-1) 0 0; font-size: .9rem; color: var(--color-muted); }

.planner-strategy__rhythm {
  margin: var(--space-3) 0 0;
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-border);
  font-size: .9rem;
  color: var(--color-muted);
}

/* ── Calendar export (P3): ICS download + auto-updating subscribe link ───── */
.planner-export__hint {
  margin: 0 0 var(--space-3);
  font-size: .9rem;
  color: var(--color-muted);
  line-height: 1.5;
}
.planner-export__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
/* The download/subscribe links are inert until the feed token has loaded. */
.planner-export__actions a[aria-disabled="true"] {
  opacity: .5;
  pointer-events: none;
}
.planner-export__urllabel {
  display: block;
  font-size: .82rem;
  font-weight: 600;
  color: var(--color-muted);
  margin-bottom: var(--space-1);
}
.planner-export__urlrow {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}
.planner-export__url {
  flex: 1 1 auto;
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  font-size: .85rem;
  font-family: var(--font-mono, monospace);
  color: var(--color-text);
  background: var(--color-bg-subtle, var(--color-divider));
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
}
.planner-export__url:focus { outline: none; box-shadow: var(--ring); }
.planner-export__status {
  margin: var(--space-3) 0 0;
  font-size: .85rem;
  color: var(--color-muted);
}
.planner-export__status.is-error { color: var(--color-danger); }

@media (max-width: 560px) {
  .planner-export__urlrow { flex-wrap: wrap; }
  .planner-export__url { flex-basis: 100%; }
}

/* =============================================================================
   PLANIFICADOR — P6: polish (month view, edge-case states, skeleton, a11y)
   ============================================================================= */

/* ── Loading skeleton (shown until the first get_plan resolves) ─────────── */
.planner-skeleton .sk-line {
  height: 14px;
  border-radius: var(--radius-input);
  background: var(--color-divider);
  animation: dash-skeleton 1.2s ease-in-out infinite; /* reuse dashboard keyframes */
  margin-bottom: var(--space-3);
}
.planner-skeleton .sk-line:last-child { margin-bottom: 0; }
.planner-skeleton .sk-line--lg { width: 60%; height: 20px; }
.planner-skeleton .sk-line--sm { width: 35%; }

/* ── Edge-case notices: danger variant + "all done" info banner ────────── */
.planner-notice--danger {
  background: rgba(220, 38, 38, .08);
  border-color: var(--color-danger);
}
.planner-notice--danger .planner-notice__body strong { color: var(--color-danger); }
body.dark .planner-notice--danger { background: rgba(220, 38, 38, .14); }

.planner-info {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-acc-high);
  border-radius: var(--radius-card);
  background: rgba(5, 150, 105, .08);
  color: var(--color-text);
  font-size: .92rem;
}
body.dark .planner-info { background: rgba(5, 150, 105, .16); }

/* ── "No llegas a todo" — compact status fix strip (sits under the badge) ─── */
.planner-warn {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin-top: var(--space-3);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-warning);
  border-radius: var(--radius-input);
  background: var(--color-warning-bg);
}
.planner-warn__text { margin: 0; color: var(--color-body); font-size: .9rem; flex: 1 1 14rem; }
.planner-warn__actions { display: inline-flex; flex-wrap: wrap; gap: var(--space-2); flex: 0 0 auto; }

/* ══════════════════════════════════════════════════════════════════════
   PLANIFICADOR — first-run guided tour (onboarding coach-marks)
   A dismissible step-by-step tour: a spotlight cutout over the relevant
   element + a tooltip card (Atrás / Siguiente / Saltar). State-aware copy is
   driven by planner.php; "seen" is remembered in localStorage. Built with the
   existing tokens so it inherits the calm light/dark look of the rest of the page.
   ════════════════════════════════════════════════════════════════════════ */

/* "Ver tutorial" replay affordance, sits under the page title */
.planner-tutorial-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: var(--space-2);
  padding: 6px var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  font: inherit;
  font-size: .82rem;
  font-weight: 500;
  color: var(--color-body);
  cursor: pointer;
  transition: color .12s ease, border-color .12s ease, background-color .12s ease;
}
.planner-tutorial-btn:hover {
  color: var(--color-primary);
  border-color: var(--color-primary);
  background: var(--color-canvas);
  text-decoration: none;
}
.planner-tutorial-btn:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}
.planner-tutorial-btn svg { width: 15px; height: 15px; flex: 0 0 auto; }

/* Header chip row (configure / settings / tutorial sit side by side under the title). */
.planner-head__btns { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

/* ══════════════════════════════════════════════════════════════════════
   PLANIFICADOR — onboarding wizard (Phase 1) + study-pace profile badge
   Modal flow: availability + a short pace quiz → a profile (intenso /
   equilibrado / lento). Built from the existing tokens; toggled with [hidden].
   ════════════════════════════════════════════════════════════════════════ */

/* Profile badge inside the Estrategia card. */
.planner-strategy__profile {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin: 0 0 var(--space-3);
}
.planner-strategy__profile-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: .8rem;
  font-weight: 600;
  color: #fff;
  background: var(--color-primary);
  white-space: nowrap;
}
.planner-strategy__profile-badge.is-intenso     { background: var(--color-secondary); }
.planner-strategy__profile-badge.is-equilibrado { background: var(--color-primary); }
.planner-strategy__profile-badge.is-lento        { background: var(--color-success); }
.planner-strategy__profile-text { font-size: .9rem; color: var(--color-muted); }

/* ── Ajustes del plan sheet (ROADMAP #22 Phase C) ───────────────────────── */
.planner-settings {
  position: fixed;
  inset: 0;
  z-index: 1150;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
}
.planner-settings__backdrop { position: absolute; inset: 0; background: rgba(16, 24, 40, .45); }
.planner-settings__panel {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 560px;
  max-height: calc(100vh - var(--space-8));
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
}
.planner-settings__panel--sm { max-width: 460px; }
.planner-settings__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--color-border);
}
.planner-settings__title { margin: 0; font-size: 1.15rem; font-weight: 700; color: var(--color-text); }
.planner-settings__close {
  width: 30px; height: 30px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  border: 0; background: none; font-size: 1.5rem; line-height: 1;
  color: var(--color-muted); cursor: pointer; border-radius: var(--radius-pill);
}
.planner-settings__close:hover { background: var(--color-canvas); color: var(--color-text); }
.planner-settings__body {
  padding: var(--space-6);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}
.planner-settings__section { display: flex; flex-direction: column; gap: var(--space-3); }
.planner-settings__stitle { margin: 0; font-size: 1rem; font-weight: 700; color: var(--color-text); }

/* Study-order options (radio cards). */
.planner-orders { display: flex; flex-direction: column; gap: var(--space-2); }
.planner-order {
  text-align: left;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2px var(--space-2);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
  cursor: pointer;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.planner-order:hover { border-color: var(--color-primary); }
.planner-order.is-selected { border-color: var(--color-primary); box-shadow: var(--ring); }
.planner-order__name { font-weight: 600; color: var(--color-text); }
.planner-order__rec {
  justify-self: end; align-self: center;
  font-size: .66rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: #fff; background: var(--color-primary);
  padding: 2px var(--space-2); border-radius: var(--radius-pill);
}
.planner-order__desc { grid-column: 1 / -1; margin: 0; font-size: .85rem; color: var(--color-muted); line-height: 1.4; }

/* Priority reorder list. */
.planner-priolist { list-style: none; margin: var(--space-1) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.planner-prio {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border); border-radius: var(--radius-input);
  background: var(--color-surface);
}
.planner-prio__ico {
  width: 30px; height: 30px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--radius-input); font-size: 1rem;
  background: var(--color-canvas);
}
.planner-prio__name { flex: 1 1 auto; font-weight: 500; color: var(--color-text); }
.planner-prio__acts { flex: 0 0 auto; display: inline-flex; gap: var(--space-1); }
.planner-prio__btn {
  width: 26px; height: 26px; border: 1px solid var(--color-border);
  background: var(--color-surface); border-radius: var(--radius-input);
  color: var(--color-body); cursor: pointer; line-height: 1;
}
.planner-prio__btn:hover:not(:disabled) { border-color: var(--color-primary); color: var(--color-primary); }
.planner-prio__btn:disabled { opacity: .35; cursor: default; }

/* Calendar export button. */
.planner-cal__export { display: inline-flex; align-items: center; gap: 6px; }

/* Overlay + backdrop. */
.planner-ob[hidden] { display: none !important; }
.planner-ob {
  position: fixed;
  inset: 0;
  z-index: 1100;                 /* above the tour layer (1000) */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
}
.planner-ob__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(16, 24, 40, .45);
}

/* Card. */
.planner-ob__card {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 520px;
  max-height: calc(100vh - var(--space-8));
  overflow-y: auto;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  padding: var(--space-6);
}
.planner-ob__close {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: none;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--color-muted);
  cursor: pointer;
  border-radius: var(--radius-pill);
}
.planner-ob__close:hover { background: var(--color-divider); color: var(--color-text); }

/* Progress dots. */
.planner-ob__progress { display: flex; gap: var(--space-1); margin-bottom: var(--space-4); }
.planner-ob__progress i {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--color-border);
}
.planner-ob__progress i.is-active { background: var(--color-primary); }
.planner-ob__progress i.is-done   { background: var(--color-secondary); }

/* Step body. */
.planner-ob__step[hidden] { display: none !important; }
.planner-ob__title { margin: 0 0 var(--space-2); font-size: 1.2rem; color: var(--color-text); }
.planner-ob__lead  { margin: 0 0 var(--space-4); color: var(--color-body); line-height: 1.5; }
.planner-ob__field { margin-bottom: var(--space-4); }
.planner-ob__label { display: block; margin-bottom: var(--space-2); font-weight: 600; color: var(--color-text); font-size: .9rem; }

.planner-ob__minutes { display: inline-flex; align-items: center; gap: var(--space-2); }
.planner-ob__minutes input {
  width: 96px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  font: inherit;
  color: var(--color-text);
  background: var(--color-surface);
}
.planner-ob__minutes input:focus-visible { outline: none; box-shadow: var(--ring); border-color: var(--color-primary); }
.planner-ob__unit { color: var(--color-muted); font-size: .9rem; }

/* Day toggles. */
.planner-ob__days { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.planner-ob__day {
  min-width: 44px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  font: inherit;
  font-size: .85rem;
  font-weight: 500;
  color: var(--color-muted);
  cursor: pointer;
}
.planner-ob__day:hover { border-color: var(--color-primary); }
.planner-ob__day.is-on {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
}
.planner-ob__day:focus-visible { outline: none; box-shadow: var(--ring); }
.planner-ob__total { margin: var(--space-3) 0 0; font-size: .88rem; color: var(--color-muted); }

/* Exam-date check. */
.planner-ob__exam {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-acc-high);
  border-radius: var(--radius-card);
  background: rgba(5, 150, 105, .08);
  color: var(--color-text);
}
.planner-ob__exam--warn { border-color: var(--color-warning); background: rgba(217, 119, 6, .10); }
.planner-ob__exam p { margin: 0 0 var(--space-2); line-height: 1.45; }
.planner-ob__exam p:last-child { margin-bottom: 0; }
.planner-ob__exam-icon { font-size: 1.2rem; line-height: 1.4; }

/* Pace quiz. */
.planner-ob__quiz { display: flex; flex-direction: column; gap: var(--space-4); }
.planner-ob__q-title { margin: 0 0 var(--space-2); font-weight: 600; color: var(--color-text); font-size: .95rem; }
.planner-ob__opt {
  display: block;
  width: 100%;
  text-align: left;
  margin-bottom: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
  font: inherit;
  font-size: .9rem;
  color: var(--color-body);
  cursor: pointer;
}
.planner-ob__opt:last-child { margin-bottom: 0; }
.planner-ob__opt:hover { border-color: var(--color-primary); }
.planner-ob__opt.is-sel {
  border-color: var(--color-primary);
  background: rgba(79, 70, 229, .08);
  color: var(--color-text);
  font-weight: 500;
}
.planner-ob__opt:focus-visible { outline: none; box-shadow: var(--ring); }

/* Result. */
.planner-ob__profile { text-align: center; margin-bottom: var(--space-4); }
.planner-ob__profile-badge {
  display: inline-flex;
  align-items: center;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-pill);
  font-size: 1rem;
  font-weight: 700;
  color: #fff;
  background: var(--color-primary);
}
.planner-ob__profile-badge.is-intenso     { background: var(--color-secondary); }
.planner-ob__profile-badge.is-equilibrado { background: var(--color-primary); }
.planner-ob__profile-badge.is-lento        { background: var(--color-success); }
.planner-ob__profile-blurb { margin: var(--space-3) 0 0; color: var(--color-body); line-height: 1.5; }

/* Footer nav. */
.planner-ob__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}
.planner-ob__skip {
  border: 0;
  background: none;
  font: inherit;
  font-size: .88rem;
  color: var(--color-muted);
  cursor: pointer;
}
.planner-ob__skip:hover { color: var(--color-text); text-decoration: underline; }
.planner-ob__nav { display: flex; gap: var(--space-2); }

body.dark .planner-ob__exam      { background: rgba(5, 150, 105, .16); }
body.dark .planner-ob__exam--warn { background: rgba(217, 119, 6, .18); }
body.dark .planner-ob__opt.is-sel { background: rgba(249, 115, 22, .18); }

/* Tour layer (created once by planner.php, appended to <body>) */
.tour-root[hidden] { display: none !important; }
.tour-root { position: fixed; inset: 0; z-index: 1000; }

/* Full-screen click shield — forces navigation via the tooltip buttons.
   Transparent for spotlight steps; dimmed for centered (welcome) steps. */
.tour-blocker {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: transparent;
}
.tour-blocker.is-dim { background: rgba(15, 23, 42, .55); }

/* Spotlight: a transparent box whose huge box-shadow dims everything else.
   Position + size are set inline (px) by the controller from the target rect. */
.tour-spot {
  position: fixed;
  z-index: 1001;
  border-radius: var(--radius-card);
  box-shadow: 0 0 0 9999px rgba(15, 23, 42, .55),
              0 0 0 2px var(--color-primary) inset;
  pointer-events: none;
  transition: top .2s ease, left .2s ease, width .2s ease, height .2s ease;
}
.tour-spot[hidden] { display: none; }

/* Tooltip card */
.tour-tip {
  position: fixed;
  z-index: 1002;
  width: min(340px, calc(100vw - 2 * var(--space-4)));
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  padding: var(--space-4) var(--space-5);
  /* leave room top-right so the × never overlaps the step badge/title */
  padding-right: calc(var(--space-5) + 20px);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  animation: tour-pop .18s ease;
}
/* Persistent exit control — dismisses the tour at any step (same as Saltar). */
.tour-tip__close {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--radius-input);
  background: none;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--color-muted);
  cursor: pointer;
}
.tour-tip__close:hover { background: var(--color-divider); color: var(--color-text); }
.tour-tip__close:focus-visible { outline: none; box-shadow: var(--ring); }
.tour-tip__step {
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--color-primary);
}
.tour-tip__title { margin: 0; font-size: 1.02rem; font-weight: 700; color: var(--color-text); }
.tour-tip__body  { margin: 0; font-size: .9rem; line-height: 1.45; color: var(--color-body); }
.tour-tip__note  { margin: var(--space-1) 0 0; font-size: .82rem; color: var(--color-muted); font-style: italic; }
.tour-tip__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-2);
}
.tour-tip__skip {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: .82rem;
  color: var(--color-muted);
  cursor: pointer;
}
.tour-tip__skip:hover { color: var(--color-text); text-decoration: underline; }
.tour-tip__nav { display: flex; gap: var(--space-2); }
.tour-tip__dots { display: flex; gap: 5px; align-items: center; }
.tour-tip__dots i {
  width: 6px;
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--color-border);
  display: inline-block;
}
.tour-tip__dots i.is-active { background: var(--color-primary); }

@keyframes tour-pop {
  from { opacity: 0; transform: translateY(4px) scale(.98); }
  to   { opacity: 1; transform: none; }
}

/* Dark mode — match the existing planner convention (per-element tints) */
body.dark .tour-blocker.is-dim { background: rgba(2, 6, 23, .66); }
body.dark .tour-spot {
  box-shadow: 0 0 0 9999px rgba(2, 6, 23, .66),
              0 0 0 2px var(--color-secondary) inset;
}

@media (max-width: 640px) {
  .tour-tip { width: calc(100vw - 2 * var(--space-3)); }
}
@media (prefers-reduced-motion: reduce) {
  .tour-spot { transition: none; }
  .tour-tip  { animation: none; }
}

/* ── Calendar controls: period nav + week/month toggle ─────────────────── */
.planner-cal__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.planner-cal__nav { display: flex; align-items: center; gap: var(--space-2); }
.planner-cal__navbtn { padding: var(--space-1) var(--space-2); line-height: 1; font-size: 1.1rem; }
.planner-cal__views { display: inline-flex; gap: 2px; }
.planner-view-btn {
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-body);
}
.planner-view-btn.is-active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
}
.planner-view-btn:focus-visible { outline: none; box-shadow: var(--ring); }

/* ── Month grid: weekday header row + compact day cells ────────────────── */
.planner-cal__grid.is-month {
  grid-template-columns: repeat(7, 1fr);
  /* Rows size to their own content (empty weeks collapse) instead of inheriting the
     base grid's `grid-auto-rows: 1fr`, which — with no fixed grid height — stretched
     every week to match the tallest busy one and left huge empty rows. Floor keeps a
     tidy minimum; busy weeks grow to fit their chips. Whole month now fits ~one screen. */
  grid-auto-rows: minmax(96px, auto);
  gap: 4px;
}
.planner-cal__dowhead {
  font-size: .68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .02em;
  color: var(--color-muted);
  text-align: center;
  padding: 0;
  margin-bottom: -2px;
}
/* Compact month cells so the full 6-week grid fits ~one screen (ROADMAP #22 — the
   reported "month view too big"). Tighter min-height + padding + chip density. */
.planner-cal__day--mini { min-height: 96px; gap: 2px; padding: var(--space-1); }
.planner-cal__day--mini .planner-cal__day-head { justify-content: flex-start; }
.planner-cal__day.is-outside { opacity: .4; background: transparent; }
.planner-cal__count {
  margin-top: auto;
  font-size: .68rem;
  font-weight: 600;
  color: var(--color-primary);
}

/* Month event chips (Google-Calendar style) — subject-tinted pills. */
.planner-cal__chip {
  display: block;
  max-width: 100%;
  font-size: .68rem;
  line-height: 1.25;
  padding: 1px 5px;
  border-radius: 5px;
  background: rgba(79, 70, 229, .16);
  color: var(--color-body);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
body.dark .planner-cal__chip { background: rgba(249, 115, 22, .16); }
.planner-cal__chip.is-done { text-decoration: line-through; opacity: .55; }

/* Today's date number → filled circle. In month view it's the sole today marker
   (drop the cell ring so it reads like a calendar app); week/day keep the ring. */
.planner-cal__day.is-today .planner-cal__dom {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  color: #fff;
}
.planner-cal__day--mini.is-today { border-color: var(--color-border); box-shadow: none; }

/* ── Responsive: stack the calendar head; tighten the month grid ───────── */
@media (max-width: 640px) {
  .planner-cal__head { flex-direction: column; align-items: flex-start; gap: var(--space-2); }
  .planner-cal__controls { width: 100%; justify-content: space-between; }
  .planner-cal__grid.is-month { gap: 2px; }
  .planner-cal__day--mini { min-height: 48px; padding: 2px; }
  .planner-cal__day--mini .planner-cal__count { font-size: .6rem; }
  .planner-cal__dowhead { font-size: .6rem; }
  /* Day view: stack the peek days above/below the focused day on narrow screens. */
  .planner-cal__grid.is-day { grid-template-columns: 1fr; }
  .planner-cal__grid.is-day .planner-cal__day.is-focused .planner-cal__tasks { max-height: none; }
}

/* ────────────────────────────────────────────────────────────────────────────
   Admin dashboard (Monetization Phase 0) — plans, limits & per-user usage.
   Reuses :root tokens; scoped under .admin-page + .admin-* to avoid collisions.
   ──────────────────────────────────────────────────────────────────────────── */
.admin-page__head { margin-bottom: var(--space-5); }
.admin-page__title { font-size: 1.5rem; font-weight: 600; color: var(--color-text); margin: 0; }
.admin-page__sub { color: var(--color-muted); margin: var(--space-1) 0 0; }

.admin-page .card { margin-bottom: var(--space-5); }
.admin-hint { color: var(--color-muted); font-size: .85rem; margin: 0 0 var(--space-4); }
.admin-loading { color: var(--color-muted); padding: var(--space-3) 0; }
.admin-muted { color: var(--color-muted); }
.admin-center { text-align: center; }
.admin-nowrap { white-space: nowrap; }

/* In-page tabs (N19): section groups toggled via the `hidden` attribute in JS. */
.admin-tabs {
  display: flex;
  gap: var(--space-1);
  flex-wrap: wrap;
  margin-bottom: var(--space-5);
  border-bottom: 1px solid var(--color-divider);
}
.admin-tab {
  font: inherit;
  font-size: .9rem;
  font-weight: 600;
  color: var(--color-muted);
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  border-radius: var(--radius-input) var(--radius-input) 0 0;
  transition: color .15s ease, border-color .15s ease, background .15s ease;
}
.admin-tab:hover { color: var(--color-text); background: var(--color-canvas); }
.admin-tab.is-active { color: var(--color-primary); border-bottom-color: var(--color-primary); }
.admin-tab:focus-visible { outline: none; box-shadow: var(--ring); }

/* Users toolbar: search + plan filter + count. */
.admin-usertools {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: var(--space-3);
}
.admin-search { flex: 1 1 16rem; min-width: 12rem; }
.admin-usercount { font-size: .8rem; margin-left: auto; }

/* Users: summary stat cards. */
.admin-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.admin-stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3);
  background: var(--color-canvas);
  border-radius: var(--radius-card);
}
.admin-stat__label { font-size: .75rem; color: var(--color-muted); }
.admin-stat__value { font-size: 1.375rem; font-weight: 600; color: var(--color-text); line-height: 1.1; }

/* Users: plan filter chips. */
.admin-planchips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}
.admin-planchip {
  font: inherit;
  font-size: .85rem;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.admin-planchip:hover { border-color: var(--color-primary); }
.admin-planchip:focus-visible { outline: none; box-shadow: var(--ring); }
.admin-planchip.is-active { color: #fff; background: var(--color-primary); border-color: var(--color-primary); }
.admin-planchip__n { font-size: .75rem; font-weight: 600; color: var(--color-muted); }
.admin-planchip.is-active .admin-planchip__n { color: rgba(255, 255, 255, .85); }

/* Users: numeric column alignment + sortable headers + row hover. */
.admin-num { text-align: right; }
.admin-th--sort { cursor: pointer; user-select: none; white-space: nowrap; }
.admin-th--sort .admin-th__l { border-bottom: 1px dashed transparent; }
.admin-th--sort:hover .admin-th__l { border-bottom-color: var(--color-border); }
.admin-th--sort:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--radius-input); }
.admin-sort-caret {
  display: inline-block;
  width: .7em;
  margin-left: var(--space-1);
  color: var(--color-primary);
  opacity: 0;
  transition: opacity .12s ease;
}
.admin-sort-caret::before { content: '\2195'; }
.admin-th--sort:hover .admin-sort-caret { opacity: .45; }
.admin-th--sort.is-asc  .admin-sort-caret,
.admin-th--sort.is-desc .admin-sort-caret { opacity: 1; }
.admin-th--sort.is-asc  .admin-sort-caret::before { content: '\2191'; }
.admin-th--sort.is-desc .admin-sort-caret::before { content: '\2193'; }
.admin-usertable tbody .admin-urow:hover > td { background: var(--color-canvas); }

/* Expand toggle + per-user detail row. */
.admin-expand {
  font: inherit;
  color: var(--color-muted);
  background: none;
  border: 0;
  cursor: pointer;
  padding: 0 var(--space-1);
  line-height: 1;
  transition: transform .15s ease, color .15s ease;
}
.admin-expand:hover { color: var(--color-text); }
.admin-expand.is-open { transform: rotate(90deg); color: var(--color-primary); }
.admin-expand:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--radius-input); }

.admin-udetail > td { background: var(--color-canvas); }
.admin-udetail__grid {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-6);
  padding: var(--space-1) var(--space-2);
}
.admin-udetail__block { display: flex; flex-direction: column; gap: var(--space-1); min-width: 8rem; }
.admin-udetail__label {
  font-size: .72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--color-muted);
}

/* Per-model cost breakdown (N50): full-width block + compact table in the detail row. */
.admin-udetail__block--wide { width: 100%; min-width: 0; }
.admin-umodels {
  width: 100%;
  border-collapse: collapse;
  font-size: .82rem;
}
.admin-umodels th,
.admin-umodels td {
  text-align: left;
  padding: var(--space-1) var(--space-3) var(--space-1) 0;
  border-bottom: 1px solid var(--color-divider);
  white-space: nowrap;
}
.admin-umodels th {
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--color-muted);
}
.admin-umodels tbody tr:last-child td { border-bottom: 0; }
.admin-umodels .admin-num { text-align: right; padding-right: 0; }

/* Global "Coste por modelo" strip (N50) above the users table. */
.admin-umodels-strip { margin-bottom: var(--space-4); }
.admin-umodels-strip__label {
  display: block;
  font-size: .72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--color-muted);
  margin-bottom: var(--space-2);
}
.admin-umodels-strip__cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--space-2);
}
.admin-umodels-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2) var(--space-3);
  background: var(--color-canvas);
  border-radius: var(--radius-card);
}
.admin-umodels-card__model { font-size: .82rem; font-weight: 600; color: var(--color-text); word-break: break-word; }
.admin-umodels-card__prov { font-size: .72rem; }
.admin-umodels-card__cost { font-size: 1.05rem; font-weight: 600; color: var(--color-text); line-height: 1.15; }
.admin-umodels-card__tok { font-size: .72rem; }

/* Per-user limit overrides (ROADMAP N49) — editor inside the Usuarios detail row. */
.admin-ovr-badge { margin-left: var(--space-2); font-size: .68rem; vertical-align: middle; }
.admin-ulim { width: 100%; }
.admin-ulim-grid {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-top: var(--space-1);
}
.admin-ulim-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-divider);
}
.admin-ulim-row:last-child { border-bottom: 0; }
.admin-ulim-row--cap { background: var(--color-surface-2, transparent); }
.admin-ulim-num,
.admin-ulim-model { display: flex; align-items: center; gap: var(--space-2); }
.admin-ulim-name {
  min-width: 9.5rem;
  font-size: .82rem;
  font-weight: 600;
  color: var(--color-text);
}
.admin-ulim-model .admin-ulim-name { min-width: 4rem; font-weight: 500; }
.admin-input--sm { padding: 2px var(--space-2); font-size: .82rem; }
.admin-ulim-val { width: 5rem; }
.admin-ulim-na { font-size: .78rem; font-style: italic; }
.admin-ulim-actions { display: flex; gap: var(--space-2); margin-top: var(--space-3); flex-wrap: wrap; }
.admin-ulim-hint { font-size: .76rem; margin: var(--space-2) 0 0; }

.admin-tablewrap { overflow-x: auto; }
.admin-table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.admin-table th,
.admin-table td { text-align: left; padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-divider); vertical-align: middle; }
.admin-table th { color: var(--color-muted); font-weight: 600; font-size: .8rem; white-space: nowrap; }
.admin-table tbody tr:last-child td { border-bottom: 0; }

.admin-input {
  font: inherit;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  padding: var(--space-1) var(--space-2);
  max-width: 100%;
}
.admin-input:focus { outline: none; box-shadow: var(--ring); border-color: var(--color-primary); }
.admin-input--num { width: 6rem; }

/* Global-setting row (e.g. simulacro negative marking): label + input + save. */
.admin-setting-row { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; }
.admin-setting-row label { font-size: .9rem; font-weight: 500; color: var(--color-text); }
.admin-setting-row .admin-input { width: 6rem; }

.admin-usage-cell { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); }
.admin-usage { color: var(--color-muted); font-size: .8rem; white-space: nowrap; }
.admin-usage strong { color: var(--color-text); }
.admin-usage--near strong { color: var(--color-warning); }
.admin-usage--over strong { color: var(--color-danger); }
.admin-usage--off { opacity: .55; }

/* Planes e IA — collapsible per-plan limit panels (N47). */
.admin-plan {
  margin-bottom: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  overflow: hidden;
  background: var(--color-surface);
}
.admin-plan:last-child { margin-bottom: 0; }
.admin-plan__head {
  font: inherit;
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  color: var(--color-text);
  background: var(--color-canvas);
  border: 0;
  cursor: pointer;
  text-align: left;
}
.admin-plan__head:hover { background: var(--color-divider); }
.admin-plan__head:focus-visible { outline: none; box-shadow: var(--ring); }
.admin-plan__chevron {
  flex: none;
  width: .5rem; height: .5rem;
  border-right: 2px solid var(--color-muted);
  border-bottom: 2px solid var(--color-muted);
  transform: rotate(-45deg);
  transition: transform .15s ease;
}
.admin-plan__head[aria-expanded="true"] .admin-plan__chevron { transform: rotate(45deg); }
.admin-plan__name { font-size: 1rem; font-weight: 600; }
.admin-plan__price { margin-left: auto; font-size: .85rem; color: var(--color-muted); }
.admin-plan__body { padding: var(--space-3) var(--space-4) var(--space-4); }
.admin-plan__body > .admin-plan__sub:first-child { margin-top: 0; }
/* Legacy title (pre-N47 markup) — kept harmless in case anything still emits it. */
.admin-plan__title { font-size: 1rem; font-weight: 600; color: var(--color-text); margin: 0 0 var(--space-2); }
.admin-plan__sub { font-size: .8125rem; font-weight: 600; color: var(--color-muted); margin: var(--space-3) 0 var(--space-2); text-transform: uppercase; letter-spacing: .03em; }
.admin-nodelimits { margin-top: 0; }

/* Opt-in row-hover tint for admin tables. */
.admin-table--hover tbody tr:hover { background: var(--color-canvas); }

/* Plantillas de asignatura */
.admin-tpl-opo { padding: var(--space-3) 0; border-bottom: 1px solid var(--color-divider); }
.admin-tpl-opo:last-child { border-bottom: 0; }
.admin-tpl-opo__title { font-size: 1rem; font-weight: 600; color: var(--color-text); margin: 0 0 var(--space-2); }
.admin-tpl-list { list-style: none; margin: 0 0 var(--space-2); padding: 0; }
.admin-tpl-list li { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; padding: var(--space-1) 0; }
.admin-tpl-name { font-weight: 500; color: var(--color-text); }
.admin-tpl-publish { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; }
.admin-tpl-empty { margin: var(--space-1) 0 0; font-size: .85rem; }

/* Catálogo de oposiciones — labeled add/edit form */
.admin-opo-form { display: flex; gap: var(--space-2) var(--space-3); flex-wrap: wrap; align-items: flex-end; margin-bottom: var(--space-4); }
.admin-field { display: flex; flex-direction: column; gap: var(--space-1); flex: 1 1 12rem; min-width: 10rem; }
.admin-field__label { font-size: .8rem; font-weight: 600; color: var(--color-muted); }
.admin-field .admin-input { width: 100%; }

/* Exámenes tab — labeled fields + live-preview chips (one field per split card; the
   sibling-divider rule below is a no-op now but kept for any future multi-field card) */
.admin-fields { display: flex; flex-direction: column; gap: var(--space-5); }
.admin-fields .admin-field { flex: 1 1 auto; gap: var(--space-2); }
.admin-fields .admin-field + .admin-field { padding-top: var(--space-5); border-top: 1px solid var(--color-divider); }
.admin-field__help { font-size: .82rem; color: var(--color-muted); line-height: 1.5; margin: 0; max-width: 64ch; }
.admin-field__help strong { color: var(--color-text); font-weight: 600; }
.admin-field__row { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; margin-top: var(--space-1); }
.admin-field__row .admin-input { width: auto; }
.admin-field__row .admin-input--num { width: 6rem; }
.admin-field__row .admin-input--csv { width: 12rem; max-width: 100%; }
.admin-field__preview {
  display: inline-flex; align-items: center;
  font-size: .8rem; font-weight: 600;
  color: var(--color-primary);
  background: var(--color-canvas);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  padding: 2px var(--space-3);
}
.admin-opo-form__actions { display: flex; gap: var(--space-2); align-items: center; }
.admin-opo-table td { vertical-align: middle; }
.admin-opo-table tbody tr[data-opo]:hover > td { background: var(--color-canvas); }
.admin-opo-actions { white-space: nowrap; text-align: right; }
.admin-opo-actions .btn { margin-left: var(--space-1); }

/* Publicar — subject picker + target-oposición checkboxes */
.js-pub-subject { width: 100%; margin-bottom: var(--space-3); }
.admin-opo-checks__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); margin-bottom: var(--space-2); }
.admin-opo-checks {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-1) var(--space-3);
  max-height: 16rem;
  overflow-y: auto;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-divider);
  border-radius: var(--radius-input);
  margin-bottom: var(--space-3);
}
.admin-opo-check { display: flex; align-items: flex-start; gap: var(--space-2); font-size: .9rem; cursor: pointer; padding: var(--space-1) 0; }
.admin-opo-check input { margin-top: 2px; flex: 0 0 auto; }

/* Insignias personalizadas (N40) — admin badge CRUD + manual grants */
.admin-empty { color: var(--color-muted); font-size: .9rem; margin: var(--space-2) 0 0; }

.badge-form { margin-bottom: var(--space-5); }
.badge-form__grid {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: flex-end;
}
.badge-form__field { display: flex; flex-direction: column; gap: var(--space-1); min-width: 8rem; }
.badge-form__field--grow { flex: 1 1 14rem; }
.badge-form__field--full { flex: 1 1 100%; }
.badge-form__field--check { justify-content: flex-end; }
.badge-form__label { font-size: .8rem; font-weight: 600; color: var(--color-muted); }
.badge-form__icon { width: 4.5rem; text-align: center; font-size: 1.1rem; }
.badge-form__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-top: var(--space-3);
}
.badge-form__hint { font-size: .85rem; color: var(--color-danger); }
.badge-form__actions { display: flex; gap: var(--space-2); margin-left: auto; }

.badge-list { display: flex; flex-direction: column; gap: var(--space-3); }
.badge-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  border: 1px solid var(--color-divider);
  border-radius: var(--radius-card);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface);
}
.badge-item--off { opacity: .7; }
.badge-item__head { display: flex; align-items: flex-start; gap: var(--space-3); }
.badge-item__icon { font-size: 1.75rem; line-height: 1; flex: 0 0 auto; }
.badge-item__main { flex: 1 1 auto; min-width: 0; }
.badge-item__title { font-weight: 600; color: var(--color-text); }
.badge-item__desc { font-size: .875rem; color: var(--color-muted); margin-top: 2px; }
.badge-item__meta { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; margin-top: var(--space-2); font-size: .8rem; }
.badge-item__actions { display: flex; gap: var(--space-1); flex: 0 0 auto; flex-wrap: wrap; justify-content: flex-end; }
.badge-item__del--locked { opacity: .55; }

.badge-item__grant { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--color-divider); }
.badge-grant-form { display: flex; gap: var(--space-2); align-items: center; flex-wrap: wrap; }
.badge-grant-form .admin-input { flex: 1 1 14rem; min-width: 10rem; }
.badge-grant__note { font-size: .8rem; color: var(--color-muted); }
.badge-grant-list { list-style: none; margin: var(--space-2) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.badge-grant { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); font-size: .875rem; }
.badge-grant__who { color: var(--color-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* N45: badge management drawer (create/edit + manual grant) */
.badge-drawer { position: fixed; inset: 0; z-index: 60; display: flex; justify-content: flex-end; }
.badge-drawer__backdrop { position: absolute; inset: 0; background: rgba(15, 23, 42, .45); }
.badge-drawer__panel {
  position: relative;
  width: min(30rem, 100%);
  height: 100%;
  overflow-y: auto;
  background: var(--color-surface);
  box-shadow: var(--shadow-pop);
  display: flex;
  flex-direction: column;
  animation: badgeDrawerIn .18s ease-out;
}
@keyframes badgeDrawerIn { from { transform: translateX(1.5rem); opacity: .5; } to { transform: translateX(0); opacity: 1; } }
.badge-drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4);
  border-bottom: 1px solid var(--color-divider);
}
.badge-drawer__title { font-size: 1.0625rem; font-weight: 700; color: var(--color-text); margin: 0; }
.badge-drawer__x {
  border: 0;
  background: transparent;
  color: var(--color-muted);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-input);
}
.badge-drawer__x:hover { background: var(--color-divider); color: var(--color-text); }
.badge-drawer__body { padding: var(--space-4); }
.badge-drawer__body .badge-form { margin-bottom: 0; }
.badge-drawer__grant { margin-top: var(--space-5); padding-top: var(--space-4); border-top: 1px solid var(--color-divider); }
.badge-drawer__subtitle { font-size: .95rem; font-weight: 600; color: var(--color-text); margin: 0 0 var(--space-3); }

/* =============================================================================
   ADMIN — N51 premium / consistency pass. Unifies the shell + shared components
   that drifted across the per-tab N45/N47 chats (sticky section nav, one empty
   state, uniform table hover, uniform stat strips). Frontend-only, :root tokens,
   no renamed JS-relied-on classes — retheme/extend in place.
   ============================================================================= */

/* Sticky section nav so the tabs stay reachable while scrolling a long tab.
   Background matches the page (--color-canvas) so content scrolls cleanly under. */
.admin-page .admin-tabs {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--color-canvas);
  padding-top: var(--space-2);
}

/* Shared empty state. The base .admin-empty (muted line) already exists above;
   --box is the richer "nothing here yet" panel used where a whole card/table is
   empty, so every tab reads the same instead of bare text / .admin-muted cells. */
.admin-empty--box {
  margin: 0;
  padding: var(--space-6) var(--space-4);
  text-align: center;
  background: var(--color-canvas);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-card);
}

/* Uniform row-hover on every admin table (the per-tab chats added
   .admin-table--hover unevenly; this makes it the default, keeping the explicit
   class harmless). Nested cost/override widgets aren't .admin-table, so untouched. */
.admin-page .admin-table tbody tr:hover > td { background: var(--color-canvas); }

/* =============================================================================
   PLANIFICADOR — ROADMAP #22 redesign (Phase A): premium layout, asignatura
   identity (icon + colour), plan-mode toggle (tareas | horario), timeline.
   Retheme in place — reuses :root tokens; --color-primary is indigo (light) /
   orange (dark), so accents auto-track the brand. Accuracy colours untouched.
   ============================================================================= */

/* Eyebrow above the page title (mirrors the dashboard/tests eyebrow). */
.planner-eyebrow {
  display: block;
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .09em;
  color: var(--color-primary);
  margin-bottom: var(--space-1);
}
.planner-head__text h1 { font-size: 1.9375rem; font-weight: 800; letter-spacing: -.025em; }

/* Countdown pill — a touch more premium (tabular number, tighter) + a calm
   hover lift, matching the dashboard stat cards. */
.planner-countdown {
  box-shadow: var(--shadow-card);
  transition: transform .18s ease, box-shadow .18s ease;
}
.planner-countdown:hover { transform: translateY(-2px); box-shadow: var(--shadow-hover); }
.planner-countdown__days { font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
@media (prefers-reduced-motion: reduce) { .planner-countdown:hover { transform: none; } }

/* ── Plan-mode segmented toggle ─────────────────────────────────────────── */
.planner-modebar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.planner-seg {
  display: inline-flex;
  padding: 3px;
  background: var(--color-canvas);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
}
.planner-seg__opt {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 0;
  background: none;
  padding: 7px 15px;
  border-radius: var(--radius-pill);
  font: inherit;
  font-size: .85rem;
  font-weight: 600;
  color: var(--color-muted);
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.planner-seg__opt svg { width: 15px; height: 15px; }
.planner-seg__opt:hover { color: var(--color-text); }
.planner-seg__opt.is-selected {
  background: var(--color-primary);
  color: #fff;
  box-shadow: var(--shadow-card);
}
.planner-modebar__hint { font-size: .85rem; color: var(--color-muted); }

/* ── Hero grid: today (main) + asignaturas (aside) ──────────────────────── */
.planner-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
}
.planner-main { display: flex; flex-direction: column; gap: var(--space-5); min-width: 0; }
.planner-aside { display: flex; flex-direction: column; gap: var(--space-5); min-width: 0; }
@media (max-width: 760px) {
  .planner-grid { grid-template-columns: 1fr; }
}

/* ── Task rows: name + asignatura chip stacked ──────────────────────────── */
.planner-task__icon {
  width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius-input);
  font-size: 1.15rem;
  background: var(--color-canvas);
  flex: 0 0 auto;
}
.planner-task__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.planner-task__body .planner-task__name { flex: none; }
.planner-task__chip {
  align-self: flex-start;
  max-width: 100%;
  font-size: .7rem;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.planner-task__chip.is-neutral { background: var(--color-canvas); color: var(--color-muted); }

/* ── Asignatura chip (subject label on tasks + attempts) — ROADMAP N25 ──────
   Shared colour-tinted pill: subject emoji + name. Background + text colour are
   set inline from the subject's migration-027 colour (a translucent tint + the
   solid hue, chosen to read on both light and dark themes); this class only sizes
   and shapes it. Falls back to neutral tokens when no inline colour is given. */
.subject-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  min-width: 0;
  font-size: .7rem;
  font-weight: 600;
  line-height: 1.4;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  background: var(--color-canvas);
  color: var(--color-muted);
}
.subject-chip__icon { flex: 0 0 auto; font-size: .8rem; line-height: 1; }
.subject-chip__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Asignaturas panel ──────────────────────────────────────────────────── */
.planner-subjects__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.planner-subj {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-input);
  transition: background .15s ease;
}
.planner-subj:hover { background: var(--color-canvas); }
.planner-subj__ico {
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 7px;
  font-size: .95rem;
  background: var(--color-canvas);
  flex: 0 0 auto;
}
.planner-subj__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.planner-subj__top { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); }
.planner-subj__name { min-width: 0; font-size: .9rem; font-weight: 500; color: var(--color-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.planner-subj__pct { flex: 0 0 auto; font-size: .8rem; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--color-body); }
.planner-subj__bar { height: 5px; border-radius: var(--radius-pill); background: var(--color-divider); overflow: hidden; }
.planner-subj__fill { display: block; height: 100%; border-radius: var(--radius-pill); background: var(--color-primary); transition: width .35s ease; }
.planner-subj__pace { font-size: .72rem; color: var(--color-muted); font-variant-numeric: tabular-nums; }

/* Unified activity-tracker pill (ROADMAP #23) — the app-wide ambient indicator that
   shows active time while reading a node (study) or inside a test, with pause +
   discard controls. Driven by Metodium.ActivityTracker (app.js). Muted by default;
   accented while studying. */
.activity-pill {
  position: fixed;
  left: var(--space-4);
  bottom: var(--space-4);
  z-index: 55;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 7px 10px 7px 14px;
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-pop);
  font-size: .85rem;
  font-weight: 600;
  color: var(--color-text);
  opacity: .82;
  transition: opacity .2s ease;
}
.activity-pill:hover { opacity: 1; }
.activity-pill.is-study { opacity: 1; }
.activity-pill[hidden] { display: none !important; }
.activity-pill__dot {
  width: 8px; height: 8px; flex: 0 0 auto; border-radius: 50%;
  background: var(--color-muted);
}
.activity-pill.is-study .activity-pill__dot {
  background: var(--color-acc-high);
  animation: activity-pulse 1.6s ease-in-out infinite;
}
.activity-pill.is-paused .activity-pill__dot { background: var(--color-muted); animation: none; }
.activity-pill__label { color: var(--color-body); }
.activity-pill.is-study .activity-pill__label { color: var(--color-text); }
.activity-pill__time { font-variant-numeric: tabular-nums; color: var(--color-primary); }
.activity-pill.is-paused .activity-pill__time { color: var(--color-muted); }
.activity-pill__pause,
.activity-pill__discard {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; flex: 0 0 auto;
  padding: 0; margin: 0;
  border: none; border-radius: 50%;
  background: transparent; color: var(--color-muted);
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.activity-pill__pause:hover   { background: var(--color-divider); color: var(--color-text); }
.activity-pill__discard:hover { background: var(--color-acc-low-bg, var(--color-divider)); color: var(--color-acc-low); }
.activity-pill__discard[hidden] { display: none !important; }
@keyframes activity-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

/* ── App-wide time widget (ROADMAP #23) ─────────────────────────────────────
   ONE widget on every page (bottom-right): a collapsed pill showing today's total
   app-time, expanding to the live counter + pausar/descartar + Pomodoro. Supersedes
   the legacy study-only mini-timer (hidden below) and the bottom-left activity pill. */
#miniTimer { display: none !important; }   /* legacy study.php timer — superseded */

.tw {
  position: fixed;
  right: var(--space-6);
  bottom: var(--space-6);
  z-index: 120;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-3);
}
.tw__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 42px;
  padding: 0 var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  background: var(--color-surface);
  box-shadow: var(--shadow-pop);
  color: var(--color-text);
  font: inherit;
  font-size: .9rem;
  font-weight: 600;
  cursor: pointer;
  opacity: .9;
  transition: opacity .2s ease, background .15s ease;
}
.tw__toggle:hover { opacity: 1; background: var(--color-divider); }
.tw__dot {
  width: 8px; height: 8px; flex: 0 0 auto; border-radius: 50%;
  background: var(--color-muted);
}
.tw.is-active .tw__dot {
  background: var(--color-acc-high);
  animation: activity-pulse 1.6s ease-in-out infinite;
}
.tw.is-paused .tw__dot { background: var(--color-warning); animation: none; }
.tw__toggletime { font-variant-numeric: tabular-nums; color: var(--color-primary); }
.tw.is-paused .tw__toggletime { color: var(--color-muted); }

.tw__panel {
  position: relative;
  width: 280px;
  max-height: calc(100vh - var(--space-8));
  overflow-y: auto;
  padding: var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.tw__panel[hidden] { display: none !important; }
.tw__min-btn {
  position: absolute; top: 8px; right: 8px;
  width: 28px; height: 28px; display: inline-grid; place-items: center;
  border: 0; border-radius: 50%; background: transparent; color: var(--color-muted);
  cursor: pointer; transition: background .15s ease, color .15s ease;
}
.tw__min-btn:hover { background: var(--color-divider); color: var(--color-text); }
/* Minimized = a small clock icon only (click to restore). */
.tw.is-min .tw__toggle {
  width: 46px; height: 46px; padding: 0; justify-content: center; border-radius: 50%;
  color: var(--color-primary);
}
.tw.is-min.is-active .tw__toggle { color: var(--color-acc-high); }
.tw__clock[hidden] { display: none !important; }
.tw__display {
  font-size: 2.25rem; font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--color-text); text-align: center; line-height: 1.1;
}
.tw__caption { font-size: .8125rem; color: var(--color-muted); text-align: center; }
.tw__tabs { display: flex; gap: var(--space-1); padding: var(--space-1); background: var(--color-divider); border-radius: var(--radius-input); }
.tw__tab {
  flex: 1 1 0; border: 0; background: none;
  border-radius: calc(var(--radius-input) - 2px);
  padding: 6px 0; font: inherit; font-size: .8125rem; font-weight: 600;
  color: var(--color-muted); cursor: pointer;
}
.tw__tab.is-active { background: var(--color-surface); color: var(--color-primary); box-shadow: var(--shadow-card); }
.tw__pomo { display: flex; flex-direction: column; gap: var(--space-2); }
.tw__pomo[hidden] { display: none !important; }
.tw__steps { display: flex; flex-direction: column; gap: var(--space-1); }
.tw__step { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.tw__step-lbl { flex: 1 1 auto; font-size: .8125rem; color: var(--color-body); }
.tw__step-btn {
  width: 26px; height: 26px; flex: 0 0 auto; border: 1px solid var(--color-border);
  border-radius: 50%; background: var(--color-surface); color: var(--color-text);
  font-size: 1rem; line-height: 1; cursor: pointer;
}
.tw__step-btn:hover { background: var(--color-divider); }
.tw__step-val { min-width: 52px; text-align: center; font-size: .8125rem; font-variant-numeric: tabular-nums; color: var(--color-text); }
.tw__cycle { font-size: .75rem; color: var(--color-muted); text-align: center; }
.tw__pomoctl { display: flex; gap: var(--space-2); justify-content: center; }
.tw__track { display: flex; gap: var(--space-2); justify-content: center; flex-wrap: wrap; }
.tw__danger { color: var(--color-danger); }
.tw__danger[hidden] { display: none !important; }
.tw__note { font-size: .75rem; color: var(--color-muted); text-align: center; margin: 0; }
@media (max-width: 640px) {
  .tw { right: var(--space-3); bottom: var(--space-3); }
  .tw__panel { width: calc(100vw - var(--space-6)); }
}

/* ── Animated "mark done" checkbox (snake-draw) — dashboard "Tu día" + planner ──
   Shared component. Wraps a native <input type=checkbox> so existing handlers work;
   the SVG draws the box outline + tick as an animated stroke when :checked. Placed
   after .planner-task__check / .tudia-task__check so its box styles win. */
.opocheck {
  position: relative; display: inline-block;
  width: 22px; height: 22px; flex: 0 0 auto; line-height: 0; cursor: pointer;
  --opc-dur: .6s;
}
.opocheck--static { cursor: default; }
.opocheck > .opocheck__box,
.opocheck > .opocheck__svg {
  position: absolute; top: 0; left: 0; display: block; width: 100%; height: 100%;
}
/* The box is a thin light square by default (1px), thickening to 2px on hover/check.
   box-sizing: border-box keeps its outer edge on the SAME 22px box as the SVG, so the
   blue snake traces the border edge instead of drawing inside a separate outline. */
.opocheck__box {
  -webkit-appearance: none; appearance: none; -webkit-tap-highlight-color: transparent;
  box-sizing: border-box; margin: 0; padding: 0; cursor: inherit; outline: none;
  background: var(--color-surface); border-radius: 5px;
  border: 1px solid; color: var(--color-border);   /* border uses currentColor */
  transition: color calc(var(--opc-dur) / 3) linear, border-width calc(var(--opc-dur) / 3) linear;
}
.opocheck__box:not(:disabled):not(:checked):hover { border-width: 2px; color: var(--color-muted); }
.opocheck__box:checked {
  border-width: 2px; color: var(--color-primary);
  transition-delay: calc(var(--opc-dur) / 1.3);
}
.opocheck__box:focus-visible { box-shadow: var(--ring); }
.opocheck__box:disabled { cursor: not-allowed; }
/* PERMANENTLY locked (e.g. review/mock done by taking its test): muted so it reads
   as non-editable. NOT applied during a transient toggle, so the draw animation on a
   just-clicked box is never dimmed. */
.opocheck.is-locked { opacity: .5; }
/* Checked: reveal the tick and let the stroke snake around to it. */
.opocheck__box:checked + .opocheck__svg { --opc-da: 16 93; --opc-do: 109; }
.opocheck__svg {
  fill: none; pointer-events: none;
  color: var(--color-primary); stroke: var(--color-primary);
  stroke-dasharray: var(--opc-da, 93); stroke-dashoffset: var(--opc-do, 94);
  stroke-linecap: round; stroke-linejoin: round; stroke-width: 2px;
  transition: stroke-dasharray var(--opc-dur), stroke-dashoffset var(--opc-dur);
}
@media (prefers-reduced-motion: reduce) {
  .opocheck__svg { transition-duration: .01ms; }
}

/* ── Progreso section (dashboard, ROADMAP #23) ──────────────────────────────── */
.dash-progress { margin: var(--space-5) 0 var(--space-2); }
.dash-progress[hidden] { display: none !important; }
.progress-card .card-header { display: flex; align-items: center; justify-content: space-between; }
.progress-head {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--space-4); margin-bottom: var(--space-4);
}
.progress-metric { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.progress-metric__label { font-size: .78rem; color: var(--color-muted); }
.progress-metric__num { font-size: 1.6rem; font-weight: 700; color: var(--color-text); font-variant-numeric: tabular-nums; line-height: 1.1; }
.progress-split { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.progress-chip {
  font-size: .74rem; font-weight: 600; padding: 2px 9px; border-radius: var(--radius-pill);
  background: var(--color-divider); color: var(--color-body);
}
.progress-chip--study { background: color-mix(in srgb, var(--color-acc-high) 20%, transparent); color: var(--color-acc-high); }
.progress-chip--test  { background: color-mix(in srgb, var(--color-primary) 18%, transparent);  color: var(--color-primary); }
.progress-chip--other { background: var(--color-divider); color: var(--color-muted); }
.progress-goal { flex: 1 1 220px; min-width: 200px; max-width: 340px; }
.progress-goal__top { display: flex; align-items: center; gap: 6px; font-size: .8rem; color: var(--color-body); margin-bottom: 6px; }
.progress-goal__val { margin-left: auto; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--color-text); }
.progress-goal__edit {
  border: none; background: transparent; color: var(--color-muted); cursor: pointer;
  padding: 0 2px; font-size: .85rem; line-height: 1;
}
.progress-goal__edit:hover { color: var(--color-primary); }
.progress-goal__bar { height: 8px; border-radius: var(--radius-pill); background: var(--color-divider); overflow: hidden; }
.progress-goal__fill { height: 100%; border-radius: var(--radius-pill); background: var(--color-acc-mid); transition: width .35s ease; }
.progress-goal__fill.is-full { background: var(--color-acc-high); }
.progress-detail[hidden] { display: none !important; }
.progress-subttl { font-size: .82rem; font-weight: 600; color: var(--color-body); margin: var(--space-4) 0 var(--space-2); }
.progress-bars { display: flex; flex-direction: column; gap: var(--space-3); }
.progress-empty { margin: 0; color: var(--color-muted); font-size: .85rem; }
.progress-barrow__top { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); margin-bottom: 4px; }
.progress-barrow__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .85rem; color: var(--color-text); }
.progress-barrow__val { flex: 0 0 auto; font-size: .78rem; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--color-body); }
.progress-barrow__track { display: flex; height: 8px; border-radius: var(--radius-pill); background: var(--color-divider); overflow: hidden; }
.progress-barrow__seg { display: block; height: 100%; }
.progress-barrow__seg--study { background: var(--color-acc-high); }
.progress-barrow__seg--test  { background: var(--color-primary); }
.progress-weeks { display: flex; align-items: flex-end; gap: var(--space-4); height: 96px; padding-top: var(--space-2); }
.progress-week { display: flex; flex-direction: column; align-items: center; gap: 6px; flex: 1 1 0; }
.progress-week__bar-wrap { display: flex; align-items: flex-end; height: 64px; }
.progress-week__bar { width: 26px; border-radius: 6px 6px 0 0; background: var(--color-acc-high); transition: height .35s ease; }
.progress-week__lbl { font-size: .68rem; color: var(--color-muted); text-align: center; }

/* ── Read-only timeline ('Con horario') ─────────────────────────────────── */
.planner-timeline { display: flex; flex-direction: column; gap: 0; }
.planner-timeline__empty { margin: 0; color: var(--color-muted); }
.planner-tl__row { display: flex; gap: var(--space-3); align-items: stretch; }
.planner-tl__time {
  width: 46px; flex: 0 0 auto;
  font-size: .78rem; font-variant-numeric: tabular-nums;
  color: var(--color-muted); padding-top: 10px;
}
.planner-tl__block {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: var(--space-3);
  margin-bottom: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-left: 3px solid var(--color-primary);
  border-radius: 0 var(--radius-input) var(--radius-input) 0;
  background: var(--color-canvas);
}
.planner-tl__check { flex: 0 0 auto; }
.planner-tl__text  { flex: 1; min-width: 0; }
.planner-tl__go    { flex: 0 0 auto; white-space: nowrap; }
.planner-tl__go.is-invisible { visibility: hidden; pointer-events: none; }
.planner-tl__name { font-size: .9rem; font-weight: 500; color: var(--color-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }  /* ellipsis net for no-period names (N26) */
.planner-tl__meta { font-size: .78rem; color: var(--color-muted); margin-top: 1px; }
.planner-tl__row.is-done .planner-tl__name { text-decoration: line-through; color: var(--color-muted); }
.planner-tl__row--end .planner-tl__endlbl { font-size: .76rem; color: var(--color-muted); padding-top: 2px; }

/* ── Study-windows editor (start times, shown in 'Con horario' mode) ────── */
.planner-windows { margin-top: var(--space-5); }
.planner-windows__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--space-3);
}
.planner-win { display: flex; flex-direction: column; align-items: center; gap: var(--space-1); }
@media (max-width: 640px) { .planner-windows__grid { grid-template-columns: repeat(4, 1fr); } }

/* ── Asignatura icon tile on the Estudiar subject card (ROADMAP #22) ─────── */
.subj-card__ico {
  width: 30px; height: 30px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 8px;
  font-size: 1.05rem;
  background: var(--color-canvas);
  flex: 0 0 auto;
}

/* ── Icono y color picker modal (Estudiar) ──────────────────────────────── */
.subj-ident {
  position: fixed; inset: 0; z-index: 1200;
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-4);
  background: rgba(16, 24, 40, .45);
}
.subj-ident__card {
  width: 100%; max-width: 400px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  padding: var(--space-5);
}
.subj-ident__title { font-size: 1.05rem; font-weight: 700; color: var(--color-text); margin-bottom: var(--space-4); }
.subj-ident__preview {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3); margin-bottom: var(--space-4);
  border: 1px solid var(--color-border); border-radius: var(--radius-input);
  background: var(--color-canvas);
}
.subj-ident__prev-ico {
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 10px; font-size: 1.35rem; flex: 0 0 auto;
}
.subj-ident__prev-name { font-weight: 600; color: var(--color-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.subj-ident__label { font-size: .78rem; font-weight: 600; color: var(--color-muted); margin-bottom: var(--space-2); }
.subj-ident__emojis {
  display: grid; grid-template-columns: repeat(9, 1fr); gap: var(--space-1);
  margin-bottom: var(--space-4);
}
.subj-ident__emoji {
  aspect-ratio: 1; border: 1px solid transparent; background: var(--color-canvas);
  border-radius: 8px; font-size: 1.1rem; cursor: pointer; line-height: 1;
}
.subj-ident__emoji:hover { border-color: var(--color-border); }
.subj-ident__emoji.is-sel { border-color: var(--color-primary); box-shadow: var(--ring); }
.subj-ident__swatches { display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--space-2); margin-bottom: var(--space-5); }
.subj-ident__swatch {
  aspect-ratio: 1; border: 2px solid transparent; border-radius: 8px; cursor: pointer;
}
.subj-ident__swatch.is-sel { border-color: var(--color-text); box-shadow: var(--ring); }
.subj-ident__foot { display: flex; justify-content: flex-end; gap: var(--space-2); }

/* ===== LEGAL PAGES (privacidad.php / terminos.php) ===== */
/* Requires: <body class="legal-page"> */

body.legal-page {
  min-height: 100vh;
  background: var(--bg);
  padding: var(--space-8) var(--space-4);
}

.legal {
  width: 100%;
  max-width: 48rem;            /* 768px */
  margin: 0 auto;
}

.legal__brand {
  display: flex;
  justify-content: center;
  margin-bottom: var(--space-6);
  text-decoration: none;
}
.legal__brand-name {
  height: 40px;
  width: auto;
  object-fit: contain;
}

.legal__card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: calc(var(--radius-card) + 0.25rem);
  box-shadow: var(--shadow-card);
  padding: var(--space-8);
  color: var(--body);
  line-height: 1.65;
}

.legal__title {
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--text);
  margin: 0 0 var(--space-2);
}
.legal__meta {
  color: var(--muted);
  font-size: .875rem;
  margin: 0 0 var(--space-6);
}

.legal__card h2 {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--text);
  margin: var(--space-6) 0 var(--space-2);
}
.legal__card p { margin: 0 0 var(--space-4); }
.legal__card ul {
  margin: 0 0 var(--space-4);
  padding-left: var(--space-5);
}
.legal__card li { margin-bottom: var(--space-2); }
.legal__card a {
  color: var(--color-primary);
  text-decoration: none;
}
.legal__card a:hover { text-decoration: underline; }

.legal__back {
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--divider);
}

.legal__footer {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-6);
  font-size: .875rem;
  color: var(--muted);
}
.legal__footer a {
  color: var(--muted);
  text-decoration: none;
}
.legal__footer a:hover { text-decoration: underline; }

/* ===== LEGAL LINK ROWS (login / register / profile footers) ===== */
.login-legal,
.pf-legal {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
  font-size: .8125rem;
  color: var(--muted);
}
.login-legal a,
.pf-legal a {
  color: var(--muted);
  text-decoration: none;
}
.login-legal a:hover,
.pf-legal a:hover { text-decoration: underline; }
.pf-legal { margin-top: var(--space-6); }

/* ===== REGISTER CONSENT CHECKBOX (register.php) ===== */
.reg-consent {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  cursor: pointer;
  font-size: .875rem;
  color: var(--body);
  line-height: 1.5;
}
.reg-consent__box {
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
  margin-top: 0.15rem;
  accent-color: var(--color-primary);
  cursor: pointer;
}
.reg-consent__text a {
  color: var(--color-primary);
  text-decoration: none;
}
.reg-consent__text a:hover { text-decoration: underline; }

/* ===== UPGRADE MODAL + PREMIUM MARKS (ROADMAP M3 = N54-B) =====
   One shared paywall/upgrade modal (Metodium.upgradeModal in app.js) + the gold
   "premium" treatment: locked features stay fully visible and clickable, marked
   with a gold star — never hidden, never greyed (Rober 2026-07-17). */

:root {
  --color-premium:     #B45309;                 /* gold text (amber-700) */
  --color-premium-bg:  rgba(217, 158, 6, .12);  /* soft gold wash */
  --color-premium-brd: rgba(217, 158, 6, .45);  /* gold border */
}
body.dark {
  --color-premium:     #FBBF24;
  --color-premium-bg:  rgba(251, 191, 36, .10);
  --color-premium-brd: rgba(251, 191, 36, .38);
}

/* Backdrop + dialog */
.upmodal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1300;                     /* above sticky bars, search + time widgets */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  background: rgba(15, 23, 42, .45);
  animation: upmodalFade .2s ease-out;
}
@keyframes upmodalFade { from { opacity: 0; } to { opacity: 1; } }
.upmodal {
  width: 100%;
  max-width: 560px;
  max-height: calc(100vh - 2 * var(--space-4));
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 3px solid var(--color-premium-brd);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
  padding: var(--space-6);
  position: relative;
  animation: upmodalPop .22s ease-out;
}
@keyframes upmodalPop {
  from { opacity: 0; transform: translateY(10px) scale(.98); }
  to   { opacity: 1; transform: none; }
}
.upmodal__close {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1;
  padding: var(--space-2);
  border-radius: var(--radius-input);
  cursor: pointer;
}
.upmodal__close:hover { color: var(--body); background: var(--color-premium-bg); }
.upmodal__eyebrow {
  margin: 0 0 var(--space-1);
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--color-premium);
}
.upmodal__star { color: var(--color-premium); }
.upmodal__title {
  margin: 0 0 var(--space-2);
  font-size: 1.25rem;
  line-height: 1.3;
}
.upmodal__msg {
  margin: 0 0 var(--space-4);
  color: var(--muted);
  font-size: .9375rem;
  line-height: 1.5;
}
.upmodal__loss {
  margin: 0 0 var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--color-premium-bg);
  border: 1px solid var(--color-premium-brd);
  border-radius: var(--radius-input);
}
.upmodal__loss-lead {
  margin: 0 0 var(--space-2);
  font-weight: 600;
  font-size: .9375rem;
}
.upmodal__loss-list {
  margin: 0;
  padding-left: 1.1rem;
  font-size: .875rem;
  line-height: 1.6;
}
.upmodal__loss-note {
  margin: var(--space-2) 0 0;
  font-size: .8125rem;
  color: var(--color-premium);
  font-weight: 600;
}
.upmodal__table {
  width: 100%;
  border-collapse: collapse;
  font-size: .8125rem;
  margin: 0 0 var(--space-4);
}
.upmodal__table th,
.upmodal__table td {
  padding: var(--space-2) var(--space-2);
  text-align: center;
  border-bottom: 1px solid var(--border);
}
.upmodal__table th { font-weight: 700; }
.upmodal__table td.upmodal__feat {
  text-align: left;
  color: var(--muted);
}
.upmodal__table .is-mine { background: var(--color-premium-bg); }
.upmodal__table td.is-yes { color: var(--color-success); font-weight: 700; }
.upmodal__table td.is-no  { color: var(--muted); }
.upmodal__mine {
  font-weight: 400;
  font-size: .6875rem;
  color: var(--muted);
}
.upmodal__actions {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
}
.upmodal__dismiss { color: var(--muted); }

@media (max-width: 480px) {
  .upmodal-backdrop { padding: var(--space-2); align-items: flex-end; }
  .upmodal { padding: var(--space-4); max-width: none; }
  .upmodal__actions { flex-direction: column-reverse; align-items: stretch; }
}

/* Welcome-taste countdown pill (fixed top-center, gold; click → modal) */
.taste-pill {
  position: fixed;
  top: var(--space-3);
  left: 50%;
  transform: translateX(-50%);
  z-index: 900;                      /* under the search palette/backdrops */
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-premium-brd);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--color-premium);
  font-size: .8125rem;
  font-weight: 600;
  box-shadow: var(--shadow-card);
  cursor: pointer;
  transition: box-shadow .2s ease-out, transform .2s ease-out;
}
.taste-pill:hover { box-shadow: var(--shadow-pop); transform: translateX(-50%) translateY(-1px); }
@media (max-width: 640px) { .taste-pill { top: auto; bottom: 4.5rem; } }

/* Generic gold premium mark — applied by JS to locked-feature controls
   (mode-seg options, buttons). Fully visible + clickable, just marked. */
.is-premium-feature {
  position: relative;
  border-color: var(--color-premium-brd) !important;
}
.is-premium-feature .premium-star,
.premium-star {
  color: var(--color-premium);
  font-size: .75em;
  line-height: 1;
  margin-left: .25em;
}

/* Planner: collapsed premium day (Free window) — gold chip instead of tasks */
.planner-cal__day--premium .planner-cal__dayfoot { display: none; }
.planner-premium-chip {
  display: inline-flex;
  align-items: center;
  gap: .35em;
  width: 100%;
  border: 1px dashed var(--color-premium-brd);
  border-radius: var(--radius-input);
  background: var(--color-premium-bg);
  color: var(--color-premium);
  font-size: .75rem;
  font-weight: 600;
  padding: var(--space-1) var(--space-2);
  cursor: pointer;
  transition: background .15s ease-out;
}
.planner-premium-chip:hover { background: var(--color-premium-brd); }

/* Free usage line (tests.php, next to "Montar examen") — Free plans only */
.usage-line {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
  font-size: .8125rem;
  color: var(--muted);
}
.usage-line__bar {
  flex: 1 1 auto;
  height: 5px;
  border-radius: var(--radius-pill);
  background: var(--border);
  overflow: hidden;
}
.usage-line__fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--color-primary);
  transition: width .3s ease-out;
}
.usage-line.is-limit .usage-line__fill { background: var(--color-premium); }
.usage-line.is-limit { color: var(--color-premium); font-weight: 600; }

/* ===== RETO POR ENLACE — share buttons (ROADMAP G1) =====
   Results header button + a per-row icon button inside the Historial row anchor
   (its click handler stops the row navigation). reto.php itself is landing-side
   (page-scoped styles), so only the in-app buttons live here. */
.tr-share {
  margin-top: var(--space-3);
}
.hist-row__share {
  flex: 0 0 auto;
  align-self: center;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: transparent;
  font-size: .9rem;
  line-height: 1;
  cursor: pointer;
  margin-right: var(--space-2);
  transition: background .15s ease-out, border-color .15s ease-out;
}
.hist-row__share:hover {
  background: var(--color-primary-soft, rgba(79, 70, 229, .08));
  border-color: var(--color-primary);
}
.hist-row__share:disabled { opacity: .5; cursor: default; }


/* ===== TESTIMONIAL ASK-CARD (ROADMAP G5 — social-proof engine) =====
   Dismissible card offered only after real success (results >=70% / streak
   milestone). Built by Metodium.Testimonial (app.js §9); toggling uses the
   `hidden` attribute only. Stars reuse the premium gold token (M3). */
.testim-card {
  margin: var(--space-4) 0;
  padding: var(--space-4);
}
.testim-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
.testim-card__title {
  font-weight: 600;
  color: var(--color-text);
}
.testim-card__close {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--color-muted);
  font-size: .85rem;
  line-height: 1;
  cursor: pointer;
}
.testim-card__close:hover {
  background: var(--color-bg-subtle);
  color: var(--color-text);
}
.testim-card__sub {
  margin: var(--space-2) 0 var(--space-3);
  color: var(--color-muted);
  font-size: .9rem;
}
.testim-stars {
  display: flex;
  gap: var(--space-1);
}
.testim-star {
  border: none;
  background: transparent;
  padding: 0 var(--space-1);
  font-size: 1.6rem;
  line-height: 1;
  color: var(--color-border-strong);
  cursor: pointer;
  transition: color .12s ease-out, transform .12s ease-out;
}
.testim-star:hover { transform: scale(1.12); }
.testim-star.is-on { color: var(--color-premium); }
.testim-card__body {
  margin-top: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.testim-card__text {
  width: 100%;
  resize: vertical;
  min-height: 64px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: .9rem;
}
.testim-card__text:focus-visible { outline: none; box-shadow: var(--ring); }
.testim-consent {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  font-size: .82rem;
  color: var(--color-muted);
  cursor: pointer;
}
.testim-consent__cb { margin-top: 2px; }
.testim-card__send { align-self: flex-start; }
.testim-card__thanks {
  margin: 0;
  font-weight: 500;
  color: var(--color-success);
}

/* G5 — admin «Testimonios» review queue rows */
.tadm-row {
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-divider);
}
.tadm-row:last-child { border-bottom: none; }
.tadm-row__top {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.tadm-row__stars {
  color: var(--color-premium);
  letter-spacing: 2px;
  font-size: .95rem;
}
.tadm-row__quote {
  margin: var(--space-2) 0;
  color: var(--color-text);
}
.tadm-row__quote--empty {
  color: var(--color-muted);
  font-style: italic;
}
.tadm-row__meta {
  margin: 0 0 var(--space-2);
  font-size: .82rem;
  color: var(--color-muted);
}
.tadm-row__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* ═══════════════════════════════════════════════════════════════════════════
   I1 — Progreso · acierto y puntos flojos (master plan, Track I)
   Extends the ROADMAP #23 Progreso card with the ACCURACY dimension: an
   "Acierto" headline in .progress-head plus three sections inside
   .progress-detail (heatmap por asignatura, evolución, puntos flojos).
   Banding reuses the --color-acc-high / -mid / -low / -none tokens, so these
   colours match the accuracy colours used everywhere else in the app.
   ═══════════════════════════════════════════════════════════════════════════ */

.progress-acc-head[hidden] { display: none !important; }
.progress-acc-head__meta { font-size: .74rem; color: var(--color-muted); margin-top: 2px; }
.progress-metric__num.progress-acc--high { color: var(--color-acc-high); }
.progress-metric__num.progress-acc--mid  { color: var(--color-acc-mid); }
.progress-metric__num.progress-acc--low  { color: var(--color-acc-low); }
.progress-metric__num.progress-acc--none { color: var(--color-acc-none); }
.progress-delta { font-weight: 600; }
.progress-delta--up   { color: var(--color-acc-high); }
.progress-delta--down { color: var(--color-acc-low); }

/* ── Heatmap por asignatura ─────────────────────────────────────────────── */
.progress-heat { display: flex; flex-direction: column; gap: var(--space-2); }
.acc-chip {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-input);
  background: var(--color-divider);
  border-left: 4px solid var(--color-acc-none);
}
.acc-chip__icon { flex: 0 0 auto; font-size: 1rem; line-height: 1; }
.acc-chip__main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.acc-chip__name {
  font-size: .85rem; color: var(--color-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.acc-chip__sub { font-size: .72rem; color: var(--color-muted); }
.acc-chip__val {
  flex: 0 0 auto; font-size: .85rem; font-weight: 700;
  font-variant-numeric: tabular-nums; color: var(--color-body);
}
.acc-chip--high { border-left-color: var(--color-acc-high); background: color-mix(in srgb, var(--color-acc-high) 10%, transparent); }
.acc-chip--high .acc-chip__val { color: var(--color-acc-high); }
.acc-chip--mid  { border-left-color: var(--color-acc-mid);  background: color-mix(in srgb, var(--color-acc-mid) 10%, transparent); }
.acc-chip--mid  .acc-chip__val { color: var(--color-acc-mid); }
.acc-chip--low  { border-left-color: var(--color-acc-low);  background: color-mix(in srgb, var(--color-acc-low) 10%, transparent); }
.acc-chip--low  .acc-chip__val { color: var(--color-acc-low); }
.acc-chip--none .acc-chip__val { color: var(--color-muted); font-weight: 600; }

/* ── Evolución del acierto (one bar per graded attempt) ─────────────────── */
.progress-trend {
  display: flex; align-items: flex-end; gap: 6px;
  min-height: 72px; padding-top: var(--space-2); flex-wrap: wrap;
}
.trend-bar-wrap { display: flex; align-items: flex-end; height: 64px; flex: 1 1 14px; max-width: 34px; }
.trend-bar {
  width: 100%; border-radius: 4px 4px 0 0;
  background: var(--color-acc-none); transition: height .35s ease;
}
.trend-bar--high { background: var(--color-acc-high); }
.trend-bar--mid  { background: var(--color-acc-mid); }
.trend-bar--low  { background: var(--color-acc-low); }
.progress-trend__axis {
  flex: 1 0 100%; margin: var(--space-2) 0 0;
  font-size: .68rem; color: var(--color-muted);
}

/* ── Tus puntos flojos ──────────────────────────────────────────────────── */
.progress-weak { display: flex; flex-direction: column; gap: var(--space-2); }
.weak-row {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-divider); border-radius: var(--radius-input);
}
.weak-row__acc {
  flex: 0 0 auto; min-width: 46px; text-align: center;
  font-size: .82rem; font-weight: 700; font-variant-numeric: tabular-nums;
  padding: 3px 6px; border-radius: var(--radius-pill);
  background: var(--color-divider); color: var(--color-body);
}
.weak-row__acc--high { background: color-mix(in srgb, var(--color-acc-high) 18%, transparent); color: var(--color-acc-high); }
.weak-row__acc--mid  { background: color-mix(in srgb, var(--color-acc-mid) 18%, transparent);  color: var(--color-acc-mid); }
.weak-row__acc--low  { background: color-mix(in srgb, var(--color-acc-low) 18%, transparent);  color: var(--color-acc-low); }
.weak-row__main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.weak-row__name {
  font-size: .85rem; color: var(--color-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.weak-row__sub { font-size: .72rem; color: var(--color-muted); }
.weak-row__cta { flex: 0 0 auto; text-decoration: none; }

@media (max-width: 560px) {
  .weak-row { flex-wrap: wrap; }
  .weak-row__main { flex: 1 1 60%; }
  .weak-row__cta { margin-left: auto; }
  .progress-acc-head { flex: 1 1 100%; }
}

/* ---------------------------------------------------------------------------
   I2 — "este test vs. tu media" line (test_results.php, under the score header)
   One quiet strip, never a card: it annotates the score, it doesn't compete with
   it. Tone comes from the shared accuracy bands, so a good/bad result reads the
   same colour language as the rest of the app. Filled by loadComparison() and
   left `hidden` until there is something true to say.
   --------------------------------------------------------------------------- */
.tr-compare {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
  margin: calc(var(--space-2) * -1) 0 var(--space-4);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-acc-none);
  border-radius: var(--radius-input);
  background: var(--color-surface);
}
.tr-compare--high { border-left-color: var(--color-acc-high); }
.tr-compare--mid  { border-left-color: var(--color-acc-mid); }
.tr-compare--low  { border-left-color: var(--color-acc-low); }

.tr-compare__icon { font-size: .95rem; line-height: 1; }
.tr-compare__head {
  font-size: .85rem; font-weight: 600; color: var(--color-text);
}
.tr-compare--high .tr-compare__head { color: var(--color-acc-high); }
.tr-compare--low  .tr-compare__head { color: var(--color-acc-low); }
.tr-compare__detail {
  font-size: .78rem; color: var(--color-muted);
}
.tr-compare__detail + .tr-compare__detail {
  padding-left: var(--space-2);
  border-left: 1px solid var(--color-divider);
}

@media (max-width: 560px) {
  .tr-compare { gap: var(--space-1); }
  .tr-compare__head { flex: 1 1 100%; }
  .tr-compare__detail + .tr-compare__detail {
    padding-left: 0; border-left: 0;
  }
}

/* ===== ROADMAP I3 — question-quality loop (bank browser) =====
   A per-question 👎 is a HARD EXCLUSION in assemble_exam.php / assemble_review.php,
   so a discarded question is shown muted (it still exists, it just never gets drawn).
   The replacement generation behind it is invisible by design — nothing here narrates it. */

.bankq__stat--discarded {
  background: var(--color-neutral-bg);
  color: var(--color-muted);
}

.bankq.is-discarded .bankq__main { opacity: .55; }
.bankq.is-discarded .bankq__q    { text-decoration: none; }

.bankq__down {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border: 0;
  background: none;
  border-radius: var(--radius-input);
  font-size: .8rem;
  line-height: 1;
  opacity: .45;
  cursor: pointer;
  transition: opacity 150ms ease-out, background-color 150ms ease-out;
}
.bankq__down:hover:not(:disabled) {
  opacity: 1;
  background: var(--color-neutral-bg);
}
.bankq__down.is-active {
  opacity: 1;
  background: var(--color-neutral-bg);
}
.bankq__down:disabled { cursor: default; opacity: .3; }
.bankq__down:focus-visible { outline: none; box-shadow: var(--ring); }

/* =============================================================================
   PACK OPOSICIÓN FINDER (ROADMAP B8 S5 — study.php)

   The user-facing surface for the Pack: a grid box that opens a modal where the
   user searches the convocatoria catalog, sees an honest counts-only summary of
   its temario, and — with the entitlement — previews the real tree before it is
   written. Everything below is token-only, so dark mode follows automatically.
   ========================================================================== */

/* ── The grid box. Same footprint as .asig-card--add, but SOLID rather than
   dashed: importing the official temario is the recommended first move, so it
   reads as an offer, not as an empty slot. ─────────────────────────────────── */
.asig-card--pack {
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 100%;
  font: inherit;
  text-align: center;
  background: var(--color-premium-bg);
  border: 1px solid var(--color-premium-brd);
  color: var(--color-text);
  transition: transform .14s ease, box-shadow .14s ease, border-color .14s ease;
}
.asig-card--pack:hover {
  border-color: var(--color-premium);
  box-shadow: var(--shadow-pop);
}
.asig-card--pack:focus-visible { outline: none; box-shadow: var(--ring); }
.asig-card--pack .asig-card__add-icon {
  background: var(--color-surface);
  color: var(--color-premium);
}
.asig-card--pack:hover .asig-card__add-icon {
  background: var(--color-premium);
  color: #fff;
}
.asig-card__add-sub {
  font-size: .8125rem;
  color: var(--color-muted);
  line-height: 1.3;
}

/* ── Modal shell ──────────────────────────────────────────────────────────── */
.pack-finder {
  position: fixed; inset: 0; z-index: 1200;
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-4);
  background: rgba(16, 24, 40, .45);
}
.pack-finder__card {
  display: flex;
  flex-direction: column;
  width: 100%; max-width: 620px;
  max-height: min(88vh, 760px);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-pop);
}
.pack-finder__head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-5) var(--space-5) var(--space-4);
  border-bottom: 1px solid var(--color-divider);
}
.pack-finder__eyebrow {
  margin: 0 0 var(--space-1);
  font-size: .75rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--color-premium);
}
.pack-finder__title { margin: 0; font-size: 1.15rem; font-weight: 700; color: var(--color-text); }
.pack-finder__close {
  flex: 0 0 auto;
  border: 0; background: none; cursor: pointer;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-input);
  font-size: 1rem; line-height: 1; color: var(--color-muted);
}
.pack-finder__close:hover { background: var(--color-neutral-bg); color: var(--color-text); }
.pack-finder__close:focus-visible { outline: none; box-shadow: var(--ring); }
.pack-finder__body {
  padding: var(--space-4) var(--space-5) var(--space-5);
  overflow-y: auto;
}

/* ── Search row ───────────────────────────────────────────────────────────── */
.pack-finder__search { display: flex; gap: var(--space-2); }
.pack-finder__input {
  flex: 1 1 auto; min-width: 0;
  padding: var(--space-2) var(--space-3);
  font: inherit;
  color: var(--color-text);
  background: var(--color-canvas);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
}
.pack-finder__input:focus { outline: none; border-color: var(--color-primary); box-shadow: var(--ring); }
.pack-finder__hint {
  margin: var(--space-3) 0 0;
  font-size: .8125rem; color: var(--color-muted);
}
.pack-finder__hint.is-error { color: var(--color-danger); }

/* ── Result rows ──────────────────────────────────────────────────────────── */
.pack-finder__results { display: flex; flex-direction: column; gap: var(--space-2); margin-top: var(--space-4); }
.pack-finder__row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-3);
  font: inherit; text-align: left; cursor: pointer;
  color: var(--color-text);
  background: var(--color-canvas);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  transition: border-color .14s ease, box-shadow .14s ease;
}
.pack-finder__row:hover { border-color: var(--color-primary); box-shadow: var(--shadow-card); }
.pack-finder__row:focus-visible { outline: none; box-shadow: var(--ring); }
.pack-finder__row.is-unready { cursor: default; opacity: .6; }
.pack-finder__row.is-unready:hover { border-color: var(--color-border); box-shadow: none; }
.pack-finder__row-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pack-finder__row-title { font-weight: 600; font-size: .9375rem; }
.pack-finder__row-meta { font-size: .8125rem; color: var(--color-muted); }

/* Results that matched only an AI synonym, never the user's own words. Labelled
   as guesses so a wrong answer is never dressed up as a right one. */
.pack-finder__suggest {
  margin: 0 0 2px;
  font-size: .875rem;
  font-weight: 600;
  color: var(--color-text);
}
.pack-finder__suggest-terms {
  margin: 0 0 var(--space-1);
  font-size: .75rem;
  color: var(--color-muted);
}

/* ── Zero results (never a dead end) ──────────────────────────────────────── */
.pack-finder__empty {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-5);
  background: var(--color-canvas);
  border: 1px solid var(--color-divider);
  border-radius: var(--radius-input);
}
.pack-finder__empty-title { margin: 0; font-weight: 600; color: var(--color-text); }
.pack-finder__empty-sub { margin: 0; font-size: .875rem; color: var(--color-muted); line-height: 1.5; }

/* ── Detail: teaser + proposal ────────────────────────────────────────────── */
.pack-finder__back {
  border: 0; background: none; cursor: pointer; padding: 0;
  font: inherit; font-size: .8125rem; color: var(--color-muted);
}
.pack-finder__back:hover { color: var(--color-primary); text-decoration: underline; }
.pack-finder__back:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--radius-input); }
.pack-finder__conv { margin: var(--space-4) 0 var(--space-1); font-size: 1rem; font-weight: 700; color: var(--color-text); }
.pack-finder__conv-meta { margin: 0 0 var(--space-4); font-size: .8125rem; color: var(--color-muted); }
.pack-finder__loading,
.pack-finder__error { margin: var(--space-4) 0 0; font-size: .875rem; color: var(--color-muted); }
.pack-finder__error { color: var(--color-danger); }

.pack-finder__stats { display: flex; gap: var(--space-3); flex-wrap: wrap; }
.pack-finder__stat {
  flex: 1 1 120px;
  padding: var(--space-3);
  background: var(--color-canvas);
  border: 1px solid var(--color-divider);
  border-radius: var(--radius-input);
}
.pack-finder__stat-num { display: block; font-size: 1.35rem; font-weight: 700; color: var(--color-text); }
.pack-finder__stat-lbl { display: block; font-size: .75rem; color: var(--color-muted); }

.pack-finder__laws { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-3); }
.pack-finder__law {
  padding: 2px var(--space-2);
  font-size: .75rem;
  color: var(--color-text);
  background: var(--color-neutral-bg);
  border-radius: var(--radius-pill);
}
.pack-finder__law.is-more { color: var(--color-muted); }
.pack-finder__note { margin: var(--space-3) 0 0; font-size: .8125rem; color: var(--color-muted); line-height: 1.5; }

.pack-finder__tree { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-4); }
.pack-finder__tree-row {
  padding: var(--space-3);
  background: var(--color-canvas);
  border-radius: var(--radius-input);
  font-size: .875rem;
}
.pack-finder__tree-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-3);
}
.pack-finder__tree-name { color: var(--color-text); font-weight: 600; }
.pack-finder__tree-count { flex: 0 0 auto; font-size: .75rem; color: var(--color-muted); white-space: nowrap; }

/* One law of a tema + what the convocatoria does and doesn't put in the exam.
   The acotación is the expensive knowledge a pack carries, so it gets room. */
.pack-finder__law-row {
  display: flex; flex-direction: column; gap: 2px;
  margin-top: var(--space-2);
  padding-left: var(--space-3);
  border-left: 2px solid var(--color-divider);
}
.pack-finder__law-name { font-size: .8125rem; font-weight: 600; color: var(--color-text); }
.pack-finder__scope { font-size: .75rem; color: var(--color-muted); line-height: 1.45; }
.pack-finder__scope.is-out { color: var(--color-danger); }
.pack-finder__scope.is-pending { color: var(--color-warning); }

/* The paywall. Premium tokens so it matches the M3 upgrade modal's language. */
.pack-finder__locked {
  margin-top: var(--space-4);
  padding: var(--space-4);
  background: var(--color-premium-bg);
  border: 1px solid var(--color-premium-brd);
  border-radius: var(--radius-input);
}
.pack-finder__locked-title { margin: 0 0 var(--space-2); font-weight: 700; color: var(--color-text); }
.pack-finder__locked-sub { margin: 0 0 var(--space-3); font-size: .875rem; color: var(--color-text); line-height: 1.55; }
.pack-finder__anchor { margin: 0 0 var(--space-4); font-size: .8125rem; color: var(--color-muted); }

/* Full-bleed primary actions inside the detail pane. */
.pack-finder__detail > .btn { width: 100%; margin-top: var(--space-4); }
.pack-finder__locked > .btn { width: 100%; }

/* ── Locked tema card (B8 S7) ─────────────────────────────────────────────────
   A tema this oposición has and this plan doesn't include yet. Same footprint as
   a real asignatura box so the grid reads as one set — you can see exactly what
   you're missing, by name. Premium (gold) tokens, matching the M3 upgrade
   language: locked stays visible, never hidden, never greyed out. */
.asig-card--locked {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 100%;
  padding: var(--space-4);
  text-align: center;
  text-decoration: none;
  background: var(--color-premium-bg);
  border: 1px dashed var(--color-premium-brd);
  transition: transform .14s ease, box-shadow .14s ease, border-color .14s ease;
}
.asig-card--locked:hover {
  border-style: solid;
  border-color: var(--color-premium);
  box-shadow: var(--shadow-pop);
}
.asig-card--locked:focus-visible { outline: none; box-shadow: var(--ring); }
.asig-card__lock {
  display: inline-grid;
  place-items: center;
  width: 40px; height: 40px;
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-premium);
}
.asig-card__locked-name {
  font-size: .9375rem;
  font-weight: 600;
  color: var(--color-text);
  line-height: 1.3;
  /* Long tema names are the norm ("Tema 4. La Ley 39/2015, de 1 de octubre…"). */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.asig-card__locked-cta { font-size: .75rem; font-weight: 600; color: var(--color-premium); }

/* ── Out-of-exam-scope rows (B8 S6) ───────────────────────────────────────────
   A pack import builds each law's whole tree but only the cited parts carry
   text. These rows stay fully visible and clickable — the law has to read
   continuously — they just stop competing for attention, with one honest label.
   Danger tokens, not a hard red fill: this is guidance, not an error. */
.tree__row.is-out-of-scope .tree__name { color: var(--color-muted); }
.tree__row.is-out-of-scope.is-selected .tree__name { color: var(--color-text); }
.tree__noscope {
  flex: 0 0 auto;                          /* .tree__row is flex with its own gap */
  padding: 1px var(--space-2);
  font-size: .6875rem;
  font-weight: 600;
  letter-spacing: .01em;
  white-space: nowrap;
  color: var(--color-danger);
  background: var(--color-danger-bg);
  border-radius: var(--radius-pill);
}

/* Thumb-first: at 375px the dialog fills the screen and the search stacks. */
@media (max-width: 480px) {
  .pack-finder { padding: 0; }
  .pack-finder__card { max-width: none; max-height: 100vh; height: 100vh; border-radius: 0; border: 0; }
  .pack-finder__search { flex-direction: column; }
  .pack-finder__search .btn { width: 100%; }
  .pack-finder__row { flex-direction: column; align-items: flex-start; gap: var(--space-2); }
}

/* ── Admin · salud del catálogo del Pack (B8 S8) ──────────────────────────────
   One block per boletín adapter, comparing what the crawl cursor claims with
   what the catalog actually holds. The alarm line is the whole point: a cursor
   ahead of an empty catalog is a silent failure, so it gets danger tokens and
   sits under the numbers that contradict each other. */
.pack-health { display: flex; flex-direction: column; gap: var(--space-3); margin: var(--space-3) 0; }
.pack-health__row {
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  background: var(--color-surface);
}
.pack-health__head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.pack-health__nums { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); }
.pack-health__num { font-size: .8125rem; color: var(--color-muted); }
.pack-health__num b { font-size: .9375rem; color: var(--color-text); }
.pack-health__alarm {
  margin: var(--space-2) 0 0;
  padding: var(--space-2) var(--space-3);
  font-size: .8125rem;
  color: var(--color-danger);
  background: var(--color-danger-bg);
  border-radius: var(--radius-input);
}

/* ── Pack finder · filtros geográficos + pantalla "aún no preparado" (B8 S8) ──
   The selects inherit the search input's shape so the row reads as one control
   group; they hide themselves when the catalog only covers one place, so a
   single-comunidad install looks exactly like it did before. */
.pack-finder__geo { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }
.pack-finder__select {
  flex: 1 1 180px; min-width: 0;
  padding: var(--space-2) var(--space-3);
  font: inherit; font-size: .875rem;
  color: var(--color-text);
  background: var(--color-canvas);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
}
.pack-finder__select:focus { outline: none; border-color: var(--color-primary); box-shadow: var(--ring); }

/* Not a paywall and not an error: a state with something to do about it. Neutral
   surface, primary action, and the honest small print underneath. */
.pack-finder__prepare {
  margin-top: var(--space-4);
  padding: var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
}
.pack-finder__prepare-title { margin: 0 0 var(--space-2); font-weight: 700; color: var(--color-text); }
.pack-finder__prepare-sub {
  margin: 0 0 var(--space-3);
  font-size: .875rem; color: var(--color-text); line-height: 1.55;
}
.pack-finder__prepare > .btn { width: 100%; }
