/* ==========================================================================
   iNka Sched — Design System v6.0 "Quiet Confidence"
   Contract: DESIGN_SYSTEM.md (project root). Read that first.
   Self-contained: defines its own tokens, safe to load on any page.

   v6.0 is a ground-up reinvention of the token/visual layer under the SAME
   ds-* component API v5.0 used — every consuming page's markup keeps working
   unchanged. Light-first, one confident accent per theme (role colors are
   now identity badges, not the primary interactive color), soft-shadow
   depth instead of glass/blur, a tunable motion-intensity system, a
   rounded/compact radius mode, and a session-persisted custom accent color.
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,500;0,9..144,600;1,9..144,500&family=Manrope:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap');

:root {
  /* ---- Surfaces / text (light theme is the default surface) ---- */
  --surface: #FAFAF8;
  --surface-raised: #FFFFFF;
  --surface-sunken: #F1F0EB;
  --text: #17171A;
  --text-secondary: rgba(23,23,26,0.7);
  --text-tertiary: rgba(23,23,26,0.60);   /* v6.0 Phase 9 audit: 0.58 measured 4.32:1, below AA 4.5:1 — 0.60 measures ~4.59:1 */
  --border: rgba(23,23,26,0.09);
  --border-strong: rgba(23,23,26,0.16);

  /* ---- Accent (single confident color per theme; the primary interactive
     color for buttons/active-states/focus). Custom-accent picker overrides
     via --accent-custom on <html>; every derived token below reacts
     automatically since they're color-mix() formulas, not hand-authored. ---- */
  --accent-custom: unset;
  --accent: var(--accent-custom, #3452EB);
  /* --accent-contrast-custom lets JS override which text color (black/white)
     stays readable on top of a user-picked custom accent — computed from the
     chosen hex's relative luminance in applyAccent() (js/design-system.js),
     since a dark custom accent would otherwise keep using the theme's
     hardcoded white/black default and could fail WCAG contrast. */
  --accent-contrast-custom: unset;
  --accent-contrast: var(--accent-contrast-custom, #FFFFFF);
  --accent-soft: color-mix(in srgb, var(--accent) 11%, transparent);
  --accent-border: color-mix(in srgb, var(--accent) 30%, transparent);
  --accent-gradient: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 72%, black 8%));

  /* ---- Role identity (badges/labels only — see DESIGN_SYSTEM.md) ---- */
  --role-admin: #5B4FE0;    --role-admin-soft: rgba(91,79,224,0.11);    --role-admin-border: rgba(91,79,224,0.3);
  --role-teacher: #0F8A6D;  --role-teacher-soft: rgba(15,138,109,0.11); --role-teacher-border: rgba(15,138,109,0.3);
  --role-exam: #C2540E;     --role-exam-soft: rgba(194,84,14,0.11);     --role-exam-border: rgba(194,84,14,0.3);

  /* ---- Status (independent of accent/role) ---- */
  --success: #12805F; --success-soft: rgba(18,128,95,0.11);
  --danger:  #C23B3B; --danger-soft:  rgba(194,59,59,0.11);
  --warning: #9C6B12; --warning-soft: rgba(156,107,18,0.11);
  --info:    #2563AD; --info-soft:    rgba(37,99,173,0.11);

  /* ---- Type ---- */
  --font-display: 'Fraunces', serif;
  --font-body: 'Manrope', sans-serif;
  --font-mono: 'IBM Plex Mono', monospace;
  --text-xs: 0.75rem;
  --text-sm: 0.8125rem;
  --text-base: 0.9375rem;
  --text-lg: 1.25rem;
  --text-xl: clamp(1.9rem, 3.4vw, 2.6rem);
  --text-hero: clamp(2.6rem, 5vw, 4.2rem);

  /* ---- Space / shape — "rounded" is the default radius mode; see
     [data-radius="compact"] below for the sharper alternative. ---- */
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
  --space-5: 20px; --space-6: 24px; --space-8: 32px; --space-9: 40px; --space-10: 48px;
  --radius-sm: 10px; --radius-md: 14px; --radius-lg: 20px; --radius-xl: 28px; --radius-pill: 999px;

  --table-cell-py: var(--space-3);
  --card-body-py: var(--space-6);

  /* ---- Depth: layered soft shadow, not glass/blur ---- */
  --shadow-color: 23,23,26;
  --shadow-sm: 0 1px 2px rgba(var(--shadow-color),0.06), 0 1px 1px rgba(var(--shadow-color),0.04);
  --shadow-md: 0 8px 24px rgba(var(--shadow-color),0.08), 0 2px 6px rgba(var(--shadow-color),0.05);
  --shadow-lg: 0 20px 56px rgba(var(--shadow-color),0.14), 0 6px 16px rgba(var(--shadow-color),0.08);
  --shadow-glow-accent: 0 0 0 1px var(--accent-border), 0 0 22px var(--accent-soft);

  /* ---- Motion intensity — [data-motion] on <html>, always overridden to 0
     by an OS-level prefers-reduced-motion request (see bottom of file). ---- */
  --motion-scale: 1;
}

/* ==========================================================================
   Themes — data-theme on <html>, set server-side from session
   (includes/theme_helper.php), instantly swappable client-side
   (js/design-system.js). :root above IS the "light" theme (the default);
   every other theme block redefines the same token set.
   ========================================================================== */

:root[data-theme="dark"] {
  --surface: #121214; --surface-raised: #1B1B1E; --surface-sunken: #232327;
  --text: #F5F4F2; --text-secondary: rgba(245,244,242,0.7); --text-tertiary: rgba(245,244,242,0.5);
  --border: rgba(245,244,242,0.08); --border-strong: rgba(245,244,242,0.15);
  --accent: var(--accent-custom, #7C93FF); --accent-contrast: var(--accent-contrast-custom, #10121E);
  --success: #4ED8A8; --success-soft: rgba(78,216,168,0.13);
  --danger:  #FF6F6F; --danger-soft:  rgba(255,111,111,0.13);
  --warning: #E3AC55; --warning-soft: rgba(227,172,85,0.13);
  --info:    #6FA9E6; --info-soft:    rgba(111,169,230,0.13);
  --shadow-color: 0,0,0;
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.3), 0 1px 1px rgba(0,0,0,0.2);
  --shadow-md: 0 10px 28px rgba(0,0,0,0.36), 0 2px 8px rgba(0,0,0,0.22);
  --shadow-lg: 0 24px 64px rgba(0,0,0,0.44), 0 8px 20px rgba(0,0,0,0.26);
}

:root[data-theme="midnight"] {
  --surface: #07080F; --surface-raised: #0F1120; --surface-sunken: #161933;
  --text: #EDEEFA; --text-secondary: rgba(237,238,250,0.7); --text-tertiary: rgba(237,238,250,0.5);
  --border: rgba(160,170,255,0.09); --border-strong: rgba(160,170,255,0.18);
  --accent: var(--accent-custom, #8B7CFF); --accent-contrast: var(--accent-contrast-custom, #11081F);
  --success: #5FE3C0; --success-soft: rgba(95,227,192,0.13);
  --danger:  #FF7A90; --danger-soft:  rgba(255,122,144,0.13);
  --warning: #E3AC55; --warning-soft: rgba(227,172,85,0.13);
  --info:    #8CA3FF; --info-soft:    rgba(140,163,255,0.13);
  --shadow-color: 0,0,0;
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.35), 0 1px 1px rgba(0,0,0,0.22);
  --shadow-md: 0 10px 28px rgba(0,0,0,0.4), 0 2px 8px rgba(0,0,0,0.24);
  --shadow-lg: 0 24px 64px rgba(0,0,0,0.48), 0 8px 20px rgba(0,0,0,0.28);
}

:root[data-theme="ocean"] {
  --surface: #061019; --surface-raised: #0D1B27; --surface-sunken: #142735;
  --text: #E8F3F8; --text-secondary: rgba(232,243,248,0.7); --text-tertiary: rgba(232,243,248,0.5);
  --border: rgba(120,190,230,0.09); --border-strong: rgba(120,190,230,0.18);
  --accent: var(--accent-custom, #47C4E8); --accent-contrast: var(--accent-contrast-custom, #06232E);
  --success: #4FD6A8; --success-soft: rgba(79,214,168,0.13);
  --danger:  #FF7570; --danger-soft:  rgba(255,117,112,0.13);
  --warning: #E0A24D; --warning-soft: rgba(224,162,77,0.13);
  --info:    #5AC8E8; --info-soft:    rgba(90,200,232,0.13);
  --shadow-color: 0,0,0;
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.32), 0 1px 1px rgba(0,0,0,0.2);
  --shadow-md: 0 10px 28px rgba(0,0,0,0.38), 0 2px 8px rgba(0,0,0,0.22);
  --shadow-lg: 0 24px 64px rgba(0,0,0,0.46), 0 8px 20px rgba(0,0,0,0.26);
}

:root[data-theme="forest"] {
  --surface: #08120D; --surface-raised: #101F17; --surface-sunken: #182E22;
  --text: #E9F5EE; --text-secondary: rgba(233,245,238,0.7); --text-tertiary: rgba(233,245,238,0.5);
  --border: rgba(130,220,170,0.09); --border-strong: rgba(130,220,170,0.18);
  --accent: var(--accent-custom, #46C98A); --accent-contrast: var(--accent-contrast-custom, #062017);
  --success: #46C98A; --success-soft: rgba(70,201,138,0.13);
  --danger:  #FF7570; --danger-soft:  rgba(255,117,112,0.13);
  --warning: #E0BB4D; --warning-soft: rgba(224,187,77,0.13);
  --info:    #5FB8D6; --info-soft:    rgba(95,184,214,0.13);
  --shadow-color: 0,0,0;
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.32), 0 1px 1px rgba(0,0,0,0.2);
  --shadow-md: 0 10px 28px rgba(0,0,0,0.38), 0 2px 8px rgba(0,0,0,0.22);
  --shadow-lg: 0 24px 64px rgba(0,0,0,0.46), 0 8px 20px rgba(0,0,0,0.26);
}

:root[data-theme="graphite"] {
  --surface: #0B0B0C; --surface-raised: #151516; --surface-sunken: #1E1E20;
  --text: #F1F1EF; --text-secondary: rgba(241,241,239,0.7); --text-tertiary: rgba(241,241,239,0.5);
  --border: rgba(255,255,255,0.07); --border-strong: rgba(255,255,255,0.14);
  --accent: var(--accent-custom, #9AA6FF); --accent-contrast: var(--accent-contrast-custom, #101227);
  --success: #6EE7B7; --success-soft: rgba(110,231,183,0.13);
  --danger:  #F87171; --danger-soft:  rgba(248,113,113,0.13);
  --warning: #FBBF24; --warning-soft: rgba(251,191,36,0.13);
  --info:    #93C5FD; --info-soft:    rgba(147,197,253,0.13);
  --shadow-color: 0,0,0;
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.3), 0 1px 1px rgba(0,0,0,0.18);
  --shadow-md: 0 10px 28px rgba(0,0,0,0.36), 0 2px 8px rgba(0,0,0,0.2);
  --shadow-lg: 0 24px 64px rgba(0,0,0,0.42), 0 8px 20px rgba(0,0,0,0.24);
}

:root[data-theme="royal"] {
  --surface: #0C0714; --surface-raised: #17101F; --surface-sunken: #221933;
  --text: #F3EFFB; --text-secondary: rgba(243,239,251,0.7); --text-tertiary: rgba(243,239,251,0.5);
  --border: rgba(196,160,255,0.09); --border-strong: rgba(196,160,255,0.18);
  --accent: var(--accent-custom, #B18CFF); --accent-contrast: var(--accent-contrast-custom, #170B26);
  --success: #5FE3B0; --success-soft: rgba(95,227,176,0.13);
  --danger:  #FF7590; --danger-soft:  rgba(255,117,144,0.13);
  --warning: #E0A24D; --warning-soft: rgba(224,162,77,0.13);
  --info:    #8CA3FF; --info-soft:    rgba(140,163,255,0.13);
  --shadow-color: 0,0,0;
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.32), 0 1px 1px rgba(0,0,0,0.2);
  --shadow-md: 0 10px 28px rgba(0,0,0,0.38), 0 2px 8px rgba(0,0,0,0.22);
  --shadow-lg: 0 24px 64px rgba(0,0,0,0.46), 0 8px 20px rgba(0,0,0,0.26);
}

:root[data-theme="sunset"] {
  --surface: #150B07; --surface-raised: #221208; --surface-sunken: #301A0D;
  --text: #FBEFE7; --text-secondary: rgba(251,239,231,0.7); --text-tertiary: rgba(251,239,231,0.5);
  --border: rgba(255,170,120,0.09); --border-strong: rgba(255,170,120,0.18);
  --accent: var(--accent-custom, #FF9B5C); --accent-contrast: var(--accent-contrast-custom, #200E04);
  --success: #5FE3B0; --success-soft: rgba(95,227,176,0.13);
  --danger:  #FF6259; --danger-soft:  rgba(255,98,89,0.13);
  --warning: #FFCC5C; --warning-soft: rgba(255,204,92,0.13);
  --info:    #6FA8DC; --info-soft:    rgba(111,168,220,0.13);
  --shadow-color: 0,0,0;
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.32), 0 1px 1px rgba(0,0,0,0.2);
  --shadow-md: 0 10px 28px rgba(0,0,0,0.38), 0 2px 8px rgba(0,0,0,0.22);
  --shadow-lg: 0 24px 64px rgba(0,0,0,0.46), 0 8px 20px rgba(0,0,0,0.26);
}

:root[data-theme="contrast"] {
  --surface: #000000; --surface-raised: #000000; --surface-sunken: #0A0A0A;
  --text: #FFFFFF; --text-secondary: #FFFFFF; --text-tertiary: #D8D8D8;
  --border: rgba(255,255,255,0.4); --border-strong: #FFFFFF;
  --accent: var(--accent-custom, #FFE24D); --accent-contrast: var(--accent-contrast-custom, #000000);
  --accent-soft: rgba(255,226,77,0.18); --accent-border: #FFE24D;
  --success: #00FF7F; --success-soft: rgba(0,255,127,0.18);
  --danger:  #FF4747; --danger-soft:  rgba(255,71,71,0.18);
  --warning: #FFD400; --warning-soft: rgba(255,212,0,0.18);
  --info:    #66CCFF; --info-soft:    rgba(102,204,255,0.18);
  --role-admin: #FFE24D; --role-admin-soft: rgba(255,226,77,0.18); --role-admin-border: #FFE24D;
  --role-teacher: #4DE9FF; --role-teacher-soft: rgba(77,233,255,0.18); --role-teacher-border: #4DE9FF;
  --role-exam: #FF7ED6; --role-exam-soft: rgba(255,126,214,0.18); --role-exam-border: #FF7ED6;
  --shadow-sm: none; --shadow-md: none; --shadow-lg: none; --shadow-glow-accent: 0 0 0 2px var(--accent);
}

/* "system" — tracks light by default; dark media query flips it to the
   Dark theme's palette. Kept intentionally simple (one OS-linked pairing,
   not nine) since a user who wants a specific dark flavor picks it by name. */
@media (prefers-color-scheme: dark) {
  :root[data-theme="system"] {
    --surface: #121214; --surface-raised: #1B1B1E; --surface-sunken: #232327;
    --text: #F5F4F2; --text-secondary: rgba(245,244,242,0.7); --text-tertiary: rgba(245,244,242,0.5);
    --border: rgba(245,244,242,0.08); --border-strong: rgba(245,244,242,0.15);
    --accent: var(--accent-custom, #7C93FF); --accent-contrast: var(--accent-contrast-custom, #10121E);
    --shadow-color: 0,0,0;
    --shadow-sm: 0 1px 2px rgba(0,0,0,0.3), 0 1px 1px rgba(0,0,0,0.2);
    --shadow-md: 0 10px 28px rgba(0,0,0,0.36), 0 2px 8px rgba(0,0,0,0.22);
    --shadow-lg: 0 24px 64px rgba(0,0,0,0.44), 0 8px 20px rgba(0,0,0,0.26);
  }
}

/* Radius mode — "rounded" is the :root default; compact sharpens every
   corner for a denser, more Stripe-like feel. */
[data-radius="compact"] {
  --radius-sm: 6px; --radius-md: 8px; --radius-lg: 12px; --radius-xl: 16px; --radius-pill: 8px;
}

/* Density */
[data-density="compact"] { --table-cell-py: 6px; --card-body-py: var(--space-4); }

/* Font size */
[data-font-size="sm"] { --text-xs: 0.6875rem; --text-sm: 0.75rem; --text-base: 0.8125rem; --text-lg: 1.125rem; }
[data-font-size="lg"] { --text-xs: 0.8125rem; --text-sm: 0.9375rem; --text-base: 1.0625rem; --text-lg: 1.375rem; }

/* Motion intensity — every transition/animation duration in this file is
   expressed as calc(<base> * var(--motion-scale)) so one switch scales the
   whole system. prefers-reduced-motion always wins regardless of the saved
   preference (the !important + placement-last is deliberate, not sloppy). */
:root { --motion-scale: 1; }
[data-motion="none"] { --motion-scale: 0; }
[data-motion="reduced"] { --motion-scale: 0.5; }
[data-motion="full"] { --motion-scale: 1.3; }
@media (prefers-reduced-motion: reduce) {
  :root, [data-motion="none"], [data-motion="reduced"], [data-motion="full"] { --motion-scale: 0 !important; }
}

/* ==========================================================================
   TEMPORARY compatibility bridge — DO NOT extend, only shrink.
   Pages not yet migrated to v6.0 markup still have inline `style="..."`
   attributes referencing the old v5.0 token names (--ink, --muted, --admin,
   --gradient-admin, etc). Without this bridge those pages would render with
   broken/missing colors the instant this stylesheet's contents changed,
   even though their structure and class names still work fine. Each alias
   below maps an old name straight onto its v6.0 replacement token; delete
   an entry only once every page referencing it has been migrated to the
   new token names directly. Track progress in UI_MIGRATION_PROGRESS.md.
   ========================================================================== */
:root {
  --ink: var(--surface); --ink-2: var(--surface-raised); --ink-3: var(--surface-sunken);
  --bright: var(--text); --body: var(--text-secondary); --muted: var(--text-tertiary);
  --rule: var(--border); --rule-strong: var(--border-strong);
  --admin: var(--accent); --admin-dim: var(--accent-soft); --admin-border: var(--accent-border);
  --teacher: var(--role-teacher); --teacher-dim: var(--role-teacher-soft); --teacher-border: var(--role-teacher-border);
  --exam: var(--role-exam); --exam-dim: var(--role-exam-soft); --exam-border: var(--role-exam-border);
  --gradient-admin: var(--accent-gradient); --gradient-teacher: var(--role-teacher); --gradient-exam: var(--role-exam);
  --success-dim: var(--success-soft); --danger-dim: var(--danger-soft); --warning-dim: var(--warning-soft); --info-dim: var(--info-soft);
  --glass-bg: var(--surface-raised); --glass-bg-strong: var(--surface-raised); --glass-border: var(--border); --glass-blur: 0px;
  --noise-texture: none;
  --shadow-glow-admin: var(--shadow-glow-accent); --shadow-glow-teacher: var(--shadow-glow-accent); --shadow-glow-exam: var(--shadow-glow-accent);
}

html { background: var(--surface); }
body {
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-body);
  transition: background-color calc(0.2s * var(--motion-scale)) ease, color calc(0.2s * var(--motion-scale)) ease;
}
.ds-btn, .ds-input, .ds-select, .ds-textarea, .ds-card, .ds-table-wrap {
  transition: background-color calc(0.2s * var(--motion-scale)) ease, border-color calc(0.2s * var(--motion-scale)) ease, color calc(0.2s * var(--motion-scale)) ease;
}

/* ==========================================================================
   Focus visibility (WCAG 2.4.7) + skip-to-content
   ========================================================================== */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
textarea:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

.ds-skip-link {
  position: absolute; top: -48px; left: var(--space-4); z-index: 999;
  background: var(--text); color: var(--surface);
  padding: var(--space-3) var(--space-5); border-radius: var(--radius-sm);
  font-family: var(--font-body); font-size: var(--text-sm); font-weight: 600;
  text-decoration: none;
  transition: top calc(0.15s * var(--motion-scale)) ease;
}
.ds-skip-link:focus-visible { top: var(--space-4); outline: 2px solid var(--surface); outline-offset: 2px; }

/* ==========================================================================
   Header (floating top bar)
   ========================================================================== */

.ds-header {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  height: 64px; padding: 0 var(--space-6);
  margin: var(--space-4) var(--space-4) 0;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-body);
  position: sticky; top: var(--space-4); z-index: 60;
}
.ds-header__brand { display: flex; align-items: center; gap: var(--space-3); text-decoration: none; }
.ds-header__logo { height: 48px; width: auto; display: block; object-fit: contain; }
.ds-header__actions { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }

.ds-step-number {
  background: var(--accent-soft); color: var(--accent);
  border-radius: 50%; width: 22px; height: 22px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700; margin-right: var(--space-2); flex-shrink: 0;
}

@media (max-width: 768px) {
  .ds-header { height: auto; flex-wrap: wrap; padding: var(--space-4) var(--space-5); margin: var(--space-3) var(--space-3) 0; }
  .ds-header__actions { width: 100%; justify-content: space-between; }
}

/* ==========================================================================
   Sidebar
   ========================================================================== */

.ds-sidebar {
  width: 264px; flex-shrink: 0;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-5) 0;
  margin: var(--space-4) 0 var(--space-4) var(--space-4);
  align-self: flex-start;
  position: sticky; top: calc(64px + var(--space-4) * 2);
  max-height: calc(100vh - 64px - var(--space-4) * 3);
  overflow-y: auto;
  transition: width calc(0.22s * var(--motion-scale)) ease;
}
.ds-nav-group { display: block; }
.ds-nav-section {
  display: flex; align-items: center; justify-content: space-between; width: 100%;
  padding: var(--space-4) var(--space-5) var(--space-2);
  font-family: var(--font-mono); font-size: 10px; font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-tertiary);
  background: none; border: none; cursor: pointer;
}
.ds-nav-section__chevron { transition: transform calc(0.18s * var(--motion-scale)) ease; flex-shrink: 0; opacity: 0.7; }
.ds-nav-group.is-collapsed .ds-nav-section__chevron { transform: rotate(-90deg); }
.ds-nav-group.is-collapsed .ds-nav-group__items { display: none; }

.ds-cmdk__item-star {
  background: none; border: none; cursor: pointer; flex-shrink: 0;
  color: var(--text-tertiary); padding: 4px; border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center; margin-left: auto;
}
.ds-cmdk__item-star:hover { color: var(--accent); background: var(--accent-soft); }
.ds-cmdk__item-star.is-favorited { color: var(--accent); }
.ds-cmdk__item-star.is-favorited svg { fill: currentColor; }

.ds-nav-item {
  display: flex; align-items: center; gap: var(--space-3); position: relative;
  margin: 2px var(--space-3); padding: 9px var(--space-4);
  border-radius: var(--radius-sm);
  color: var(--text-secondary); text-decoration: none; font-size: var(--text-sm);
  transition: background calc(0.18s * var(--motion-scale)) ease, color calc(0.18s * var(--motion-scale)) ease, padding calc(0.18s * var(--motion-scale)) ease;
}
.ds-nav-item:hover { background: var(--surface-sunken); color: var(--text); }
.ds-nav-item.is-active {
  background: var(--accent-soft); color: var(--accent); font-weight: 600;
  padding-left: calc(var(--space-4) + 8px);
}
.ds-nav-item.is-active::before {
  content: ''; position: absolute; left: 4px; top: 50%; transform: translateY(-50%);
  width: 3px; height: 16px; border-radius: var(--radius-pill); background: var(--accent);
}
/* Role-tinted variants exist for pages that want portal identity on a nav
   item (rare — most nav now uses the plain accent above). */
.ds-nav-item--teacher:hover { color: var(--role-teacher); background: var(--role-teacher-soft); }
.ds-nav-item--teacher.is-active { color: var(--role-teacher); background: var(--role-teacher-soft); }
.ds-nav-item--teacher.is-active::before { background: var(--role-teacher); }
.ds-nav-item--exam:hover { color: var(--role-exam); background: var(--role-exam-soft); }
.ds-nav-item--exam.is-active { color: var(--role-exam); background: var(--role-exam-soft); }
.ds-nav-item--exam.is-active::before { background: var(--role-exam); }

.ds-sidebar-toggle { display: none; }
.ds-sidebar-backdrop { display: none; }

@media (max-width: 900px) {
  .ds-sidebar-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; border-radius: var(--radius-sm);
    background: var(--surface-sunken); border: 1px solid var(--border-strong); color: var(--text);
    cursor: pointer;
  }
  .ds-sidebar {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 1001;
    width: min(280px, 82vw); margin: 0; border-radius: 0; border-width: 0 1px 0 0;
    max-height: none; transform: translateX(-100%);
    transition: transform calc(0.25s * var(--motion-scale)) ease;
    overflow-y: auto; box-shadow: 8px 0 24px rgba(0,0,0,0.2);
  }
  .ds-sidebar.is-open { transform: translateX(0); }
  .ds-sidebar-backdrop {
    display: block; position: fixed; inset: 0; z-index: 1000;
    background: rgba(0,0,0,0.45); opacity: 0; pointer-events: none;
    transition: opacity calc(0.2s * var(--motion-scale)) ease;
  }
  .ds-sidebar-backdrop.is-open { opacity: 1; pointer-events: auto; }
}

.ds-nav-item__label, .ds-nav-section__label {
  transition: opacity calc(0.15s * var(--motion-scale)) ease, width calc(0.15s * var(--motion-scale)) ease;
  white-space: nowrap; overflow: hidden;
}
.ds-sidebar-rail-toggle {
  display: flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; margin: 0 var(--space-3) var(--space-3);
  border-radius: var(--radius-sm); border: 1px solid var(--border-strong);
  background: var(--surface-sunken); color: var(--text-tertiary); cursor: pointer;
  transition: color calc(0.15s * var(--motion-scale)) ease;
}
.ds-sidebar-rail-toggle:hover { color: var(--text); }
@media (max-width: 900px) { .ds-sidebar-rail-toggle { display: none; } }

@media (min-width: 901px) {
  .ds-page[data-sidebar="collapsed"] .ds-sidebar { width: 72px; overflow: visible; }
  .ds-page[data-sidebar="collapsed"] .ds-nav-item__label,
  .ds-page[data-sidebar="collapsed"] .ds-nav-section__label { opacity: 0; width: 0; }
  .ds-page[data-sidebar="collapsed"] .ds-nav-item { justify-content: center; }
  .ds-page[data-sidebar="collapsed"] .ds-nav-item.is-active { padding-left: var(--space-4); }
  .ds-page[data-sidebar="collapsed"] .ds-nav-item.is-active::before { left: 2px; }
  .ds-page[data-sidebar="collapsed"] .ds-sidebar-rail-toggle svg { transform: rotate(180deg); }
}

/* ==========================================================================
   Card
   ========================================================================== */

.ds-card {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition: box-shadow calc(0.25s * var(--motion-scale)) ease, transform calc(0.25s * var(--motion-scale)) ease, border-color calc(0.25s * var(--motion-scale)) ease;
}
.ds-card__header { padding: var(--space-5) var(--space-6) var(--space-4); border-bottom: 1px solid var(--border); }
.ds-card__body { padding: var(--card-body-py); }
.ds-card__footer { padding: var(--space-4) var(--space-6); border-top: 1px solid var(--border-strong); display: flex; align-items: center; justify-content: space-between; }

.ds-card--interactive { position: relative; cursor: pointer; }
.ds-card--interactive:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.ds-card--accent:hover { border-color: var(--accent-border); box-shadow: var(--shadow-glow-accent); }
.ds-card--admin:hover { border-color: var(--role-admin-border); }
.ds-card--teacher:hover { border-color: var(--role-teacher-border); }
.ds-card--exam:hover { border-color: var(--role-exam-border); }

/* ==========================================================================
   Stat card
   ========================================================================== */

.ds-stats-row { display: flex; gap: 0; border-bottom: 1px solid var(--border-strong); flex-wrap: wrap; }
.ds-stat-card { flex: 1 1 0; min-width: 140px; padding: var(--space-4) var(--space-6); border-right: 1px solid var(--border); position: relative; }
.ds-stat-card:last-child { border-right: none; }
.ds-stat-card__value { font-family: var(--font-mono); font-size: 28px; font-weight: 500; color: var(--text); line-height: 1; margin-bottom: var(--space-1); font-variant-numeric: tabular-nums; }
.ds-stat-card__label { font-size: var(--text-xs); color: var(--text-tertiary); letter-spacing: 0.04em; text-transform: uppercase; }
.ds-stat-card__accent { position: absolute; bottom: 0; left: var(--space-6); height: 3px; width: 32px; border-radius: var(--radius-pill); background: var(--accent-gradient); }

@media (max-width: 768px) { .ds-stat-card { flex: 1 1 50%; border-bottom: 1px solid var(--border); border-right: none; } }
@media (max-width: 480px) { .ds-stat-card { flex: 1 1 100%; } }

/* ==========================================================================
   Badge
   ========================================================================== */

.ds-badge {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: 0.06em; text-transform: uppercase;
  font-weight: 600; padding: 3px 10px; border-radius: var(--radius-pill); border: 1px solid transparent;
}
.ds-badge--admin   { color: var(--role-admin);   background: var(--role-admin-soft);   border-color: var(--role-admin-border); }
.ds-badge--teacher { color: var(--role-teacher); background: var(--role-teacher-soft); border-color: var(--role-teacher-border); }
.ds-badge--exam    { color: var(--role-exam);    background: var(--role-exam-soft);    border-color: var(--role-exam-border); }
.ds-badge--accent  { color: var(--accent);  background: var(--accent-soft);  border-color: var(--accent-border); }
.ds-badge--success { color: var(--success); background: var(--success-soft); border-color: color-mix(in srgb, var(--success) 30%, transparent); }
.ds-badge--danger  { color: var(--danger);  background: var(--danger-soft);  border-color: color-mix(in srgb, var(--danger) 30%, transparent); }
.ds-badge--warning { color: var(--warning); background: var(--warning-soft); border-color: color-mix(in srgb, var(--warning) 30%, transparent); }
.ds-badge--info    { color: var(--info);    background: var(--info-soft);    border-color: color-mix(in srgb, var(--info) 30%, transparent); }

/* ==========================================================================
   Button
   ========================================================================== */

.ds-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  font-family: var(--font-body); font-size: var(--text-sm); font-weight: 600;
  padding: 10px 20px; border-radius: var(--radius-pill); border: 1px solid var(--border-strong);
  background: var(--surface-raised); color: var(--text);
  text-decoration: none; cursor: pointer; position: relative;
  transition: transform calc(0.15s * var(--motion-scale)) ease, box-shadow calc(0.15s * var(--motion-scale)) ease, background calc(0.15s * var(--motion-scale)) ease, opacity calc(0.15s * var(--motion-scale)) ease;
}
.ds-btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.ds-btn:active { transform: translateY(0); }
.ds-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ds-btn--sm { padding: 6px 14px; font-size: var(--text-xs); }

.ds-btn--primary { background: var(--accent-gradient); color: var(--accent-contrast); border-color: transparent; }
.ds-btn--primary:hover { box-shadow: var(--shadow-glow-accent); }
.ds-btn--primary.ds-btn--teacher { background: var(--role-teacher); }
.ds-btn--primary.ds-btn--exam    { background: var(--role-exam); }

.ds-btn--danger       { background: var(--danger-soft); color: var(--danger); border-color: transparent; }
.ds-btn--danger:hover { background: color-mix(in srgb, var(--danger-soft) 55%, var(--danger) 25%); }

.ds-btn--ghost { background: transparent; border-color: var(--border-strong); color: var(--text-secondary); }
.ds-btn--ghost:hover { border-color: var(--accent); color: var(--accent); }

/* ==========================================================================
   Forms
   ========================================================================== */

.ds-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-5); }
.ds-field { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.ds-field--full { grid-column: 1 / -1; }
.ds-field__label {
  font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-tertiary);
  text-transform: uppercase; letter-spacing: 0.04em;
}

.ds-input, .ds-select, .ds-textarea {
  width: 100%; height: 46px;
  background: var(--surface-sunken); border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  color: var(--text); font-family: var(--font-body); font-size: var(--text-base); padding: 0 var(--space-4);
  transition: border-color calc(0.15s * var(--motion-scale)) ease, box-shadow calc(0.15s * var(--motion-scale)) ease;
}
.ds-textarea { height: auto; min-height: 110px; padding: var(--space-3) var(--space-4); resize: vertical; }
.ds-input:focus, .ds-select:focus, .ds-textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft);
}
.ds-select { appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--text-tertiary) 50%), linear-gradient(135deg, var(--text-tertiary) 50%, transparent 50%); background-position: calc(100% - 20px) center, calc(100% - 15px) center; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }

@media (max-width: 480px) { .ds-input, .ds-select, .ds-textarea { font-size: 16px; } }

/* Section divider — groups related fields within one ds-form-grid under a
   labeled header (formalizes a pattern several forms already hand-rolled
   with inline styles). Use on a ds-field--full. */
.ds-form-section {
  font-family: var(--font-mono); font-size: var(--text-xs); text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--text-tertiary); border-bottom: 1px solid var(--border);
  padding-bottom: var(--space-2);
}
.ds-form-section:not(:first-child) { margin-top: var(--space-2); }

/* Floating label — label sits inside the control until focused or filled,
   then rises above it. Opt-in via ds-field--floating (changes the required
   DOM order to input-then-label, which plain ds-field doesn't use) rather
   than changing the base component, so existing forms are unaffected. */
.ds-field--floating { position: relative; }
.ds-field--floating .ds-input,
.ds-field--floating .ds-select,
.ds-field--floating .ds-textarea { padding-top: 22px; padding-bottom: 8px; }
.ds-field--floating .ds-field__label {
  position: absolute; left: var(--space-4); top: 50%; transform: translateY(-50%);
  font-family: var(--font-body); text-transform: none; letter-spacing: 0; font-size: var(--text-base);
  color: var(--text-tertiary); pointer-events: none; background: transparent;
  transform-origin: left top;
  transition: transform calc(0.15s * var(--motion-scale)) ease, color calc(0.15s * var(--motion-scale)) ease, top calc(0.15s * var(--motion-scale)) ease;
}
.ds-field--floating .ds-input:focus ~ .ds-field__label,
.ds-field--floating .ds-input:not(:placeholder-shown) ~ .ds-field__label,
.ds-field--floating .ds-select ~ .ds-field__label,
.ds-field--floating .ds-textarea:focus ~ .ds-field__label,
.ds-field--floating .ds-textarea:not(:placeholder-shown) ~ .ds-field__label {
  top: 13px; font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; font-family: var(--font-mono);
  color: var(--accent);
}
.ds-field--floating .ds-textarea ~ .ds-field__label { top: 16px; transform: none; }
.ds-field--floating .ds-textarea:focus ~ .ds-field__label,
.ds-field--floating .ds-textarea:not(:placeholder-shown) ~ .ds-field__label { top: 8px; }

/* ==========================================================================
   Table
   ========================================================================== */

.ds-table-wrap {
  overflow-x: auto; overflow-y: auto; max-height: var(--ds-table-max-height, none);
  border: 1px solid var(--border-strong); border-radius: var(--radius-md); background: var(--surface-raised);
}
.ds-table { width: 100%; border-collapse: separate; border-spacing: 0 6px; font-size: var(--text-sm); min-width: 480px; }
.ds-table th, .ds-table td { text-align: left; padding: var(--table-cell-py) var(--space-4); color: var(--text-secondary); white-space: nowrap; }
.ds-table th {
  position: sticky; top: 0; z-index: 1;
  font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--text-tertiary); background: var(--surface-sunken);
  padding-top: var(--space-3); padding-bottom: var(--space-3);
}
.ds-table tbody td { background: var(--surface-sunken); transition: background calc(0.15s * var(--motion-scale)) ease; }
.ds-table tbody tr:hover td { background: color-mix(in srgb, var(--surface-sunken) 80%, var(--accent) 6%); }
.ds-table tbody td:first-child { border-top-left-radius: var(--radius-sm); border-bottom-left-radius: var(--radius-sm); }
.ds-table tbody td:last-child { border-top-right-radius: var(--radius-sm); border-bottom-right-radius: var(--radius-sm); }
.ds-table td.ds-table__cell--wrap { white-space: normal; }

@media (max-width: 680px) {
  .ds-table, .ds-table thead, .ds-table tbody, .ds-table th, .ds-table td, .ds-table tr { display: block; }
  .ds-table { min-width: 0; }
  .ds-table thead { display: none; }
  .ds-table tr { margin-bottom: var(--space-3); border: 1px solid var(--border-strong); border-radius: var(--radius-sm); overflow: hidden; }
  .ds-table td { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); text-align: right; white-space: normal; }
  .ds-table td[data-label]::before {
    content: attr(data-label); font-family: var(--font-mono); font-size: 10px;
    text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-tertiary); text-align: left;
  }
}

/* Resizable columns — opt-in via ds-table--resizable. Each resizable <th>
   gets a draggable handle on its trailing edge (js/design-system.js wires
   the drag); width is applied as an inline style, session-local only (no
   persistence — a per-view convenience, not a saved preference). */
.ds-table--resizable th { position: relative; overflow: hidden; }
.ds-table__resize-handle {
  position: absolute; top: 0; right: 0; bottom: 0; width: 6px; cursor: col-resize;
  touch-action: none;
}
.ds-table__resize-handle:hover, .ds-table__resize-handle.is-resizing { background: var(--accent-border); }
/* Column resizing is a mouse-hover drag interaction with no touch equivalent
   wired up (js/design-system.js only listens for mouse events) — hide the
   handle on touch-primary devices rather than leave a control that silently
   does nothing when tapped. */
@media (hover: none), (pointer: coarse) {
  .ds-table__resize-handle { display: none; }
}

/* Expandable rows — a toggle button reveals a full-width detail row beneath
   the summary row. Opt-in per table: add a leading <th>/<td> containing
   ds-table__expand-toggle, and a sibling <tr class="ds-table__expand-row"
   hidden> (colspan'd) holding the detail content. */
.ds-table__expand-toggle {
  background: none; border: none; cursor: pointer; color: var(--text-tertiary);
  padding: 4px; display: inline-flex; align-items: center; justify-content: center;
  transition: transform calc(0.15s * var(--motion-scale)) ease, color calc(0.15s * var(--motion-scale)) ease;
}
.ds-table__expand-toggle:hover { color: var(--text); }
.ds-table__expand-toggle.is-open { transform: rotate(90deg); color: var(--accent); }
.ds-table__expand-row { display: none; }
.ds-table__expand-row.is-open { display: table-row; }
.ds-table__expand-row td {
  background: var(--surface); border-top: none; padding: var(--space-2) var(--space-4) var(--space-4);
  white-space: normal; color: var(--text-secondary); font-size: var(--text-sm);
}
/* The mobile card-mode rule below (`.ds-table tr { display: block }`) has
   higher specificity than the bare `.ds-table__expand-row` rule above and
   would otherwise show every detail row unconditionally on a phone. Not
   needed there anyway — mobile card-mode already shows every field per row,
   so there's no clutter to hide behind a toggle in the first place. */
@media (max-width: 680px) {
  .ds-table__expand-toggle { display: none; }
  .ds-table__expand-row { display: block; }
}

/* ==========================================================================
   Toolbar
   ========================================================================== */

.ds-toolbar { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-4); }
.ds-toolbar__search { position: relative; flex: 1 1 240px; min-width: 0; }
.ds-toolbar__search .ds-input { padding-left: 36px; }
.ds-toolbar__search-icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--text-tertiary); pointer-events: none; }
.ds-toolbar__filters { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.ds-toolbar__filters .ds-select { width: auto; min-width: 140px; }

@media (max-width: 480px) { .ds-toolbar__search { flex-basis: 100%; } }

/* ==========================================================================
   Empty state
   ========================================================================== */

.ds-empty { text-align: center; padding: var(--space-8) var(--space-5); color: var(--text-tertiary); }
.ds-empty__icon { font-size: 32px; margin-bottom: var(--space-3); opacity: 0.55; }
.ds-empty__title { font-size: var(--text-sm); color: var(--text-secondary); margin-bottom: var(--space-2); }
.ds-empty__action { margin-top: var(--space-4); }
.ds-empty--framed { background: var(--surface-raised); border-radius: var(--radius-lg); border: 1px solid var(--border-strong); }

/* ==========================================================================
   Alert
   ========================================================================== */

.ds-alert {
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-4); border-radius: var(--radius-md); border: 1px solid transparent;
  font-size: var(--text-sm);
  animation: ds-alert-in calc(0.25s * var(--motion-scale)) ease-out;
}
@keyframes ds-alert-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }
.ds-alert--success { background: var(--success-soft); border-color: color-mix(in srgb, var(--success) 30%, transparent); color: var(--success); }
.ds-alert--danger  { background: var(--danger-soft);  border-color: color-mix(in srgb, var(--danger) 30%, transparent);  color: var(--danger); }
.ds-alert--warning { background: var(--warning-soft); border-color: color-mix(in srgb, var(--warning) 30%, transparent); color: var(--warning); }
.ds-alert--info    { background: var(--info-soft);    border-color: color-mix(in srgb, var(--info) 30%, transparent);    color: var(--info); }

/* ==========================================================================
   Toast notifications (v6.1) — transient, stacking, top-right. Unlike
   .ds-alert (inline, persistent, colored background) these are floating
   cards on the neutral surface with a colored left-border stripe + icon,
   matching the accent-stripe pattern already used for notification-center
   cards. See js/design-system.js's showToast() for the controller.
   ========================================================================== */

.ds-toast-container {
  position: fixed; top: var(--space-5); right: var(--space-5); z-index: 4000;
  display: flex; flex-direction: column; gap: var(--space-3);
  width: min(380px, calc(100vw - var(--space-8)));
  pointer-events: none;
}
.ds-toast {
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: var(--space-3);
  background: var(--surface-raised); border: 1px solid var(--border-strong); border-left: 3px solid currentColor;
  border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
  padding: var(--space-3) var(--space-4);
  position: relative; overflow: hidden;
  animation: ds-toast-in calc(0.25s * var(--motion-scale)) ease-out;
}
.ds-toast.is-leaving { animation: ds-toast-out calc(0.2s * var(--motion-scale)) ease-in forwards; }
@keyframes ds-toast-in { from { opacity: 0; transform: translateX(24px); } to { opacity: 1; transform: translateX(0); } }
@keyframes ds-toast-out { from { opacity: 1; transform: translateX(0); max-height: 200px; margin-top: 0; } to { opacity: 0; transform: translateX(24px); max-height: 0; margin-top: calc(-1 * var(--space-3)); } }
.ds-toast__icon { flex-shrink: 0; width: 18px; text-align: center; font-size: 15px; margin-top: 1px; }
.ds-toast__body { flex: 1; min-width: 0; font-size: var(--text-sm); color: var(--text); line-height: 1.45; }
.ds-toast__close { flex-shrink: 0; background: none; border: none; color: var(--text-tertiary); cursor: pointer; padding: 2px; font-size: 12px; line-height: 1; }
.ds-toast__close:hover { color: var(--text); }
.ds-toast__progress {
  position: absolute; left: 0; bottom: 0; height: 2px; background: currentColor; opacity: 0.35;
  animation: ds-toast-progress linear forwards; animation-play-state: running;
}
@keyframes ds-toast-progress { from { width: 100%; } to { width: 0%; } }

.ds-toast--success { color: var(--success); }
.ds-toast--danger  { color: var(--danger); }
.ds-toast--warning { color: var(--warning); }
.ds-toast--info    { color: var(--info); }
.ds-toast--success .ds-toast__body,
.ds-toast--danger  .ds-toast__body,
.ds-toast--warning .ds-toast__body,
.ds-toast--info    .ds-toast__body { color: var(--text); }

@media (max-width: 480px) {
  .ds-toast-container { left: var(--space-3); right: var(--space-3); top: var(--space-3); width: auto; }
}

/* ==========================================================================
   Modal
   ========================================================================== */

.ds-modal {
  display: none; position: fixed; inset: 0; z-index: 1000;
  background: rgba(15,15,18,0.5);
  align-items: center; justify-content: center; padding: var(--space-5);
}
.ds-modal.is-open { display: flex; }
.ds-modal__dialog {
  width: 100%; max-width: 520px; max-height: calc(100vh - 40px); overflow-y: auto;
  background: var(--surface-raised); border: 1px solid var(--border); border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
}
.ds-modal__header { display: flex; align-items: center; justify-content: space-between; padding: var(--space-5) var(--space-6); border-bottom: 1px solid var(--border); }
.ds-modal__title { font-family: var(--font-display); font-size: var(--text-lg); color: var(--text); }
.ds-modal__close { background: none; border: none; color: var(--text-tertiary); cursor: pointer; font-size: 1.2rem; line-height: 1; padding: var(--space-1); }
.ds-modal__close:hover { color: var(--text); }
.ds-modal__body { padding: var(--space-6); color: var(--text-secondary); }
.ds-modal__footer { padding: var(--space-4) var(--space-6); border-top: 1px solid var(--border-strong); display: flex; justify-content: flex-end; gap: var(--space-3); }

.ds-modal__dialog { animation: ds-modal-in calc(0.18s * var(--motion-scale)) ease-out; }
.ds-modal.is-closing .ds-modal__dialog { animation: ds-modal-out calc(0.15s * var(--motion-scale)) ease-in forwards; }
@keyframes ds-modal-in { from { opacity: 0; transform: translateY(8px) scale(0.98); } to { opacity: 1; transform: translateY(0) scale(1); } }
@keyframes ds-modal-out { from { opacity: 1; transform: translateY(0) scale(1); } to { opacity: 0; transform: translateY(8px) scale(0.98); } }

/* ==========================================================================
   Confirmation modal (v6.1) — one lazily-created instance reused for every
   confirmAction() call (see js/design-system.js), replacing native
   confirm() across the app. Built on the .ds-modal shell above, so it gets
   the same backdrop/Escape/focus-trap/entrance-exit animation for free.
   ========================================================================== */

.ds-confirm-modal__dialog { max-width: 440px; }
.ds-confirm-modal__icon {
  width: 48px; height: 48px; border-radius: 50%; margin: var(--space-6) auto 0;
  background: var(--danger-soft); color: var(--danger);
  display: flex; align-items: center; justify-content: center; font-size: 20px;
}
/* Default variant is danger (delete/remove actions). A non-destructive
   confirmation (e.g. "Activate this timetable?") passes { variant: 'primary' }
   to confirmAction() to swap both the icon and the OK button out of red. */
.ds-confirm-modal--primary .ds-confirm-modal__icon { background: var(--accent-soft); color: var(--accent); }
.ds-confirm-modal__dialog .ds-modal__header { border-bottom: none; justify-content: center; text-align: center; padding-top: var(--space-4); }
.ds-confirm-modal__dialog .ds-modal__body { text-align: center; padding-top: 0; }
.ds-confirm-modal__message { font-size: var(--text-sm); line-height: 1.6; }
.ds-confirm-modal__message strong { display: block; margin-top: var(--space-2); color: var(--text); font-family: var(--font-mono); font-size: var(--text-sm); }
.ds-confirm-modal__dialog .ds-modal__footer { justify-content: center; }

/* ==========================================================================
   Settings panel — theme / accent / radius / density / font-size / motion /
   sidebar personalization, inside a standard ds-modal (#dsSettingsModal).
   ========================================================================== */

.ds-settings-group { margin-bottom: var(--space-6); }
.ds-settings-group:last-child { margin-bottom: 0; }
.ds-settings-group__label {
  font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-tertiary);
  text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: var(--space-3); display: block;
}

.ds-theme-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: var(--space-3); }
.ds-theme-swatch {
  display: flex; flex-direction: column; align-items: center; gap: var(--space-2);
  padding: var(--space-3); border-radius: var(--radius-md);
  border: 1px solid var(--border-strong); background: var(--surface-sunken);
  cursor: pointer; font-family: var(--font-body); font-size: var(--text-xs); color: var(--text-secondary);
  transition: border-color calc(0.15s * var(--motion-scale)) ease, transform calc(0.15s * var(--motion-scale)) ease, box-shadow calc(0.15s * var(--motion-scale)) ease;
}
.ds-theme-swatch:hover { transform: translateY(-2px); box-shadow: var(--shadow-sm); }
.ds-theme-swatch.is-selected { border-color: var(--accent); color: var(--text); box-shadow: var(--shadow-glow-accent); }
.ds-theme-swatch__preview { width: 100%; height: 36px; border-radius: var(--radius-sm); display: flex; overflow: hidden; border: 1px solid var(--border); }
.ds-theme-swatch__preview span { flex: 1; }

.ds-option-pills { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.ds-option-pill {
  padding: 8px 16px; border-radius: var(--radius-pill); border: 1px solid var(--border-strong);
  background: var(--surface-sunken); color: var(--text-secondary); font-size: var(--text-sm); cursor: pointer;
  transition: border-color calc(0.15s * var(--motion-scale)), color calc(0.15s * var(--motion-scale)), background calc(0.15s * var(--motion-scale));
}
.ds-option-pill:hover { color: var(--text); }
.ds-option-pill.is-selected { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
/* On phones, a scrollable single-row tab strip reads more intentionally than
   letting 3-5 pills wrap onto a second/third line (used by the notification
   center's Inbox/Archived/All tabs and the Account page's tab bar, among
   others). */
@media (max-width: 480px) {
  .ds-option-pills { flex-wrap: nowrap; overflow-x: auto; padding-bottom: 2px; }
  .ds-option-pill { flex-shrink: 0; }
}

/* Custom accent picker — a handful of curated presets plus a native color
   input for anything else. Presets are just accent hex values rendered as
   filled circles; the native input covers the "anything else" case without
   custom color-wheel UI. */
.ds-accent-grid { display: flex; gap: var(--space-3); flex-wrap: wrap; align-items: center; }
.ds-accent-swatch {
  width: 32px; height: 32px; border-radius: 50%; border: 2px solid transparent;
  cursor: pointer; padding: 0; position: relative;
  transition: transform calc(0.15s * var(--motion-scale)) ease, border-color calc(0.15s * var(--motion-scale)) ease;
}
.ds-accent-swatch:hover { transform: scale(1.08); }
.ds-accent-swatch.is-selected { border-color: var(--text); }
.ds-accent-swatch.is-selected::after {
  content: ''; position: absolute; inset: 0; margin: auto; width: 8px; height: 8px;
  border-radius: 50%; background: #fff; mix-blend-mode: difference;
}
.ds-accent-custom-input {
  width: 32px; height: 32px; border-radius: 50%; border: 1px dashed var(--border-strong);
  cursor: pointer; padding: 0; background: none; overflow: hidden;
}
.ds-accent-custom-input::-webkit-color-swatch-wrapper { padding: 0; }
.ds-accent-custom-input::-webkit-color-swatch { border: none; border-radius: 50%; }

.ds-settings-trigger {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: var(--radius-sm);
  background: var(--surface-sunken); border: 1px solid var(--border-strong); color: var(--text);
  cursor: pointer; transition: border-color calc(0.15s * var(--motion-scale)), transform calc(0.4s * var(--motion-scale));
}
.ds-settings-trigger:hover { border-color: var(--accent); transform: rotate(30deg); }

/* ==========================================================================
   Bar chart / heatmap / timeline / progress — data visualization primitives
   ========================================================================== */

.ds-bar-chart { display: flex; flex-direction: column; gap: var(--space-3); }
.ds-bar-chart__row { display: flex; align-items: center; gap: var(--space-3); }
.ds-bar-chart__label { flex: 0 0 96px; font-size: var(--text-xs); color: var(--text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-bar-chart__track { flex: 1; height: 10px; border-radius: var(--radius-pill); background: var(--surface-sunken); overflow: hidden; }
.ds-bar-chart__bar { height: 100%; border-radius: var(--radius-pill); background: var(--accent-gradient); transition: width calc(0.4s * var(--motion-scale)) ease; }
.ds-bar-chart__value { flex: 0 0 auto; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-tertiary); min-width: 28px; text-align: right; }

.ds-heatmap { display: flex; gap: var(--space-2); }
.ds-heatmap__cell {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: var(--space-3) var(--space-2); border-radius: var(--radius-sm);
  background: var(--accent-soft); border: 1px solid var(--border);
}
.ds-heatmap__cell--today { border-color: var(--accent-border); }
.ds-heatmap__dow { font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; color: var(--text-tertiary); }
.ds-heatmap__value { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 600; color: var(--text); }

.ds-timeline { list-style: none; position: relative; }
.ds-timeline::before { content: ''; position: absolute; left: 15px; top: 8px; bottom: 8px; width: 1px; background: var(--border-strong); }
.ds-timeline__item { position: relative; display: flex; gap: var(--space-3); padding: var(--space-3) 0; }
.ds-timeline__dot {
  position: relative; z-index: 1; width: 32px; height: 32px; border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  background: var(--surface-raised); border: 1px solid var(--border-strong); color: var(--accent);
}
.ds-timeline__body { min-width: 0; padding-top: 4px; }
.ds-timeline__title { font-size: var(--text-sm); color: var(--text); }
.ds-timeline__meta { font-size: var(--text-xs); color: var(--text-tertiary); font-family: var(--font-mono); margin-top: 2px; }

.ds-progress { display: flex; align-items: center; gap: var(--space-3); }
.ds-progress__track { flex: 1; height: 8px; border-radius: var(--radius-pill); background: var(--surface-sunken); overflow: hidden; }
.ds-progress__bar { height: 100%; border-radius: var(--radius-pill); background: var(--accent-gradient); transition: width calc(0.4s * var(--motion-scale)) ease; }
.ds-progress--teacher .ds-progress__bar { background: var(--role-teacher); }
.ds-progress--exam .ds-progress__bar { background: var(--role-exam); }
.ds-progress__label { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-tertiary); flex-shrink: 0; min-width: 40px; text-align: right; }

/* Sparkline — tiny inline trend indicator (SVG polyline drawn by the
   caller; this just sizes/colors the wrapper). */
.ds-sparkline { display: inline-block; vertical-align: middle; color: var(--accent); }
.ds-sparkline svg { display: block; }

/* Progress ring (donut/circle) — for completion percentages, sized by
   caller via width/height on the SVG; stroke uses currentColor so a
   wrapping .ds-badge--* or inline color still themes it. */
.ds-ring { position: relative; display: inline-flex; align-items: center; justify-content: center; color: var(--accent); }
.ds-ring circle { transition: stroke-dashoffset calc(0.6s * var(--motion-scale)) ease; }
.ds-ring__value {
  position: absolute; font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 600; color: var(--text);
}

/* ==========================================================================
   Mini calendar
   ========================================================================== */

.ds-mini-cal__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-3); }
.ds-mini-cal__title { font-family: var(--font-display); font-size: var(--text-sm); color: var(--text); }
.ds-mini-cal__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; text-align: center; }
.ds-mini-cal__dow { font-family: var(--font-mono); font-size: 9px; color: var(--text-tertiary); text-transform: uppercase; padding-bottom: 4px; }
.ds-mini-cal__day { position: relative; aspect-ratio: 1; display: flex; align-items: center; justify-content: center; font-size: 11px; color: var(--text-secondary); border-radius: var(--radius-sm); }
.ds-mini-cal__day--today { background: var(--accent-soft); color: var(--accent); font-weight: 700; }
.ds-mini-cal__day--marked::after { content: ''; position: absolute; bottom: 3px; left: 50%; transform: translateX(-50%); width: 4px; height: 4px; border-radius: 50%; background: var(--role-exam); }
.ds-mini-cal__day--empty { visibility: hidden; }

/* ==========================================================================
   Full month calendar
   ========================================================================== */

.ds-calendar__header { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: var(--space-3); }
.ds-calendar__title { font-family: var(--font-display); font-size: var(--text-lg); color: var(--text); }
.ds-calendar__nav { display: flex; gap: var(--space-2); }

.ds-calendar__grid { display: grid; grid-template-columns: repeat(7, 1fr); }
.ds-calendar__dow {
  background: var(--surface-sunken); color: var(--text-tertiary); padding: var(--space-3) 5px; text-align: center;
  font-family: var(--font-mono); font-weight: 600; font-size: 10px; text-transform: uppercase;
  letter-spacing: 0.05em; border-bottom: 1px solid var(--border-strong);
}
.ds-calendar__day { min-height: 110px; border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); padding: var(--space-3); position: relative; background: var(--surface-raised); }
.ds-calendar__day:nth-child(7n) { border-right: none; }
.ds-calendar__day--empty { background: var(--surface); }
.ds-calendar__day-number { font-family: var(--font-mono); font-weight: 600; font-size: 12px; color: var(--text-tertiary); margin-bottom: var(--space-2); }
.ds-calendar__day--today .ds-calendar__day-number {
  background: var(--accent); color: var(--accent-contrast); width: 26px; height: 26px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
}

.ds-calendar__event {
  background: var(--accent-soft); border-left: 3px solid var(--accent); color: var(--text);
  padding: 6px 8px; border-radius: 6px; font-size: 10px; margin-bottom: 4px; cursor: pointer;
  transition: background calc(0.15s * var(--motion-scale)) ease;
}
.ds-calendar__event:hover { background: color-mix(in srgb, var(--accent-soft) 60%, var(--accent) 25%); }
.ds-calendar__event__time { font-weight: 600; color: var(--accent); font-size: 9px; font-family: var(--font-mono); }
.ds-calendar__event__title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 2px; }

.ds-calendar__date-badge {
  background: var(--accent-soft); border: 1px solid var(--accent-border); color: var(--accent);
  width: 56px; height: 56px; border-radius: var(--radius-md); display: flex; flex-direction: column;
  align-items: center; justify-content: center; flex-shrink: 0;
}
.ds-calendar__date-badge__day { font-size: 20px; font-weight: 700; font-family: var(--font-mono); line-height: 1; }
.ds-calendar__date-badge__month { font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em; font-family: var(--font-mono); margin-top: 2px; }

.ds-calendar--teacher .ds-calendar__day--today .ds-calendar__day-number { background: var(--role-teacher); color: #fff; }
.ds-calendar--teacher .ds-calendar__event { background: var(--role-teacher-soft); border-left-color: var(--role-teacher); }
.ds-calendar--teacher .ds-calendar__event:hover { background: color-mix(in srgb, var(--role-teacher-soft) 60%, var(--role-teacher) 25%); }
.ds-calendar--teacher .ds-calendar__event__time { color: var(--role-teacher); }
.ds-calendar--teacher .ds-calendar__date-badge { background: var(--role-teacher-soft); border-color: var(--role-teacher-border); color: var(--role-teacher); }

.ds-calendar--exam .ds-calendar__day--today .ds-calendar__day-number { background: var(--role-exam); color: #fff; }
.ds-calendar--exam .ds-calendar__event { background: var(--role-exam-soft); border-left-color: var(--role-exam); }
.ds-calendar--exam .ds-calendar__event:hover { background: color-mix(in srgb, var(--role-exam-soft) 60%, var(--role-exam) 25%); }
.ds-calendar--exam .ds-calendar__event__time { color: var(--role-exam); }
.ds-calendar--exam .ds-calendar__date-badge { background: var(--role-exam-soft); border-color: var(--role-exam-border); color: var(--role-exam); }

@media (max-width: 768px) { .ds-calendar__day { min-height: 80px; } .ds-calendar__event__title { display: none; } }

/* ==========================================================================
   Week/cycle grid — the flagship scheduling experience (v6.0 Phase 3).
   Columns = cycle days, rows = time slots. Distinct from ds-calendar above:
   this is for the repeating Day 1..Day N regular timetable (no real dates),
   not date-based exam scheduling. Lesson blocks are draggable; see
   js/design-system.js for the HTML5 drag-and-drop wiring.
   ========================================================================== */

.ds-week-grid {
  display: grid;
  grid-template-columns: 120px repeat(var(--ds-week-days, 5), 1fr);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--surface-raised);
}
.ds-week-grid__corner, .ds-week-grid__day-header {
  background: var(--surface-sunken); padding: var(--space-3); text-align: center;
  font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-tertiary); border-bottom: 1px solid var(--border-strong); border-right: 1px solid var(--border);
}
.ds-week-grid__slot-label {
  background: var(--surface-sunken); padding: var(--space-3); font-family: var(--font-mono); font-size: 11px;
  color: var(--text-tertiary); border-right: 1px solid var(--border-strong); border-bottom: 1px solid var(--border);
  display: flex; flex-direction: column; justify-content: center;
}
.ds-week-grid__cell {
  min-height: 76px; padding: var(--space-2); border-right: 1px solid var(--border); border-bottom: 1px solid var(--border);
  position: relative; transition: background calc(0.15s * var(--motion-scale)) ease;
}
.ds-week-grid__cell.is-dragover { background: var(--accent-soft); }
.ds-week-grid__cell.is-move-target { background: var(--accent-soft); box-shadow: inset 0 0 0 2px var(--accent); }
.ds-week-grid__cell--break { background: var(--surface-sunken); }

.ds-lesson-block {
  background: var(--accent-soft); border-left: 3px solid var(--accent); border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3); cursor: grab; -webkit-user-select: none; user-select: none;
  transition: box-shadow calc(0.15s * var(--motion-scale)) ease, transform calc(0.15s * var(--motion-scale)) ease, opacity calc(0.15s * var(--motion-scale)) ease;
}
.ds-lesson-block:hover { box-shadow: var(--shadow-sm); transform: translateY(-1px); }
.ds-lesson-block:active { cursor: grabbing; }
.ds-lesson-block.is-dragging { opacity: 0.4; }
.ds-lesson-block.is-selected-for-move { box-shadow: 0 0 0 2px var(--accent); }
.ds-lesson-block__subject { font-size: var(--text-sm); font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-lesson-block__teacher { font-size: 10px; color: var(--text-tertiary); margin-top: 2px; display: flex; align-items: center; gap: 4px; }
.ds-lesson-block__avatar {
  width: 16px; height: 16px; border-radius: 50%; background: var(--accent); color: var(--accent-contrast);
  display: inline-flex; align-items: center; justify-content: center; font-size: 8px; font-weight: 700; flex-shrink: 0;
}

/* Hover card — appears on lesson-block focus/hover with full detail;
   positioned by the caller's JS (a simple show/hide, no popover library). */
.ds-hover-card {
  position: absolute; z-index: 50; min-width: 220px;
  background: var(--surface-raised); border: 1px solid var(--border-strong); border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg); padding: var(--space-4);
  opacity: 0; pointer-events: none; transform: translateY(4px);
  transition: opacity calc(0.15s * var(--motion-scale)) ease, transform calc(0.15s * var(--motion-scale)) ease;
}
.ds-hover-card.is-visible { opacity: 1; pointer-events: auto; transform: translateY(0); }

@media (max-width: 900px) {
  .ds-week-grid { grid-template-columns: 90px repeat(var(--ds-week-days, 5), minmax(140px, 1fr)); overflow-x: auto; }
}

/* ==========================================================================
   Exam timetable grid — on-screen-only theming for the shared
   .exam-grid-table markup built by includes/exam_timetable_grid.php.
   That table carries fixed light inline styles on purpose (captured
   verbatim into a separate print window) — these rules use !important to
   win over plain inline styles for on-screen display only.
   ========================================================================== */

#exam-timetable-view h2 { color: var(--text) !important; }
#exam-timetable-view .info { color: var(--text-tertiary) !important; }
.exam-grid-table { border-color: var(--border-strong) !important; }
.exam-grid-table th, .exam-grid-table td { border-color: var(--border) !important; }
.exam-grid-table thead th { background-color: var(--surface-sunken) !important; }
.exam-grid-table tbody th { background-color: var(--surface-sunken) !important; color: var(--text) !important; }
.exam-grid-table tbody td { background-color: var(--surface-raised) !important; }
.exam-grid-table tbody td strong { color: var(--text) !important; }

/* ==========================================================================
   Loading overlay
   ========================================================================== */

.ds-loading-overlay {
  display: none; position: fixed; inset: 0; z-index: 3000;
  background: rgba(15,15,18,0.6);
  align-items: center; justify-content: center;
}
.ds-loading-overlay.is-open { display: flex; }
.ds-loading-overlay__content {
  background: var(--surface-raised); border: 1px solid var(--border); border-radius: var(--radius-xl);
  padding: var(--space-8); text-align: center; box-shadow: var(--shadow-lg);
}
.ds-loading-overlay__title { font-family: var(--font-display); color: var(--accent); margin-top: var(--space-4); font-size: var(--text-lg); }
.ds-loading-overlay__sub { color: var(--text-tertiary); font-size: var(--text-xs); margin-top: var(--space-2); }
.ds-spinner {
  width: 44px; height: 44px; margin: 0 auto;
  border: 3px solid var(--border-strong); border-top-color: var(--accent); border-radius: 50%;
  animation: ds-spin calc(0.8s / max(var(--motion-scale), 0.34)) linear infinite;
}
@keyframes ds-spin { to { transform: rotate(360deg); } }

/* ==========================================================================
   Command palette
   ========================================================================== */

.ds-cmdk-trigger {
  display: flex; align-items: center; gap: var(--space-2);
  padding: 8px 14px; border-radius: var(--radius-pill);
  border: 1px solid var(--border-strong); background: var(--surface-sunken);
  color: var(--text-tertiary); font-size: var(--text-sm); cursor: pointer;
  transition: border-color calc(0.15s * var(--motion-scale)) ease, color calc(0.15s * var(--motion-scale)) ease;
}
.ds-cmdk-trigger:hover { color: var(--text); border-color: var(--accent); }
.ds-cmdk-trigger kbd {
  font-family: var(--font-mono); font-size: 10px; padding: 2px 6px; border-radius: 4px;
  background: var(--surface-raised); color: var(--text-tertiary); border: 1px solid var(--border-strong);
}
@media (max-width: 768px) { .ds-cmdk-trigger span:not(.ds-cmdk-trigger__icon) { display: none; } }

.ds-cmdk {
  display: none; position: fixed; inset: 0; z-index: 2000;
  background: rgba(15,15,18,0.5);
  align-items: flex-start; justify-content: center; padding: 12vh var(--space-5) var(--space-5);
}
.ds-cmdk.is-open { display: flex; }
.ds-cmdk__dialog {
  width: 100%; max-width: 560px; max-height: 60vh; display: flex; flex-direction: column;
  background: var(--surface-raised); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); overflow: hidden;
  animation: ds-modal-in calc(0.16s * var(--motion-scale)) ease-out;
}
.ds-cmdk__input-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--border); }
.ds-cmdk__input-row svg { color: var(--text-tertiary); flex-shrink: 0; }
.ds-cmdk__input { flex: 1; background: none; border: none; outline: none; color: var(--text); font-family: var(--font-body); font-size: var(--text-base); }
.ds-cmdk__input::placeholder { color: var(--text-tertiary); }
.ds-cmdk__results { overflow-y: auto; padding: var(--space-2); }
.ds-cmdk__row { display: flex; align-items: center; border-radius: var(--radius-sm); }
.ds-cmdk__row.is-highlighted { background: var(--accent-soft); }
.ds-cmdk__row.is-highlighted .ds-cmdk__item { color: var(--accent); }
.ds-cmdk__item { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3); color: var(--text-secondary); text-decoration: none; font-size: var(--text-sm); cursor: pointer; }
.ds-cmdk__item-icon { width: 20px; text-align: center; flex-shrink: 0; color: var(--text-tertiary); }
.ds-cmdk__row.is-highlighted .ds-cmdk__item-icon { color: var(--accent); }
.ds-cmdk__empty { padding: var(--space-6) var(--space-5); text-align: center; color: var(--text-tertiary); font-size: var(--text-sm); }

/* ==========================================================================
   Breadcrumb
   ========================================================================== */

.ds-breadcrumb { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; padding: var(--space-3) var(--space-8) 0; font-size: var(--text-xs); color: var(--text-tertiary); font-family: var(--font-mono); }
.ds-breadcrumb a { color: var(--text-tertiary); text-decoration: none; transition: color calc(0.15s * var(--motion-scale)) ease; }
.ds-breadcrumb a:hover { color: var(--text); }
.ds-breadcrumb__current { color: var(--text-secondary); }
.ds-breadcrumb__sep { opacity: 0.5; }
@media (max-width: 768px) { .ds-breadcrumb { padding: var(--space-3) var(--space-5) 0; } }

/* ==========================================================================
   Page layout — ds-page > ds-shell (sidebar+main row) > ds-main
   ========================================================================== */

.ds-container { max-width: 1440px; margin: 0 auto; }

.ds-page {
  display: flex; flex-direction: column; min-height: 100vh; width: 100%;
  background-color: var(--surface); color: var(--text); font-family: var(--font-body); overflow-x: hidden;
}

.ds-shell { display: flex; flex: 1; min-width: 0; }
.ds-main { flex: 1; min-width: 0; padding: var(--space-6) var(--space-8); overflow-x: auto; }

.ds-section { margin-bottom: var(--space-6); }
.ds-section:last-child { margin-bottom: 0; }
.ds-section__title { font-family: var(--font-display); font-size: var(--text-lg); color: var(--text); margin-bottom: var(--space-4); }

@media (max-width: 900px) { .ds-shell { flex-direction: column; } .ds-main { padding: var(--space-5); } }

/* ==========================================================================
   Hero band
   ========================================================================== */

.ds-hero { padding: var(--space-8) var(--space-8) var(--space-5); border-bottom: 1px solid var(--border); }
.ds-hero__eyebrow { font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-tertiary); margin-bottom: var(--space-3); }
.ds-hero__title { font-family: var(--font-display); font-size: var(--text-xl); line-height: 1.1; letter-spacing: -0.02em; color: var(--text); }
.ds-hero__title em { font-style: italic; color: var(--accent); }
.ds-hero__title--teacher em { color: var(--role-teacher); }
.ds-hero__title--exam em { color: var(--role-exam); }
.ds-hero__sub { margin-top: var(--space-3); font-size: var(--text-base); color: var(--text-secondary); font-weight: 400; line-height: 1.65; }

@media (max-width: 768px) { .ds-hero { padding: var(--space-6) var(--space-5) var(--space-4); } }

/* ==========================================================================
   Footer
   ========================================================================== */

.ds-footer { border-top: 1px solid var(--border); padding: var(--space-4) var(--space-8); display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-3); background: var(--surface); }
.ds-footer__copy { font-size: var(--text-xs); color: var(--text-tertiary); font-family: var(--font-mono); }
.ds-footer__links { display: flex; gap: var(--space-5); flex-wrap: wrap; }
.ds-footer__links a { font-size: var(--text-xs); color: var(--text-tertiary); text-decoration: none; transition: color calc(0.18s * var(--motion-scale)); }
.ds-footer__links a:hover { color: var(--text); }

@media (max-width: 680px) { .ds-footer { flex-direction: column; text-align: center; padding: var(--space-4) var(--space-5); } }

/* ==========================================================================
   Dropdown
   ========================================================================== */

.ds-dropdown { position: relative; }
.ds-dropdown-menu {
  position: absolute; top: 100%; right: 0;
  background: var(--surface-raised); border: 1px solid var(--border); border-radius: var(--radius-md);
  box-shadow: var(--shadow-md); min-width: 200px; margin-top: var(--space-2);
  display: none; z-index: 1000; overflow: hidden; transform-origin: top right;
}
.ds-dropdown-menu.is-open { display: block; animation: ds-dropdown-in calc(0.16s * var(--motion-scale)) ease-out; }
@keyframes ds-dropdown-in { from { opacity: 0; transform: scale(0.96) translateY(-4px); } to { opacity: 1; transform: scale(1) translateY(0); } }
.ds-dropdown-menu a { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-3) var(--space-4); color: var(--text-secondary); text-decoration: none; font-size: var(--text-sm); transition: background calc(0.2s * var(--motion-scale)), color calc(0.2s * var(--motion-scale)); }
.ds-dropdown-menu a:hover { background: var(--surface-sunken); color: var(--text); }
.ds-dropdown-divider { height: 1px; background: var(--border-strong); margin: var(--space-2) 0; }

/* ==========================================================================
   Activity list / quick actions
   ========================================================================== */

.ds-activity { list-style: none; }
.ds-activity__item { display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
.ds-activity__item:last-child { border-bottom: none; }
.ds-activity__icon { width: 32px; height: 32px; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; flex-shrink: 0; background: var(--accent-soft); color: var(--accent); }
.ds-activity__body { min-width: 0; }
.ds-activity__title { font-size: var(--text-sm); color: var(--text); }
.ds-activity__meta { font-size: var(--text-xs); color: var(--text-tertiary); font-family: var(--font-mono); margin-top: 2px; }

.ds-quick-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--space-4); }
.ds-quick-action {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2);
  padding: var(--space-5); background: var(--surface-raised); border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg); text-decoration: none; color: var(--text); box-shadow: var(--shadow-sm);
  transition: transform calc(0.2s * var(--motion-scale)) ease, border-color calc(0.2s * var(--motion-scale)) ease, box-shadow calc(0.2s * var(--motion-scale)) ease;
}
.ds-quick-action:hover { transform: translateY(-3px); border-color: var(--accent-border); box-shadow: var(--shadow-glow-accent); }
.ds-quick-action__icon { width: 36px; height: 36px; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; background: var(--accent-soft); color: var(--accent); }
.ds-quick-action__label { font-size: var(--text-sm); font-weight: 600; }
.ds-quick-action__desc { font-size: var(--text-xs); color: var(--text-tertiary); }

/* ==========================================================================
   Generic responsive grid / key-value list
   ========================================================================== */

.ds-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--space-4); }
.ds-grid--2up { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

.ds-kv-row { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
.ds-kv-row:last-child { border-bottom: none; }
.ds-kv-label { font-family: var(--font-mono); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-tertiary); }
.ds-kv-value { font-size: var(--text-sm); color: var(--text); text-align: right; }

@media (max-width: 480px) {
  .ds-kv-row { flex-direction: column; align-items: flex-start; gap: 4px; }
  .ds-kv-value { text-align: left; }
}
