/**
 * Roddier App — Design System
 * Inspired by Apple HIG (macOS Sequoia / iOS 18): monochrome white/black,
 * hierarchical surfaces, labels with graduated opacities, system colors for statuses.
 *
 * Structure:
 *   1. Semantic tokens (--bg-*, --label-*, --fill-*, --separator, --tint)
 *   2. System colors (red, green, etc. Apple values)
 *   3. Radii + shadows
 *   4. Legacy aliases (--navy, --paper, etc.) mapped to tokens
 *
 * In dark mode, only the tokens in the [data-theme="dark"] block change;
 * all downstream components follow automatically.
 */

:root {
  color-scheme: light;

  /* ─── Unified page gutter: main, nav, footer and radio player all share
     the same value. Redefined at >=1024px in app-theme.css. ─── */
  --page-gutter: clamp(1rem, 3vw, 2.5rem);

  /* ─── 1. Backgrounds (Apple iOS grouped - gray page, white cards that pop) ─── */
  --bg-primary:   #f2f2f7;            /* page : systemGroupedBackground */
  --bg-secondary: #ffffff;            /* cards : secondarySystemGroupedBackground */
  --bg-tertiary:  #f2f2f7;            /* sub-elements inside card / inputs */
  --bg-elevated:  #ffffff;            /* modals, sheets, popovers */

  /* ─── 2. Fills (translucent interactive backgrounds, like systemFill) ─── */
  --fill-primary:    rgba(0,0,0,0.05);
  --fill-secondary:  rgba(0,0,0,0.04);
  --fill-tertiary:   rgba(0,0,0,0.03);
  --fill-quaternary: rgba(0,0,0,0.02);

  /* ─── 3. Labels (text in 4 opacity levels — Apple labelColor) ─── */
  --label-primary:    #000000;
  --label-secondary:  rgba(60,60,67,0.78);  /* a11y: 0.60 failed WCAG AA (3.4:1) → 0.78 ≈ 4.9:1 on white and #f2f2f7 */
  --label-tertiary:   rgba(60,60,67,0.30);
  --label-quaternary: rgba(60,60,67,0.18);

  /* ─── 4. Separators (fines hairlines Apple) ─── */
  --separator:        rgba(60,60,67,0.29);
  --separator-opaque: #c6c6c8;

  /* ─── 5. Tint (accent — brand navy, colorful app) ─── */
  --tint:           #0f2544;
  --tint-secondary: #16335a;

  /* ─── 6. System colors (statuses — official iOS/macOS light values) ────── */
  --system-red:    #ff3b30;
  --system-orange: #ff9500;
  --system-yellow: #ffcc00;
  --system-green:  #34c759;
  --system-blue:   #007aff;
  --system-indigo: #5856d6;
  --system-purple: #af52de;
  --system-pink:   #ff2d55;
  --system-teal:   #5ac8fa;
  --system-gray:   #8e8e93;

  /* ─── 7. Radii Apple ─── */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-xl: 18px;

  /* ─── 8. Shadows (subtle, never heavy — Apple dislikes aggressive drop shadows) ─── */
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.04);
  --shadow-md: 0 4px 16px rgba(0,0,0,0.08);
  --shadow-lg: 0 12px 32px rgba(0,0,0,0.12);
  --shadow-xl: 0 24px 60px rgba(0,0,0,0.16);

  /* ─── 9. Legacy aliases (do not remove — ~200 downstream selectors use them) ─── */
  --navy:    var(--label-primary);
  --navy2:   #1a1a1a;
  /* BRAND navy for BACKGROUNDS/borders (light text on top) — stable, does not
     follow the theme like --navy (which is used as a contrasting text color). */
  --brand-navy:  #0f2544;
  --brand-navy2: #16335a;
  --text:    var(--label-primary);
  /* Historical aliases: per-screen stylesheets and Code module views
     use --text-primary / --text-secondary, which were never defined.
     Without them, text kept its navy fallback and became unreadable in dark mode. */
  --text-primary:   var(--label-primary);
  --text-secondary: var(--label-secondary);
  --cream:   var(--bg-primary);        /* body = page grise Apple */
  --cream-2: var(--bg-tertiary);
  --paper:   var(--bg-secondary);       /* cards = white that pops against the page */
  --off:     var(--bg-tertiary);        /* sub-elements = soft grey */
  --white:   var(--bg-secondary);       /* alias card blanc */
  --accent:    var(--tint);
  --accent-l:  var(--fill-primary);
  --accent-2:  var(--tint-secondary);
  --accent-2-l: var(--fill-secondary);
  --blue:    var(--tint);
  --blue-l:  var(--fill-primary);
  --blue-ll: var(--fill-tertiary);
  --slate:   var(--label-secondary);
  --slate-l: var(--label-tertiary);
  --border:  var(--separator);
  --border2: var(--separator-opaque);

  /* Statuses mapped to system colors */
  --orange:   var(--system-orange);
  --orange-l: rgba(255,149,0,0.10);
  --green:    var(--system-green);
  --green-l:  rgba(52,199,89,0.10);
  --purple:   var(--system-purple);
  --purple-l: rgba(175,82,222,0.10);
  --pink:     var(--system-pink);
  --pink-l:   rgba(255,45,85,0.10);
  --cyan:     var(--system-teal);
  --cyan-l:   rgba(90,200,250,0.12);
  --amber:    var(--system-orange);
  --amber-l:  rgba(255,149,0,0.10);

  /* ─── Expanded palette 2026-05-26 (subtle premium — use sparingly) ───
     No bright colors on base surfaces: use fills to
     subtly tint KPIs, callouts, or categories. */
  --accent-3:    #6366f1;                  /* soft indigo: info / premium category */
  --accent-3-l:  rgba(99,102,241,0.08);
  --accent-4:    #14b8a6;                  /* refined teal: data / stats */
  --accent-4-l:  rgba(20,184,166,0.08);
  --paper-warm:  #fafaf7;                  /* calmed card background (~ cream-paper) */

  /* ─── Apple System Colors — thematic color by section (2026-05-26) ───
     Inspired by iOS Settings: each major section has its own icon color.
     Medium vividness (saturated but not fluorescent). Remains readable: white
     text on a saturated background, navy text on a soft background. */
  --sys-blue:    #0a84ff;                  /* Dashboard */
  --sys-indigo:  #5e5ce6;                  /* Planning */
  --sys-purple:  #bf5af2;                  /* Statistics */
  --sys-pink:    #ff375f;                  /* Communication / notifications */
  --sys-red:     #ff453a;                  /* Exams / urgent */
  --sys-orange:  #ff9f0a;                  /* Vehicles */
  --sys-yellow:  #ffd60a;                  /* Admin app */
  --sys-green:   #30d158;                  /* Students / training */
  --sys-mint:    #66d4cf;                  /* GDPR / security */
  --sys-teal:    #40c8e0;                  /* Accounting */
  --sys-cyan:    #64d2ff;                  /* Documents */
  --sys-gray:    #8e8e93;                  /* Settings */
  --sys-brown:   #ac8e68;                  /* Archives */

  /* Soft versions for tinted backgrounds (8-10 % opacity in light) */
  --sys-blue-soft:    rgba(10,132,255,0.10);
  --sys-indigo-soft:  rgba(94,92,230,0.10);
  --sys-purple-soft:  rgba(191,90,242,0.10);
  --sys-pink-soft:    rgba(255,55,95,0.10);
  --sys-red-soft:     rgba(255,69,58,0.10);
  --sys-orange-soft:  rgba(255,159,10,0.10);
  --sys-yellow-soft:  rgba(255,214,10,0.14);
  --sys-green-soft:   rgba(48,209,88,0.10);
  --sys-mint-soft:    rgba(102,212,207,0.12);
  --sys-teal-soft:    rgba(64,200,224,0.12);
  --sys-cyan-soft:    rgba(100,210,255,0.12);
  --sys-gray-soft:    rgba(142,142,147,0.12);
  --sys-brown-soft:   rgba(172,142,104,0.12);

  /* Apple-like easing - natural curves for micro-animations */
  --ease-out-smooth: cubic-bezier(0.32, 0.72, 0, 1);     /* iOS sheet present */
  --ease-spring:     cubic-bezier(0.22, 1, 0.36, 1);     /* hover lift naturel */

  /* Focus ring signature (instead of the browser outline) */
  --ring-focus:  0 0 0 3px rgba(94,127,168,0.18);        /* desaturated blue halo */

  /* Layered Apple-style shadows - depth without heaviness */
  --shadow-soft:    0 1px 3px rgba(0,0,0,0.06), 0 4px 12px rgba(0,0,0,0.04);
  --shadow-raised:  0 2px 6px rgba(0,0,0,0.06), 0 12px 28px rgba(0,0,0,0.08);
  --shadow-overlay: 0 8px 24px rgba(0,0,0,0.10), 0 24px 60px rgba(0,0,0,0.14);

  /* ════════════════════════════════════════════════════════════════════
     FOUNDATION KIT (2026-06-18) — tokens shared by the “UI kit”
     (public/css/ui-kit.css, sheet.css). Override NOTHING above: these are
     ADDITIONS. Dark equivalents are in the [data-theme="dark"] block.
     ──────────────────────────────────────────────────────────────────── */

  /* ─── Motion — standardized curves + durations (micro-interactions) ─── */
  --ease:        cubic-bezier(0.22, 0.61, 0.36, 1);   /* soft ease-out, default */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);   /* slight bounce (entries) */
  --dur-fast: 0.15s;
  --dur:      0.25s;
  --dur-slow: 0.40s;

  /* ─── COOL shadows, 3 layers (navy shade #0f2544, never pure black) ───
     Apple-like depth without heaviness. Complement the historical --shadow-sm/md/lg
     (which remain black); these navy variants are preferred for the kit. */
  --shadow-sm: 0 1px 2px rgba(15,37,68,0.06), 0 1px 1px rgba(15,37,68,0.04);
  --shadow-md: 0 1px 2px rgba(15,37,68,0.06), 0 4px 14px rgba(15,37,68,0.08);
  --shadow-lg: 0 4px 14px rgba(15,37,68,0.08), 0 14px 36px rgba(15,37,68,0.12);

  /* ─── Concentric radii ───────────────────────────────────────────────
     “Concentric corners” convention: a child inset by N px from
     a parent with radius R must have radius (R − N) so the curves
     remain parallel. Scale: sm 6 → md 10 → lg 14 → xl 18 (existing),
     + pill = full capsule. */
  --r-pill: 100px;

  /* ─── Desaturated radial halo (“blue light” guidelines: #5e7fa8) ─── */
  --halo-color: rgba(94, 127, 168, 0.20);

  /* ─── Kit glass (bottom sheet / Dynamic Island toast) ─── */
  --glass-bg:     rgba(255, 255, 255, 0.72);
  --glass-border: rgba(255, 255, 255, 0.55);
  --scrim:        rgba(15, 37, 68, 0.32);   /* darkened backdrop under a sheet */
  --island-bg:    rgba(20, 22, 28, 0.92);   /* floating dark pill (toast) */
  --island-fg:    #f5f5f7;
}

/* Base — body in pure white (day) / pure black (night).
   Solid background, no gradient or colored glow (minimalist philosophy 2026-05-25). */
body.app-body {
  background: var(--cream);
  min-height: 100vh;    /* fallback for browsers without dvh */
  min-height: 100dvh;   /* dynamic height: follows the browser bar appearing and collapsing
                           (iOS Safari/Firefox) -> the bottom of the app always fills the
                           screen, no empty band and no jump when the URL bar shrinks
                           to a pill. */
  font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'SF Pro Display', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  color: var(--text);
  margin: 0;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* ─── Auth pages (login) ───────────────────────────────────────── */
.app-auth {
  min-height: calc(100vh - 80px);
  min-height: calc(100dvh - 80px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1rem;
}
.app-auth-card {
  width: 100%;
  max-width: 440px;
  background: var(--paper);
  border-radius: 18px;
  padding: clamp(1.5rem, 5vw, 2.75rem);
  box-shadow: var(--shadow-xl);
  border: 1px solid var(--border);
  position: relative;
  overflow: hidden;
}
.app-auth-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--brand-navy), var(--accent-2), var(--accent));
}
.app-logo {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  text-decoration: none;
  margin-bottom: 1.5rem;
}
.app-logo-title {
  font-size: 1.15rem;
  font-weight: 800;
  color: var(--navy);
  line-height: 1.1;
  letter-spacing: -0.01em;
}
.app-logo-sub {
  font-size: 0.78rem;
  color: var(--slate);
  font-weight: 500;
}
.app-auth-title {
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--navy);
  margin: 0 0 0.4rem;
  letter-spacing: -0.02em;
}
.app-auth-lead {
  font-size: 0.88rem;
  color: var(--slate);
  margin: 0 0 1.5rem;
  line-height: 1.55;
}
.app-auth-help {
  font-size: 0.82rem;
  color: var(--slate);
  margin-top: 1.5rem;
  text-align: center;
  line-height: 1.6;
}
.app-auth-help a { color: var(--blue); text-decoration: none; font-weight: 600; }
.app-auth-help a:hover { text-decoration: underline; }

/* ─── Form (Apple HIG global) ───────────────────────────────────────
   All .app-form forms automatically inherit the modern look.
   For card sections, add class .form-fancy + .form-section
   (see dedicated block at the bottom of the file).
   ────────────────────────────────────────────────────────────────── */
.app-form { display: flex; flex-direction: column; gap: 1rem; }
.app-form-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
.app-field { display: flex; flex-direction: column; gap: 0.4rem; }
.app-field-full { grid-column: 1 / -1; }
/* 2-column form grid: a field alone on the last row takes the full
   width (removes the half-card field with a large empty space on the right). */
.app-form-grid > .app-field:nth-child(odd):last-child { grid-column: 1 / -1; }
.app-label {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--label-primary);
  letter-spacing: 0;
}
.app-form input[type="text"],
.app-form input[type="email"],
.app-form input[type="password"],
.app-form input[type="tel"],
.app-form input[type="date"],
.app-form input[type="month"],
.app-form input[type="week"],
.app-form input[type="time"],
.app-form input[type="number"],
.app-form input[type="search"],
.app-form input[type="url"],
.app-form select,
.app-filters select,
.app-form textarea {
  font-family: inherit;
  font-size: 0.95rem;
  padding: 0.75rem 0.9rem;
  border: 1.5px solid var(--separator);
  border-radius: 10px;
  background: var(--bg-secondary);
  color: var(--label-primary);
  transition: border-color 0.15s ease, box-shadow 0.18s ease, background 0.15s ease;
  width: 100%;
  box-sizing: border-box;
}
.app-form input:hover:not(:focus),
.app-form select:hover:not(:focus),
.app-filters select:hover:not(:focus),
.app-form textarea:hover:not(:focus) {
  border-color: var(--separator-opaque);
}
.app-form input:focus,
.app-form select:focus,
.app-filters select:focus,
.app-form textarea:focus {
  outline: none;
  border-color: var(--tint);
  box-shadow: 0 0 0 4px var(--fill-primary);
  background-color: var(--bg-elevated);
}
.app-form textarea { resize: vertical; min-height: 90px; line-height: 1.5; }
.app-form select,
.app-filters select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  padding-right: 2.5rem;
}
.app-form-actions {
  display: flex;
  gap: 0.7rem;
  grid-column: 1 / -1;
  justify-content: flex-end;
  margin-top: 0.5rem;
}
/* Apple-style Checkbox / Radio: `accent-color` instead of the browser default */
.app-form input[type="checkbox"],
.app-form input[type="radio"] {
  accent-color: var(--tint);
  width: 18px;
  height: 18px;
  cursor: pointer;
}

/* ─── Boutons ───────────────────────────────────────────────────── */
.app-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.65rem 1.1rem;
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  border-radius: 10px;
  cursor: pointer;
  text-decoration: none;
  background: var(--paper);
  color: var(--navy);
  border: 1.5px solid var(--border);
  transition: all 0.15s ease;
  letter-spacing: 0.01em;
}
.app-btn:hover {
  background: var(--off);
  border-color: var(--border2);
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}
.app-btn-sm { padding: 0.45rem 0.85rem; font-size: 0.82rem; }

.app-btn-primary {
  background: var(--tint);
  color: var(--bg-primary) !important;
  border: 1.5px solid var(--tint);
}
.app-btn-primary:hover {
  background: var(--tint-secondary);
  border-color: var(--tint-secondary);
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}
.app-btn-outline { background: transparent; color: var(--label-primary); border: 1.5px solid var(--separator-opaque); }
.app-btn-outline:hover { border-color: var(--tint); color: var(--tint); background: var(--fill-tertiary); }
.app-btn-ghost {
  background: var(--off);
  color: var(--slate);
  border: 1px solid var(--border);
  padding: 0.55rem 0.85rem;
  border-radius: 8px;
  font-size: 0.82rem;
  font-weight: 500;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.app-btn-ghost:hover { background: var(--white); color: var(--navy); border-color: var(--border2); }
.app-btn-ghost-link {
  background: none;
  border: none;
  color: var(--blue);
  font-weight: 600;
  font-size: 0.85rem;
  padding: 0.4rem 0;
  cursor: pointer;
  text-decoration: none;
  text-align: left;
}
.app-btn-ghost-link:hover { text-decoration: underline; }

/* ─── Alerts ────────────────────────────────────────────────────── */
.app-alert {
  padding: 0.85rem 1.1rem;
  border-radius: 10px;
  font-size: 0.88rem;
  margin-bottom: 1rem;
  border-left: 3px solid;
}
.app-alert-error { background: #fef2f2; color: #991b1b; border-color: #dc2626; }
.app-alert-info  { background: var(--blue-ll); color: var(--navy); border-color: var(--blue); }
/* Success alert: it was missing, so views improvised hardcoded colors
   (light island in the dark theme). The tokens below change with the theme on their own. */
.app-alert-success { background: var(--green-l); color: var(--navy); border-color: var(--system-green); }

/* ─── Nav top bar premium : sticky + backdrop-blur (luxury saas) ───── */
.app-nav {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(255, 255, 255, 0.72);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--separator);
}
:root[data-theme="dark"] .app-nav {
  background: rgba(28, 28, 30, 0.72);
}
.app-nav-admin {
  background: linear-gradient(135deg, var(--navy), var(--navy2));
  color: #fff;
  border-bottom-color: transparent;
}
.app-nav-inner {
  max-width: none;
  margin: 0;
  padding: 0.85rem var(--page-gutter);
  display: flex;
  align-items: center;
  gap: 1.5rem;
}
.app-nav-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  font-weight: 800;
  font-size: 1rem;
  color: var(--navy);
  letter-spacing: -0.01em;
  flex-shrink: 0;
}
.app-nav-admin .app-nav-brand { color: #fff; }
.app-nav-admin .app-nav-brand small { color: var(--blue-l); font-weight: 400; }
.app-nav-links {
  display: flex;
  gap: 0.4rem;
  flex: 1;
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  min-width: 0;
}
.app-nav-links::-webkit-scrollbar { display: none; }
.app-nav-links a {
  padding: 0.5rem 0.85rem;
  border-radius: 8px;
  text-decoration: none;
  color: var(--label-secondary);
  font-size: 0.85rem;
  font-weight: 500;
  transition: background 0.15s, color 0.15s;
  white-space: nowrap;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
}
.app-nav-admin .app-nav-links a { color: rgba(255,255,255,0.7); }
.app-nav-links a:hover { background: var(--fill-quaternary); color: var(--label-primary); }
.app-nav-admin .app-nav-links a:hover { background: rgba(255,255,255,0.08); color: #fff; }
.app-nav-links a.active { background: var(--fill-primary); color: var(--label-primary); font-weight: 600; }
.app-nav-admin .app-nav-links a.active { background: rgba(255,255,255,0.12); color: #fff; }
/* Compact mode: added by JS (`initNavFit`) when links overflow their space
   → navigation with icons only (the label remains available via tooltip + screen readers).
   Ensures no item is clipped, regardless of the number of items / the role.

   ANTI-FLASH (FOUC) — selector :not(.nav-ready): until fitNav (nav-hamburger.js)
   has measured and set .nav-ready, ONLY the icons are shown. Otherwise labels
   paint at full size on the first frame, then disappear when .nav-compact
   is chosen → “text appearing/disappearing” flicker, especially visible on
   Safari (the synchronous primer measures poorly during parsing). With this guard, the
   labels appear only AFTER measurement (so never incorrectly), in full bar mode
   only. Independent of JS timing, unlike the primer. */
.app-nav-inner.nav-compact .app-nav-links a,
.app-nav:not(.nav-ready) .app-nav-inner .app-nav-links a { font-size: 0; padding: 0.5rem 0.55rem; gap: 0; }
.app-nav-inner.nav-compact .app-nav-links a .nav-icon,
.app-nav:not(.nav-ready) .app-nav-inner .app-nav-links a .nav-icon { margin-right: 0; }
.app-nav-inner.nav-compact .app-nav-switcher-label,
.app-nav:not(.nav-ready) .app-nav-switcher-label { display: none; }
.app-nav-user {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}
.app-nav-icon-btn {
  width: 38px;
  height: 38px;
  border-radius: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: rgba(255,255,255,0.7);
  text-decoration: none;
  transition: background 0.15s, color 0.15s;
}
.app-nav-admin .app-nav-icon-btn { color: rgba(255,255,255,0.7); }
.app-nav-admin .app-nav-icon-btn:hover { background: rgba(255,255,255,0.08); color: #fff; }
.app-nav-admin .app-nav-icon-btn.active { background: rgba(255,255,255,0.15); color: #fff; }
/* Non-admin variant (normal white nav) */
.app-nav:not(.app-nav-admin) .app-nav-icon-btn { color: #5e7fa8; }
.app-nav:not(.app-nav-admin) .app-nav-icon-btn:hover { background: var(--off); color: var(--tint); }
.app-nav-user-info { text-align: right; }
.app-nav-user-name { font-size: 0.85rem; font-weight: 700; color: var(--navy); line-height: 1.2; }
.app-nav-admin .app-nav-user-name { color: #fff; }
.app-nav-user-sub { font-size: 0.72rem; color: var(--slate); }
.app-nav-admin .app-nav-user-sub { color: var(--blue-l); }

/* ─── Role switcher (manager ↔ instructor) ────────────────────── */
.app-nav-switcher {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.75rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--navy);
  background: var(--cream-2);
  border: 1px solid var(--border);
  border-radius: 100px;
  text-decoration: none;
  margin-right: 0.5rem;
  white-space: nowrap;
}
.app-nav-switcher:hover {
  background: var(--brand-navy);
  color: #fff;
  border-color: var(--brand-navy);
}
.app-nav-admin .app-nav-switcher {
  background: rgba(255,255,255,0.1);
  color: #fff;
  border-color: rgba(255,255,255,0.2);
}
.app-nav-admin .app-nav-switcher:hover {
  background: rgba(255,255,255,0.2);
  border-color: rgba(255,255,255,0.4);
}
/* Narrow screens: switch to icon-only mode to avoid clipping the account in the nav */
@media (max-width: 1366px) {
  .app-nav-switcher-label { display: none; }
  .app-nav-switcher { padding: 0.4rem; margin-right: 0.35rem; }
}
/* On mobile (stacked nav), hide the text label, keep the icon */
@media (max-width: 768px) {
  .app-nav-switcher span { display: none; }
  .app-nav-switcher { padding: 0.4rem 0.5rem; }
}

/* ─── Main / Page header ────────────────────────────────────────── */
.app-main {
  max-width: 1200px;
  margin: 0 auto;
  padding: 2rem 1.5rem 4rem;
  position: relative;
}

/* ─── iOS safe areas (notch / status bar / home indicator) ───
   In full screen (added to the home screen) + viewport-fit=cover, content
   runs edge to edge: margins are added back through env(). max() → NO effect
   where there is no notch (Android, desktop, iPhone without a notch, classic
   browser) because env() is 0 there. Also fixes iOS landscape (side notch). */
@supports (padding: env(safe-area-inset-top)) {
  /* Status bar (portrait): set on .app-nav (not .app-nav-inner) because it must
     apply ALSO in collapsed mode, where .app-nav.is-collapsed .app-nav-inner
     redefines the padding (higher specificity) and would override the margin. */
  .app-nav { padding-top: env(safe-area-inset-top); }
  /* Side notch (landscape, expanded bar). */
  .app-nav-inner {
    padding-left: max(clamp(1rem, 3vw, 2.5rem), env(safe-area-inset-left));
    padding-right: max(clamp(1rem, 3vw, 2.5rem), env(safe-area-inset-right));
  }
  .app-main {
    padding-left: max(1.5rem, env(safe-area-inset-left));
    padding-right: max(1.5rem, env(safe-area-inset-right));
  }
  .app-auth { padding-top: max(2rem, calc(env(safe-area-inset-top) + 1rem)); }
}
.app-page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.75rem;
}
.app-page-header h1 {
  font-size: clamp(1.6rem, 4vw, 2.1rem);
  font-weight: 800;
  color: var(--navy);
  margin: 0.25rem 0 0.4rem;
  letter-spacing: -0.025em;
  line-height: 1.15;
}
.app-page-header p {
  font-size: 0.92rem;
  color: var(--slate);
  margin: 0;
}
/* "tag" badge at the top of pages — as on the website (“NEWSLETTER”, “SECTORS”...) */
.app-section-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  background: var(--blue-l);
  color: var(--blue);
  padding: 0.3rem 0.75rem;
  border-radius: 100px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 0.6rem;
}

/* ─── Cards (premium 2026-05-25 : paper bg + warm shadow) ─────────── */
.app-card {
  background: var(--paper);
  border: 1px solid var(--separator);
  border-radius: 14px;
  padding: 1.5rem;
  margin-bottom: 1.25rem;
  box-shadow: var(--shadow-sm);
  position: relative;
  overflow: hidden;
  transition: box-shadow 0.18s ease, border-color 0.18s ease;
}
/* Accent bars above cards were removed (Apple HIG palette: no
   colored decorative elements on surfaces; typography carries
   the visual information). The classes remain valid for compatibility. */
.app-card-soft { background: var(--off); border-color: var(--border); }
.app-card-success { background: linear-gradient(135deg, #f0fdf4, #fff); border-color: #86efac; }
.app-card-title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--navy);
  margin: 0 0 1rem;
  letter-spacing: -0.01em;
}
.app-two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem;
  margin-bottom: 1.25rem;
}
.app-two-col > .app-card { margin-bottom: 0; }
.app-muted {
  color: var(--slate);
  font-size: 0.9rem;
  line-height: 1.6;
}
.app-muted a { color: var(--blue); text-decoration: none; font-weight: 600; }
.app-muted a:hover { text-decoration: underline; }

/* ─── KPI grid ──────────────────────────────────────────────────── */
.app-kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1rem;
  margin-bottom: 1.5rem;
}
.app-kpi {
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1.1rem 1.3rem;
  position: relative;
  overflow: hidden;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.app-kpi::before { content: none; }
.app-kpi-icon {
  position: absolute;
  top: 0.9rem; right: 0.9rem;
  width: 32px; height: 32px;
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  opacity: 0.85;
}
.app-kpi-blue .app-kpi-icon   { background: #eff6ff; color: #2563eb; }
.app-kpi-green .app-kpi-icon  { background: #f0fdf4; color: #16a34a; }
.app-kpi-orange .app-kpi-icon { background: #fff7ed; color: #ea580c; }
.app-kpi-purple .app-kpi-icon { background: #faf5ff; color: #7c3aed; }
.app-kpi-pink .app-kpi-icon   { background: #fdf2f8; color: #db2777; }
.app-kpi:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,0.08); }

/* Live pulse for the "visiteurs en direct" KPI */
.app-live-dot {
  display: inline-block;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: #16a34a;
  box-shadow: 0 0 0 0 rgba(22,163,74,0.5);
  animation: livePulse 2s ease-in-out infinite;
  margin-right: 0.4rem;
  vertical-align: middle;
}
@keyframes livePulse {
  0%   { box-shadow: 0 0 0 0 rgba(22,163,74,0.5); }
  70%  { box-shadow: 0 0 0 8px rgba(22,163,74,0); }
  100% { box-shadow: 0 0 0 0 rgba(22,163,74,0); }
}

/* Colored variants of section tags */
.app-section-tag-green  { background: #f0fdf4; color: #16a34a; }
.app-section-tag-orange { background: #fff7ed; color: #ea580c; }
.app-section-tag-purple { background: #faf5ff; color: #7c3aed; }
.app-section-tag-pink   { background: #fdf2f8; color: #db2777; }
/* Dark mode: these variants have a hardcoded light pastel (light island on a
   dark page). Dark shade + light text. The -indigo/-teal/-blue/-red variants
   already use theme variables. */
:root[data-theme="dark"] .app-section-tag-green  { background: rgba(34,197,94,0.16);  color: #4ade80; }
:root[data-theme="dark"] .app-section-tag-orange { background: rgba(234,88,12,0.18);   color: #fb923c; }
:root[data-theme="dark"] .app-section-tag-purple { background: rgba(124,58,237,0.20);  color: #a78bfa; }
:root[data-theme="dark"] .app-section-tag-pink   { background: rgba(219,39,119,0.18);  color: #f472b6; }

/* ─── Toolbar / filter bar ───────────────────────────────────────
   For filter bars at the top of pages (newsletter list, etc.):
   aligned horizontal layout, soft background, pro "search bar" look. */
.app-toolbar {
  display: flex;
  align-items: stretch;
  gap: 0.6rem;
  padding: 0.85rem;
  background: linear-gradient(135deg, #f8fafc, #f1f5f9);
  border: 1px solid var(--border);
  border-radius: 14px;
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
}
.app-toolbar-search {
  flex: 1;
  min-width: 240px;
  position: relative;
}
.app-toolbar-search svg {
  position: absolute;
  left: 0.85rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--slate-l);
  pointer-events: none;
}
.app-toolbar-search input {
  width: 100%;
  height: 42px;
  padding: 0 0.85rem 0 2.5rem;
  font-family: inherit;
  font-size: 0.9rem;
  border: 1.5px solid var(--border);
  border-radius: 10px;
  background: var(--paper);
  color: var(--text);
  box-sizing: border-box;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.app-toolbar-search input:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(0,0,0,0.12);
}
.app-toolbar-select {
  position: relative;
  min-width: 200px;
}
.app-toolbar-select select {
  height: 42px;
  padding: 0 2rem 0 0.85rem;
  font-family: inherit;
  font-size: 0.88rem;
  border: 1.5px solid var(--border);
  border-radius: 10px;
  background: var(--paper);
  color: var(--text);
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  width: 100%;
  box-sizing: border-box;
}
.app-toolbar-select::after {
  content: '';
  position: absolute;
  right: 0.85rem;
  top: 50%;
  transform: translateY(-25%);
  width: 8px; height: 8px;
  border-right: 2px solid var(--slate);
  border-bottom: 2px solid var(--slate);
  transform: translateY(-50%) rotate(45deg);
  margin-top: -2px;
  pointer-events: none;
}
.app-toolbar-select select:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(0,0,0,0.12);
}
.app-toolbar-btn {
  height: 42px;
  padding: 0 1.3rem;
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  border-radius: 10px;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  white-space: nowrap;
}
.app-toolbar-btn-primary {
  background: var(--brand-navy);
  color: #fff;
  border: 1.5px solid var(--brand-navy);
}
.app-toolbar-btn-primary:hover { background: var(--brand-navy2); }
.app-toolbar-btn-ghost {
  background: transparent;
  color: var(--slate);
  border: 1.5px solid transparent;
  text-decoration: none;
}
.app-toolbar-btn-ghost:hover { color: var(--navy); background: var(--paper); border-color: var(--border); }
.app-kpi-label {
  font-size: 0.74rem;
  font-weight: 600;
  color: var(--slate);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 0.4rem;
}
.app-kpi-value {
  font-size: 1.85rem;
  font-weight: 800;
  color: var(--navy);
  line-height: 1.05;
  letter-spacing: -0.02em;
}
.app-kpi-value-sm { font-size: 1.05rem; line-height: 1.3; }
.app-kpi-sub {
  font-size: 0.78rem;
  color: var(--slate);
  margin-top: 0.35rem;
}

/* ─── Tables ────────────────────────────────────────────────────── */
.app-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}
.app-table thead th {
  text-align: left;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--label-secondary);
  padding: 0.65rem 0.5rem 0.55rem;
  border-bottom: 1px solid var(--separator);
  background: transparent;
}
.app-table tbody td {
  padding: 0.85rem 0.5rem;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.app-table tbody tr:last-child td { border-bottom: none; }
.app-cell-name { font-weight: 600; color: var(--navy); }
.app-cell-sub { font-size: 0.78rem; color: var(--slate); }
.app-row-archived { opacity: 0.5; }
.app-row-archived .app-cell-name::after {
  content: ' (archivé)';
  color: var(--slate);
  font-size: 0.75rem;
  font-weight: 400;
}

/* ─── Polish 2026-05-25: management components ───────────────── */

/* Card-style table wrapper (rounded + shadow + border) */
.app-table-wrap {
  background: var(--paper);
  border: 1px solid var(--border2);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 4px 16px rgba(0,0,0,0.05), 0 1px 3px rgba(0,0,0,0.04);
  margin-bottom: 1.25rem;
}
.app-table-wrap .app-table { margin: 0; }
.app-table-wrap > table { width: 100%; border-collapse: collapse; }
/* Horizontal scrolling container added by page-loader.js around tables
   without wrappers (prevents their right columns from being cut off on mobile). */
.app-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
/* Inline code (URLs, identifiers…): must wrap to avoid overflowing
   the screen on mobile. <pre><code> blocks are excluded (they scroll). */
:not(pre) > code { overflow-wrap: anywhere; word-break: break-word; }
.app-table tbody tr {
  transition: background 0.15s ease;
}
.app-table tbody tr:hover {
  background: var(--blue-ll);
}
.app-table-zebra tbody tr:nth-child(even) { background: rgba(0,0,0,0.015); }
.app-table-zebra tbody tr:nth-child(even):hover { background: var(--blue-ll); }
/* Minimalist Apple style: no background, only a thin separator at the bottom */
.app-table thead th {
  background: transparent;
  border-top: 0;
  border-bottom: 1px solid var(--separator);
}
.app-table th { padding: 0.7rem 0.9rem 0.55rem; }
.app-table td { padding: 0.85rem 0.9rem; }
.app-table th:first-child, .app-table td:first-child { padding-left: 1.1rem; }
.app-table th:last-child, .app-table td:last-child { padding-right: 1.1rem; }

/* Badges (status, etc.) — small colored pills */
.app-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.22rem 0.62rem;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  white-space: nowrap;
  line-height: 1.3;
}
/* Badge containing a SENTENCE rather than a short label. Without this, the “white-space:
   nowrap” from .app-badge produced a 397px badge inside a 320px card: it
   overflowed its card and covered neighboring content. Uppercase and letter spacing,
   designed for one word, are also removed: unreadable in a sentence. */
.app-badge--phrase {
  white-space: normal;
  text-align: left;
  max-width: 100%;
  text-transform: none;
  letter-spacing: 0;
  line-height: 1.35;
  border-radius: 10px;
  padding: 0.3rem 0.6rem;
}
.app-badge-success { background: #dcfce7; color: #16a34a; }
.app-badge-info    { background: #dbeafe; color: #1e40af; }
.app-badge-warning { background: #fef3c7; color: #92400e; }
.app-badge-danger  { background: #fee2e2; color: #991b1b; }
.app-badge-neutral { background: #e5e7eb; color: #374151; }
.app-badge-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

/* Tags (CPF, AAC, Pro, etc.) — lightweight, multicolored */
.app-tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 5px;
  font-size: 0.7rem;
  font-weight: 600;
  white-space: nowrap;
  letter-spacing: 0.02em;
}
.app-tag-blue   { background: var(--blue-ll); color: var(--navy); }
.app-tag-green  { background: var(--green-l); color: var(--green); }
.app-tag-amber  { background: var(--amber-l); color: var(--amber); }
.app-tag-red    { background: #fef2f2; color: #b91c1c; }
.app-tag-purple { background: var(--purple-l); color: var(--purple); }
.app-tag-slate  { background: #f1f5f9; color: var(--slate); }

/* Stat cards (big-number KPI, e.g. accounting balance) */
.app-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1rem;
}
.app-stat-card {
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1.1rem 1.25rem;
  text-align: center;
  position: relative;
  overflow: hidden;
}
.app-stat-card::before { content: none; }
.app-stat-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--slate);
  font-weight: 700;
  margin-bottom: 0.4rem;
}
.app-stat-value {
  font-size: 1.85rem;
  font-weight: 800;
  color: var(--tint);
  font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
  letter-spacing: -0.02em;
  line-height: 1.1;
}
/* Colored semantic values (management choice: clearer accounting, less
   monochrome): collected/positive in green, due/unpaid in red, info in blue. */
.app-stat-value-success { color: #16a34a; }
.app-stat-value-danger  { color: #dc2626; }
.app-stat-value-info    { color: #0369a1; }

/* Section header (title + actions on the right) */
.app-section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-bottom: 1rem;
}
.app-section-header h2 {
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--navy);
  margin: 0;
  letter-spacing: -0.01em;
}

/* Empty state */
.app-empty-state {
  text-align: center;
  padding: 2.5rem 1rem;
  color: var(--slate);
  font-style: italic;
}
.app-empty-state strong {
  color: var(--navy);
  font-style: normal;
  display: block;
  margin-bottom: 0.3rem;
}

/* Cards cliquables (dashboards type "Contrats actifs / Formules") */
.app-card-clickable {
  cursor: pointer;
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
  text-decoration: none;
  color: inherit;
  display: block;
}
.app-card-clickable:hover {
  transform: translateY(-2px);
  box-shadow: 0 20px 50px rgba(0,0,0,0.12), 0 4px 10px rgba(0,0,0,0.06);
  border-color: var(--blue);
}

/* Compact breadcrumb above the page title */
.app-breadcrumb {
  font-size: 0.78rem;
  color: var(--slate);
  margin: 0 0 0.3rem;
}
.app-breadcrumb a {
  color: var(--blue);
  text-decoration: none;
  font-weight: 600;
}
.app-breadcrumb a:hover { text-decoration: underline; }

/* Menu Actions ▾ (dropdown) */
.app-actions {
  position: relative;
  display: inline-block;
}
.app-actions > summary {
  list-style: none;
  cursor: pointer;
  padding: 0.42rem 0.85rem;
  background: var(--paper);
  border: 1px solid var(--border2);
  border-radius: 6px;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--navy);
  transition: all 0.15s ease;
  user-select: none;
}
.app-actions > summary:hover {
  background: var(--blue-ll);
  border-color: var(--blue);
}
.app-actions > summary::-webkit-details-marker { display: none; }
.app-actions > summary::marker { content: ''; }
.app-actions[open] > summary { background: var(--blue-ll); border-color: var(--blue); }
.app-actions-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.35rem;
  min-width: 220px;
  box-shadow: 0 12px 36px rgba(0,0,0,0.14);
  z-index: 50;
}
.app-actions-menu button, .app-actions-menu a {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.5rem 0.7rem;
  border: 0;
  background: transparent;
  cursor: pointer;
  border-radius: 6px;
  font-size: 0.85rem;
  color: var(--text);
  text-decoration: none;
  transition: background 0.15s ease;
}
.app-actions-menu button:hover, .app-actions-menu a:hover {
  background: var(--blue-ll);
  color: var(--navy);
}
.app-actions-menu button.danger {
  color: #dc2626;
  font-weight: 600;
}
.app-actions-menu button.danger:hover {
  background: #fef2f2;
  color: #b91c1c;
}
.app-actions-menu hr {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 0.35rem 0;
}

/* Inline form filters for lists */
.app-filters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 0.85rem;
  align-items: end;
}

/* Dot color (companion to colored entities: student, instructor) */
.app-color-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  vertical-align: middle;
  margin-right: 0.4rem;
}
.app-color-dot-lg { width: 14px; height: 14px; }

/* Definition list (dl) for detail cards */
.app-defs {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.5rem 1.1rem;
  margin: 0;
  font-size: 0.88rem;
}
.app-defs dt {
  color: var(--slate);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
  padding-top: 0.05rem;
}
.app-defs dd { margin: 0; color: var(--text); }
.app-defs dd strong { color: var(--navy); font-weight: 700; }

/* Card grid (overviews) */
.app-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1rem;
}

/* Max-width container for narrow forms */
.app-container-narrow { max-width: 760px; margin-left: auto; margin-right: auto; }

/* ═══════════════════════════════════════════════════════════════════
   PREMIUM PASS 2026-05-25 — typographic polish + luxury components
   ═══════════════════════════════════════════════════════════════════ */

/* Type: tighter letter-spacing at higher levels, adjusted weights */
.app-page-header h1 {
  font-size: clamp(1.6rem, 3.5vw, 2.2rem);
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.1;
  color: var(--navy);
  margin: 0;
}
.app-page-header p {
  color: var(--slate);
  font-size: 0.92rem;
  line-height: 1.6;
  margin: 0.5rem 0 0;
  font-weight: 400;
}

/* Section title (h2) plus structured content */
.app-card-title {
  font-size: 0.78rem;
  font-weight: 800;
  color: var(--slate);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 0 0 1rem;
}
.app-card h2:not(.app-card-title) {
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--navy);
  letter-spacing: -0.015em;
  margin: 0 0 0.5rem;
}

/* Primary button: lift effect + warm shadow */
.app-btn-primary {
  background: var(--brand-navy);
  color: #fff;
  border-color: var(--brand-navy);
  font-weight: 600;
  letter-spacing: 0.005em;
  box-shadow: 0 1px 2px rgba(0,0,0,0.08);
  transition: all 0.18s cubic-bezier(0.4, 0, 0.2, 1);
}
.app-btn-primary:hover {
  background: var(--brand-navy2);
  border-color: var(--brand-navy2);
  transform: translateY(-1px);
  box-shadow: 0 6px 18px rgba(0,0,0,0.18), 0 2px 4px rgba(0,0,0,0.08);
}
.app-btn {
  transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
  border-radius: 8px;
}
.app-btn-outline {
  background: var(--paper);
  border-color: var(--border2);
  color: var(--navy);
}
.app-btn-outline:hover {
  border-color: var(--navy);
  background: var(--white);
  color: var(--navy);
}

/* Stat cards: flat Apple background, with no gradient or decorative accent */
.app-stat-card {
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1.3rem 1.4rem;
  text-align: center;
  position: relative;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.app-stat-card:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}

/* Table thead refinements : Apple-style, sobre, fond transparent */
.app-table thead th {
  background: transparent;
  border-top: 0;
  border-bottom: 1px solid var(--separator);
  color: var(--label-secondary);
}
.app-table tbody tr:hover {
  background: var(--cream-2);
}
.app-table-zebra tbody tr:nth-child(even) {
  background: rgba(0, 0, 0, 0.02);
}
.app-table-wrap {
  background: var(--paper);
  border-color: var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow-md);
}

/* Clickable cards: better animation */
.app-card-clickable {
  border-color: var(--border);
  width: 100%;
  box-sizing: border-box;
}
.app-card-clickable:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-lg);
  border-color: var(--accent-2);
}

/* Tags: harmony with warm palette */
.app-tag-blue   { background: var(--blue-l); color: var(--navy); }
.app-tag-amber  { background: var(--accent-2-l); color: var(--accent-2); }
.app-tag-purple { background: var(--accent-l); color: var(--accent); }

/* Page header : breadcrumb plus discret */
.app-breadcrumb {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 700;
  color: var(--accent-2);
  margin: 0 0 0.45rem;
}
.app-breadcrumb a {
  color: var(--accent-2);
}
.app-breadcrumb a:hover {
  color: var(--accent);
}

/* Form fields : look premium */
.app-form input[type="text"],
.app-form input[type="email"],
.app-form input[type="tel"],
.app-form input[type="password"],
.app-form input[type="number"],
.app-form input[type="date"],
.app-form input[type="datetime-local"],
.app-form input[type="search"],
.app-form input[type="color"],
.app-form select,
.app-form textarea {
  background: var(--paper);
  border: 1px solid var(--border2);
  border-radius: 8px;
  padding: 0.65rem 0.9rem;
  font-size: 0.92rem;
  color: var(--text);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  font-family: inherit;
}
.app-form input:focus,
.app-form select:focus,
.app-form textarea:focus {
  outline: none;
  border-color: var(--accent-2);
  box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.10);
}
.app-label {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--slate);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Nav links : better hover */
.app-nav-links a {
  font-weight: 600;
  letter-spacing: -0.005em;
}
.app-nav-links a.active {
  background: var(--cream-2);
  color: var(--navy);
  font-weight: 700;
}
.app-nav-brand {
  letter-spacing: -0.02em;
}

/* Alerts, warm palette: info deliberately reuses the one set higher up,
   the warning exists only here. */
.app-alert-info {
  background: var(--accent-2-l);
  color: var(--text);
  border-color: var(--accent-2);
}
.app-alert-warning {
  background: #fff8ea;
  color: #78410a;
  border-color: var(--amber);
}

/* App-main: full width on large screens, generous side padding */
.app-main {
  padding: 2rem var(--page-gutter) 2rem;
  max-width: none;
  margin: 0;
}
@media (max-width: 768px) {
  .app-main { padding: 1.5rem var(--page-gutter) 1.5rem; }
}
/* Inner nav: same thing, full screen */
.app-nav-inner {
  max-width: none;
  padding: 0.85rem var(--page-gutter);
}
/* Footer inner pareil */
.app-footer-inner {
  max-width: none;
  padding: 0;
}

/* Full-width footer (Apple-style) - see also the structure block further below */
.app-footer a { color: var(--label-secondary); text-decoration: none; }
.app-footer a:hover { color: var(--label-primary); text-decoration: underline; }

/* Defs list : look premium */
.app-defs dt {
  color: var(--slate);
  font-weight: 700;
  letter-spacing: 0.06em;
}
.app-defs dd strong { color: var(--navy); font-weight: 700; }

/* Empty state : plus visible */
.app-empty-state {
  padding: 3rem 1rem;
  color: var(--slate);
}
.app-empty-state strong {
  color: var(--navy);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  display: block;
  margin-bottom: 0.4rem;
  font-style: normal;
}

/* Actions menu: better visuals */
.app-actions > summary {
  background: var(--paper);
  border-color: var(--border2);
  font-weight: 600;
}
.app-actions > summary:hover {
  background: var(--cream-2);
  border-color: var(--accent-2);
}
.app-actions-menu {
  background: var(--paper);
  border-color: var(--border);
  box-shadow: var(--shadow-lg);
}
.app-actions-menu button:hover,
.app-actions-menu a:hover {
  background: var(--cream-2);
  color: var(--navy);
}

/* ─── Progression ───────────────────────────────────────────────── */
.app-progress-list { display: flex; flex-direction: column; gap: 0.9rem; }
.app-progress-row { display: flex; flex-direction: column; gap: 0.35rem; }
.app-progress-label {
  display: flex;
  justify-content: space-between;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--navy);
}
.app-progress-count {
  font-size: 0.78rem;
  color: var(--slate);
  font-weight: 500;
}
.app-progress-bar {
  height: 8px;
  background: var(--off);
  border-radius: 100px;
  overflow: hidden;
}
.app-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--blue), var(--brand-navy2));
  border-radius: 100px;
  transition: width 0.6s ease;
}

/* ─── Sessions list ─────────────────────────────────────────────── */
.app-session-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}
.app-session-item {
  display: flex;
  gap: 1rem;
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--border);
}
.app-session-list-detailed .app-session-item { padding: 1.2rem 0; }
.app-session-item:last-child { border-bottom: none; }
.app-session-date {
  flex-shrink: 0;
  width: 90px;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--blue);
  font-family: 'JetBrains Mono', 'Courier New', monospace;
}
.app-session-time {
  font-size: 0.72rem;
  color: var(--slate);
  font-weight: 500;
  margin-top: 0.15rem;
}
.app-session-body { flex: 1; min-width: 0; }
.app-session-type {
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--navy);
  margin-bottom: 0.2rem;
}
.app-session-meta {
  font-size: 0.78rem;
  color: var(--slate);
  margin-bottom: 0.3rem;
}
.app-session-notes {
  font-size: 0.85rem;
  color: var(--text);
  line-height: 1.55;
  margin-top: 0.4rem;
  padding-left: 0.7rem;
  border-left: 2px solid var(--border2);
}
.app-session-themes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.5rem;
}
.app-theme-chip {
  display: inline-block;
  padding: 0.2rem 0.6rem;
  border-radius: 100px;
  font-size: 0.72rem;
  font-weight: 600;
  background: var(--blue-ll);
  color: var(--blue);
  border: 1px solid var(--blue-l);
}
.app-theme-chip[data-level="3"] { background: #ecfdf5; color: #15803d; border-color: #86efac; }
.app-theme-chip[data-level="4"] { background: var(--brand-navy); color: #fff; border-color: var(--brand-navy); }

/* ─── Theme picker (admin log-session) ──────────────────────────── */
.app-theme-cat {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1rem 1.2rem 1.2rem;
  margin: 0 0 1rem;
}
.app-theme-cat legend {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--blue);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0 0.5rem;
}
.app-theme-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 0.85rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border);
}
.app-theme-row:last-child { border-bottom: none; }
.app-theme-check {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  cursor: pointer;
  font-size: 0.88rem;
  color: var(--text);
}
.app-theme-check input { width: 16px; height: 16px; accent-color: var(--blue); cursor: pointer; }
.app-theme-row select {
  font-family: inherit;
  font-size: 0.78rem;
  padding: 0.35rem 2rem 0.35rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background-color: var(--white);
  color: var(--text);
}
.app-theme-row select:disabled { opacity: 0.4; background: var(--off); }

/* ─── Documents ─────────────────────────────────────────────────── */
.app-doc-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.7rem; }
.app-doc-item {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.9rem 1rem;
  background: var(--off);
  border: 1px solid var(--border);
  border-radius: 10px;
}
.app-doc-icon {
  width: 40px; height: 40px;
  background: var(--blue-ll);
  color: var(--blue);
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.app-doc-body { flex: 1; min-width: 0; }
.app-doc-type {
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--slate);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.app-doc-title { font-weight: 600; color: var(--navy); font-size: 0.92rem; }
.app-doc-date { font-size: 0.78rem; color: var(--slate); margin-top: 0.15rem; }

/* ─── Credential display (after new student creation) ───────────── */
.app-cred-box {
  background: var(--off);
  border: 1px dashed var(--border2);
  border-radius: 10px;
  padding: 1rem 1.2rem;
  margin-top: 1rem;
  font-family: 'JetBrains Mono', 'Courier New', monospace;
}
.app-cred-row {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 0.5rem 0;
}
.app-cred-row + .app-cred-row { border-top: 1px solid var(--border); }
.app-cred-label {
  font-family: inherit;
  font-size: 0.75rem;
  color: var(--slate);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  min-width: 130px;
}
.app-cred-value {
  font-size: 1rem;
  font-weight: 700;
  color: var(--navy);
  background: var(--paper);
  padding: 0.3rem 0.6rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  user-select: all;
}

/* ─── Apple-style footer: 4 columns + bottom legal line ──────────── */
.app-footer {
  background: var(--bg-secondary);
  border-top: 1px solid var(--separator);
  padding: 2rem var(--page-gutter) 1.25rem;
  margin-top: 1.5rem;
}
/* Instructor mode: showcase footer hidden ONLY on a touch device (tablet).
   On PC / screens with a mouse (fine pointer), it remains visible. */
@media (pointer: coarse) {
  .app-footer-ens { display: none !important; }
}
/* Tablet / touch (html.app-touch-lock set by head.ejs according to pointer:coarse):
   - no double-tap zoom (touch-action: manipulation), scrolling still works;
   - text selection and copying are disabled (locked-down app experience).
   Text entry in fields remains selectable. On desktop (mouse): everything works normally. */
html.app-touch-lock { touch-action: manipulation; }
html.app-touch-lock, html.app-touch-lock body {
  -webkit-user-select: none; -moz-user-select: none; user-select: none; -webkit-touch-callout: none;
}
html.app-touch-lock input, html.app-touch-lock textarea, html.app-touch-lock select,
html.app-touch-lock [contenteditable], html.app-touch-lock [contenteditable] * {
  -webkit-user-select: text; -moz-user-select: text; user-select: text;
}
.app-footer-inner {
  max-width: none;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  font-size: 0.78rem;
  color: var(--label-secondary);
}
.app-footer-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1.5rem 2rem;
}
.app-footer-col strong {
  display: block;
  color: var(--label-primary);
  font-size: 0.78rem;
  font-weight: 700;
  margin-bottom: 0.5rem;
  letter-spacing: 0.01em;
}
.app-footer-col p {
  margin: 0;
  font-size: 0.76rem;
  line-height: 1.55;
  color: var(--label-secondary);
}
.app-footer-brand { font-size: 0.88rem !important; letter-spacing: -0.01em; }
/* Brand (logo + name) moved from the top banner to the footer (bottom left).
   Reuses the Roddier APP logo (or the driving school's premium logo). The SVG already adapts to the
   theme (circle/road inverted in dark mode). */
.brand-mark {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
  margin-bottom: 0.5rem;
}
.brand-mark-logo { flex-shrink: 0; display: block; }
.brand-mark-img { height: 26px; max-width: 130px; object-fit: contain; display: block; }
.brand-mark-name {
  font-size: 0.95rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--navy);
  line-height: 1;
}
.brand-mark-name small { font-weight: 500; color: var(--label-secondary); letter-spacing: 0; }
.brand-mark:hover .brand-mark-name { color: var(--tint, #5e7fa8); }
:root[data-theme="dark"] .brand-mark-name { color: #f2f2f7; }
.app-footer-links {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.app-footer-links a {
  font-size: 0.76rem;
  color: var(--label-secondary);
  text-decoration: none;
}
.app-footer-links a:hover { color: var(--label-primary); text-decoration: underline; }
.app-footer-bottom {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--separator);
  font-size: 0.72rem;
  color: var(--label-secondary);  /* a11y: tertiary (0.30) = 1.7:1, unreadable → secondary readable */
  flex-wrap: wrap;
}
.app-footer-sep { opacity: 0.5; }
.app-footer-version {
  font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
  font-size: 0.7rem;
}
@media (max-width: 640px) {
  /* Data-entry grids declared with an inline style (grid-template-columns with
     explicit columns, e.g. "1fr 1fr" or "130px 1fr 1.4fr auto"): a @media
     cannot override an inline style without !important → switch to
     1 column. Safeguards: only grids directly containing
     fields (label/input/select/textarea) are targeted — never auto-fit grids /
     auto-fill (already fluid) or schedule-style calendars (div cells).
     :where() = zero specificity: any dedicated !important rule (e.g.
     .dispo-add-grid below) keeps the final say. */
  :where([style*="grid-template-columns"]:not([style*="auto-fit"]):not([style*="auto-fill"]):has(> label, > input, > select, > textarea)) {
    grid-template-columns: 1fr !important;
  }
  .app-footer { padding: 1.5rem var(--page-gutter) 1rem; }
  .app-footer-cols { gap: 1.25rem; }
}

/* ─── Responsive ────────────────────────────────────────────────── */
@media (max-width: 880px) {
  .app-two-col { grid-template-columns: 1fr; }
  .app-form-grid { grid-template-columns: 1fr; }
  .app-nav-inner { gap: 1rem; padding: 0.7rem 1rem; }
  /* Single line: brand · links (condensed into icons by initNavFit) · user on the right.
     (Links are no longer reordered at full width — that put day/night + sign-out in the middle.) */
  .app-nav-user { margin-left: auto; }
  .app-main { padding: 1.5rem 1rem 3rem; }
  .app-card { padding: 1.2rem; }
  .app-table { font-size: 0.82rem; }
  .app-table thead th, .app-table tbody td { padding: 0.5rem 0.4rem; }
  .app-table th:nth-child(3),
  .app-table td:nth-child(3),
  .app-table th:nth-child(6),
  .app-table td:nth-child(6) { display: none; }
  .app-session-item { flex-direction: column; gap: 0.4rem; }
  .app-session-date { width: auto; }
  .app-theme-row { grid-template-columns: 1fr; }
  .app-theme-row select { justify-self: start; }
  .app-cred-row { flex-direction: column; gap: 0.2rem; }
  .app-cred-label { min-width: 0; }
}

/* ───────────────────────────────────────────────────────────────────
   PREMIUM LOOK & FEEL — Signature light halos + micro-animations
   Consistent with roddier.pro (Julien Roddier color palette)
   ─────────────────────────────────────────────────────────────────── */

/* Signature halo on the body (subtle, light mode) */
body.app-body { position: relative; }
body.app-body::before {
  content: '';
  position: fixed;
  inset: 0;
  background:
    radial-gradient(ellipse 50% 40% at 95% 5%, rgba(0,0,0,0.07), transparent 70%),
    radial-gradient(ellipse 45% 35% at 5% 95%, rgba(22,163,74,0.05), transparent 70%);
  pointer-events: none;
  z-index: 0;
}
/* .app-nav excluded: it keeps its position:sticky + z-index:100 (see above)
   to remain sticky AND above the content (otherwise the notifications panel
   ended up trapped below page buttons). It already sits above the
   animated background thanks to its z-index:100 > -1. */
.app-main, .app-footer { position: relative; z-index: 1; }

/* Smooth color transitions on all elements (for theme changes) */
.app-card, .app-kpi, .app-auth-card, .app-nav,
.app-form input, .app-form select, .app-form textarea,
.app-btn, .app-toolbar, .app-table tbody td {
  transition: background-color 0.25s ease, border-color 0.25s ease, color 0.2s ease, box-shadow 0.25s ease, transform 0.15s ease;
}

/* Subtle animation when the cards load */
@keyframes appCardIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
/* PAGE entry: on every navigation, content fades in + slides slightly
   upward (“app opening / changing” feel). Runs in all cases. */
@keyframes appPageIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes appFadeOnly { from { opacity: 0; } to { opacity: 1; } }
.app-main { animation: appPageIn 0.42s var(--ease-out-smooth, cubic-bezier(0.22,0.61,0.36,1)) both; }
.app-card, .app-kpi { animation: appCardIn 0.35s ease backwards; }
.app-kpi:nth-child(1) { animation-delay: 0.05s; }
.app-kpi:nth-child(2) { animation-delay: 0.1s; }
.app-kpi:nth-child(3) { animation-delay: 0.15s; }
.app-kpi:nth-child(4) { animation-delay: 0.2s; }
.app-kpi:nth-child(5) { animation-delay: 0.25s; }
/* “Reduce motion”: we keep a LIVING interface—simple fade-ins (without
sliding) and smooth transitions remain (color/opacity do not interfere).
Not everything is disabled anymore; otherwise, the app feels frozen. */
@media (prefers-reduced-motion: reduce) {
  .app-main, .app-card, .app-kpi { animation: appFadeOnly 0.3s ease both; }
  .app-kpi { animation-delay: 0s; }
}

/* Page loading bar (slow navigation) - see `page-loader.js`. */
.app-page-loader {
  position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 99999;
  pointer-events: none; opacity: 0; transition: opacity 0.2s ease;
  background: linear-gradient(90deg, transparent, var(--accent-2, #0f2544), transparent);
  background-size: 40% 100%; background-repeat: no-repeat;
}
.app-page-loader.active { opacity: 1; animation: appLoaderSlide 1.05s ease-in-out infinite; }
@keyframes appLoaderSlide {
  0%   { background-position: -40% 0; }
  100% { background-position: 140% 0; }
}

/* Stronger hover lift on interactive cards */
a.app-card:hover, .app-card.app-card-interactive:hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 50px rgba(0,0,0,0.12), 0 4px 10px rgba(0,0,0,0.06);
}

/* ═══════════════════════════════════════════════════════════
   KIOSK MODE — dedicated tablet
   Set by device-id.js (html.app-kiosk) when the school enables kiosk mode on
   the device. Hides the account / sign-out / workspace switch, and
   a discreet button (injected by the JS) opens the exit through the
   school code. Combined with iOS Guided Access = tablet locked onto Roddier APP.
   ═══════════════════════════════════════════════════════════ */
html.app-kiosk .app-nav-user { display: none !important; }

/* ═══════════════════════════════════════════════════════════
   PLANNING — premium components (day / week / month)
   Uses only var() → adapts to dark mode on its own.
   ═══════════════════════════════════════════════════════════ */
.app-planning-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  align-items: center;
  justify-content: space-between;   /* tabs on the left, filters on the right */
  margin: 1rem 0;
}
.app-planning-tabs {
  display: inline-flex;
  background: var(--off);
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 4px;
  gap: 0;
  height: 38px;
  box-sizing: border-box;
  box-shadow: var(--shadow-sm);
}
.app-planning-tab {
  display: inline-flex;
  align-items: center;
  padding: 0 1.1rem;
  border-radius: 100px;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-decoration: none;
  color: var(--slate);
  transition: color 0.18s, background 0.18s;
}
.app-planning-tab:hover { color: var(--navy); }
.app-planning-tab[aria-selected="true"] {
  background: var(--paper);
  color: var(--accent);
  box-shadow: 0 2px 6px rgba(0,0,0,0.08), 0 0 0 1px rgba(0,0,0,0.04);
}

/* Office / Instructor filters — pills consistent with tabs (38px high) */
.app-planning-filters {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
}
.app-planning-filter {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 38px;
  box-sizing: border-box;
  padding: 0 0.85rem 0 1rem;
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 100px;
  transition: border-color 0.18s, box-shadow 0.18s;
  cursor: pointer;
}
.app-planning-filter:hover { border-color: var(--accent-2); box-shadow: var(--shadow-sm); }
.app-planning-filter:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(0,0,0,0.10); }
.app-planning-filter-label {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--slate);
}
.app-planning-filter select {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  outline: 0;
  padding: 0 1.4rem 0 0;
  font-size: 0.85rem;
  font-weight: 600;
  font-family: inherit;
  color: var(--navy);
  cursor: pointer;
  max-width: 200px;
  text-overflow: ellipsis;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235c6373' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.2rem center;
}

/* ─── Vue SEMAINE ─── */
.app-planning-week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 0.6rem;
  margin: 1rem 0;
}
.app-planning-week-day {
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.7rem;
  min-height: 140px;
  display: flex;
  flex-direction: column;
  transition: box-shadow 0.18s;
}
.app-planning-week-day:hover { box-shadow: var(--shadow-md); }
.app-planning-week-day.is-weekend { background: var(--off); }
.app-planning-week-day.is-today {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), var(--shadow-md);
}
.app-planning-week-day-head {
  margin-bottom: 0.55rem;
  text-align: center;
  border-bottom: 1px solid var(--border);
  padding-bottom: 0.45rem;
}
.app-planning-week-day-name {
  font-size: 0.68rem;
  text-transform: uppercase;
  color: var(--slate);
  font-weight: 700;
  letter-spacing: 0.06em;
}
.app-planning-week-day.is-today .app-planning-week-day-name { color: var(--accent); }
.app-planning-week-day-num {
  font-size: 1.15rem;
  font-weight: 800;
  color: var(--navy);
  font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
  letter-spacing: -0.02em;
}
.app-planning-week-day.is-today .app-planning-week-day-num { color: var(--accent); }
.app-planning-week-empty {
  font-size: 0.78rem;
  color: var(--slate);
  text-align: center;
  margin: auto 0;
  font-style: italic;
}
.app-planning-week-events { display: flex; flex-direction: column; gap: 0.35rem; }
.app-planning-week-evt {
  color: #fff;
  border-radius: 6px;
  padding: 0.4rem 0.55rem;
  font-size: 0.74rem;
  line-height: 1.3;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,0.12);
  transition: transform 0.12s;
}
.app-planning-week-evt:hover { transform: translateY(-1px); box-shadow: 0 4px 10px rgba(0,0,0,0.18); }
.app-planning-week-evt-time {
  font-weight: 700;
  font-family: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
  font-size: 0.66rem;
  opacity: 0.92;
}
.app-planning-week-evt-name { font-weight: 600; font-size: 0.78rem; }
.app-planning-week-evt-meta { opacity: 0.82; font-size: 0.66rem; }

/* ─── Vue MOIS ─── */
.app-planning-month-head {
  text-align: center;
  font-size: 0.68rem;
  text-transform: uppercase;
  color: var(--slate);
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border);
}
.app-planning-month-cell {
  min-height: 90px;
  padding: 0.4rem;
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 0.72rem;
}
.app-planning-month-cell.is-other-month { opacity: 0.45; background: var(--off); }
.app-planning-month-cell.is-today {
  background: var(--accent-l);
  border-color: var(--accent);
}
.app-planning-month-cell-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 0.3rem;
}
.app-planning-month-num { font-weight: 700; color: var(--navy); }
.app-planning-month-cell.is-today .app-planning-month-num { color: var(--accent); }
.app-planning-month-count { font-size: 0.62rem; color: var(--slate); }
.app-planning-month-evt {
  color: #fff;
  border-radius: 3px;
  padding: 1px 5px;
  margin-bottom: 2px;
  font-size: 0.62rem;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.app-planning-month-more {
  font-size: 0.62rem;
  color: var(--slate);
  text-decoration: none;
  font-weight: 600;
}
.app-planning-month-more:hover { color: var(--accent); }

/* ─── Planning: smartphone adaptation / small tablet ───────────────────
   The DAY view (time grid) is handled in planning.ejs (minimum width of
   column + scrolling card). Here: WEEK / MONTH views + toolbar. */
@media (max-width: 768px) {
  /* WEEK: 7 unreadable ~50px columns → stack into 2 columns
     (small tablet), then 1 column (phone, rule below). */
  .app-planning-week { grid-template-columns: repeat(2, 1fr); gap: 0.5rem; }
  .app-planning-week-day { min-height: 0; }
}
@media (max-width: 540px) {
  /* WEEK: full-width vertical list (agenda) — readable events. */
  .app-planning-week { grid-template-columns: 1fr; }

  /* Toolbar: full-width segmented tabs + stacked filters. */
  .app-planning-toolbar { gap: 0.6rem; }
  .app-planning-tabs { width: 100%; justify-content: center; }
  .app-planning-tab { flex: 1; justify-content: center; padding: 0 0.6rem; }
  .app-planning-filters { width: 100%; }
  .app-planning-filter { flex: 1 1 auto; min-width: 0; }
  .app-planning-filter select { max-width: none; width: 100%; }

  /* MONTH: more compact cells to fit the width without overflowing. */
  .app-planning-month-cell { min-height: 64px; padding: 0.3rem; }

  /* Header actions: compact 3-column grid (instead of 7 buttons
     stacked full width). display:grid takes precedence over the inline flex style.
     Row 1: ← Today →. Row 2: Download Preview Email.
     “+ New event” occupies its own full-width row. */
  .app-planning-actions {
    display: grid !important;
    /* !important: the student record header rule (.app-page-header>div:last-child)
       has higher specificity and would otherwise force 2 columns. */
    grid-template-columns: repeat(3, 1fr) !important;
    gap: 0.4rem;
  }
  .app-planning-actions .app-btn { padding: 0.55rem 0.4rem; font-size: 0.8rem; }
  .app-planning-actions #new-event-btn { grid-column: 1 / -1; }
}

/* ─── Legend ─── */
.app-planning-legend-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.3rem 0.75rem;
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: 100px;
  font-size: 0.78rem;
  color: var(--navy);
}

/* ── Theme switch: 3-position toggle (Light / Auto / Dark) ──
   Visual order from left to right: Light, System, Dark. */
.app-theme-switch {
  box-sizing: border-box;   /* height 38 includes border + padding, otherwise the thumb (absolute) shifts against the opts (flex) */
  display: inline-flex;
  align-items: center;
  position: relative;
  background: var(--off);
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 4px;
  gap: 0;
  height: 38px;
  box-shadow: var(--shadow-sm);
}
.app-theme-switch-thumb {
  position: absolute;
  top: 4px;
  left: 4px;
  width: 36px;
  height: 28px;
  background: #ffffff;
  border-radius: 100px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.18), 0 0 0 1px rgba(0,0,0,0.08);
  transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.2s;
  z-index: 1;
}
:root[data-theme="dark"] .app-theme-switch-thumb {
  background: #ffffff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.50), 0 0 0 1px rgba(255,255,255,0.06);
}
:root[data-theme="dark"] .app-theme-switch-opt[aria-pressed="true"] {
  color: #000000;
}
.app-theme-switch-opt {
  position: relative;
  z-index: 2;
  width: 36px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 0;
  color: var(--slate);
  cursor: pointer;
  padding: 0;
  border-radius: 100px;
  transition: color 0.2s;
}
.app-theme-switch-opt svg { width: 15px; height: 15px; }
.app-theme-switch-opt:hover { color: var(--navy); }
.app-theme-switch-opt[aria-pressed="true"] { color: var(--accent); }

/* Thumb position according to the active pref (option width 36px) */
[data-theme-pref="light"] .app-theme-switch-thumb { transform: translateX(0); }
[data-theme-pref="auto"]  .app-theme-switch-thumb { transform: translateX(36px); }
[data-theme-pref="dark"]  .app-theme-switch-thumb { transform: translateX(72px); }
/* Fallback: before bootstrap has set the pref, place the thumb on "auto" */
:root:not([data-theme-pref]) .app-theme-switch-thumb { transform: translateX(36px); }

/* Admin nav variant (dark background) */
.app-nav-admin .app-theme-switch {
  background: rgba(255,255,255,0.06);
  border-color: rgba(255,255,255,0.12);
}
.app-nav-admin .app-theme-switch-thumb {
  background: rgba(255,255,255,0.18);
  box-shadow: 0 1px 4px rgba(0,0,0,0.25);
}
.app-nav-admin .app-theme-switch-opt { color: rgba(255,255,255,0.62); }
.app-nav-admin .app-theme-switch-opt:hover { color: #fff; }
.app-nav-admin .app-theme-switch-opt[aria-pressed="true"] { color: #fff; }

/* ── Legacy compatibility: the old .app-theme-toggle remains styled
   in case a view has not yet migrated to the switch. */
.app-theme-toggle {
  width: 36px; height: 30px;
  border-radius: 100px;
  background: var(--off);
  border: 1px solid var(--border);
  color: var(--slate);
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: color 0.2s, background 0.2s, border-color 0.2s;
  font-family: inherit;
}
.app-theme-toggle:hover { color: var(--accent); border-color: var(--accent-2); }
.app-nav-admin .app-theme-toggle { background: rgba(255,255,255,0.06); border-color: rgba(255,255,255,0.12); color: rgba(255,255,255,0.75); }
.app-nav-admin .app-theme-toggle:hover { background: rgba(255,255,255,0.12); color: #fff; }
.app-theme-toggle .icon-sun,
.app-theme-toggle .icon-moon,
.app-theme-toggle .icon-system { width: 16px; height: 16px; display: none; }
[data-theme-pref="auto"]  .app-theme-toggle .icon-system { display: block; }
[data-theme-pref="light"] .app-theme-toggle .icon-sun    { display: block; }
[data-theme-pref="dark"]  .app-theme-toggle .icon-moon   { display: block; }
:root:not([data-theme-pref]) .app-theme-toggle .icon-system { display: block; }

/* ───────────────────────────────────────────────────────────────────
   DARK MODE — CSS variable INVERSION approach
   (consistent with dev.roddier.pro/assets/style.css)

   Strategy: invert the base variables so that everything
   using var(--navy), var(--text), var(--white), etc. adapts
   automatically. No need to override 50 selectors.

   - var(--navy)  : dark text color in light → becomes light in dark
   - var(--white) : card background in light → becomes slate-navy in dark
   - var(--off)   : sub-card background → becomes even more elevated
   - --blue remains fairly similar (just brighter in dark)

   theme.js applies [data-theme="light"] or "dark" to <html> (never empty).
   ─────────────────────────────────────────────────────────────────── */

:root[data-theme="dark"] {
  color-scheme: dark;

  /* ─── Backgrounds (Apple macOS dark — no pure black, soft gray that rests the eyes) ─── */
  --bg-primary:   #1c1c1e;            /* page : darkSystemGroupedBackground */
  --bg-secondary: #2c2c2e;            /* cards : secondarySystem dark */
  --bg-tertiary:  #3a3a3c;            /* sub-elements / inputs */
  --bg-elevated:  #2c2c2e;            /* modals dark */

  /* ─── Fills (translucent, more opaque than in light mode) ─── */
  --fill-primary:    rgba(255,255,255,0.16);
  --fill-secondary:  rgba(255,255,255,0.12);
  --fill-tertiary:   rgba(255,255,255,0.08);
  --fill-quaternary: rgba(255,255,255,0.05);

  /* ─── Labels (4 opacities, white base) ─── */
  --label-primary:    #ffffff;
  --label-secondary:  rgba(235,235,245,0.60);
  --label-tertiary:   rgba(235,235,245,0.30);
  --label-quaternary: rgba(235,235,245,0.18);

  /* ─── Separators (gris froid Apple) ─── */
  --separator:        rgba(84,84,88,0.65);
  --separator-opaque: #38383a;

  /* ─── Tint (accent — blanc en dark) ─── */
  --tint:           #ffffff;
  --tint-secondary: #f0f0f0;

  /* ─── System colors (official Apple dark variants) ─────── */
  --system-red:    #ff453a;
  --system-orange: #ff9f0a;
  --system-yellow: #ffd60a;
  --system-green:  #30d158;
  --system-blue:   #0a84ff;
  --system-indigo: #5e5ce6;
  --system-purple: #bf5af2;
  --system-pink:   #ff375f;
  --system-teal:   #64d2ff;
  --system-gray:   #8e8e93;

  /* ─── Shadows (few drop-shadows in dark mode — Apple favors borders) ─── */
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.40);
  --shadow-md: 0 4px 16px rgba(0,0,0,0.50);
  --shadow-lg: 0 12px 32px rgba(0,0,0,0.60);
  --shadow-xl: 0 24px 60px rgba(0,0,0,0.70);

  /* ─── Status fills (dark: increased opacity to remain legible) ─── */
  --orange-l: rgba(255,159,10,0.16);
  --green-l:  rgba(48,209,88,0.16);
  --purple-l: rgba(191,90,242,0.16);
  --pink-l:   rgba(255,55,95,0.16);
  --cyan-l:   rgba(100,210,255,0.18);
  --amber-l:  rgba(255,159,10,0.16);

  /* ─── Legacy alias overrides for dark (--navy2 is hardcoded in light) ─── */
  --navy2: #f0f0f0;
  /* Brand navy, one step lighter in dark mode to remain visible/readable. */
  --brand-navy:  #21487a;
  --brand-navy2: #2d5b94;

  /* ─── Expanded palette: dark variants (slightly more saturated for readability) ─── */
  --accent-3:    #818cf8;                  /* indigo plus clair en dark */
  --accent-3-l:  rgba(129,140,248,0.14);
  --accent-4:    #2dd4bf;                  /* brightened teal */
  --accent-4-l:  rgba(45,212,191,0.14);
  --paper-warm:  #2c2c2e;                  /* alignment bg-secondary*/

  /* ─── Apple System Colors dark — illuminated colors (iOS convention) ─── */
  --sys-blue:    #0a84ff;
  --sys-indigo:  #7d7aff;
  --sys-purple:  #d77eff;
  --sys-pink:    #ff5e85;
  --sys-red:     #ff6961;
  --sys-orange:  #ffbe55;
  --sys-yellow:  #ffe46b;
  --sys-green:   #5dde7f;
  --sys-mint:    #82e0db;
  --sys-teal:    #67d8ec;
  --sys-cyan:    #84def4;
  --sys-gray:    #a9a9b0;
  --sys-brown:   #c2a888;

  /* More opaque soft colors in dark mode so they remain visible on a dark background */
  --sys-blue-soft:    rgba(10,132,255,0.18);
  --sys-indigo-soft:  rgba(125,122,255,0.20);
  --sys-purple-soft:  rgba(215,126,255,0.18);
  --sys-pink-soft:    rgba(255,94,133,0.18);
  --sys-red-soft:     rgba(255,105,97,0.18);
  --sys-orange-soft:  rgba(255,190,85,0.18);
  --sys-yellow-soft:  rgba(255,228,107,0.20);
  --sys-green-soft:   rgba(93,222,127,0.18);
  --sys-mint-soft:    rgba(130,224,219,0.20);
  --sys-teal-soft:    rgba(103,216,236,0.20);
  --sys-cyan-soft:    rgba(132,222,244,0.20);
  --sys-gray-soft:    rgba(169,169,176,0.20);
  --sys-brown-soft:   rgba(194,168,136,0.20);

  /* Ring focus (more visible outline on a dark background) */
  --ring-focus:  0 0 0 3px rgba(129,140,248,0.30);

  /* Dark shadows — they work mostly by contrast (Apple uses few) */
  --shadow-soft:    0 1px 3px rgba(0,0,0,0.40), 0 4px 12px rgba(0,0,0,0.30);
  --shadow-raised:  0 2px 6px rgba(0,0,0,0.50), 0 12px 28px rgba(0,0,0,0.50);
  --shadow-overlay: 0 8px 24px rgba(0,0,0,0.55), 0 24px 60px rgba(0,0,0,0.60);

  /* ─── Foundation kit: dark equivalents (2026-06-18) ───
     Motion + radii are theme-independent → not redefined here.
     Shadows: in dark mode, use deep black again (light navy does not work
     on a black background). Glass + scrim + halo adjusted for the dark background. */
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.40);
  --shadow-md: 0 4px 16px rgba(0,0,0,0.50);
  --shadow-lg: 0 12px 32px rgba(0,0,0,0.60);

  --halo-color:   rgba(94, 127, 168, 0.28);
  --glass-bg:     rgba(40, 42, 48, 0.72);
  --glass-border: rgba(255, 255, 255, 0.12);
  --scrim:        rgba(0, 0, 0, 0.55);
  --island-bg:    rgba(28, 30, 36, 0.94);
  --island-fg:    #f5f5f7;
}

/* Body in dark mode — pure black background, no colored glow */
:root[data-theme="dark"] body.app-body {
  background: var(--cream);
  color: var(--text);
}
:root[data-theme="dark"] body.app-body::before {
  background: none;
}

/* Cards / surfaces using hardcoded #fff backgrounds (not through var) */
:root[data-theme="dark"] .app-card,
:root[data-theme="dark"] .app-kpi,
:root[data-theme="dark"] .app-auth-card,
:root[data-theme="dark"] .app-nav:not(.app-nav-admin),
:root[data-theme="dark"] .app-footer {
  background: var(--white);
  border-color: var(--border);
  box-shadow: 0 10px 40px rgba(0,0,0,0.3), 0 2px 6px rgba(0,0,0,0.15);
}
:root[data-theme="dark"] .app-card-soft,
:root[data-theme="dark"] .app-doc-item,
:root[data-theme="dark"] .app-cred-box,
:root[data-theme="dark"] .app-card-success { background: var(--off); border-color: var(--border); }

/* Forms / inputs */
:root[data-theme="dark"] .app-form input,
:root[data-theme="dark"] .app-form select,
:root[data-theme="dark"] .app-form textarea,
:root[data-theme="dark"] .app-toolbar-search input,
:root[data-theme="dark"] .app-toolbar-select select { background-color: var(--off); border-color: var(--border); color: var(--text); }
:root[data-theme="dark"] .app-toolbar { background: linear-gradient(135deg, var(--white), var(--off)); border-color: var(--border); }

/* The admin nav keeps its navy look (dark gradient) in LIGHT as in DARK */
.app-nav-admin {
  background: linear-gradient(135deg, #0f2544, #1a3a6b) !important;
  color: #fff;
  border-bottom-color: transparent;
}
.app-nav-admin .app-nav-brand,
.app-nav-admin .app-nav-brand span { color: #fff !important; }
.app-nav-admin .app-nav-brand small { color: #93c5fd !important; font-weight: 500; }
.app-nav-admin .app-nav-links a { color: rgba(255,255,255,0.72); }
.app-nav-admin .app-nav-links a:hover { background: rgba(255,255,255,0.10); color: #fff; }
.app-nav-admin .app-nav-links a.active { background: rgba(255,255,255,0.16); color: #fff; }

/* Tables / other dark details */
:root[data-theme="dark"] .app-table thead th { color: var(--slate); border-bottom-color: var(--border); }
:root[data-theme="dark"] .app-table tbody td { border-bottom-color: var(--border); }
:root[data-theme="dark"] .app-progress-bar { background: var(--border); }
:root[data-theme="dark"] .app-alert-error { background: rgba(220,38,38,0.15); color: #fca5a5; border-color: #dc2626; }
:root[data-theme="dark"] .app-alert-info { background: var(--blue-l); color: var(--text); border-color: var(--blue); }
:root[data-theme="dark"] .app-btn-ghost { background: var(--off); color: var(--slate); border-color: var(--border); }
:root[data-theme="dark"] .app-btn-ghost:hover { background: var(--border); color: var(--text); }

/* Override to keep a white/light background on some elements
   with hardcoded backgrounds in EJS files (wiki tips, alerts, etc.) */
:root[data-theme="dark"] .wiki-tip { background: var(--off) !important; color: var(--text); border-color: var(--border) !important; }
:root[data-theme="dark"] .wiki-warn { background: rgba(234,88,12,0.10) !important; color: #fcd9b6 !important; border-color: rgba(234,88,12,0.4) !important; }
:root[data-theme="dark"] .wiki-section { background: var(--white); border-color: var(--border); color: var(--text); }
:root[data-theme="dark"] .wiki-section code { background: var(--off); color: #ffffff; border-color: var(--border); }
:root[data-theme="dark"] .wiki-toc { background: var(--white); border-color: var(--border); }
:root[data-theme="dark"] .wiki-toc a { background: var(--off); color: var(--text); border-color: var(--border); }
:root[data-theme="dark"] .wiki-toc a:hover { background: var(--border); }

/* Force adaptation on inline sections with white/light background styles */
/* Auto-darkens elements that carry an inline white background. EXCEPTION: the preview of
   the email signature must remain white (simulation of an email on the recipient's side) —
   otherwise its background turned dark while its inline navy text stayed navy
   → invisible. */
:root[data-theme="dark"] [style*="background:#fff"]:not(.signature-preview-wrapper),
:root[data-theme="dark"] [style*="background: #fff"]:not(.signature-preview-wrapper),
:root[data-theme="dark"] [style*="background:#ffffff"]:not(.signature-preview-wrapper),
:root[data-theme="dark"] [style*="background:white"]:not(.signature-preview-wrapper) { background: var(--white) !important; color: var(--text) !important; }

/* Primary buttons in dark mode: same azure as in light, readable white text */
:root[data-theme="dark"] .app-btn-primary {
  background: var(--th-grad, var(--brand-navy)) !important;
  border-color: transparent !important;
  color: #ffffff !important;
  box-shadow: 0 1px 2px rgba(0,0,0,0.35), 0 6px 16px rgba(37,99,235,0.30);
}
:root[data-theme="dark"] .app-btn-primary:hover {
  background: var(--th-grad-h, var(--brand-navy2)) !important;
  border-color: transparent !important;
  box-shadow: 0 4px 14px rgba(37,99,235,0.40);
}
:root[data-theme="dark"] .app-btn-outline { color: var(--text) !important; border-color: var(--border2); }
:root[data-theme="dark"] .app-btn-outline:hover { background: var(--off); color: var(--text) !important; border-color: #ffffff; }

/* SVG logo: inverted in dark mode — white circle + navy blue road (aligned with site). */
:root[data-theme="dark"] .app-logo-svg .logo-circle { fill: #ffffff !important; }
:root[data-theme="dark"] .app-logo-svg .logo-road   { stroke: #0f2544 !important; }
/* Static logos on entry pages (login, registration, errors — wrapper .app-logo):
   use the same inversion in dark mode as the nav logo, otherwise the midnight-blue circle blends into the
   dark background (#1c1c1e). White circle + midnight-blue road. (Custom school logos = <img>, not targeted.) */

/* The admin menu is ALWAYS navy blue (light and dark). The navy logo
   would blend into it (navy circle on navy background → invisible). So this menu always
   uses the inverted variant: white disc + navy road, clearly visible. */
.app-nav-admin .app-logo-svg .logo-circle { fill: #ffffff !important; }
.app-nav-admin .app-logo-svg .logo-road   { stroke: #0f2544 !important; }
:root[data-theme="dark"] .app-nav-admin .app-logo-svg .logo-road { stroke: #0f2544 !important; }

/* Cards with hardcoded light backgrounds via inline styles (linear-gradient, rgba, etc.)
   → force them into dark mode through an override layer. Covers patterns found in
   EJS files: .app-card with style="background:linear-gradient(...,#eff6ff...)". */
:root[data-theme="dark"] .app-card[style*="linear-gradient"],
:root[data-theme="dark"] .app-card[style*="background:#fff"],
:root[data-theme="dark"] .app-card[style*="background: #fff"],
:root[data-theme="dark"] .app-card[style*="background:#fafafa"],
:root[data-theme="dark"] .app-card[style*="background:#f0fdf4"],
:root[data-theme="dark"] .app-card[style*="background:#fef3c7"] {
  background: var(--white) !important;
  border-color: var(--border) !important;
}
/* Surfaces blanches/claires brutes (sections, divs) → fond sombre */
:root[data-theme="dark"] section[style*="background:#fff"],
:root[data-theme="dark"] section[style*="background:linear-gradient"],
:root[data-theme="dark"] div[style*="background:#fafafa"],
:root[data-theme="dark"] div[style*="background:#f9fafb"],
:root[data-theme="dark"] div[style*="background:#f0f9ff"],
:root[data-theme="dark"] div[style*="background:#fef3c7"] {
  background: var(--white) !important;
  color: var(--text) !important;
}

/* Email signature preview: force light rendering (regardless of the active mode)
   to show what a recipient would see in light mode. The source code to
   copy (inside the <pre>) keeps its @media intact. */
.signature-preview-wrapper {
  color-scheme: light !important;
  background: #ffffff !important;
  color: #0f2544 !important;
}
.signature-preview-wrapper * {
  color-scheme: light !important;
}

/* ───────────────────────────────────────────────────────────────────
   RESPONSIVE — Strengthen small screens (<480px)
   ─────────────────────────────────────────────────────────────────── */
@media (max-width: 480px) {
  .app-main { padding: 1.25rem 0.85rem 2.5rem; }
  .app-card { padding: 1rem; border-radius: 12px; }
  .app-page-header h1 { font-size: 1.4rem; }
  .app-page-header p { font-size: 0.85rem; }
  .app-section-tag { font-size: 0.62rem; padding: 0.25rem 0.6rem; }
  .app-kpi { padding: 0.95rem 1rem; }
  .app-kpi-value { font-size: 1.55rem; }
  .app-kpi-label { font-size: 0.68rem; }
  .app-btn { padding: 0.65rem 1rem; font-size: 0.85rem; }
  .app-btn-sm { padding: 0.4rem 0.75rem; font-size: 0.78rem; }
  .app-toolbar { padding: 0.7rem; }
  .app-toolbar-search { min-width: 100%; }
  .app-toolbar-select { min-width: 100%; }
  .app-form-actions { flex-direction: column; align-items: stretch; }
  .app-form-actions .app-btn { width: 100%; }
  .app-nav-inner { padding: 0.6rem 0.85rem; gap: 0.6rem; }
  .app-nav-brand { font-size: 0.92rem; }
  .app-nav-links a { padding: 0.4rem 0.7rem; font-size: 0.8rem; }
  .app-nav-icon-btn, .app-theme-toggle { width: 34px; height: 34px; }
  .app-auth-card { padding: 1.5rem 1.25rem; border-radius: 14px; }
  .app-auth-title { font-size: 1.3rem; }
}

/* ═══════════════════════════════════════════════════════════
   MOBILE HAMBURGER MENU
   Below 768px: `nav-links` + `nav-user` turn into
   a side panel that slides in from the right, triggered
   by a hamburger button at the top right.
   ═══════════════════════════════════════════════════════════ */
.app-nav-hamburger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  background: transparent;
  border: 1px solid var(--separator);
  border-radius: 8px;
  cursor: pointer;
  color: var(--label-primary);
  padding: 0;
  margin-left: auto;
  flex-shrink: 0;
  transition: background 0.15s;
}
.app-nav-hamburger:hover { background: var(--fill-quaternary); }
.app-nav-hamburger .ham-line { transition: transform 0.25s ease, opacity 0.2s ease; transform-origin: center; }
.app-nav.is-mobile-open .app-nav-hamburger .ham-line-1 { transform: translate(0, 6px) rotate(45deg); }
.app-nav.is-mobile-open .app-nav-hamburger .ham-line-2 { opacity: 0; }
.app-nav.is-mobile-open .app-nav-hamburger .ham-line-3 { transform: translate(0, -6px) rotate(-45deg); }

/* Mobile drawer container: neutral on desktop (links + user block
   keep their place in the bar); it only becomes a panel at <=768px. */
.app-nav-drawer { display: contents; }
/* The drawer close button is always created in JS. On desktop,
   the drawer is display:contents → the close button would appear in the bar
   (to the right of the logo). It is hidden by default; the <=768px block shows it again. */
.app-nav-drawer-close { display: none; }

.app-nav-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  z-index: 998;
  opacity: 0;
  transition: opacity 0.25s ease;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
}

/* No horizontal scrolling on mobile: the nav drawer (position:fixed) must not
   widen the page. clip = no scroll container (preserves position:sticky
   for .app-nav and table headers); hidden as fallback (older Safari). */
@media (max-width: 768px) {
  html, body { overflow-x: hidden; overflow-x: clip; }
}

/* ─── Nav collapsed into hamburger menu ───────────────────────────────────
   Triggered by the .is-collapsed class set by nav-hamburger.js: either
   the screen is narrow (<=768px), or the bar content OVERFLOWS (the
   admin nav on a tablet, with its long row of tool icons). Controlled by
   actual measurement → no icon is clipped, regardless of item count/width. */
/* On WebKit/iOS, an ancestor with backdrop-filter / filter / transform /
   will-change / contain (or captured by a named view transition) becomes the
   containing block for its position:fixed descendants: the full-screen drawer
   would be rendered INSIDE the bar, behind the page content. Collapsed
   bar = NONE of these properties, ever. */
.app-nav.is-collapsed {
  -webkit-backdrop-filter: none !important;
  backdrop-filter: none !important;
  filter: none !important;
  transform: none !important;
  will-change: auto !important;
  contain: none !important;
  view-transition-name: none !important;
}
/* At <=768px the bar is ALWAYS collapsed: remove these properties from the
   first paint (before JS sets .is-collapsed) and during the capture
   of navigation view transitions (they enforce render containment). */
@media (max-width: 768px) {
  .app-nav {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    filter: none !important;
    transform: none !important;
    will-change: auto !important;
    contain: none !important;
    view-transition-name: none !important;
  }
}
/* Opaque background on the collapsed bar (blur is removed above because it would trap
   the position:fixed drawer). The admin nav keeps its navy gradient. */
.app-nav.is-collapsed:not(.app-nav-admin),
:root[data-theme="dark"] .app-nav.is-collapsed:not(.app-nav-admin) { background: var(--bg-elevated); }
.app-nav.is-collapsed .app-nav-hamburger { display: inline-flex; }
.app-nav.is-collapsed .app-nav-inner { padding: 0.7rem 1rem; gap: 0.6rem; }

/* ── Mobile anti-flicker (FOUC) ────────────────────────────────────────────
   At ≤768px the bar is ALWAYS collapsed. Before nav-hamburger.js sets
   .is-collapsed (the app fully reloads on every navigation), the hamburger
   is already shown and the inline links / user block are hidden:
   the first paint shows the collapsed state, without flashing the full bar on
   every page change. JS then takes over (creating the drawer).
   Bonus: even if a stray 'resize' (URL bar while scrolling) briefly removes
   .is-collapsed, the links remain hidden → no flicker. */
@media (max-width: 768px) {
  .app-nav-hamburger { display: inline-flex; }
  .app-nav:not(.is-collapsed) .app-nav-links,
  .app-nav:not(.is-collapsed) .app-nav-user { display: none; }
}
/* In the drawer (vertical panel), labels are ALWAYS kept: icon-only
   mode (.nav-compact, for a tight horizontal bar) makes no sense
   here and would remove the menu labels. */
.app-nav.is-collapsed .app-nav-inner.nav-compact .app-nav-links a { font-size: 0.95rem; padding: 0.7rem 0.85rem; gap: 0.6rem; }
.app-nav.is-collapsed .app-nav-inner.nav-compact .app-nav-links a .nav-icon { margin-right: 0.55rem; }
.app-nav.is-collapsed .app-nav-inner.nav-compact .app-nav-switcher-label { display: inline; }

/* Drawer: FULL-SCREEN panel below the bar, appearing IN PLACE (fade).
   .app-nav-drawer is created by nav-hamburger.js (which moves .app-nav-links +
   .app-nav-user into it). When not collapsed it is neutral (display:contents, see above). */
.app-nav.is-collapsed .app-nav-drawer {
  display: flex;
  flex-direction: column;
  position: fixed;
  inset: 0;                 /* FULL SCREEN: covers everything, no page strip */
  box-sizing: border-box;
  background: var(--bg-elevated);
  z-index: 1300;
  padding: calc(0.7rem + env(safe-area-inset-top, 0px)) max(0.9rem, env(safe-area-inset-right, 0px)) calc(0.9rem + env(safe-area-inset-bottom, 0px)) max(0.9rem, env(safe-area-inset-left, 0px));
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  gap: 0.2rem;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  /* No animation by default: .is-collapsed is set (and remeasured) when
     EVERY page loads; a transition here makes the full-screen drawer
     fade from 1 → 0 on every navigation = flicker. Opening/closing
     animations are re-enabled through .nav-ready, set by JS AFTER
     the first paint (therefore after the initial collapse, which remains instant). */
  transition: none;
}
.app-nav.is-collapsed.nav-ready .app-nav-drawer {
  transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}
.app-nav.is-collapsed.is-mobile-open .app-nav-drawer {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.18s ease;
}
/* Admin nav = white text: the panel gets a navy background to remain readable. */
.app-nav-admin.is-collapsed .app-nav-drawer { background: var(--brand-navy); }
/* Close cross at the top of the full-screen panel. */
.app-nav.is-collapsed .app-nav-drawer-close {
  align-self: flex-end;
  flex: none;
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent;
  border: 1px solid var(--separator);
  border-radius: 9px;
  color: var(--label-primary);
  cursor: pointer;
  margin: 0 0 0.4rem;
}
.app-nav-admin.is-collapsed .app-nav-drawer-close { color: #fff; border-color: rgba(255,255,255,0.3); }

/* Links + user block: normal flow inside the panel */
.app-nav.is-collapsed .app-nav-drawer .app-nav-links,
.app-nav.is-collapsed .app-nav-drawer .app-nav-user {
  position: static;
  transform: none;
  width: auto;
  max-width: none;
  height: auto;
  background: transparent;
  box-shadow: none;
  padding: 0;
  flex: none;
  overflow: visible;
  flex-direction: column;
  align-items: stretch;
  gap: 0.25rem;
}
.app-nav.is-collapsed .app-nav-drawer .app-nav-user {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: auto;            /* account / sign-out pushed to the bottom of the drawer */
  padding-top: 0.8rem;
  border-top: 1px solid var(--separator);
}
.app-nav.is-collapsed .app-nav-links a {
  padding: 0.7rem 0.8rem;
  font-size: 0.95rem;
  border-radius: 10px;
  width: 100%;
  box-sizing: border-box;   /* padding included -> the link does not overflow by 11px */
  justify-content: flex-start;
  gap: 0.7rem;
}
.app-nav.is-collapsed .app-nav-user-info { text-align: left; }

/* OPEN menu: the hamburger stays visible ABOVE the drawer and turns into a
   close button (existing ham-line animation) -> the close button is EXACTLY where the burger was
   (top right). Clicking it closes the drawer (same button, same handler). The separate close button
   for the drawer becomes unnecessary. */
.app-nav.is-mobile-open .app-nav-hamburger {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + 8px);
  right: 13px;
  z-index: 1401;
  display: inline-flex !important;
}
.app-nav.is-collapsed .app-nav-drawer-close { display: none !important; }

/* Mobile drawer: NEVER any horizontal scrolling. overflow-y:auto changes overflow-x to
   'auto' -> a slightly too-wide label (device font metrics) could
   scroll to the right and cut off the icons on the left. Force overflow-x:hidden everywhere
   in the drawer, and rows are guaranteed to shrink (min-width:0, box-sizing). */
.app-nav.is-collapsed .app-nav-drawer,
.app-nav.is-mobile-open .app-nav-drawer .app-nav-links { overflow-x: hidden; max-width: 100%; }
.app-nav.is-mobile-open .app-nav-drawer .app-nav-links a,
.app-nav.is-mobile-open .app-nav-drawer .app-nav-links .app-nav-grouptrigger,
.app-nav.is-mobile-open .app-nav-drawer .app-nav-links .app-nav-dropdown { min-width: 0; max-width: 100%; box-sizing: border-box; }

/* Submenu (expanded section) INSIDE the mobile drawer: accordion INSERTED into the list,
   opaque, WITHOUT a glass effect. Otherwise app-theme.css forces position:absolute (it floats
   above it) and liquid-glass.css adds a backdrop-filter (it blurs the colored icons
   behind it -> unwanted gradient). Scoped to .is-mobile-open (never desktop). */
.nav-layout-side .app-nav.is-mobile-open:not(.app-nav-admin):not(.super-nav) .app-nav-drawer .app-nav-dropdown {
  position: static;
  width: 100%;
  min-width: 0;
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border: none;
  box-shadow: none;
  padding: 0.1rem 0 0.3rem 1.4rem;
}

/* MOBILE DRAWER OPEN = VERTICAL list. An @media(max-width:900px) rule forces
   .app-nav-links to flex-direction:row (horizontal bar of the sidebar navs); by
   its specificity it won inside the drawer -> inline links stretched across the full
   height (open menu broken). Take control again with higher specificity,
   scoped to .is-mobile-open ONLY (NEVER affects the closed state). */
.nav-layout-side .app-nav.is-mobile-open:not(.app-nav-admin):not(.super-nav) .app-nav-drawer .app-nav-links {
  flex-direction: column;
  align-items: stretch;
  overflow-y: auto;
  overflow-x: hidden;
  width: 100%;
  max-width: 100%;
}
.app-nav.is-mobile-open .app-nav-drawer .app-nav-links > a,
.app-nav.is-mobile-open .app-nav-drawer .app-nav-links > .app-nav-group { flex: 0 0 auto; width: 100%; }


/* ADMIN drawer: the “tools” block is a row of ICONS ONLY (support,
   health, settings, sign-out…). Stacked as-is in the drawer, it overflows and
   remains unreadable (no labels). Expand it into a full-width vertical list,
   with each tool showing its label (aria-label) next to the icon. */
.app-nav-admin.is-collapsed .app-nav-drawer .app-nav-user {
  flex-direction: column;
  align-items: stretch;
  align-self: stretch;
  flex-wrap: nowrap;
  width: 100%;
  margin-left: 0;          /* cancels the margin-left:auto that pushed it to the right */
  margin-top: 0.4rem;
  gap: 0.15rem;
  border-top-color: rgba(255, 255, 255, 0.16);
}
.app-nav-admin.is-collapsed .app-nav-drawer .app-nav-user > span { display: none !important; } /* vertical separators (inline style → !important) */
.app-nav-admin.is-collapsed .app-nav-drawer .app-nav-user .app-nav-icon-btn {
  width: 100%;
  box-sizing: border-box;   /* padding included -> does not overflow the drawer width */
  height: auto;
  justify-content: flex-start;
  gap: 0.7rem;
  padding: 0.7rem 0.8rem;
  border-radius: 10px;
}
.app-nav-admin.is-collapsed .app-nav-drawer .app-nav-user .app-nav-icon-btn::after {
  content: attr(aria-label);
  font-size: 0.95rem;
  font-weight: 500;
}

/* ═══════════════════════════════════════════════════════════
   RESPONSIVE MOBILE COMPLET (iPhone SE / 11 / 12 / 13 / 14)
   Target 375px-480px: clean switch to 1 column, tables
   horizontally scrollable, header buttons stack, etc.
   ═══════════════════════════════════════════════════════════ */
@media (max-width: 720px) {
  /* Generic grids: clean switch to 1 column */
  .app-stat-grid { grid-template-columns: repeat(2, 1fr); gap: 0.6rem; }

  /* Tables: horizontal wrapper to prevent viewport overflow */
  .app-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .app-table { font-size: 0.82rem; }
  .app-table th, .app-table td { padding: 0.5rem 0.55rem; white-space: nowrap; }
  /* (No more display:block here: it shrank narrow tables — their
     content no longer filled the card. Tables keep width:100% (thus
     full width when content is narrow), and page-loader.js wraps them
     in .app-table-scroll when they are too wide → scrolling.) */

  /* Modals: use all available width (the box, not the full-screen overlay) */
  .app-modal-card,
  dialog.app-modal { max-width: calc(100vw - 1rem) !important; margin: 0.5rem; }
  .app-modal-body, .app-modal-body { padding: 0.9rem 1rem; }
  .app-modal-header h3 { font-size: 1rem; }

  /* Page header: stacked title + actions */
  .app-page-header { flex-direction: column; align-items: stretch; gap: 0.8rem; }
  .app-page-header > div:first-child { width: 100%; }
  .app-page-header h1 { font-size: 1.25rem; }

  /* “Full-width” form footer (negative margins aligned with desktop
     padding): on mobile, card padding is smaller → the negative overflow
     extended beyond the screen. Disable horizontal overflow. */
  .admin-sticky-footer { margin-left: 0 !important; margin-right: 0 !important; padding-left: 0.4rem !important; padding-right: 0.4rem !important; }

  /* Quick-add menu : full width mobile */
  .quick-add-wrapper { width: 100%; }
  .quick-add-wrapper .quick-add-trigger { width: 100%; justify-content: center; }
  .quick-add-menu { left: 0; right: 0; min-width: 0; }

  /* Nav: handled by the hamburger rules (see previous block @media 768px) */
}

@media (max-width: 480px) {
  /* Student record header: buttons in a 2-column grid */
  .app-page-header > div:last-child:not(:only-child) {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
    width: 100%;
  }
  .app-page-header > div:last-child:not(:only-child) > * { width: 100%; }

  /* Stats grid: 1 column on very small screens */
  .app-stat-grid { grid-template-columns: 1fr; }

  /* Tabs: they scroll sideways rather than wrap. */
  .parameters-tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; flex-wrap: nowrap; }
  .parameters-tabs::-webkit-scrollbar { display: none; }
  .param-tab { flex-shrink: 0; white-space: nowrap; }

  /* Filtres compacts */
  .app-filters { flex-direction: column; align-items: stretch; }
  .app-filters > * { width: 100%; }

  /* Form grids in modals: strictly 1 column */
  .app-modal-body .form-grid { grid-template-columns: 1fr !important; gap: 0.7rem; }

  /* Availability addition forms (student area): 3 fields (day/time/time)
side by side overflowed the card on smartphones → 2 columns, fields at
full width. The + Add button (4th cell of the weekly form) moves below the row. */
  .availability-add-grid { grid-template-columns: 1fr 1fr !important; }
  .availability-add-grid > * { min-width: 0; }

  /* Reduced internal padding */
  .app-card { padding: 0.85rem; }
}

/* Safe area iOS notch */
@supports (padding: env(safe-area-inset-bottom)) {
  .app-main { padding-bottom: max(2rem, env(safe-area-inset-bottom) + 1rem); }
}
/* Clearance for the floating mobile menu: the last content must be able to scroll
   above the strip it occupies. */
@media (max-width: 768px) {
  .app-footer { padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 5rem); }
  body:not(:has(.app-footer)) .app-main { padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 5.5rem); }
}

/* ═══════════════════════════════════════════════════════════
   PRINTING — @media print rules for clean PDF exports
   (used by the Print button in the schedule and student/vehicle records)
   ═══════════════════════════════════════════════════════════ */
@media print {
  /* Aggressive height/margin reset to prevent blank pages */
  html, body, body.app-body {
    margin: 0 !important;
    padding: 0 !important;
    background: #fff !important;
    color: #000 !important;
    color-scheme: light !important;
    min-height: 0 !important;
    height: auto !important;
    overflow: visible !important;
  }
  body.app-body::before, body.app-body::after {
    content: none !important;
    display: none !important;
    background: none !important;
  }

  /* Force light palette for printing, regardless of the active theme */
  :root, :root[data-theme="dark"] {
    --cream: #fff; --cream-2: #fff; --paper: #fff; --off: #f5f5f5;
    --navy: #000; --navy2: #222; --text: #000;
    --slate: #555; --border: #ccc; --border2: #aaa;
    --accent: #000; --accent-2: #1a1a1a;
  }

  /* Hide all navigational and interactive chrome */
  .app-nav, .app-footer,
  .app-planning-toolbar,
  .app-planning-actions,
  .app-page-header > div:nth-child(2),
  .app-btn, button {
    display: none !important;
  }

  /* Flatten layout: no excessive padding that pushes content to the next page */
  .app-main {
    padding: 0 !important;
    max-width: none !important;
    margin: 0 !important;
  }

  /* Cards: no shadow, no "page-break-inside: avoid" that creates blank
     pages when a card is taller than one page. Let the browser
     handle page breaks naturally. */
  .app-card {
    box-shadow: none !important;
    border: 0.5pt solid #ccc !important;
    margin: 0 0 0.3cm 0 !important;
    padding: 0.3cm !important;
    overflow: visible !important;
    page-break-inside: auto !important;
    break-inside: auto !important;
  }

  /* Header impression compact */
  .app-page-header {
    margin: 0 0 0.3cm 0 !important;
    padding: 0 !important;
  }
  .app-page-header h1 { font-size: 13pt !important; margin: 0 !important; line-height: 1.2 !important; }
  .app-page-header p  { font-size: 9pt !important; margin: 0 !important; color: #555 !important; }

  /* Schedule grid: no scrolling, natural height */
  #planning-grid {
    overflow: visible !important;
    overflow-x: visible !important;
    height: auto !important;
    page-break-inside: auto !important;
    break-inside: auto !important;
  }
  .planning-evt {
    box-shadow: none !important;
    border: 0.5pt solid rgba(0,0,0,0.25);
    page-break-inside: avoid;
  }

  /* Hide the schedule legend when printing (saves space) */
  .app-planning-legend-tag { display: none !important; }
  .app-card:has(.app-planning-legend-tag) { display: none !important; }

  /* Stripped-down links in print: no underline */
  a { color: inherit !important; text-decoration: none !important; }

  /* A4 landscape format for the schedule (the widest) */
  @page {
    size: A4 landscape;
    margin: 0.8cm;
  }
}

/* ───────────────────────────────────────────────────────────────────
   ANIMATED LOGO — Pulsing navy circle + white road drawing itself
   Consistent with dev.roddier.pro (the showcase website)
   ─────────────────────────────────────────────────────────────────── */
/* Rounded path that draws itself then erases itself from LEFT TO RIGHT (entry + exit),
   aligned with the website. Only dashoffset values >= 0 (iOS/WebKit clamps
   negatives → “drew itself then jumped”): dasharray 1200 (period 2400 → 0 and
   2400 = “full”), instant invisible jump 0->2400 (step-end), then 2400->1200
   = erasure from left to right. */
@keyframes roadDraw {
  0%   { stroke-dashoffset: 1200; }
  15%  { stroke-dashoffset: 0; }
  64%  { stroke-dashoffset: 0; animation-timing-function: step-end; }
  65%  { stroke-dashoffset: 2400; }
  90%  { stroke-dashoffset: 1200; }
  100% { stroke-dashoffset: 1200; }
}
@keyframes circlePulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}
.app-logo-svg .logo-circle {
  transform-origin: 512px 512px;
  /* circlePulse removed 2026-05-24 — Julien's preference: static logo */
}
.app-logo-svg .logo-road {
  stroke-dasharray: 1200;
  stroke-dashoffset: 1200;
  animation: roadDraw 13s ease-in-out infinite;
  animation-delay: 0.2s;
}
@media (prefers-reduced-motion: reduce) {
  .app-logo-svg .logo-circle, .app-logo-svg .logo-road { animation: none !important; }
  .app-logo-svg .logo-road { stroke-dashoffset: 0; opacity: 1; }
}

/* ═══════════════════════════════════════════════════════════
   FANCY FORM — shared styles for premium forms
   (registration, login, recovery, profile). Approach: sections
   with icons, inputs with tinted focus glow, prominent buttons.
   ═══════════════════════════════════════════════════════════ */

/* Wider container for multi-section forms */
.app-auth-wide { align-items: flex-start; padding-top: 3rem; padding-bottom: 3rem; }
.app-auth-card-form { max-width: 600px; }

/* Callout tarif (page inscription) */
.price-callout {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem 1.25rem;
  background: linear-gradient(135deg, var(--bg-tertiary), var(--bg-secondary));
  border: 1px solid var(--separator);
  border-radius: 14px;
  margin: 0 0 1.5rem;
  box-shadow: var(--shadow-sm);
}
.price-callout-trial { font-size: 0.95rem; font-weight: 700; color: var(--label-primary); }
.price-callout-amount {
  font-size: 1.6rem; font-weight: 800; color: var(--label-primary);
  letter-spacing: -0.02em; font-feature-settings: 'tnum';
}
.price-callout-sub { font-size: 0.78rem; color: var(--label-secondary); margin-top: 0.15rem; }
.price-callout-right { text-align: right; }

/* Alertes form */
.form-alert {
  display: flex;
  gap: 0.85rem;
  padding: 1rem 1.1rem;
  border-radius: 12px;
  font-size: 0.88rem;
  margin: 0 0 1.25rem;
}
.form-alert-error {
  background: rgba(255,59,48,0.08);
  border-left: 3px solid var(--system-red);
  color: var(--label-primary);
}
.form-alert-icon { font-size: 1.2rem; flex-shrink: 0; color: var(--system-red); line-height: 1; }

/* Form fancy : sections, champs, focus glow */
.form-fancy { display: flex; flex-direction: column; gap: 1.25rem; }
.form-section {
  background: var(--bg-tertiary);
  border: 1px solid var(--separator);
  border-radius: 14px;
  padding: 1.25rem 1.35rem 1.35rem;
  position: relative;
}
.form-section-head {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin: -0.25rem -0.25rem 1.1rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--separator);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--label-secondary);
}
.form-section-icon { width: 16px; height: 16px; color: var(--label-primary); flex-shrink: 0; }

.form-field { display: block; margin-bottom: 0.85rem; }
.form-field:last-child { margin-bottom: 0; }
.form-label {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--label-primary);
  margin-bottom: 0.4rem;
}
.form-label-hint { font-weight: 400; color: var(--label-tertiary); font-size: 0.78rem; }

.form-fancy input[type="text"],
.form-fancy input[type="email"],
.form-fancy input[type="password"],
.form-fancy input[type="tel"],
.form-fancy input[type="number"],
.form-fancy input[type="date"],
.form-fancy input[type="time"],
.form-fancy textarea,
.form-fancy select {
  width: 100%;
  padding: 0.75rem 0.9rem;
  border: 1.5px solid var(--separator);
  border-radius: 10px;
  background-color: var(--bg-secondary);
  color: var(--label-primary);
  font-size: 0.95rem;
  font-family: inherit;
  transition: border-color 0.15s ease, box-shadow 0.18s ease, background 0.15s ease;
  box-sizing: border-box;
}
.form-fancy input:hover, .form-fancy textarea:hover, .form-fancy select:hover {
  border-color: var(--separator-opaque);
}
.form-fancy input:focus, .form-fancy textarea:focus, .form-fancy select:focus {
  outline: none;
  border-color: var(--tint);
  box-shadow: 0 0 0 4px var(--fill-primary);
  background: var(--bg-elevated);
}

.form-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0.85rem; margin-bottom: 0.85rem; }
.form-grid-postcode-city { display: grid; grid-template-columns: 1fr 2fr; gap: 0.85rem; margin-bottom: 0.85rem; }
@media (max-width: 480px) {
  .form-grid-2, .form-grid-postcode-city { grid-template-columns: 1fr; }
}

/* SIREN with status on the right */
.form-field-with-status { position: relative; }
.form-field-status {
  position: absolute;
  right: 0.85rem;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--label-secondary);
  max-width: 60%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  pointer-events: none;
}
.form-field-status.is-loading { color: var(--label-secondary); }
.form-field-status.is-success { color: var(--system-green); }
.form-field-status.is-error   { color: var(--system-red); }

/* Improved checkbox style */
.form-checkbox-inline {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  padding: 0.85rem 1rem;
  background: var(--fill-tertiary);
  border-radius: 10px;
  font-size: 0.88rem;
  line-height: 1.5;
  cursor: pointer;
  transition: background 0.15s ease;
  margin-bottom: 0.85rem;
}
.form-checkbox-inline:hover { background: var(--fill-secondary); }
.form-checkbox-inline input[type="checkbox"] {
  margin: 0.18rem 0 0;
  width: 18px; height: 18px;
  accent-color: var(--tint);
  flex-shrink: 0;
}

/* More impactful submit button */
.form-submit-btn {
  width: 100%;
  padding: 1rem;
  font-size: 1rem;
  font-weight: 700;
  border-radius: 12px;
  box-shadow: var(--shadow-md);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.form-submit-btn:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-lg);
}

/* Widget Altcha */
.altcha-widget {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.7rem 0.95rem;
  background: var(--fill-tertiary);
  border: 1px solid var(--separator);
  border-radius: 10px;
  font-size: 0.85rem;
  color: var(--label-secondary);
  margin-bottom: 1rem;
  transition: background 0.2s ease, border-color 0.2s ease;
}
.altcha-icon { width: 16px; height: 16px; flex-shrink: 0; }
.altcha-widget.is-success {
  background: rgba(52,199,89,0.08);
  border-color: rgba(52,199,89,0.3);
  color: var(--system-green);
}
.altcha-widget.is-error {
  background: rgba(255,59,48,0.08);
  border-color: rgba(255,59,48,0.3);
  color: var(--system-red);
}

/* ═══════════════════════════════════════════════════════════════════
   PREMIUM POLISH 2026-05-26 — Apple HIG micro-finishes
   Strictly additive: breaks no existing component and does
   nothing but enrich the depth / typography / focus details.
   All referenced variables are defined in :root.
   ═══════════════════════════════════════════════════════════════════ */

/* ─── Typography: tabular digits for financial/accounting values ─── */
.app-kpi-value,
.app-stat-value,
.price-callout-amount,
.app-table td .number,
.app-cell-amount {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1, 'kern' 1;
}

/* ─── Titles: fine letter spacing on large titles (Apple HIG) ─── */
.app-page-header h1 {
  font-feature-settings: 'kern' 1, 'ss01' 1;
}
.app-auth-title,
.app-kpi-value {
  font-feature-settings: 'kern' 1;
}

/* ─── Uniform focus ring: replaces ad-hoc box-shadows ─── */
.app-form input:focus,
.app-form select:focus,
.app-form textarea:focus,
.form-fancy input:focus,
.form-fancy textarea:focus,
.form-fancy select:focus,
.app-toolbar-search input:focus,
.app-toolbar-select select:focus {
  box-shadow: var(--ring-focus);
}

/* Slightly more pronounced labels (form readability) */
.app-form .app-label,
.form-fancy .form-label {
  font-weight: 600;
}

/* ─── Buttons: subtle tactile :active feedback (iOS-like) ──── */
.app-btn:active,
.app-toolbar-btn:active,
.form-submit-btn:active {
  transform: scale(0.985);
  transition-duration: 0.06s;
}
.app-btn-primary {
  /* Very light inner shadow to add volume to the filled button */
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10), 0 1px 2px rgba(0,0,0,0.10);
}
.app-btn-primary:hover {
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.12), 0 6px 18px rgba(0,0,0,0.18), 0 2px 4px rgba(0,0,0,0.08);
}

/* ─── Cards : natural cubic-bezier transition ─── */
.app-card,
.app-kpi,
.app-stat-card,
.app-card-clickable {
  transition:
    transform 0.18s var(--ease-spring),
    box-shadow 0.20s var(--ease-spring),
    border-color 0.18s ease;
}

/* ─── KPI: multi-layer shadows (already premium, adding a nuance) ─── */
.app-kpi {
  box-shadow: var(--shadow-soft);
}
.app-kpi:hover {
  box-shadow: var(--shadow-raised);
}
/* Very light categorical tints to indicate the KPI type
   (free use — apply `.app-kpi-tint-X` to the KPIs). */
.app-kpi-tint-revenue  { background: linear-gradient(180deg, rgba(52,199,89,0.04), var(--paper) 60%); }
.app-kpi-tint-students { background: linear-gradient(180deg, var(--accent-3-l), var(--paper) 60%); }
.app-kpi-tint-data     { background: linear-gradient(180deg, var(--accent-4-l), var(--paper) 60%); }
.app-kpi-tint-alert    { background: linear-gradient(180deg, rgba(255,149,0,0.05), var(--paper) 60%); }

/* ─── Dialogs <dialog> : frosted glass + ring focus (iOS / macOS sheet) ─── */
dialog {
  background: var(--bg-elevated);
  color: var(--label-primary);
  border: 1px solid var(--separator);
  border-radius: var(--radius-lg);
  padding: 0;
  box-shadow: var(--shadow-overlay);
  max-width: 92vw;
}
dialog::backdrop {
  background: rgba(0,0,0,0.32);
  -webkit-backdrop-filter: saturate(140%) blur(6px);
  backdrop-filter: saturate(140%) blur(6px);
}
:root[data-theme="dark"] dialog::backdrop {
  background: rgba(0,0,0,0.55);
}

/* “Liquid” appearance (Apple sheet): the box emerges with a slight
   overshoot (spring) instead of a flat fade — triggered automatically on dialog[open] */
@keyframes appDialogIn {
  0%   { opacity: 0; transform: translateY(14px) scale(0.94); }
  62%  { opacity: 1; transform: translateY(-2px) scale(1.008); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
dialog[open] {
  animation: appDialogIn 0.34s var(--ease-out-smooth);
}
/* Same opening for <div class="app-modal"> modals (.show system): animate
   the card (equivalent to the <dialog> box) with the SAME keyframes/duration →
   consistent opening across “Edit,” “Exam,” “Contact,” scheduling, etc. */
.app-modal.show .app-modal-card {
  animation: appDialogIn 0.34s var(--ease-out-smooth);
}
@media (prefers-reduced-motion: reduce) {
  dialog[open] { animation: none; }
  .app-modal.show .app-modal-card { animation: none; }
}

/* ─── Unified modal system (<dialog>) ──────────────────────────────
   Shared skeleton for all modals: Contact, Document, Code,
   Dossier, etc. Uses <dialog class="app-modal"> + sub-elements.
   All pages load app.css → shared CSS, zero duplication.
   ─────────────────────────────────────────────────────────────── */
/* Shared surface for ALL modals: <dialog class="app-modal"> AND the
   .app-modal/.app-modal-card system. ONE definition → identical rendering
   (adaptive glass), zero duplication. */
dialog.app-modal,
.app-modal-card {
  /* border-box: essential so padding (sometimes inline, e.g. record
     or code-modal) is INCLUDED in the width/height. Without it, on mobile, the
     box = width + padding overflowed the screen (408px > 390) and extended beyond its
     height without allowing scrolling. */
  box-sizing: border-box;
  border: 1px solid var(--lg-border, var(--separator));
  border-radius: 16px;
  box-shadow: var(--lg-highlight, 0 0 0 transparent), var(--lg-shadow-lg, var(--shadow-overlay, 0 32px 80px rgba(15,37,68,0.32)));
  background: var(--lg-surface-strong, var(--bg-elevated));
  -webkit-backdrop-filter: blur(30px) saturate(180%);
  backdrop-filter: blur(30px) saturate(180%);
  color: var(--label-primary);
  overflow: hidden;
}
/* Native dialog: sizing + centering handled by the browser (`::backdrop`). */
dialog.app-modal { max-width: 600px; width: calc(100% - 2rem); padding: 0; }
.app-modal-sm { max-width: 440px; }
.app-modal-lg { max-width: 820px; }
/* Overlay for the .app-modal system (no <dialog> → background div + flex centering). */
.app-modal {
  position: fixed; inset: 0; z-index: 1100;
  /* border-box: without it, inner padding was added to the screen width
     (446px on a 430px phone), and the pop-up was no longer centered. */
  box-sizing: border-box;
  display: none; align-items: center; justify-content: center; padding: 1rem;
  background: rgba(10, 18, 32, 0.28);
  /* NO backdrop-filter here: it would create a "backdrop root" that prevents
     the card (.app-modal-card, blur30) from blurring the PAGE — it would only blur
     the overlay, producing a different result from <dialog>. The card handles the blur. */
}
.app-modal.show { display: flex; }
/* An unopened <dialog> MUST remain hidden (UA display:none). The quick-add
   pop-ups use <dialog class="app-modal sheet">; but .sheet (css/sheet.css,
   KIT component div-sheet) declares “display:flex” and loads AFTER app.css →
   with equal specificity (0,1,0), it overrode .app-modal{display:none}, and with
   .app-modal{inset:0} the sheet was no longer pushed off-screen → the modals
   remained VISIBLE (blurred overlay) on the dashboard. Explicitly restore the
   hiding of closed <dialog> elements: specificity (0,2,1) → beats .sheet and .app-modal,
   without [open], therefore neutral as soon as showModal() opens it. */
dialog.app-modal:not([open]) { display: none; }
/* Native <dialog class="app-modal"> modals opened via showModal(): displayed by
   the [open] attribute (not .show). Unlike <div class="app-modal"> elements (full-screen
   overlay + centered .app-modal-card), here the <dialog> IS the box (content as
   direct children: header/body/footer or title/form/sections). So render it as
   a centered CARD stacked vertically (the overlay comes from the native ::backdrop).
   Without flex-direction:column, children were laid out IN A ROW (flex row) → broken CSS. */
dialog.app-modal[open] {
  display: flex;
  flex-direction: column;
  position: fixed;
  inset: 0;
  margin: auto;
  width: calc(100% - 2rem);
  max-width: 600px;
  height: fit-content;
  max-height: calc(100vh - 2rem);
  padding: 0;
  overflow: auto;
}
.app-modal-card {
  width: 100%; max-height: calc(100vh - 2rem);
  display: flex; flex-direction: column; box-sizing: border-box;
}
.app-modal-card.size-sm  { max-width: 380px; }
.app-modal-card.size-md  { max-width: 520px; }
.app-modal-card.size-lg  { max-width: 720px; }
.app-modal-card.size-xl  { max-width: 960px; }
.app-modal-card.size-xxl { max-width: min(1180px, 96vw); }

.app-modal-header,
.app-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.35rem 1.5rem 1.15rem;
  border-bottom: 1px solid var(--separator);
  gap: 0.8rem;
  flex-shrink: 0;
}
.app-modal-header h2,
.app-modal-header h3,
.app-modal-header h3,
.app-modal-title {
  margin: 0;
  font-size: 1.12rem;
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--label-primary);
  line-height: 1.25;
}
.app-modal-close,
.app-modal-close {
  background: var(--fill-quaternary);
  border: none;
  cursor: pointer;
  font-size: 1.25rem;
  line-height: 1;
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--label-secondary);
  border-radius: 50%;
  flex-shrink: 0;
  transition: background 0.15s ease, color 0.15s ease, transform 0.12s ease;
}
.app-modal-close:hover,
.app-modal-close:hover {
  background: var(--fill-tertiary);
  color: var(--label-primary);
  transform: scale(1.06);
}
.app-modal-close:active,
.app-modal-close:active { transform: scale(0.94); }

.app-modal-body,
.app-modal-body {
  padding: 1.35rem 1.5rem;
  overflow-y: auto;
}
.app-modal-body { max-height: calc(85vh - 9rem); }
.app-modal-body { flex: 1 1 auto; min-height: 0; }  /* scroll inside the flex card */
.app-modal-body > p:first-child { margin-top: 0; }
.app-modal-body > p:last-child  { margin-bottom: 0; }

/* Subsection inside the body (rounded fieldset style) */
.app-modal-section {
  margin-top: 1rem;
  padding: 0.95rem 1.1rem;
  border: 1px solid var(--separator);
  border-radius: 10px;
  background: var(--fill-quaternary);
}
.app-modal-section:first-child { margin-top: 0; }
.app-modal-section-title {
  margin: 0 0 0.6rem;
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--label-secondary);
}

/* Form fields in modal (labels + inputs) */
.app-modal-field {
  display: block;
  margin-bottom: 1rem;
}
.app-modal-field:last-child { margin-bottom: 0; }
.app-modal-label {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--label-primary);
  margin-bottom: 0.45rem;
}
.app-modal input[type="text"],
.app-modal input[type="email"],
.app-modal input[type="tel"],
.app-modal input[type="number"],
.app-modal input[type="date"],
.app-modal input[type="datetime-local"],
.app-modal input[type="file"],
.app-modal select,
.app-modal textarea,
.app-modal-card input:not([type="checkbox"]):not([type="radio"]),
.app-modal-card select,
.app-modal-card textarea {
  width: 100%;
  padding: 0.7rem 0.85rem;
  border: 1.5px solid var(--separator);
  border-radius: 10px;
  font-family: inherit;
  font-size: 0.93rem;
  background: var(--bg-secondary);
  color: var(--label-primary);
  box-sizing: border-box;
  transition: border-color 0.15s, box-shadow 0.18s, background 0.15s;
}
.app-modal input[type="file"],
.app-modal-card input[type="file"] { padding: 0.5rem 0.85rem; }
.app-modal input:hover:not(:focus),
.app-modal select:hover:not(:focus),
.app-modal textarea:hover:not(:focus),
.app-modal-card input:hover:not(:focus),
.app-modal-card select:hover:not(:focus),
.app-modal-card textarea:hover:not(:focus) {
  border-color: var(--separator-opaque);
}
.app-modal input:focus,
.app-modal select:focus,
.app-modal textarea:focus,
.app-modal-card input:focus,
.app-modal-card select:focus,
.app-modal-card textarea:focus {
  outline: none;
  border-color: var(--tint);
  box-shadow: 0 0 0 4px var(--fill-primary);
  background-color: var(--bg-elevated);
}
.app-modal textarea,
.app-modal-card textarea { resize: vertical; min-height: 110px; }
/* Modal selects: same chevron as .app-form select (no more native OS arrow) */
.app-modal select,
.app-modal-card select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  padding-right: 2.5rem;
}

/* Cartes radio (Email/SMS, etc.) */
.app-modal-radio-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.6rem;
  margin-bottom: 1.1rem;
}
.app-modal-radio-card {
  display: flex;
  gap: 0.6rem;
  align-items: center;
  padding: 0.75rem 0.9rem;
  border: 1.5px solid var(--separator);
  border-radius: 10px;
  cursor: pointer;
  font-size: 0.92rem;
  background: var(--bg-secondary);
  transition: border-color 0.15s, background 0.15s, box-shadow 0.15s;
}
.app-modal-radio-card:hover { background: var(--bg-elevated); }
.app-modal-radio-card:has(input:disabled) { opacity: 0.45; cursor: not-allowed; }
.app-modal-radio-card:has(input:checked) {
  border-color: var(--tint);
  background: var(--bg-elevated);
  box-shadow: 0 0 0 3px var(--fill-primary);
}
.app-modal-radio-card input { margin: 0; accent-color: var(--tint); }
.app-modal-radio-card > span {
  display: flex; flex-direction: column;
  line-height: 1.3; font-weight: 600;
}
.app-modal-radio-card small {
  font-size: 0.74rem; font-weight: 400;
  color: var(--label-secondary); margin-top: 0.15rem;
}

/* Footer pinned to the bottom (action buttons) */
.app-modal-footer,
.app-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  padding: 0.95rem 1.5rem;
  border-top: 1px solid var(--separator);
  background: var(--bg-tertiary);
  border-radius: 0 0 16px 16px;
  flex-wrap: wrap;
  flex-shrink: 0;
}

/* Specific to the .app-modal system (markup label > span, form-grid, etc. —
   no <dialog>). The rest of the style is shared with .app-modal above. */
.app-modal-body label { display: block; margin-bottom: 0.95rem; }
.app-modal-body label > span {
  display: block; font-size: 0.82rem; font-weight: 600;
  color: var(--label-primary); margin-bottom: 0.4rem;
}
.app-modal-body .form-grid {
  display: grid; gap: 0.95rem;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.app-modal-body .form-row-full { grid-column: 1 / -1; }
.app-modal-card input[type="checkbox"],
.app-modal-card input[type="radio"] {
  accent-color: var(--tint); width: 18px; height: 18px; cursor: pointer;
}
.app-modal-footer .app-btn-secondary {
  background: var(--bg-secondary); color: var(--label-primary);
  border: 1.5px solid var(--separator);
}
.app-modal-footer .app-btn-secondary:hover {
  background: var(--bg-elevated); border-color: var(--separator-opaque);
}
.app-modal-error {
  margin: 0 1.5rem 1rem; padding: 0.85rem 1.1rem;
  background: rgba(255, 59, 48, 0.08); color: var(--label-primary);
  border-left: 3px solid var(--system-red); border-radius: 10px;
  font-size: 0.88rem; display: none;
}
.app-modal-error.show { display: block; }
.app-modal-error ul { margin: 0.4rem 0 0 1.2rem; padding: 0; }
@media (max-width: 540px) {
  .app-modal-card { max-width: 100% !important; max-height: calc(100vh - 1rem); }
  .app-modal-footer { flex-direction: column-reverse; }
  .app-modal-footer .app-btn { width: 100%; }
}

/* Errors in modal */
.app-modal-error {
  margin-top: 0.5rem;
  padding: 0.7rem 0.95rem;
  background: rgba(255, 59, 48, 0.08);
  color: #a51d14;
  border-left: 3px solid var(--system-red, #ff3b30);
  border-radius: 10px;
  font-size: 0.88rem;
}

/* Backdrop: already defined on dialog::backdrop in the previous section,
   but force blur for app modals (consistent with macOS sheets). */
.app-modal::backdrop {
  background: rgba(10, 18, 32, 0.28);
  /* No blur on the overlay (consistent with <div> modals): the glass box
     (dialog.app-modal / .app-modal-card, blur30) blurs the page. */
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

@media (max-width: 560px) {
  .app-modal-radio-grid { grid-template-columns: 1fr; }
  .app-modal {
    width: calc(100% - 1rem);
    border-radius: 16px;
  }
  .app-modal-header { padding: 1.1rem 1.2rem 1rem; }
  .app-modal-body   { padding: 1.1rem 1.2rem; }
  .app-modal-footer {
    padding: 1rem 1.2rem;
    flex-direction: column-reverse;
  }
  .app-modal-footer .app-btn { width: 100%; }
}

/* ─── Horizontal scrolling affordance for tables ─────────────────────
   page-loader.js sets .can-scroll-left / .can-scroll-right on containers
   that scroll (.app-table-scroll / .app-table-wrap / .compo-tablewrap) based
   on position: a shadow is painted at the edge where more columns remain.
   The default background-attachment (scroll) keeps the shadow fixed at the edge
   while the content scrolls. No opaque strip: “glass” panels
   (signature-premium) remain translucent. Placed AFTER the shortened background
   rule for .app-table-wrap (above) so the image survives. */
.app-table-scroll, .app-table-wrap, .compo-tablewrap {
  --edge-hint-l: transparent;
  --edge-hint-r: transparent;
  background-image:
    radial-gradient(farthest-side at 0 50%, var(--edge-hint-l), transparent),
    radial-gradient(farthest-side at 100% 50%, var(--edge-hint-r), transparent);
  background-position: left center, right center;
  background-size: 14px 100%, 14px 100%;
  background-repeat: no-repeat;
}
.can-scroll-left { --edge-hint-l: var(--edge-hint, rgba(11, 27, 58, 0.22)); }
.can-scroll-right { --edge-hint-r: var(--edge-hint, rgba(11, 27, 58, 0.22)); }
:root[data-theme="dark"] .can-scroll-left,
:root[data-theme="dark"] .can-scroll-right { --edge-hint: rgba(0, 0, 0, 0.6); }

/* ─── Tables: subtle sticky header (useful on long lists) ─── */
.app-table-wrap {
  box-shadow: var(--shadow-soft);
}
.app-table-wrap.sticky-head thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--paper);
  backdrop-filter: saturate(120%);
}

/* ─── Teacher tablet mode (current lesson page) ─────────────────
   Larger touch targets, more visible primary buttons, inputs
   comfortable for touch-screen use inside a
   vehicle (sometimes moving, gloves possible).
   ─────────────────────────────────────────────────────────────── */
.lesson-tablet .app-btn {
  min-height: 48px;
  padding: 0.85rem 1.4rem;
  font-size: 0.95rem;
  font-weight: 600;
}
.lesson-tablet .app-btn-primary {
  min-height: 52px;
  padding: 1rem 1.6rem;
  font-size: 1rem;
  box-shadow: 0 4px 12px rgba(15, 37, 68, 0.15);
}
.lesson-tablet .app-form input[type="text"],
.lesson-tablet .app-form input[type="number"],
.lesson-tablet .app-form input[type="time"],
.lesson-tablet .app-form input[type="date"],
.lesson-tablet .app-form select,
.lesson-tablet .app-form textarea {
  min-height: 48px;
  padding: 0.85rem 1rem;
  font-size: 1rem;
  border-radius: 10px;
}
.lesson-tablet .app-form textarea {
  min-height: 110px;
}
.lesson-tablet .app-form label {
  display: block;
  margin-bottom: 1rem;
}
.lesson-tablet .app-card {
  padding: 1.4rem 1.5rem;
}
/* Larger radio buttons/checkboxes for touch */
.lesson-tablet input[type="radio"],
.lesson-tablet input[type="checkbox"] {
  width: 20px;
  height: 20px;
  accent-color: var(--tint);
}
/* Competency grids: larger cells */
.lesson-tablet .competence-grid label,
.lesson-tablet .competence-row {
  min-height: 56px;
  padding: 0.7rem 0.95rem;
}
@media (max-width: 720px) {
  .lesson-tablet .app-form > div[style*="grid-template-columns"] {
    grid-template-columns: 1fr !important;
  }
}

/* ─── Segmented control (Settings / HR sub-tabs) ────────────────
   iOS UISegmentedControl — pill background with filled active tab.
   Used by parametres-tabs.ejs and hr-tabs.ejs. */
.parameters-tabs {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--fill-tertiary);
  border-radius: var(--radius-md, 10px);
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
}
.param-tab {
  padding: 0.5rem 0.95rem;
  font-size: 0.86rem;
  font-weight: 500;
  color: var(--label-secondary);
  text-decoration: none;
  border-radius: 8px;
  white-space: nowrap;
  transition: background 0.18s ease, color 0.18s ease, box-shadow 0.18s ease;
}
.param-tab:hover { color: var(--label-primary); background: var(--fill-quaternary); }
.param-tab.is-active {
  color: var(--label-primary);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm), 0 0 0 0.5px var(--separator);
  font-weight: 600;
}

/* ─── Settings: tabs grouped into labeled sections ────────────────────
   parametres-tabs.ejs (grouped version). Each section is a small
   segmented control topped by a label. hr-tabs.ejs keeps the flat
   .parametres-tabs bar above — do not mix the two. */
.param-sections {
  display: flex;
  flex-wrap: wrap;
  gap: 1.1rem 1.5rem;
  align-items: flex-start;
  margin-bottom: 1.5rem;
}
.param-group { display: flex; flex-direction: column; gap: 0.4rem; }
.param-group-label {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--label-tertiary, var(--label-secondary));
  padding-left: 0.3rem;
}
.param-group-tabs {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--fill-tertiary);
  border-radius: var(--radius-md, 10px);
  flex-wrap: wrap;
}
@media (max-width: 720px) {
  .param-sections { gap: 0.9rem; }
  .param-group { width: 100%; }
  .param-group-tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; flex-wrap: nowrap; }
  .param-group-tabs::-webkit-scrollbar { display: none; }
}

/* ─── Section tags: soft variants using the expanded palette ─── */
.app-section-tag-indigo { background: var(--accent-3-l); color: var(--accent-3); }
.app-section-tag-teal   { background: var(--accent-4-l); color: var(--accent-4); }

/* ─── Tags: aligned with the new palette ─── */
.app-tag-indigo { background: var(--accent-3-l); color: var(--accent-3); }
.app-tag-teal   { background: var(--accent-4-l); color: var(--accent-4); }

/* ─── Nav: more natural hover transitions ─── */
.app-nav-links a {
  transition:
    background-color 0.16s var(--ease-spring),
    color 0.16s ease;
}

/* ─── Input hover: path feedback (before focus) ─── */
.app-form input:not(:focus):hover,
.app-form select:not(:focus):hover,
.app-form textarea:not(:focus):hover {
  border-color: var(--separator-opaque);
}

/* ─── Clickable card: gentler lift instead of the brutal -3px jump ─── */
.app-card-clickable:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-raised);
}

/* ─── Smooth scroll global (Apple-like) ─── */
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* ─── Links: never use the browser's underlined blue (monochrome app) ───
   “Raw” links (without a class) use the current text color; the
   underline appears only on hover and only for them (styled links
   — buttons, cells, nav — keep their own rendering through more
   specific selectors). */
a { color: inherit; text-decoration: none; }
a:not([class]):hover { text-decoration: underline; }

/* ─── Text selection: color consistent with the tint ─── */
::selection {
  background: var(--fill-primary);
  color: var(--label-primary);
}

/* ─── Scrollbar fine (WebKit/Blink) — Apple touch ─── */
*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
*::-webkit-scrollbar-thumb {
  background: var(--separator);
  border-radius: 100px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover {
  background: var(--separator-opaque);
  background-clip: padding-box;
  border: 2px solid transparent;
}
*::-webkit-scrollbar-track { background: transparent; }


/* ──────────────────────────────────────────────────────────────────────
 * Apple System Colors — thematic color by section (2026-05-26)
 * ──────────────────────────────────────────────────────────────────────
 * Inspired by iOS Settings: each major section has its own color. The color
 * serves as a visual indicator, not as gratuitous decoration.
 *
 * Opt-in classes:
 *  - .nav-icon            : rounded 28×28 box around nav SVGs
 *                           (color applied via the .nav-icon-{section} class)
 *  - .app-tag-{color}     : badge (already: indigo, teal, blue, green, etc.)
 *  - .app-btn-{color}     : tinted variant of .app-btn-primary
 *  - .app-kpi-tint-{name} : soft gradient background for a category
 *  - .app-section-bar-{c} : vertical bar left of a section title
 *  - .app-empty-tint-{c}  : empty state with a lightly colored background
 * ────────────────────────────────────────────────────────────────────── */

/* iOS Settings-style colored box around nav icons.
   Set it on the <span class="nav-icon"> that wraps the SVG.
   Remains backward-compatible: existing navs without .nav-icon continue
   to display their inline SVG. */
.app-nav-links a .nav-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  margin-right: 0.45rem;
  flex-shrink: 0;
  background: var(--fill-secondary);
  color: var(--label-secondary);
  transition: background 0.15s ease, color 0.15s ease, transform 0.15s var(--ease-spring);
}
.app-nav-links a .nav-icon svg {
  width: 14px;
  height: 14px;
  display: block;
  stroke: currentColor;
}
.app-nav-links a:hover .nav-icon  { transform: scale(1.04); }
.app-nav-links a.active .nav-icon { box-shadow: 0 1px 2px rgba(0,0,0,0.18); }

/* Larger client-side nav icons (schools / students / instructors).
   The admin back office (.app-nav-admin) keeps its original size. Julien's request. */
.app-nav:not(.app-nav-admin) .app-nav-links a .nav-icon { width: 36px; height: 36px; border-radius: 9px; }
.app-nav:not(.app-nav-admin) .app-nav-links a .nav-icon svg { width: 22px; height: 22px; }
/* Slightly more readable badge on the enlarged icon. */
.app-nav:not(.app-nav-admin) .app-nav-links a .nav-badge { min-width: 17px; height: 17px; line-height: 17px; font-size: 0.62rem; top: -6px; right: -7px; }

/* Notification badge placed on a section icon (same style as
   messaging). The count is injected by JS from /management/notifications.json. */
.app-nav-links a .nav-icon { position: relative; }
.app-nav-links a .nav-badge {
  position: absolute; top: -5px; right: -6px;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 999px; background: var(--system-red, #ff3b30);
  color: #fff; font-size: 0.6rem; font-weight: 700; line-height: 16px;
  text-align: center; box-shadow: 0 0 0 2px var(--bg-secondary, #fff);
  pointer-events: none;
}
.app-nav-links a .nav-badge[hidden] { display: none; }

/* Themed variants: saturated background + white icon (on light nav) */
.nav-icon-blue   { background: var(--sys-blue)   !important; color: #fff !important; }
.nav-icon-indigo { background: var(--sys-indigo) !important; color: #fff !important; }
.nav-icon-purple { background: var(--sys-purple) !important; color: #fff !important; }
.nav-icon-pink   { background: var(--sys-pink)   !important; color: #fff !important; }
.nav-icon-red    { background: var(--sys-red)    !important; color: #fff !important; }
.nav-icon-orange { background: var(--sys-orange) !important; color: #fff !important; }
.nav-icon-yellow { background: var(--sys-yellow) !important; color: #1a1a1a !important; }
.nav-icon-green  { background: var(--sys-green)  !important; color: #fff !important; }
.nav-icon-mint   { background: var(--sys-mint)   !important; color: #1a1a1a !important; }
.nav-icon-teal   { background: var(--sys-teal)   !important; color: #fff !important; }
.nav-icon-cyan   { background: var(--sys-cyan)   !important; color: #1a1a1a !important; }
.nav-icon-gray   { background: var(--sys-gray)   !important; color: #fff !important; }
.nav-icon-brown  { background: var(--sys-brown)  !important; color: #fff !important; }

/* Back-office admin (.app-nav-admin, dark gradient): keeps the saturated boxes
   (white icons, readable on a dark background). CLIENT navs (school / instructor /
   student / parent) switch to the “Apple” style: outline glyph, and only the module
   ACTIVE (clicked) returns to a SOLID SQUARE in ITS color (.nav-icon-<couleur>). The
   color marks the current screen + notification badges, not the whole row. */
html:not(.nav-layout-side) .app-nav:not(.app-nav-admin) .app-nav-links a:not(.active) .nav-icon {
  background: transparent !important;
  color: color-mix(in srgb, var(--label-primary) 68%, transparent) !important;
  box-shadow: none !important;
}
html:not(.nav-layout-side) .app-nav:not(.app-nav-admin) .app-nav-links a:not(.active):hover .nav-icon { color: var(--label-primary) !important; }
/* Active: do NOT override the background → the .nav-icon-<couleur> class above
   takes over (--sys-X background + white glyph). Julien's request: “the square
   in color rather than black.” */
/* A school's branded nav uses the SAME treatment: since Liquid Glass,
   its bar is the glass material (the app.css:4139 brand gradient is replaced by
   liquid-glass.css, loaded afterwards) — so line glyphs + active in --brand-primary
   (the school's color), perfectly readable on the glass. No dedicated rule. */
/* Julien's request (2026-06-10): NO “frame” (active-link background badge)
   around the colored square. On glass + a bright seasonal background, this badge
   `a.active` (translucent grey) picked up the tint and formed an ugly frame. The
   current screen is already indicated by the colored icon + bold label → remove the
   badge for CLIENT navs. Admin (opaque dark nav) keeps its own. */
.app-nav:not(.app-nav-admin) .app-nav-links a.active { background: transparent !important; }
.app-nav:not(.app-nav-admin) .app-nav-links a:hover  { background: transparent !important; }

/* ─── Navigation “Appearance” popover (theme-switch.ejs, showIntensity) ───
   Holds the background intensity slider for ALL user roles (student /
   instructor / parent / client) without widening the bar. Glass surface = same tokens
   as the rest of the Liquid Glass system → adapts to light/dark automatically. */
.app-appearance-wrap { position: relative; display: inline-flex; align-items: center; }
.app-appearance-trigger { color: var(--label-secondary, #6b7280); }
.app-appearance-trigger[aria-expanded="true"] { color: var(--label-primary); background: var(--off, rgba(0,0,0,0.05)); }
/* Super-nav navy (super-admin area): the intensity button uses app-btn-ghost
   (light background + border, designed for light surfaces) → it clashes with navy. Align it
   EXACTLY with the other bar icons (.app-nav-icon-btn).
   Scoped to .app-nav-admin → no impact on light navs (client/instructor). */
.app-nav-admin .app-btn-ghost.app-appearance-trigger {
  width: 38px; height: 38px; padding: 0; justify-content: center;
  background: transparent; border: none; border-radius: 8px;
  box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none;
  color: rgba(255, 255, 255, 0.7); transition: background 0.15s, color 0.15s;
}
.app-nav-admin .app-appearance-trigger svg { width: 18px; height: 18px; }
.app-nav-admin .app-btn-ghost.app-appearance-trigger:hover { background: rgba(255, 255, 255, 0.08); color: #fff; border-color: transparent; }
.app-nav-admin .app-btn-ghost.app-appearance-trigger[aria-expanded="true"] { background: rgba(255, 255, 255, 0.15); color: #fff; }
.app-appearance-pop {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 1200;
  width: 248px;
  padding: 0.9rem 1rem 1rem;
  background: var(--lg-surface-strong, var(--bg-elevated, #fff));
  border: 1px solid var(--lg-border, rgba(0,0,0,0.08));
  border-radius: 16px;
  box-shadow: var(--lg-highlight, none), var(--lg-shadow-lg, 0 16px 44px rgba(0,0,0,0.20));
  -webkit-backdrop-filter: blur(var(--lg-blur-card, 18px)) saturate(1.6);
  backdrop-filter: blur(var(--lg-blur-card, 18px)) saturate(1.6);
}
.app-appearance-pop[hidden] { display: none; }
.app-appearance-pop-title { font-weight: 650; font-size: 0.86rem; margin: 0 0 0.7rem; color: var(--label-primary); }
.app-appearance-pop-row { display: flex; align-items: center; gap: 0.55rem; }
.app-appearance-pop-row span { font-size: 0.72rem; color: var(--label-tertiary, #9ca3af); white-space: nowrap; }
.app-appearance-pop-row input[type="range"] { flex: 1; min-width: 0; accent-color: var(--brand-primary, var(--brand-navy)); cursor: pointer; }
.app-appearance-pop-note { margin: 0.7rem 0 0; font-size: 0.72rem; line-height: 1.4; color: var(--label-tertiary, #9ca3af); }
/* Tablet/mobile: nav-user moves into the drawer and the button can be anywhere
   in the row → a popover anchored to the trigger would overflow. Switch it to
   a SHEET anchored to the bottom of the screen (fixed + L/R margins): width constrained by the
   viewport, so overflow is impossible, and it is the natural mobile gesture.
   Remains a DOM descendant of .app-appearance-wrap → outside-click still works. */
@media (max-width: 768px) {
  .app-appearance-pop {
    position: fixed;
    top: auto;
    left: 12px;
    right: 12px;
    bottom: 14px;
    width: auto;
    z-index: 2000;
    /* Opaque sheet (readable over the drawer) + dark full-screen backdrop
       (spread box-shadow, no added element): a true action sheet. The overlay
       does not intercept clicks → tapping outside closes it (click outside .app-appearance-wrap). */
    background: var(--bg-elevated, #fff);
    box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.34), 0 -8px 30px rgba(0, 0, 0, 0.18);
  }
}

/* ─── Tags: full palette (adds to app-tag-blue/green/amber/red/purple/slate/indigo/teal) ─── */
.app-tag-pink   { background: var(--sys-pink-soft);   color: var(--sys-pink); }
.app-tag-orange { background: var(--sys-orange-soft); color: var(--sys-orange); }
.app-tag-yellow { background: var(--sys-yellow-soft); color: #b47e00; }
.app-tag-mint   { background: var(--sys-mint-soft);   color: #0d8e87; }
.app-tag-cyan   { background: var(--sys-cyan-soft);   color: #0c89c2; }
.app-tag-gray   { background: var(--sys-gray-soft);   color: var(--sys-gray); }
.app-tag-brown  { background: var(--sys-brown-soft);  color: #7c5f3e; }
/* In dark mode: lighter text (soft-* values are already made more opaque by data-theme dark) */
:root[data-theme="dark"] .app-tag-yellow { color: var(--sys-yellow); }
:root[data-theme="dark"] .app-tag-mint   { color: var(--sys-mint); }
:root[data-theme="dark"] .app-tag-cyan   { color: var(--sys-cyan); }
:root[data-theme="dark"] .app-tag-brown  { color: var(--sys-brown); }

/* ─── Section tags: equivalent (existing) — palette extensions ─── */
.app-section-tag-blue   { background: var(--sys-blue-soft);   color: var(--sys-blue); }
.app-section-tag-red    { background: var(--sys-red-soft);    color: var(--sys-red); }
.app-section-tag-orange { background: var(--sys-orange-soft); color: var(--sys-orange); }
.app-section-tag-yellow { background: var(--sys-yellow-soft); color: #b47e00; }
.app-section-tag-mint   { background: var(--sys-mint-soft);   color: #0d8e87; }
.app-section-tag-cyan   { background: var(--sys-cyan-soft);   color: #0c89c2; }
.app-section-tag-gray   { background: var(--sys-gray-soft);   color: var(--sys-gray); }
:root[data-theme="dark"] .app-section-tag-yellow { color: var(--sys-yellow); }
:root[data-theme="dark"] .app-section-tag-mint   { color: var(--sys-mint); }
:root[data-theme="dark"] .app-section-tag-cyan   { color: var(--sys-cyan); }

/* ─── Themed action buttons (derived from .app-btn-primary) ─── */
.app-btn-blue,
.app-btn-indigo,
.app-btn-purple,
.app-btn-pink,
.app-btn-red,
.app-btn-orange,
.app-btn-yellow,
.app-btn-green,
.app-btn-mint,
.app-btn-teal,
.app-btn-cyan,
.app-btn-gray,
.app-btn-brown {
  color: #fff;
  border: 1.5px solid transparent;
  box-shadow: 0 1px 2px rgba(0,0,0,0.06), inset 0 1px 0 rgba(255,255,255,0.12);
  transition: filter 0.15s ease, transform 0.10s ease;
}
.app-btn-blue   { background: var(--sys-blue);   border-color: var(--sys-blue); }
.app-btn-indigo { background: var(--sys-indigo); border-color: var(--sys-indigo); }
.app-btn-purple { background: var(--sys-purple); border-color: var(--sys-purple); }
.app-btn-pink   { background: var(--sys-pink);   border-color: var(--sys-pink); }
.app-btn-red    { background: var(--sys-red);    border-color: var(--sys-red); }
.app-btn-orange { background: var(--sys-orange); border-color: var(--sys-orange); }
.app-btn-yellow { background: var(--sys-yellow); border-color: var(--sys-yellow); color: #1a1a1a; }
.app-btn-green  { background: var(--sys-green);  border-color: var(--sys-green); }
.app-btn-mint   { background: var(--sys-mint);   border-color: var(--sys-mint); color: #0a3633; }
.app-btn-teal   { background: var(--sys-teal);   border-color: var(--sys-teal); }
.app-btn-cyan   { background: var(--sys-cyan);   border-color: var(--sys-cyan); color: #0a2533; }
.app-btn-gray   { background: var(--sys-gray);   border-color: var(--sys-gray); }
.app-btn-brown  { background: var(--sys-brown);  border-color: var(--sys-brown); }
.app-btn-blue:hover,
.app-btn-indigo:hover,
.app-btn-purple:hover,
.app-btn-pink:hover,
.app-btn-red:hover,
.app-btn-orange:hover,
.app-btn-yellow:hover,
.app-btn-green:hover,
.app-btn-mint:hover,
.app-btn-teal:hover,
.app-btn-cyan:hover,
.app-btn-gray:hover,
.app-btn-brown:hover { filter: brightness(0.94); }

/* Dark mode: keep the bright colors (lit through the dark variables) */
:root[data-theme="dark"] .app-btn-blue,
:root[data-theme="dark"] .app-btn-indigo,
:root[data-theme="dark"] .app-btn-purple,
:root[data-theme="dark"] .app-btn-pink,
:root[data-theme="dark"] .app-btn-red,
:root[data-theme="dark"] .app-btn-orange,
:root[data-theme="dark"] .app-btn-green,
:root[data-theme="dark"] .app-btn-teal,
:root[data-theme="dark"] .app-btn-gray,
:root[data-theme="dark"] .app-btn-brown { color: #fff !important; }
:root[data-theme="dark"] .app-btn-yellow,
:root[data-theme="dark"] .app-btn-mint,
:root[data-theme="dark"] .app-btn-cyan  { color: #1a1a1a !important; }

/* ─── KPI tints : extensions palette System (light gradient vers paper) ─── */
.app-kpi-tint-blue   { background: linear-gradient(180deg, var(--sys-blue-soft),   var(--paper) 60%); }
.app-kpi-tint-indigo { background: linear-gradient(180deg, var(--sys-indigo-soft), var(--paper) 60%); }
.app-kpi-tint-purple { background: linear-gradient(180deg, var(--sys-purple-soft), var(--paper) 60%); }
.app-kpi-tint-pink   { background: linear-gradient(180deg, var(--sys-pink-soft),   var(--paper) 60%); }
.app-kpi-tint-red    { background: linear-gradient(180deg, var(--sys-red-soft),    var(--paper) 60%); }
.app-kpi-tint-orange { background: linear-gradient(180deg, var(--sys-orange-soft), var(--paper) 60%); }
.app-kpi-tint-yellow { background: linear-gradient(180deg, var(--sys-yellow-soft), var(--paper) 60%); }
.app-kpi-tint-green  { background: linear-gradient(180deg, var(--sys-green-soft),  var(--paper) 60%); }
.app-kpi-tint-mint   { background: linear-gradient(180deg, var(--sys-mint-soft),   var(--paper) 60%); }
.app-kpi-tint-teal   { background: linear-gradient(180deg, var(--sys-teal-soft),   var(--paper) 60%); }
.app-kpi-tint-cyan   { background: linear-gradient(180deg, var(--sys-cyan-soft),   var(--paper) 60%); }
.app-kpi-tint-gray   { background: linear-gradient(180deg, var(--sys-gray-soft),   var(--paper) 60%); }
.app-kpi-tint-brown  { background: linear-gradient(180deg, var(--sys-brown-soft),  var(--paper) 60%); }

/* ─── Section bar: colored vertical bar to the left of a section title
       (add the class to an <h2> or an .app-section-header) ─── */
.app-section-bar-blue,
.app-section-bar-indigo,
.app-section-bar-purple,
.app-section-bar-pink,
.app-section-bar-red,
.app-section-bar-orange,
.app-section-bar-yellow,
.app-section-bar-green,
.app-section-bar-mint,
.app-section-bar-teal,
.app-section-bar-cyan,
.app-section-bar-gray,
.app-section-bar-brown {
  padding-left: 0.7rem;
  border-left: 3px solid currentColor;
}
.app-section-bar-blue   { color: var(--sys-blue); }
.app-section-bar-indigo { color: var(--sys-indigo); }
.app-section-bar-purple { color: var(--sys-purple); }
.app-section-bar-pink   { color: var(--sys-pink); }
.app-section-bar-red    { color: var(--sys-red); }
.app-section-bar-orange { color: var(--sys-orange); }
.app-section-bar-yellow { color: #b47e00; }
.app-section-bar-green  { color: var(--sys-green); }
.app-section-bar-mint   { color: #0d8e87; }
.app-section-bar-teal   { color: var(--sys-teal); }
.app-section-bar-cyan   { color: #0c89c2; }
.app-section-bar-gray   { color: var(--sys-gray); }
.app-section-bar-brown  { color: #7c5f3e; }
:root[data-theme="dark"] .app-section-bar-yellow { color: var(--sys-yellow); }
:root[data-theme="dark"] .app-section-bar-mint   { color: var(--sys-mint); }
:root[data-theme="dark"] .app-section-bar-cyan   { color: var(--sys-cyan); }
:root[data-theme="dark"] .app-section-bar-brown  { color: var(--sys-brown); }
/* Force navy/text on the title itself for readability; the color
   is only used by the bar through currentColor → border-left */
.app-section-bar-blue,
.app-section-bar-indigo,
.app-section-bar-purple,
.app-section-bar-pink,
.app-section-bar-red,
.app-section-bar-orange,
.app-section-bar-yellow,
.app-section-bar-green,
.app-section-bar-mint,
.app-section-bar-teal,
.app-section-bar-cyan,
.app-section-bar-gray,
.app-section-bar-brown { /* the colour above drives the bar through currentColor */ }
.app-section-bar-blue   > h1, .app-section-bar-blue   > h2,
.app-section-bar-indigo > h1, .app-section-bar-indigo > h2,
.app-section-bar-purple > h1, .app-section-bar-purple > h2,
.app-section-bar-pink   > h1, .app-section-bar-pink   > h2,
.app-section-bar-red    > h1, .app-section-bar-red    > h2,
.app-section-bar-orange > h1, .app-section-bar-orange > h2,
.app-section-bar-yellow > h1, .app-section-bar-yellow > h2,
.app-section-bar-green  > h1, .app-section-bar-green  > h2,
.app-section-bar-mint   > h1, .app-section-bar-mint   > h2,
.app-section-bar-teal   > h1, .app-section-bar-teal   > h2,
.app-section-bar-cyan   > h1, .app-section-bar-cyan   > h2,
.app-section-bar-gray   > h1, .app-section-bar-gray   > h2,
.app-section-bar-brown  > h1, .app-section-bar-brown  > h2 { color: var(--navy); }

/* ─── Tinted empty states (pale background in the theme color) ─── */
.app-empty-tint-blue,
.app-empty-tint-indigo,
.app-empty-tint-purple,
.app-empty-tint-pink,
.app-empty-tint-red,
.app-empty-tint-orange,
.app-empty-tint-yellow,
.app-empty-tint-green,
.app-empty-tint-mint,
.app-empty-tint-teal,
.app-empty-tint-cyan,
.app-empty-tint-gray,
.app-empty-tint-brown {
  border-radius: var(--radius-md);
  border: 1px dashed var(--separator);
}
.app-empty-tint-blue   { background: var(--sys-blue-soft); }
.app-empty-tint-indigo { background: var(--sys-indigo-soft); }
.app-empty-tint-purple { background: var(--sys-purple-soft); }
.app-empty-tint-pink   { background: var(--sys-pink-soft); }
.app-empty-tint-red    { background: var(--sys-red-soft); }
.app-empty-tint-orange { background: var(--sys-orange-soft); }
.app-empty-tint-yellow { background: var(--sys-yellow-soft); }
.app-empty-tint-green  { background: var(--sys-green-soft); }
.app-empty-tint-mint   { background: var(--sys-mint-soft); }
.app-empty-tint-teal   { background: var(--sys-teal-soft); }
.app-empty-tint-cyan   { background: var(--sys-cyan-soft); }
.app-empty-tint-gray   { background: var(--sys-gray-soft); }
.app-empty-tint-brown  { background: var(--sys-brown-soft); }


/* ──────────────────────────────────────────────────────────────────────
 * Custom Branding (premium option) — 2026-05-26
 * ──────────────────────────────────────────────────────────────────────
 * When a school enables Custom Branding, its pages inject
 *   <style>:root { --brand-primary: #xxxxxx; }</style>
 * at the top. The selectors below apply this variable to
 * strategic places in the app (nav header + primary buttons +
 * active tab pills), with --navy as fallback (app branding).
 *
 * The fallback matters: if the variable is not defined, the app
 * keeps the application's own look — no broken cascade.
 * ────────────────────────────────────────────────────────────────────── */

/* Navigation: tinted background when a school has active branding */
.app-nav.app-nav-branded {
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--brand-primary, var(--navy)) 92%, transparent),
    color-mix(in srgb, var(--brand-primary, var(--navy)) 80%, transparent));
  border-bottom-color: transparent;
  color: #fff;
}
.app-nav.app-nav-branded .app-nav-brand,
.app-nav.app-nav-branded .app-nav-user-name,
.app-nav.app-nav-branded .app-nav-user-info { color: #fff; }
.app-nav.app-nav-branded .app-nav-brand small { color: rgba(255,255,255,0.78); font-weight: 400; }
.app-nav.app-nav-branded .app-nav-user-sub { color: rgba(255,255,255,0.7); }
.app-nav.app-nav-branded .app-nav-links a { color: rgba(255,255,255,0.75); }
.app-nav.app-nav-branded .app-nav-links a:hover { background: rgba(255,255,255,0.10); color: #fff; }
.app-nav.app-nav-branded .app-nav-links a.active { background: rgba(255,255,255,0.18); color: #fff; }
.app-nav.app-nav-branded .app-nav-icon-btn { color: rgba(255,255,255,0.85); }
.app-nav.app-nav-branded .app-nav-icon-btn:hover { background: rgba(255,255,255,0.10); color: #fff; }

/* Custom logo uploaded by the school — light white backing for transparent PNGs */
.app-logo-custom {
  background: rgba(255,255,255,0.95);
  padding: 2px 6px;
  border-radius: 6px;
}
.app-nav:not(.app-nav-branded) .app-logo-custom { background: transparent; padding: 0; }

/* ═══════════════════════════════════════════════════════════
   Student record modal: sectioned 4-column grid
   (shared by "New student" and "Edit" — eleves-list + eleve-detail)
   ═══════════════════════════════════════════════════════════ */
.learner-edit-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.6rem 0.8rem;
  max-height: 75vh;
  overflow-y: auto;
}
.learner-edit-grid label > span {
  font-size: 0.74rem;
  font-weight: 500;
  color: var(--label-secondary);
  margin-bottom: 0.2rem;
  display: block;
}
@media (max-width: 720px) {
  .learner-edit-grid { grid-template-columns: repeat(2, 1fr); }
  .learner-edit-grid > label[style*="grid-column:span 3"],
  .learner-edit-grid > label[style*="grid-column:span 4"] { grid-column: 1/-1 !important; }
}


/* ===== Status banners (.app-flash) & toasts (window.appToast) =====
   Subtle, Apple-style: colored left border + tinted background adapting to
   dark mode (color-mix with the surface). No glass: an alert must
   remain perfectly readable. Compatible with existing server banners
   (without an icon) AND toasts (with an SVG icon). */
.app-flash {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  padding: 0.8rem 1rem;
  border: 1px solid var(--separator);
  border-left: 3px solid var(--label-secondary);
  border-radius: 12px;
  background: var(--fill-tertiary);
  color: var(--label-primary);
  font-size: 0.9rem;
  line-height: 1.4;
}
.app-flash > svg { flex: 0 0 auto; width: 18px; height: 18px; margin-top: 1px; }
.app-flash > span { flex: 1 1 auto; min-width: 0; }
.app-flash-success { border-left-color: var(--system-green);  background: color-mix(in srgb, var(--system-green) 12%, var(--bg-secondary)); }
.app-flash-success > svg { color: var(--system-green); }
.app-flash-error   { border-left-color: var(--system-red);    background: color-mix(in srgb, var(--system-red) 12%, var(--bg-secondary)); }
.app-flash-error > svg { color: var(--system-red); }
.app-flash-warning { border-left-color: var(--system-orange); background: color-mix(in srgb, var(--system-orange) 14%, var(--bg-secondary)); }
.app-flash-warning > svg { color: var(--system-orange); }
.app-flash-info    { border-left-color: var(--system-blue);   background: color-mix(in srgb, var(--system-blue) 12%, var(--bg-secondary)); }
.app-flash-info > svg { color: var(--system-blue); }

/* Toast stack: a single foreground container (above the nav,
   modals, and help bubble). Fixes the toast that appeared below the
   bouton « Ajouter ». */
#app-toast-stack {
  position: fixed;
  bottom: 1.25rem;
  right: 1.25rem;
  z-index: 10000;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  max-width: min(360px, calc(100vw - 2rem));
  pointer-events: none;
}
#app-toast-stack .app-flash {
  pointer-events: auto;
  cursor: pointer;
  background: var(--bg-elevated);
  box-shadow: var(--shadow-lg, 0 8px 28px rgba(15, 37, 68, 0.18));
  animation: appToastIn 0.34s cubic-bezier(0.34, 1.56, 0.64, 1);
}
#app-toast-stack .app-flash-success { background: color-mix(in srgb, var(--system-green) 12%, var(--bg-elevated)); }
#app-toast-stack .app-flash-error   { background: color-mix(in srgb, var(--system-red) 12%, var(--bg-elevated)); }
#app-toast-stack .app-flash-warning { background: color-mix(in srgb, var(--system-orange) 14%, var(--bg-elevated)); }
#app-toast-stack .app-flash-info    { background: color-mix(in srgb, var(--system-blue) 12%, var(--bg-elevated)); }
@keyframes appToastIn {
  from { opacity: 0; transform: translateY(16px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  #app-toast-stack .app-flash { animation: none; }
}

/* ===== Toast « Dynamic Island » (opts.island = true) =====================
   Floating DARK pill, centred at the top, that stretches as it appears
   (width + opacity), then folds away on exit. Readable (light text on
   a dark background regardless of theme); only the icon carries the
   type color, preserving the uniform “island” appearance. */
#app-toast-island {
  position: fixed;
  top: max(0.75rem, env(safe-area-inset-top));
  left: 50%;
  transform: translateX(-50%);
  z-index: 10001;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  width: max-content;
  max-width: min(440px, calc(100vw - 1.5rem));
  pointer-events: none;
}
.app-island {
  pointer-events: auto;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.6rem 1.1rem;
  border-radius: var(--r-pill, 100px);
  background: var(--island-bg, rgba(20,22,28,0.92));
  color: var(--island-fg, #f5f5f7);
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.3;
  box-shadow: var(--shadow-lg);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
  backdrop-filter: saturate(160%) blur(14px);
  transform-origin: top center;
  animation: appIslandIn 0.42s var(--ease-spring, cubic-bezier(0.34,1.56,0.64,1));
}
.app-island > svg { flex: 0 0 auto; width: 17px; height: 17px; }
.app-island > span { flex: 1 1 auto; min-width: 0; }
.app-island-success > svg { color: var(--system-green); }
.app-island-error   > svg { color: var(--system-red); }
.app-island-warning > svg { color: var(--system-orange); }
.app-island-info    > svg { color: var(--system-blue); }
.app-island--out { animation: appIslandOut 0.26s var(--ease, ease) forwards; }
@keyframes appIslandIn {
  from { opacity: 0; transform: scaleX(0.4) scaleY(0.7) translateY(-8px); }
  60%  { opacity: 1; }
  to   { opacity: 1; transform: none; }
}
@keyframes appIslandOut {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: scaleX(0.5) scaleY(0.6) translateY(-8px); }
}
@media (prefers-reduced-motion: reduce) {
  .app-island { animation: none; }
  .app-island--out { animation: none; opacity: 0; }
}

/* ── Support conversation thread (tickets) — bubbles readable in light AND dark ───
   Does NOT use var(--navy) (redefined as a text color): explicit colors,
   high-contrast in both themes. “mine” = blue bubble aligned right,
   « them » = neutral surface aligned left. */
.tk-thread { display: flex; flex-direction: column; gap: 0.8rem; }
.tk-row { display: flex; }
.tk-row.mine { justify-content: flex-end; }
.tk-bubble {
  max-width: 80%; padding: 0.7rem 0.9rem; border-radius: 14px;
  border-bottom-left-radius: 4px;
  background: var(--bg-tertiary); color: var(--text);
}
.tk-row.mine .tk-bubble {
  background: #2f5e8f; color: #fff;
  border-bottom-left-radius: 14px; border-bottom-right-radius: 4px;
}
.tk-meta { font-size: 0.7rem; opacity: 0.7; margin-bottom: 0.2rem; }
.tk-body { font-size: 0.9rem; white-space: pre-wrap; word-wrap: break-word; }

/* ════════════════════════════════════════════════════════════════════
   “Dev mode” banner (staging/dev only - rendered by head.ejs when
   isDevEnv, never in production). Same banner as the roddier.dev showcase.
   `pointer-events:none`: purely a marker, never blocks a click.
   ════════════════════════════════════════════════════════════════════ */
.app-dev-banner {
  position: fixed;
  top: 0; left: 0; right: 0;
  background: #d70015;  /* a11y: #ff3b30 = 3.5:1 under white → #d70015 ≈ 4.6:1 */
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  /* FIXED height = exactly the offset applied to the body and nav (1.85rem):
     banner and bar stay flush regardless of the engine's font rendering
     (with padding alone, the actual height varied -> ~5px gap below the banner). */
  height: 1.85rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 1rem;
  z-index: 9999;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.20);
  pointer-events: none;
}
.app-dev-banner::before { content: '\26A0  '; }
/* Content and sticky nav move down by the banner height. */
body.has-dev-banner { padding-top: 1.85rem; }
body.has-dev-banner .app-nav { top: 1.85rem; }
/* Never when printing (invoices, certificates, record sheets). */
@media print {
  .app-dev-banner { display: none !important; }
  body.has-dev-banner { padding-top: 0 !important; }
}

/* ─── Code Review: accessibility (non-native speakers / dyslexia) ──────────────
 * The ETG exam is in FRENCH only: it is not translated; users are helped to learn
 * IN FRENCH. “Facilitated reading” mode = larger, more spacious font + enhanced
 * contrast, enabled through a class on <body> (preference persisted in localStorage).
 * Respects the brand palette (navy #0f2544). */

/* Simplified French version of the explanation (“In plain terms: …”). */
.code-explication-simple {
  display: block;
  margin-top: 0.5rem;
  color: var(--text-primary, #0f2544);
  font-weight: 400;
}
.code-explication-simple-tag { font-weight: 600; }

/* “Listen” button / accessible reading toggle while an action is in progress. */
.code-tts-btn.is-speaking { background: var(--white); border-color: var(--navy, #0f2544); }

/* Easier reading mode: enlarges and spaces out revision text, strengthens the
 * contrast. Targets the revision screen only (#quiz-app and its toolbar). */
body.code-lecture-facilitee #quiz-app { line-height: 1.7; }
body.code-lecture-facilitee #quiz-app .code-enonce {
  font-size: 1.35rem !important;
  line-height: 1.6;
  letter-spacing: 0.01em;
  color: #0f2544;
}
body.code-lecture-facilitee #quiz-app .code-option {
  font-size: 1.12rem;
  padding-top: 0.7rem;
  padding-bottom: 0.7rem;
  line-height: 1.5;
}
body.code-lecture-facilitee #quiz-app .code-feedback { font-size: 1.05rem; line-height: 1.65; }
body.code-lecture-facilitee #quiz-app .code-explication-simple { font-size: 1.08rem; }


/* === Environment ribbon (staging/dev only) — replaces the full-width banner ===
   Common convention: small diagonal ribbon in the top-right corner, no longer pushes content. */
.app-dev-banner, .sent-dev-banner, .dev-banner {
  top: 15px !important; left: -46px !important; right: auto !important; bottom: auto !important;
  width: auto !important; height: auto !important;
  transform: rotate(-45deg) !important; transform-origin: center !important;
  background: #b45309 !important; color: #fff !important;
  padding: 4px 48px !important; font-size: 10px !important; font-weight: 800 !important; letter-spacing: .16em !important;
  box-shadow: 0 2px 8px rgba(0,0,0,.35) !important; display: block !important; border-radius: 0 !important;
}
.app-dev-banner::before, .sent-dev-banner::before, .dev-banner::before { content: '' !important; }
body.has-dev-banner { padding-top: 0 !important; }
/* This zero reset only applies to bars attached AT THE TOP. The bottom bar
   (phone tab bar) is attached at the bottom: forcing top:0 on it stretched it across
   the full screen height and covered the entire page; nothing remained clickable. */
body.has-dev-banner .app-nav, body.has-dev-banner nav:not(.app-tabbar), body.has-dev-banner .rd-progress { top: 0 !important; }


/* ─── Radio player (global footer) ────────────────────────────────── */
.rmb{--rmb-accent:#2563eb;box-sizing:border-box;width:100%;margin:0 0 1.25rem;padding:.55rem .6rem;border:1px solid var(--separator);border-radius:18px;background:var(--bg-secondary);box-shadow:0 6px 24px rgba(15,37,68,.07)}
.rmb[hidden]{display:none}
.rmb-bar{display:flex;align-items:center;gap:.55rem;min-width:0}
.rmb-art{position:relative;flex:0 0 auto;width:46px;height:46px;border-radius:12px;overflow:hidden;display:block}
.rmb-cover{width:100%;height:100%;object-fit:cover;display:block}
.rmb-ph{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:800;font-size:.85rem;letter-spacing:.02em;background:#5e7fa8}
.rmb-ph[hidden]{display:none}
.rmb-now{flex:1 1 auto;min-width:0;padding-left:.15rem}
.rmb-now b{display:block;font-size:.9rem;font-weight:700;line-height:1.2;color:var(--label-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rmb-now small{display:block;color:var(--label-secondary);font-size:.76rem;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rmb.buf .rmb-now small{opacity:.6}

.rmb-ctrls{display:flex;align-items:center;gap:.15rem;flex:0 0 auto}
.rmb-btn{display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:50%;background:transparent;color:var(--label-secondary);cursor:pointer;padding:0}
.rmb-btn svg{width:18px;height:18px}
.rmb-btn-nav{width:34px;height:34px}
.rmb-btn-nav:hover{background:rgba(37,99,235,.1);color:var(--rmb-accent)}
.rmb-btn-main{width:42px;height:42px;background:var(--rmb-accent);color:#fff;box-shadow:0 3px 10px rgba(37,99,235,.28)}
.rmb-btn-main svg{width:20px;height:20px}
.rmb-btn-main:hover{filter:brightness(1.06)}

.rmb-fav{flex:0 0 auto;position:relative;width:34px;height:34px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:50%;background:transparent;color:var(--label-tertiary,#9aa8bd);cursor:pointer;padding:0}
.rmb-fav svg{width:18px;height:18px}
/* Same rule as elsewhere: the asterisk stays small, while the touch target is 44×44.
   The .55rem gap between buttons is enough; no neighboring item is hit. */
.rmb-fav::after{content:"";position:absolute;inset:-5px}
.rmb-fav:hover{background:rgba(37,99,235,.1)}
.rmb-fav.on{color:#e0a107}
.rmb-fav.on svg{fill:currentColor}
.rmb-fav:disabled{opacity:.35;cursor:default}

.rmb-volwrap{display:flex;align-items:center;gap:.3rem;flex:0 1 auto;min-width:0}
.rmb-vol{flex:0 1 90px;min-width:60px;accent-color:var(--rmb-accent);cursor:pointer}
.rmb-icbtn{flex:0 0 auto;height:34px;min-width:34px;display:inline-flex;align-items:center;justify-content:center;gap:.35rem;padding:0 .5rem;border:0;border-radius:10px;background:transparent;color:var(--label-secondary);cursor:pointer;font:inherit;font-size:.78rem;font-weight:600}
.rmb-icbtn svg{width:17px;height:17px;flex:0 0 auto}
.rmb-icbtn:hover{background:rgba(37,99,235,.1);color:var(--rmb-accent)}
.rmb-icbtn.on{background:var(--rmb-accent);color:#fff}
.rmb-stations .rmb-lb{white-space:nowrap}

/* Stations panel: search + pinned favorites + library */
.rmb-panel{margin-top:.55rem;padding-top:.55rem;border-top:1px solid var(--separator)}
.rmb-panel[hidden]{display:none}
.rmb-searchrow{position:relative;display:flex;align-items:center}
.rmb-search-ico{position:absolute;left:.6rem;display:inline-flex;color:var(--label-tertiary,#9aa8bd);pointer-events:none}
.rmb-search-ico svg{width:16px;height:16px}
.rmb-search{width:100%;box-sizing:border-box;padding:.5rem .7rem .5rem 2.1rem;border:1px solid var(--separator);border-radius:12px;background:var(--bg-primary);color:inherit;font:inherit;font-size:.85rem}
.rmb-search:focus{outline:none;border-color:var(--rmb-accent);box-shadow:0 0 0 3px rgba(37,99,235,.14)}

/* Reader filter pills: a single row that scrolls if it overflows.
   The count next to the label avoids opening a filter only to discover it is empty. */
/* Prompt after three failed reconnection attempts: discreet, but accessible. */
.rmb-try-next{display:inline-block;margin-left:.15rem;padding:0 .35rem;border:0;background:transparent;
  color:var(--rmb-accent,#2563eb);font:inherit;font-size:inherit;font-weight:600;
  text-decoration:underline;cursor:pointer}
.rmb-try-next:hover{opacity:.8}

.rmb-chips{display:flex;gap:.3rem;margin-top:.5rem;overflow-x:auto;overflow-y:hidden;padding-bottom:.2rem;scrollbar-width:thin}
.rmb-chips::-webkit-scrollbar{height:4px}
.rmb-chips::-webkit-scrollbar-thumb{background:rgba(0,0,0,.18);border-radius:99px}
.rmb-chip-f{flex:0 0 auto;display:inline-flex;align-items:center;gap:.3rem;
  border:1px solid var(--separator,#e3e6ec);background:transparent;color:inherit;
  border-radius:999px;padding:.24rem .6rem;font-size:.76rem;font-weight:600;
  cursor:pointer;white-space:nowrap;line-height:1.3}
.rmb-chip-f:hover{background:rgba(37,99,235,.07)}
.rmb-chip-f.on{background:var(--rmb-accent,#2563eb);border-color:var(--rmb-accent,#2563eb);color:#fff}
.rmb-chip-n{font-size:.68rem;font-weight:500;opacity:.62}
.rmb-chip-f.on .rmb-chip-n{opacity:.8}
@media (max-width:640px){.rmb-chip-f{font-size:.8rem;padding:.3rem .65rem}}

.rmb-favrow{display:flex;align-items:center;gap:.35rem;flex-wrap:wrap;margin-top:.5rem}
.rmb-favrow[hidden]{display:none}
.rmb-favlab{font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--label-tertiary,#9aa8bd);margin-right:.15rem}
.rmb-chip{padding:.25rem .6rem;border:1px solid var(--separator);border-radius:999px;background:var(--bg-primary);color:var(--label-primary);font:inherit;font-size:.76rem;font-weight:600;cursor:pointer;white-space:nowrap}
.rmb-chip:hover{border-color:var(--rmb-accent);color:var(--rmb-accent)}

.rmb-list{margin-top:.5rem;max-height:236px;overflow-y:auto;display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:2px}
.rmb-row{display:flex;align-items:center;gap:.2rem;border-radius:10px;min-width:0}
.rmb-row:hover{background:rgba(37,99,235,.07)}
.rmb-row.on{background:rgba(37,99,235,.12)}
.rmb-rowmain{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:.5rem;padding:.35rem .4rem;border:0;background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}
.rmb-rowph{flex:0 0 auto;width:26px;height:26px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;color:#fff;font-size:.63rem;font-weight:800}
.rmb-rowtx{min-width:0;display:block}
.rmb-rowtx b{display:block;font-size:.8rem;font-weight:600;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rmb-rowtx em{display:block;font-style:normal;font-size:.7rem;color:var(--label-tertiary,#9aa8bd);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rmb-row.on .rmb-rowtx b{color:var(--rmb-accent)}
.rmb-rowfav{flex:0 0 auto;width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:50%;background:transparent;color:var(--label-tertiary,#9aa8bd);cursor:pointer;padding:0}
.rmb-rowfav svg{width:14px;height:14px}
.rmb-rowfav[aria-pressed="true"]{color:#e0a107}
.rmb-rowfav[aria-pressed="true"] svg{fill:currentColor}
.rmb-empty{margin:.6rem 0 .2rem;text-align:center;font-size:.8rem;color:var(--label-secondary)}
.rmb-empty[hidden]{display:none}

/* Mobile: two clear lines - station + transport, then tools. */
@media (max-width:640px){
  .rmb-bar{flex-wrap:wrap;row-gap:.45rem}
  .rmb-art{order:0;width:40px;height:40px}
  .rmb-now{order:1;flex:1 1 0}
  .rmb-ctrls{order:2}
  .rmb-fav{order:3}
  .rmb-volwrap{order:4;flex:1 1 auto;min-width:110px}
  .rmb-vol{flex:1 1 auto;min-width:52px}
  .rmb-stations{order:5;margin-left:auto}
  .rmb-more{order:6}
  .rmb-stations .rmb-lb{display:none}
  .rmb-list{grid-template-columns:1fr;max-height:210px}
}

/* ─── Compact reader block in the sidebar ──────────────────────
   Play/pause + current station + mute + volume, next to
   search and sign-out. Always within reach, on every page. */

/* ── Full-screen “complete player” window (/music) ────────────────────────── */
.rmb-modal{position:fixed;inset:0;z-index:1200;display:flex;align-items:stretch;justify-content:center;background:rgba(8,18,33,.55)}
.rmb-modal[hidden]{display:none}
/* Stored window: invisible and unreachable, but ALWAYS displayed — a
   hidden element may have its media suspended, and closing the
   window must not stop the music. */
.rmb-modal-stowed{visibility:hidden;opacity:0;pointer-events:none}
.rmb-modal-sheet{position:relative;width:100%;max-width:920px;margin:auto;height:100%;max-height:100%;background:var(--bg-primary,#f4f6f9);overflow:auto;box-shadow:0 12px 50px rgba(0,0,0,.35);-webkit-overflow-scrolling:touch}
.rmb-modal-close{position:sticky;top:0;z-index:2;display:block;margin:.5rem .5rem -1.6rem auto;width:40px;height:40px;border:0;border-radius:50%;background:var(--bg-secondary,#fff);color:var(--label-primary,#0f2544);font-size:1.5rem;line-height:1;cursor:pointer;box-shadow:0 2px 12px rgba(15,37,68,.18)}
.rmb-modal-body{padding:0 1rem 1.5rem}
.rmb-modal-loading{padding:3rem 1rem;text-align:center;color:var(--label-secondary,#7d94b5)}
body.rmb-modal-open{overflow:hidden}
@media (min-width:640px){
  .rmb-modal{padding:2.5vh 1rem}
  .rmb-modal-sheet{height:auto;max-height:95vh;border-radius:20px}
}


/* ─── Player: equalizer, scheduled stop, compact mode ──────────────────────
   Three additions born from the same use: background radio in a venue open
   all day. */

/* The equalizer sits in the artwork corner: it takes no space on its
   own, and it is the only way to see that playback is active without turning up the volume. */
.rmb-eq{position:absolute;right:3px;bottom:3px;display:none;align-items:flex-end;gap:1.5px;height:11px;padding:1.5px 2px;border-radius:3px;background:rgba(0,0,0,.42)}
.rmb-playing .rmb-eq{display:flex}
.rmb-eq i{display:block;width:2px;height:3px;border-radius:1px;background:#fff;transform-origin:bottom;animation:rmb-eq-danse .9s ease-in-out infinite}
.rmb-eq i:nth-child(2){animation-duration:.66s;animation-delay:.14s}
.rmb-eq i:nth-child(3){animation-duration:1.08s;animation-delay:.3s}
@keyframes rmb-eq-danse{0%,100%{height:3px}50%{height:9px}}

/* Scheduled stop shows the remaining time in minutes. Aligned digits: the
   countdown must not make the bar jump. */
.rmb-veille .rmb-lb{font-variant-numeric:tabular-nums;white-space:nowrap}

/* Compact mode: keep enough to identify and stop playback; remove the rest.
   This is not cosmetic hiding — removed controls remain
   accessible by keyboard and in the panel. */
.rmb-collapsed{padding:.35rem .5rem}
.rmb-collapsed .rmb-art{width:32px;height:32px;border-radius:9px}
.rmb-collapsed .rmb-now small,
.rmb-collapsed .rmb-btn-nav,
.rmb-collapsed .rmb-fav,
.rmb-collapsed .rmb-volwrap,
.rmb-collapsed .rmb-veille,
.rmb-collapsed .rmb-more{display:none}
.rmb-collapsed .rmb-btn-main{width:34px;height:34px}
.rmb-collapsed .rmb-btn-main svg{width:16px;height:16px}
.rmb-collapsed .rmb-stations .rmb-lb{display:none}

/* Shortcuts, written where the player opens: a shortcut that nobody
   does not recognize is useless. */
.rmb-aide{margin:.6rem 0 .1rem;color:var(--label-tertiary,#9aa8bd);font-size:.72rem;line-height:1.7}
.rmb-aide kbd{display:inline-block;min-width:1.1em;padding:.05em .35em;border:1px solid var(--separator);border-bottom-width:2px;border-radius:4px;background:var(--bg-primary);color:var(--label-secondary);font:inherit;font-size:.9em;text-align:center}

/* The station panel opens instead of appearing. */
@media (prefers-reduced-motion: no-preference){
  .rmb-panel:not([hidden]){animation:rmb-ouvre .18s ease-out}
  @keyframes rmb-ouvre{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
}

@media (prefers-reduced-motion: reduce){
  .rmb-eq i{animation:none;height:6px}
}


/* The dock: a service player kept at the bottom of the page
Spotify, Deezer and Tidal cannot be controlled externally. Their
player is therefore kept as-is, with THEIR buttons. The frame does not move
within the page — moving it would reload it — the window is what changes
shape around it. */
.rmb-modal-dock{position:fixed;inset:auto 0 0 auto;display:block;background:transparent;
  z-index:1150;pointer-events:none;padding:0 .75rem .75rem 0}
.rmb-modal-dock .rmb-modal-sheet{pointer-events:auto;width:min(460px,calc(100vw - 1.5rem));
  max-width:460px;height:auto;max-height:none;margin:0 0 0 auto;border-radius:16px;
  overflow:hidden;box-shadow:0 10px 40px rgba(8,18,33,.28)}
.rmb-modal-dock .rmb-modal-body{padding:0}

/* Everything used to CHOOSE disappears: at the dock, users listen; they no longer choose. */
.rmb-modal-dock .mz-top,
.rmb-modal-dock .mz-tabs,
.rmb-modal-dock .mz-input,
.rmb-modal-dock .mz-results,
.rmb-modal-dock .mz-hint,
.rmb-modal-dock .mz-dock{display:none}

/* Only the selected service panel remains. */
.rmb-modal-dock .mz-panel{display:none}
.rmb-modal-dock[data-quai=spotify] .mz-panel[data-panel=spotify],
.rmb-modal-dock[data-quai=deezer]  .mz-panel[data-panel=deezer],
.rmb-modal-dock[data-quai=tidal]   .mz-panel[data-panel=tidal],
.rmb-modal-dock[data-quai=youtube] .mz-panel[data-panel=youtube]{display:block}

/* Integrations adapt to the height provided: request their
   compact form without changing their address — changing it would reload them. */
.rmb-modal-dock .mz-frame,
.rmb-modal-dock .mz-frame--spotify{height:152px;border:0;display:block;width:100%}
.rmb-modal-dock[data-quai=deezer] .mz-frame{height:96px}

/* The close button remains, and it STOPS playback: it does not store the player. */
.rmb-modal-dock .rmb-modal-close{position:absolute;top:.35rem;right:.35rem;margin:0;
  width:28px;height:28px;font-size:1.05rem;z-index:3}

/* The bottom bar when it controls a service instead of a radio station. */
.rmb-service .rmb-fav{opacity:.3}
/* For a service we cannot control, our arrows and volume would do
   nothing: they are removed, not grayed out for decoration. */
.rmb-not-controllable .rmb-btn-nav,
.rmb-not-controllable .rmb-volwrap,
.rmb-not-controllable .rmb-fav{display:none}

@media (max-width:640px){
  .rmb-modal-dock{inset:auto 0 0 0;padding:0 .5rem .5rem}
  .rmb-modal-dock .rmb-modal-sheet{width:100%;max-width:none}
}


/* ─── The player day to day ──────────────────────────────────────────────────
   The bar lives in the footer: scrolling through a schedule made it
   easy to lose. It sticks to the bottom ONLY WHILE playing — pinned permanently,
   it would waste space. */
.rmb-collee{
  position:fixed;
  left:calc(var(--nav-w, 252px) + 1rem); right:1rem; bottom:.75rem;
  width:auto; margin:0;
  z-index:900;
  background:var(--bg-elevated,#fff);
  box-shadow:0 10px 34px rgba(15,37,68,.16);
}
/* Content leaves room for the bar, otherwise the footer goes underneath it. */
body.rmb-bar-pinned{padding-bottom:96px}

@media (max-width:900px){
  .rmb-collee{left:.5rem;right:.5rem;bottom:.5rem}
}

/* Emergency mute: wider than an icon because it must be found quickly. */
.rmb-silence{
  flex:0 0 auto;padding:.4rem .8rem;border:1px solid var(--separator);border-radius:999px;
  background:transparent;color:var(--label-secondary);font:inherit;font-size:.8rem;
  font-weight:650;cursor:pointer;white-space:nowrap;
  transition:background-color .15s ease,color .15s ease,border-color .15s ease;
}
.rmb-silence:hover{background:var(--fill-quaternary,rgba(128,128,128,.09))}
.rmb-silence:focus-visible{outline:2px solid var(--rmb-accent);outline-offset:2px}
.rmb-silence.on{background:var(--rmb-accent);border-color:transparent;color:#fff}
.rmb-collapsed .rmb-silence{display:none}

/* The heart for the current title — distinct from the star, which targets the STATION. */
.rmb-aime.on{color:#e0245e}
.rmb-aime.on svg{fill:currentColor}

/* The panel's three views: stations, history, scheduling. */
.rmb-views{display:flex;gap:.25rem;margin:.5rem 0 0}
.rmb-view{
  appearance:none;border:0;background:transparent;color:var(--label-secondary);
  font:inherit;font-size:.78rem;font-weight:650;padding:.3rem .6rem;border-radius:8px;cursor:pointer;
}
.rmb-view:hover{background:var(--fill-quaternary,rgba(128,128,128,.09))}
.rmb-view:focus-visible{outline:2px solid var(--rmb-accent);outline-offset:2px}
.rmb-view.is-active{color:var(--label-primary);background:var(--fill-tertiary,rgba(128,128,128,.14))}

/* History: one row = one title, its heart, its station, and its time. */
.rmb-histo{margin-top:.5rem;max-height:236px;overflow-y:auto}
.rmb-history-l{display:flex;align-items:center;gap:.4rem;padding:.3rem .1rem;border-bottom:1px solid var(--separator)}
.rmb-history-l:last-child{border-bottom:0}
.rmb-history-t{min-width:0}
.rmb-history-t b{display:block;font-size:.84rem;font-weight:650;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rmb-history-t small{display:block;color:var(--label-tertiary,#9aa8bd);font-size:.74rem}

/* The day's schedule. */
.rmb-prog{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:.5rem .8rem;margin-top:.6rem}
/* An explicit display overrides the hidden attribute: without this line,
   scheduling remains visible below the station list. */
.rmb-prog[hidden]{display:none}
.rmb-prog-l{display:flex;align-items:center;gap:.4rem;font-size:.8rem;color:var(--label-secondary)}
.rmb-prog-l span{flex:0 0 auto}
.rmb-prog-h,.rmb-prog-s{
  flex:1 1 auto;min-width:0;padding:.32rem .5rem;border:1px solid var(--separator);
  border-radius:8px;background:var(--bg-primary);color:inherit;font:inherit;font-size:.8rem;
}
.rmb-prog-note{grid-column:1/-1;margin:.1rem 0 0;color:var(--label-tertiary,#9aa8bd);font-size:.74rem;line-height:1.5}

/* Search continues elsewhere when no station matches. */
.rmb-ailleurs{margin:.5rem 0 0}
.rmb-elsewhere-b{
  width:100%;padding:.5rem .7rem;border:1px dashed var(--separator);border-radius:10px;
  background:transparent;color:var(--rmb-accent);font:inherit;font-size:.82rem;font-weight:650;cursor:pointer;
}
.rmb-elsewhere-b:hover{background:rgba(37,99,235,.07)}

/* Dropping a station onto favorites. */
.rmb-favrow.rmb-depot{outline:2px dashed var(--rmb-accent);outline-offset:3px;border-radius:8px}

@media (prefers-reduced-motion:reduce){.rmb-silence{transition:none}}

/* ─── The player listens to the establishment ───────────────────────────────
   What the team plays, and announcements that play over the music. */
.rmb-team{display:flex;flex-wrap:wrap;align-items:center;gap:.3rem;margin:.5rem 0 0}
.rmb-team[hidden]{display:none}
.rmb-team-t{color:var(--label-tertiary,#9aa8bd);font-size:.74rem;font-weight:650;margin-right:.2rem}
.rmb-team-b{
  padding:.25rem .6rem;border:1px solid var(--separator);border-radius:999px;
  background:transparent;color:var(--label-secondary);font:inherit;font-size:.76rem;
  font-weight:600;cursor:pointer;
}
.rmb-team-b:hover{background:var(--fill-quaternary,rgba(128,128,128,.09));color:var(--rmb-accent)}

.rmb-announcement-f{display:flex;gap:.4rem;margin:.6rem 0 0}
.rmb-announcement-f[hidden]{display:none}
.rmb-announcement-t{
  flex:1 1 auto;min-width:0;padding:.4rem .7rem;border:1px solid var(--separator);
  border-radius:999px;background:var(--bg-primary);color:inherit;font:inherit;font-size:.8rem;
}
.rmb-announcement-b{
  flex:0 0 auto;padding:.4rem .9rem;border:0;border-radius:999px;
  background:var(--rmb-accent);color:#fff;font:inherit;font-size:.8rem;font-weight:650;cursor:pointer;
}

/* During an announcement, the bar shows it: users must understand why the volume dropped. */
.rmb-announcement{outline:2px solid var(--rmb-accent);outline-offset:2px}
.rmb-announcement .rmb-now small{color:var(--rmb-accent);font-weight:650}

/* ── THE WAITING PAGE ─────────────────────────────────────────────────────────
 * Shown when the service switches from one machine to another. It must reassure without
 * revealing any internal operation, and provide ONE sign of life: without motion, a waiting
 * page reads like a dead page.
 */
.patience-ring {
  display: inline-block; width: 34px; height: 34px; margin-bottom: 0.9rem;
  border-radius: 50%; border: 3px solid var(--separator, rgba(127,127,127,0.25));
  border-top-color: var(--tint, #1f6fe0);
  animation: patience-tourne 1.1s linear infinite;
}
.patience-when { margin-top: 1rem; font-variant-numeric: tabular-nums; }
@keyframes patience-tourne { to { transform: rotate(360deg); } }

/* Some people configure their device to limit animations — often because
   animations make them dizzy. Respect this choice: the ring stops, the page
   remains readable and reloads anyway. */
@media (prefers-reduced-motion: reduce) {
  .patience-ring { animation: none; }
}

/* ── THE ANNOUNCEMENT BANNER ───────────────────────────────────────────────────
 * Planned maintenance is not an alert: the tone stays calm, the color informs
 * without shouting. That is the difference between “we are letting you know” and “something is wrong.”
 */
.annonce-bandeau {
  padding: 0.55rem 1rem; font-size: 0.88rem; line-height: 1.45; text-align: center;
  background: var(--azur-clair, #cfe0fa); color: var(--sur-azur, #0f4592);
  border-bottom: 1px solid var(--azur, #1f6fe0);
}
.annonce-bandeau .announcement-what { opacity: 0.85; }
