/* ============================================================================
 * liquid-glass.css — "Liquid Glass" styling (Apple-like translucent material)
 *
 * ISOLATED AND REVERSIBLE ADDITION: this file only overrides the appearance of the
 * existing components (.app-card, .app-nav, .app-modal-card, etc.) using
 * translucent surfaces + background blur. No HTML/JS structure is touched.
 *
 * TO RETURN TO THE CURRENT VERSION: remove the <link liquid-glass.css> line
 * in views/partials/head.ejs (or git revert the commit). Nothing else.
 *
 * Keeps the visual identity (navy/desaturated blues, system font) — only the
 * MATERIAL changes (translucency, depth), not the brand colors.
 * ========================================================================== */

:root {
  --lg-blur: 22px;
  --lg-saturate: 180%;
  --lg-surface:        rgba(255, 255, 255, 0.62);
  --lg-surface-strong: rgba(255, 255, 255, 0.74);
  --lg-surface-soft:   rgba(255, 255, 255, 0.50);
  /* Nav bar: more translucent background than the cards so the background
     (which scrolls underneath) shows through, while keeping the icons readable. */
  --lg-nav-surface:    rgba(255, 255, 255, 0.66);
  /* Blur on large surfaces (cards/modals) — reduced on tablets (GPU). */
  --lg-blur-card:      30px;
  --lg-border:         rgba(255, 255, 255, 0.50);
  /* RIM (specular edge) — REDESIGN 2026-06-24: Apple "Liquid Glass".
     BEFORE: 4 inner shadows, including a white band at 0.85 alpha → hard edge,
     PLASTIC look. NOW: a single soft line at the top (catches ambient
     light) + a very subtle outline. Subtle, never any glaring white. */
  --lg-highlight:      inset 0 1px 0 rgba(255, 255, 255, 0.45), inset 0 0 0 0.5px rgba(255, 255, 255, 0.16);
  /* SHEEN (formerly "specular") — REDESIGN 2026-06-24.
     BEFORE: a glossy DIAGONAL sweep (linear-gradient 125deg at 0.42 alpha) that
     put a gloss band on every surface → plastic look, and a HARD band
     in dark/Firefox (the ::after painted this raw gradient because the SVG lens filter
     was not applied outside Chromium). NOW: a VERY soft vertical veil,
     concentrated at the very top of the surface (diffuse ambient light), which fades
     quickly — no band, no diagonal. Token name retained (used everywhere). */
  --lg-specular:       linear-gradient(180deg, rgba(255, 255, 255, 0.18) 0%, rgba(255, 255, 255, 0.05) 14%, rgba(255, 255, 255, 0) 34%);
  --lg-shadow:         0 8px 30px rgba(15, 37, 68, 0.10);
  --lg-shadow-lg:      0 24px 60px rgba(15, 37, 68, 0.16);
}
:root[data-theme="dark"] {
  --lg-surface:        rgba(28, 28, 36, 0.55);
  --lg-surface-strong: rgba(34, 34, 44, 0.70);
  --lg-surface-soft:   rgba(28, 28, 36, 0.42);
  --lg-nav-surface:    rgba(24, 24, 32, 0.62);
  --lg-border:         rgba(255, 255, 255, 0.10);
  /* Dark: almost invisible rim (0.08), never pure white. THIS IS THE FIX
     for the reported « reflet dur en dark / Firefox »: no bright edge remains. */
  --lg-highlight:      inset 0 1px 0 rgba(255, 255, 255, 0.08), inset 0 0 0 0.5px rgba(255, 255, 255, 0.05);
  /* Dark: almost no top veil (0.05). In Firefox (no SVG lens), the ::after
     now paints only a hint of light at the top → no more hard diagonal band. */
  --lg-specular:       linear-gradient(180deg, rgba(255, 255, 255, 0.055) 0%, rgba(255, 255, 255, 0.015) 16%, rgba(255, 255, 255, 0) 36%);
  --lg-shadow:         0 8px 30px rgba(0, 0, 0, 0.40);
  --lg-shadow-lg:      0 24px 60px rgba(0, 0, 0, 0.55);
}

/* ANIMATED seasonal background: a wash of colors (the season's hue) that
   blends across the ENTIRE background and slowly drifts like an "aurora". The ::before layer
   is full-screen, fixed, behind the content; the glass cards frost it.
   The body.season-X class is set by seasonal-bg.js. */
body.app-body { background: var(--bg-primary); }
body.app-body::before,
body.app-body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  transition: background 0.8s ease;
  will-change: transform;
}
/* Intensity is a personal per-device setting (seasonal-bg.js + Appearance
   slider): --season-intensity (default 1) MULTIPLIES the opacity. The
   "aurora" animation below is NOT changed — only the color level varies. */
body.app-body::before { opacity: calc(0.88 * var(--season-intensity, 1)); filter: saturate(1.45); animation: appDriftA 16s ease-in-out infinite alternate; }
body.app-body::after  { opacity: calc(0.80 * var(--season-intensity, 1)); filter: saturate(1.45); animation: appDriftB 21s ease-in-out infinite alternate; }
@keyframes appDriftA {
  from { transform: translate3d(-24%, -17%, 0) scale(1.45); }
  to   { transform: translate3d(24%, 17%, 0) scale(1.72); }
}
@keyframes appDriftB {
  from { transform: translate3d(22%, 19%, 0) scale(1.6) rotate(15deg); }
  to   { transform: translate3d(-22%, -17%, 0) scale(1.38) rotate(-17deg); }
}
/* Accessibility: if the user asks for less motion, the drift stops.
   The background stays colorful (the washes are painted); only the motion is disabled —
   this is Apple behavior (the system setting takes precedence over visual identity). */
@media (prefers-reduced-motion: reduce) {
  body.app-body::before,
  body.app-body::after { animation: none; }
}
/* Tablet/mobile (pointer:coarse): a background drifting beneath glass surfaces
   forces the GPU to re-filter every frame. The drift is frozen (the washes remain
   painted, the background stays colorful), and the blur on large surfaces is reduced. */
@media (pointer: coarse) {
  body.app-body::before,
  body.app-body::after { animation: none; }
  :root { --lg-blur-card: 14px; }
}

/* ── SPRING — tender green, sun, pink & lavender (vibrant, premium) ── */
body.app-body.season-spring::before {
  background:
    radial-gradient(48% 52% at 22% 26%, rgba(74,222,128,0.66), transparent 76%),
    radial-gradient(46% 50% at 76% 72%, rgba(253,224,120,0.58), transparent 76%),
    radial-gradient(40% 44% at 52% 50%, rgba(110,231,183,0.34), transparent 80%);
}
body.app-body.season-spring::after {
  background:
    radial-gradient(44% 48% at 82% 20%, rgba(244,114,182,0.62), transparent 76%),
    radial-gradient(44% 48% at 18% 84%, rgba(167,139,250,0.60), transparent 76%);
}
/* ── SUMMER — sun, sky & sea (gold, orange, azure, turquoise) ── */
body.app-body.season-summer::before {
  background:
    radial-gradient(48% 52% at 22% 26%, rgba(251,191,36,0.64), transparent 76%),
    radial-gradient(46% 50% at 76% 72%, rgba(251,146,60,0.60), transparent 76%),
    radial-gradient(40% 44% at 52% 50%, rgba(253,224,71,0.32), transparent 80%);
}
body.app-body.season-summer::after {
  background:
    radial-gradient(44% 48% at 82% 20%, rgba(56,189,248,0.60), transparent 76%),
    radial-gradient(44% 48% at 18% 84%, rgba(45,212,191,0.58), transparent 76%);
}
/* ── AUTUMN — foliage: orange, gold, red & brown ── */
body.app-body.season-autumn::before {
  background:
    radial-gradient(48% 52% at 22% 26%, rgba(249,115,22,0.64), transparent 76%),
    radial-gradient(46% 50% at 76% 72%, rgba(245,158,11,0.62), transparent 76%),
    radial-gradient(40% 44% at 52% 50%, rgba(217,119,6,0.30), transparent 80%);
}
body.app-body.season-autumn::after {
  background:
    radial-gradient(44% 48% at 82% 20%, rgba(239,68,68,0.56), transparent 76%),
    radial-gradient(44% 48% at 18% 84%, rgba(180,83,9,0.56), transparent 76%);
}
/* ── WINTER — frost: icy blue, mint, purple & slate ── */
body.app-body.season-winter::before {
  background:
    radial-gradient(48% 52% at 22% 26%, rgba(125,211,252,0.66), transparent 76%),
    radial-gradient(46% 50% at 76% 72%, rgba(94,234,212,0.56), transparent 76%),
    radial-gradient(40% 44% at 52% 50%, rgba(186,230,253,0.34), transparent 80%);
}
body.app-body.season-winter::after {
  background:
    radial-gradient(44% 48% at 82% 20%, rgba(129,140,248,0.60), transparent 76%),
    radial-gradient(44% 48% at 18% 84%, rgba(148,163,184,0.52), transparent 76%);
}

/* ── SEASONAL ACCENTS: the current season becomes a COLOR SOURCE for
   the whole interface (vitrine AND app). --season-accent = vibrant tint (icons,
   borders, halos); --season-accent-2 = complementary tint (gradients);
   --season-ink = AA-CONTRAST variant for TEXT on a light background. The classes
   body.season-* are set by seasonal-bg.js. Fallback (before JS) = navy accent. ── */
body.app-body {
  --season-accent: var(--accent);
  --season-accent-2: var(--accent-2);
  --season-ink: var(--accent);
}
body.app-body.season-spring { --season-accent:#22c55e; --season-accent-2:#ec4899; --season-ink:#0f7a3d; }
body.app-body.season-summer { --season-accent:#f59e0b; --season-accent-2:#06b6d4; --season-ink:#b45309; }
body.app-body.season-autumn { --season-accent:#ea580c; --season-accent-2:#b45309; --season-ink:#c2410c; }
body.app-body.season-winter { --season-accent:#0ea5e9; --season-accent-2:#6366f1; --season-ink:#0369a1; }
/* In dark mode, the seasonal ink must be lightened to remain readable. */
:root[data-theme="dark"] body.app-body.season-spring { --season-ink:#4ade80; }
:root[data-theme="dark"] body.app-body.season-summer { --season-ink:#fbbf24; }
:root[data-theme="dark"] body.app-body.season-autumn { --season-ink:#fb923c; }
:root[data-theme="dark"] body.app-body.season-winter { --season-ink:#38bdf8; }

/* Dark variants: keep the same hues but use subtler washes. */
:root[data-theme="dark"] body.app-body::before { opacity: 0.26; }
:root[data-theme="dark"] body.app-body::after  { opacity: 0.22; }

/* --- Surfaces en verre ----------------------------------------------------- */
.app-card,
.app-stat-card,
.app-kpi-card,
.app-stat-grid > div,
.codengo-panel {
  background: var(--lg-surface-soft);
  background-image: var(--lg-specular);
  -webkit-backdrop-filter: blur(var(--lg-blur-card, 30px)) saturate(190%);
  backdrop-filter: blur(var(--lg-blur-card, 30px)) saturate(190%);
  border: 1px solid var(--lg-border);
  box-shadow: var(--lg-highlight), var(--lg-shadow);
  border-radius: var(--radius-xl, 18px);
}
/* Hover: background-COLOR (not the shorthand) to preserve the specular. */
.app-card-clickable:hover {
  background-color: var(--lg-surface-strong);
  box-shadow: var(--lg-highlight), var(--lg-shadow-lg);
}

/* Navigation bar (sticky) — floating glass. The admin area (navy) keeps its
   opaque background to remain readable.

   TWO-LAYER ARCHITECTURE (compatible with all browsers):
   1) the nav uses simple FROSTED GLASS (blur, WITHOUT url) → rendered by Chromium,
      Firefox AND Safari. This is the baseline guaranteed everywhere.
   2) lens REFRACTION (SVG filter) is placed on ::after — rendered by
      Chromium only. Firefox/Safari cannot apply an SVG filter in
      backdrop-filter: the layer then has no effect, and the frosted glass (1) remains.
   Essential because putting url() directly on the nav broke Firefox/Safari
   (they parse the declaration but do nothing with it → NO blur, sharp content behind). */
.app-nav:not(.app-nav-admin) {
  background: var(--lg-nav-surface);
  /* True FROSTED blur (18px) — supported by ALL browsers. BEFORE: only 3px
     (we relied on the ::after SVG lens for most of the blur) → in Firefox/Safari,
     which ignore the lens, the bar barely looked frosted. The ::after adds
     refraction in Chromium; everywhere else, this blur IS the glass. */
  -webkit-backdrop-filter: blur(18px) saturate(180%);
  backdrop-filter: blur(18px) saturate(180%);
  border-bottom: 1px solid var(--lg-border);
  box-shadow: var(--lg-highlight), var(--lg-shadow);
}
/* AA readability: on glass, nav links use a solid color (the
   60% rgba from app.css composited over the glass falls below 4.5:1, even on a light background).
   Hover/active states already use label-primary. */
.app-nav:not(.app-nav-admin) .app-nav-links a {
  color: var(--label-primary);
}

/* Refraction layer (lens) — all unique floating surfaces ---
   Same two-layer architecture as the nav: the element keeps its frosted glass
   (rendered by all browsers), while the ::after carries the SVG filter (rendered by Chromium;
   no effect elsewhere). Reserved for surfaces that appear ALONE on screen (nav, open modal,
   palette, expanded menus, login card) — never for repeated elements
   (cards, table rows): GPU cost.
   The menus (quick-add, notification, contextual) are already positioned absolute/fixed with
   z-index: they create their own stacking context, so they are left unchanged. Only the
   static cards need it. */
.app-modal-card,
.app-auth-card {
  position: relative;
  isolation: isolate;
}
.app-nav:not(.app-nav-admin)::after,
.app-modal-card::after,
.app-auth-card::after,
dialog.app-modal::after,
.quick-add-menu::after,
.app-notif-panel::after,
.ev-context-menu::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  -webkit-backdrop-filter: url(#lg-refract);
  backdrop-filter: url(#lg-refract);
  /* The specular gradient is painted by ALL browsers (only the refraction
     is Chromium-specific), so the glass reflection is universal. */
  background: var(--lg-specular);
}
/* Collapsed nav (mobile hamburger): deliberately opaque — the layer is also disabled. */
.app-nav.is-collapsed::after { display: none; }
/* Dark mode: OVERRIDE the opaque rule from app.css
   (`:root[data-theme="dark"] .app-nav:not(.app-nav-admin) { background: var(--white) }`,
   solid in dark mode) to preserve the translucent refracting glass. Same specificity,
   but liquid-glass.css loads AFTER app.css → it wins. Collapsed mode (mobile
   hamburger, .is-collapsed) deliberately remains opaque (small-screen readability). */
:root[data-theme="dark"] .app-nav:not(.app-nav-admin) {
  background: var(--lg-nav-surface);
  border-bottom: 1px solid var(--lg-border);
  box-shadow: var(--lg-highlight), var(--lg-shadow);
}
/* Apply the same dark-mode override to the other surfaces: the dark block in app.css
   makes cards, KPI, the login card, and buttons opaque again (solid backgrounds), which
   would extinguish the glass, rim, and reflection. Tokens already adapted for dark mode above. */
:root[data-theme="dark"] .app-card,
:root[data-theme="dark"] .app-stat-card,
:root[data-theme="dark"] .app-kpi-card,
:root[data-theme="dark"] .app-kpi,
:root[data-theme="dark"] .app-stat-grid > div,
:root[data-theme="dark"] .codengo-panel,
:root[data-theme="dark"] .app-auth-card {
  background: var(--lg-surface-soft);
  background-image: var(--lg-specular);
  border-color: var(--lg-border);
  box-shadow: var(--lg-highlight), var(--lg-shadow);
}
:root[data-theme="dark"] .app-auth-card,
:root[data-theme="dark"] .app-modal-card {
  background-color: var(--lg-surface-strong);
}
/* (Outline/ghost buttons in dark theme: keep the base app.css style —
   glass removed on 2026-06-13, as in light mode. See the “Buttons” note below.) */

/* Tabs (settings / HR) — glass pill. */
.parameters-tabs {
  background: var(--lg-surface-soft);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  backdrop-filter: blur(16px) saturate(160%);
  border: 1px solid var(--lg-border);
  border-radius: 999px;
  box-shadow: var(--lg-highlight);
  padding: 4px;
}
.param-tab.is-active {
  background: var(--lg-surface-strong);
  box-shadow: var(--lg-highlight), 0 2px 8px rgba(15, 37, 68, 0.12);
  border-radius: 999px;
}

/* Modals — thick frosted glass on the card; the overlay does not blur (otherwise it
   creates a backdrop root that prevents the card from blurring the page → different rendering
   from <dialog>). .app-modal-card carries the blur (like the dialog box). */
.app-modal {
  background: rgba(10, 18, 32, 0.28);
}
.app-modal-card {
  background: var(--lg-surface-strong);
  -webkit-backdrop-filter: blur(var(--lg-blur-card, 30px)) saturate(180%);
  backdrop-filter: blur(var(--lg-blur-card, 30px)) saturate(180%);
  border: 1px solid var(--lg-border);
  box-shadow: var(--lg-highlight), var(--lg-shadow-lg);
}

/* Buttons — REDESIGN 2026-06-24 (“global redesign” mandate, to be confirmed by Julien):
   the PRIMARY button remains solid/tinted (correct Apple behavior: the primary
   action is solid, not glass). SECONDARY buttons (outline/ghost)
   receive a DISCREET glass material: translucent surface + light blur + soft
   border. NO pill, NO shiny gloss — sharp corners retained. Reversible.
   NOTE: reverses the 2026-06-13 note (“classic buttons”) at the request of the
   new mandate; restrained values were chosen to avoid making it look “plastic” again. */
.app-btn-outline,
.app-btn-ghost {
  background-color: var(--lg-surface-soft);
  -webkit-backdrop-filter: blur(12px) saturate(170%);
  backdrop-filter: blur(12px) saturate(170%);
  box-shadow: var(--lg-highlight);
}
.app-btn-outline:hover,
.app-btn-ghost:hover {
  background-color: var(--lg-surface-strong);
  box-shadow: var(--lg-highlight), var(--lg-shadow);
}
/* The primary only gets a thin line of light at the top (premium, not plastic). */
.app-btn-primary { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22), var(--lg-shadow); }

/* Section dropdown menus (grouped nav) — floating glass, consistent with the
   nav and the modals. BEFORE: opaque panel (--bg-elevated). Now: same
   material used by the other floating surfaces, light + dark (see the dark block below). */
.app-nav-dropdown {
  background: var(--lg-surface-strong);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  backdrop-filter: blur(22px) saturate(180%);
  border: 1px solid var(--lg-border);
  box-shadow: var(--lg-highlight), var(--lg-shadow-lg);
}
:root[data-theme="dark"] .app-nav-dropdown {
  background: var(--lg-surface-strong);
  border: 1px solid var(--lg-border);
  box-shadow: var(--lg-highlight), var(--lg-shadow-lg);
}

/* Form fields — SHARED BASE for ALL fields in the app (not only those
   in .app-form/.form-fancy). Goal: (1) no form should look “unstyled”
   (border + rounded corners everywhere); (2) `box-sizing:border-box` prevents a field
   with width:100% + padding from OVERFLOWING onto its neighbor (the “overlapping cells”).
   Values aligned with .app-form/.form-fancy (1.5px var(--separator), 10px) → ZERO
   visual change for forms that are already styled. Slight translucency is retained
   (vibrancy, without backdrop-filter: glass-on-glass = an Apple anti-pattern). The `range`
   and `color` are excluded (otherwise the intensity slider / picker would get a border). */
.app-main input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):not([type="color"]),
.app-main select,
.app-main textarea,
.app-modal-card input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):not([type="color"]),
.app-modal-card select,
.app-modal-card textarea {
  background-color: var(--lg-surface-soft);
  border: 1.5px solid var(--separator);
  border-radius: 10px;
  box-sizing: border-box;
}
/* Standard padding on input + textarea only — NOT select elements (otherwise it overrides
   the padding-right that leaves room for the custom arrow). 0.75rem 0.9rem = .app-form. */
.app-main input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):not([type="color"]),
.app-main textarea,
.app-modal-card input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):not([type="color"]),
.app-modal-card textarea {
  padding: 0.75rem 0.9rem;
}
/* Consistent focus on ALL fields (even without a form class): brand ring. */
.app-main input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):not([type="color"]):focus,
.app-main select:focus,
.app-main textarea:focus,
.app-modal-card input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):not([type="color"]):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);
}
/* Dropdown arrow on ALL select elements (otherwise a select without an arrow
   looks like a text field — this was the case in .form-fancy forms). Same
   chevron + same padding-right as .app-form. The background (vibrancy) remains beneath the image. */
.app-main select,
.app-modal-card select {
  -webkit-appearance: none;
  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: 0.75rem 2.5rem 0.75rem 0.9rem;
}

/* Badges & dots — light glass. */
.app-badge {
  -webkit-backdrop-filter: blur(8px) saturate(160%);
  backdrop-filter: blur(8px) saturate(160%);
}

/* Page header: lets the background show through (no solid background). */
.app-page-header { background: transparent; }

/* === PROPAGATION — rest of the app ======================================== */

/* Admin area navigation (back office): dark glass (translucent navy)
   to remain readable while staying consistent with the rest. */
.app-nav-admin {
  background: rgba(15, 37, 68, 0.72);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.25);
}

/* Login / sign-up pages. */
.app-auth {
  background:
    radial-gradient(1000px 680px at 10% -8%, rgba(94, 127, 168, 0.22), transparent 60%),
    radial-gradient(900px 640px at 112% 6%, rgba(15, 37, 68, 0.14), transparent 55%),
    var(--bg-primary);
  background-attachment: fixed;
}

/* Login page: we REVEAL the seasonal animated background (otherwise hidden by the
   opaque background above) and make it much brighter than in the app — the
   space's home page must be colorful. The card remains glass, so it stays
   perfectly readable. The tints + the animation come from body.app-body
   (see seasonal-bg.js + .season-* above), so this is automatically
   seasonal and already animated. Targeted via .app-auth-seasonal → only affects login. */
.app-auth.app-auth-seasonal { background: transparent; background-attachment: initial; }
body.app-body:has(.app-auth-seasonal)::before { opacity: 0.88; filter: saturate(1.35); }
body.app-body:has(.app-auth-seasonal)::after  { opacity: 0.80; filter: saturate(1.35); }
/* In dark mode, pastels stand out poorly against an almost black background: make them
   « luire » (screen mode) for a clearly colorful background, without changing light mode. */
:root[data-theme="dark"] body.app-body:has(.app-auth-seasonal)::before,
:root[data-theme="dark"] body.app-body:has(.app-auth-seasonal)::after { mix-blend-mode: screen; filter: saturate(1.25); }
:root[data-theme="dark"] body.app-body:has(.app-auth-seasonal)::before { opacity: 0.82; }
:root[data-theme="dark"] body.app-body:has(.app-auth-seasonal)::after  { opacity: 0.74; }
.app-auth-card {
  background: var(--lg-surface-strong);
  -webkit-backdrop-filter: blur(var(--lg-blur-card, 30px)) saturate(180%);
  backdrop-filter: blur(var(--lg-blur-card, 30px)) saturate(180%);
  border: 1px solid var(--lg-border);
  box-shadow: var(--lg-highlight), var(--lg-shadow-lg);
}

/* Alerts / callouts. */
.app-alert {
  -webkit-backdrop-filter: blur(10px) saturate(160%);
  backdrop-filter: blur(10px) saturate(160%);
}

/* Native <dialog> modals (⌘K command palette, other dialogs).
   `dialog.x` specificity to override the component's inline styles. */
dialog.cmdk-modal,
dialog.app-modal {
  background: var(--lg-surface-strong) !important;
  -webkit-backdrop-filter: blur(var(--lg-blur-card, 30px)) saturate(180%);
  backdrop-filter: blur(var(--lg-blur-card, 30px)) saturate(180%);
  border: 1px solid var(--lg-border) !important;
  box-shadow: var(--lg-highlight), var(--lg-shadow-lg) !important;
}
dialog::backdrop {
  background: rgba(10, 18, 32, 0.28);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

/* Floating toasts (window.appToast): tinted glass islands that float
   above the content. .app-flash banners placed INSIDE the page remain
   opaque (they often sit on a card that is already glass, for readability). */
#app-toast-stack .app-flash {
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid var(--lg-border);
  box-shadow: var(--lg-highlight), var(--lg-shadow-lg);
}
#app-toast-stack .app-flash-success { background: color-mix(in srgb, var(--system-green) 14%, var(--lg-surface-strong)); }
#app-toast-stack .app-flash-error   { background: color-mix(in srgb, var(--system-red) 14%, var(--lg-surface-strong)); }
#app-toast-stack .app-flash-warning { background: color-mix(in srgb, var(--system-orange) 16%, var(--lg-surface-strong)); }
#app-toast-stack .app-flash-info    { background: color-mix(in srgb, var(--system-blue) 14%, var(--lg-surface-strong)); }

/* Admin SSE toast (screen sharing) — moved out of admin-notif.js inline styles:
   readable navy glass island, using the same material as the rest. */
.admin-share-toast {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 2147483000;
  background: rgba(15, 37, 68, 0.80);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid rgba(255, 255, 255, 0.22);
  color: #fff;
  text-decoration: none;
  padding: 0.75rem 1rem;
  border-radius: 16px;
  font: 600 14px 'Roboto', -apple-system, system-ui, sans-serif;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 10px 30px rgba(0, 0, 0, 0.25);
  max-width: 320px;
  display: none;
  line-height: 1.4;
}

/* Planning: toolbar, filters, tabs, days (week) and cells (month).
   The .is-today / .is-weekend states keep their own colors. */
.app-planning-tabs,
.app-planning-filter,
.app-planning-week-day,
.app-planning-month-cell {
  background: var(--lg-surface);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  backdrop-filter: blur(14px) saturate(160%);
  border: 1px solid var(--lg-border);
}

/* KPI (legacy tiles). */
.app-kpi {
  background: var(--lg-surface);
  -webkit-backdrop-filter: blur(var(--lg-blur)) saturate(var(--lg-saturate));
  backdrop-filter: blur(var(--lg-blur)) saturate(var(--lg-saturate));
  border: 1px solid var(--lg-border);
  box-shadow: var(--lg-highlight), var(--lg-shadow);
}

/* “Liquid glass” list (opt-in .app-table-glass, e.g. student list): rounded
   translucent rows as “floating pills” (border-spacing), with a glass effect on
   hover, with the entire row clickable. The blur/veil already comes from the .app-card
   around it; therefore, only a translucent background is applied to the cells. */
.app-table.app-table-glass { border-collapse: separate; border-spacing: 0 6px; }
.app-table-glass thead th { border-bottom: none; padding-bottom: 0.35rem; }
/* SIMPLE rim on cells (a single inset): the full --lg-highlight rim
   (3 shadows) multiplied across hundreds of cells is expensive for a minor detail
   invisible at this scale. */
.app-table-glass tbody td { border-bottom: none; background: var(--lg-surface-soft); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45); transition: background 0.16s ease; }
.app-table-glass tbody td:first-child { border-radius: 13px 0 0 13px; }
.app-table-glass tbody td:last-child  { border-radius: 0 13px 13px 0; }
/* Zebra striping would add an opaque background that breaks the glass → align it. */
.app-table-glass.app-table-zebra tbody tr:nth-child(even) td { background: var(--lg-surface-soft); }
.app-table-glass tbody tr.app-row-link { cursor: pointer; }
/* Hover: translucent brand tint (desaturated blue) — clearly visible in light
   AND dark modes, while remaining “glass.” */
.app-table-glass tbody tr:hover td,
.app-table-glass.app-table-zebra tbody tr:nth-child(even):hover td { background: rgba(94, 127, 168, 0.20); }
@media (prefers-reduced-transparency: reduce) {
  .app-table-glass tbody td { background: var(--bg-secondary); box-shadow: none; }
  .app-table-glass tbody tr:hover td { background: var(--blue-ll); }
}

/* === LIQUID MOTION =========================================================
   The material behaves like a liquid (Apple principle):
   1. GEL: controls compress when pressed and spring back.
   2. SURGE: floating surfaces emerge from their source with a
      slight overshoot (spring), never with a flat fade.
   3. MOVING LIGHT: a reflection sweeps across the glass when the interface moves
      (scroll, hover) — no gratuitous continuous animation.
   Everything is disabled under prefers-reduced-motion (block at the end of the section). */

:root { --lg-spring: cubic-bezier(0.34, 1.56, 0.64, 1); }

/* 1 ── Gel press: fast compression, spring back. */
.app-btn,
.app-nav-links a,
.app-nav-icon-btn,
.param-tab,
.quick-add-item {
  transition: transform 0.28s var(--lg-spring), background-color 0.15s ease,
              box-shadow 0.2s ease, color 0.15s ease, border-color 0.15s ease;
}
.app-btn:active { transform: scale(0.965); transition-duration: 0.08s; }
.app-nav-links a:active,
.app-nav-icon-btn:active,
.param-tab:active { transform: scale(0.94); transition-duration: 0.08s; }
.quick-add-item:active { transform: scale(0.985); transition-duration: 0.08s; }

/* 2 ── REDESIGN 2026-06-24: LIGHT SWEEPS (glint) were REMOVED.
   BEFORE: a white band (rgba .36 / .32) swept across the nav on scroll and the cards
   on hover → it was the main plastic “tell” (animated display-case gloss), and the
   band had no dark variant and glared harshly in Firefox dark mode. Apple glass does not
   give itself away with a moving band; its light is diffuse and fixed (rim + soft
   sheen from the tokens). Therefore, ONLY an elevation response on hover remains. */

/* 3 ── Hover on clickable cards: gentle elevation (lift + shadow + denser
   surface), with no animated reflection. It feels like “the glass moves closer to the light.” */
.app-card-clickable {
  background-image: var(--lg-specular);
  transition: transform 0.28s var(--lg-spring), background-color 0.2s ease, box-shadow 0.2s ease;
}
.app-card-clickable:hover {
  transform: translateY(-2px);
  background-color: var(--lg-surface-strong);
  box-shadow: var(--lg-highlight), var(--lg-shadow-lg);
}

/* 4 ── Smooth navigation: cross-fade between pages (multi-page View Transitions,
   recent Chromium/Safari; others navigate normally).
   The nav has its own transition name: it appears PERSISTENT while
   the content fades — an app-like feel, with no more white flash. */
@view-transition { navigation: auto; }
::view-transition-old(root),
::view-transition-new(root) { animation-duration: 0.26s; }
.app-nav:not(.app-nav-admin) { view-transition-name: app-nav; }
.app-nav-admin { view-transition-name: app-nav-admin; }

/* 5 ── Entry cascades: cards arrive with a slight stagger (completes the
   KPI stagger from app.css; backwards prevents any flash). */
.app-card:nth-child(1) { animation-delay: 0.03s; }
.app-card:nth-child(2) { animation-delay: 0.07s; }
.app-card:nth-child(3) { animation-delay: 0.11s; }
.app-card:nth-child(4) { animation-delay: 0.15s; }
.app-card:nth-child(5) { animation-delay: 0.19s; }
.app-card:nth-child(6) { animation-delay: 0.23s; }

/* “+ Add” menu items: short stagger on expansion. */
.quick-add-menu.show .quick-add-item { animation: lgItemIn 0.3s cubic-bezier(0.22, 0.61, 0.36, 1) backwards; }
.quick-add-menu.show .quick-add-item:nth-child(1) { animation-delay: 0.02s; }
.quick-add-menu.show .quick-add-item:nth-child(2) { animation-delay: 0.05s; }
.quick-add-menu.show .quick-add-item:nth-child(3) { animation-delay: 0.08s; }
.quick-add-menu.show .quick-add-item:nth-child(4) { animation-delay: 0.11s; }
.quick-add-menu.show .quick-add-item:nth-child(5) { animation-delay: 0.14s; }
.quick-add-menu.show .quick-add-item:nth-child(6) { animation-delay: 0.17s; }
.quick-add-menu.show .quick-add-item:nth-child(7) { animation-delay: 0.20s; }
.quick-add-menu.show .quick-add-item:nth-child(8) { animation-delay: 0.23s; }
@keyframes lgItemIn {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

/* Accessibility: all fluid motion is disabled if the system requests it
   (entries remain a simple fade, consistent with the philosophy of app.css:
   a living interface without translation). */
@media (prefers-reduced-motion: reduce) {
  .app-btn, .app-nav-links a, .app-nav-icon-btn, .param-tab, .quick-add-item { transition: none; }
  .app-btn:active, .app-nav-links a:active, .app-nav-icon-btn:active,
  .param-tab:active, .quick-add-item:active { transform: none; }
  .app-nav:not(.app-nav-admin)::before { animation: none; }
  .app-card-clickable:hover { animation: none; }
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
  .app-card { animation-delay: 0s; }
  .quick-add-menu.show .quick-add-item { animation: appFadeOnly 0.25s ease backwards; animation-delay: 0s; }
}

/* --- Fallback if the browser does not support backdrop-filter -------------------- */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  :root {
    --lg-surface: rgba(255, 255, 255, 0.96);
    --lg-surface-strong: rgba(255, 255, 255, 0.98);
    --lg-surface-soft: rgba(255, 255, 255, 0.92);
    --lg-nav-surface: rgba(255, 255, 255, 0.96);
  }
  :root[data-theme="dark"] {
    --lg-surface: rgba(32, 32, 42, 0.96);
    --lg-surface-strong: rgba(38, 38, 50, 0.98);
    --lg-surface-soft: rgba(32, 32, 42, 0.92);
    --lg-nav-surface: rgba(32, 32, 42, 0.96);
  }
}

/* --- Accessibility: if the user reduces transparency ----------------------- */
@media (prefers-reduced-transparency: reduce) {
  /* The tokens become opaque: all their consumers (including the
     partials' `<style>` blocks — notif panel, menus, help) follow automatically. */
  :root {
    --lg-surface: rgba(255, 255, 255, 0.96);
    --lg-surface-strong: rgba(255, 255, 255, 0.98);
    --lg-surface-soft: rgba(255, 255, 255, 0.92);
    --lg-nav-surface: rgba(255, 255, 255, 0.96);
    --lg-specular: none;
  }
  :root[data-theme="dark"] {
    --lg-surface: rgba(32, 32, 42, 0.96);
    --lg-surface-strong: rgba(38, 38, 50, 0.98);
    --lg-surface-soft: rgba(32, 32, 42, 0.92);
    --lg-nav-surface: rgba(32, 32, 42, 0.96);
    --lg-specular: none;
  }
  .app-card, .app-stat-card, .app-kpi-card, .app-kpi, .app-stat-grid > div, .codengo-panel,
  .app-nav:not(.app-nav-admin), .app-modal-card, .parameters-tabs,
  .app-auth-card, .app-alert,
  dialog.cmdk-modal, dialog.app-modal,
  .quick-add-menu, .app-notif-panel, .ev-context-menu,
  .app-planning-tabs, .app-planning-filter,
  .app-planning-week-day, .app-planning-month-cell,
  .app-btn-outline, .app-btn-ghost {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    background: var(--bg-secondary);
  }
  /* Fields: longhand to preserve the custom chevron on select elements. */
  .app-main input, .app-main select, .app-main textarea {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    background-color: var(--bg-secondary);
  }

  .app-nav-admin { -webkit-backdrop-filter: none !important; backdrop-filter: none !important; background: var(--navy, #0f2544); }
  /* Refraction and glint layers: all removed. */
  .app-nav:not(.app-nav-admin)::before,
  .app-nav:not(.app-nav-admin)::after,
  .app-modal-card::after, .app-auth-card::after,
  dialog.app-modal::after, dialog.cmdk-modal::after,
  .quick-add-menu::after, .app-notif-panel::after, .ev-context-menu::after { display: none !important; }
  /* Overlays/toasts outside the main block: also made opaque. */
  .app-welcome, .help-card, #app-toast-stack .app-flash {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    background: var(--bg-secondary);
  }
  /* Veils: the darkening stays, the blur goes. */
  .help-overlay, .app-modal, dialog::backdrop {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }
  .admin-share-toast { -webkit-backdrop-filter: none !important; backdrop-filter: none !important; background: var(--navy, #0f2544); }
  body.app-body, .app-auth { background: var(--bg-primary); }
}

/* Accessibility: enhanced contrast -------------------------------------- */
@media (prefers-contrast: more) {
  :root { --lg-border: rgba(10, 26, 50, 0.55); }
  :root[data-theme="dark"] { --lg-border: rgba(255, 255, 255, 0.60); }
}

/* Select INSIDE a filter pill (planning): no background of its own.
   The pill already provides the glass; without this, liquid-glass gives the select its
   own light background → a « carré blanc » behind the value (e.g. « Tous »).
   Keep it transparent + keep the dropdown arrow. */
.app-planning-filter select {
  background-color: transparent;
  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;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* Clean filters (.app-filters): fields without a white background — the value (e.g. « Tous »)
   no longer sits on a white square. A subtle outline remains, and the menu arrow is preserved. */
.app-filters select,
.app-filters input,
.app-filters textarea {
  background-color: transparent;
  border: 1px solid var(--separator);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.app-filters select {
  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.65rem center;
}
.app-filters select:focus,
.app-filters input:focus,
.app-filters textarea:focus {
  border-color: var(--accent);
}

/* ════════════════════════════════════════════════════════════════════════════
 * RODDIER SIGNATURE — admin shell (Phase 1)
 * 
 * Single converged concept: glass material (above, A) + side bar
 * structure (B) + brand gradient (C), within the navy visual identity. Tokens from app.css.
 * MENU LAYOUT = USER preference: class on <html>
 *   .nav-layout-side (default) → side bar
 *   .nav-layout-top           → top bar
 * set BEFORE the 1st paint by the head.ejs script (reading localStorage
 * 'app-nav-layout', like the theme → no flash, no server round trip).
 * SCOPE: standard back-office only → .app-nav-admin:not(.super-nav).
 * The publisher account (super-nav + macOS dock) retains its own structure.
 * ========================================================================== */
:root {
  --brand-grad: linear-gradient(120deg, #0f2544 0%, #1f4a86 34%, #2f6fb0 64%, #3f93c8 100%);
  --admin-side: rgba(15, 37, 68, 0.55);
  --admin-side-line: rgba(255, 255, 255, 0.12);
}
:root[data-theme="dark"] {
  --brand-grad: linear-gradient(120deg, #0f2544 0%, #1c3f72 34%, #285a96 64%, #3478b4 100%);
  --admin-side: rgba(13, 24, 44, 0.62);
  --admin-side-line: rgba(255, 255, 255, 0.09);
}

/* ── Brand gradient hero (opt-in via .app-hero on the page header) ─────────── */
.app-page-header.app-hero {
  background: var(--brand-grad); color: #fff;
  border-radius: var(--radius-xl, 18px); padding: 1.5rem 1.8rem; margin-bottom: 1.6rem;
  box-shadow: 0 16px 44px rgba(15, 37, 68, 0.28);
  position: relative; overflow: hidden; isolation: isolate;
}
.app-page-header.app-hero::before { content: none !important; }   /* neutralises the cockpit halo */
.app-page-header.app-hero::after {
  content: ""; position: absolute; right: -40px; top: -70px; width: 260px; height: 260px;
  border-radius: 50%; background: radial-gradient(circle, rgba(255,255,255,0.18), transparent 70%);
  pointer-events: none; z-index: -1;
}
.app-page-header.app-hero h1 { color: #fff; }
.app-page-header.app-hero p,
.app-page-header.app-hero .app-muted { color: rgba(255,255,255,0.86) !important; }
.app-page-header.app-hero .app-breadcrumb,
.app-page-header.app-hero .app-breadcrumb a { color: rgba(255,255,255,0.82); }
.app-page-header.app-hero .app-section-tag { background: rgba(255,255,255,0.18); color: #fff; }
.app-page-header.app-hero .app-btn-primary { background: #fff !important; color: #0f2544 !important; border-color: #fff !important; }
.app-page-header.app-hero .app-btn-outline { background: rgba(255,255,255,0.12) !important; color: #fff !important; border-color: rgba(255,255,255,0.55) !important; }

/* ── SHARED back-office bar appearance (navy glass) ────────────────────────── */
.app-nav-admin:not(.super-nav) {
  background: var(--admin-side) !important;
  -webkit-backdrop-filter: blur(28px) saturate(180%); backdrop-filter: blur(28px) saturate(180%);
  border: 1px solid var(--admin-side-line) !important;
  box-shadow: var(--lg-highlight), var(--lg-shadow-lg);
}
.app-nav-admin:not(.super-nav)::after,
.app-nav-admin:not(.super-nav)::before { display: none !important; }
.app-nav-admin:not(.super-nav) .app-nav-links a.active {
  position: relative; background: rgba(255,255,255,0.14) !important; color: #fff !important;
}
.app-nav-admin:not(.super-nav) .app-nav-links a.active::before {
  content: ""; position: absolute; background: #7aa2d6; border-radius: 3px; box-shadow: 0 0 8px rgba(122,162,214,0.55);
}

/* ── “LEFT” LAYOUT (side bar) — default ────────────────────────────────────── */
.nav-layout-side .app-nav-admin:not(.super-nav) {
  position: fixed; top: 12px; left: 12px; width: 244px; height: calc(100vh - 24px);
  border-radius: var(--radius-xl, 18px); z-index: 1000;
}
.nav-layout-side .app-nav-admin:not(.super-nav) .app-nav-inner {
  flex-direction: column; align-items: stretch; height: 100%; padding: 1rem 0.75rem; gap: 0.15rem; overflow: visible;
}
.nav-layout-side .app-nav-admin:not(.super-nav) .app-nav-brand { padding: 0.3rem 0.45rem 0.9rem; }
.nav-layout-side .app-nav-admin:not(.super-nav) .app-nav-links {
  flex-direction: column; align-items: stretch; gap: 3px; width: 100%; margin: 0.1rem 0 0; overflow-y: auto;
}
.nav-layout-side .app-nav-admin:not(.super-nav) .app-nav-links a {
  width: 100%; box-sizing: border-box; border-radius: 11px; padding: 0.55rem 0.65rem;
}
.nav-layout-side .app-nav-admin:not(.super-nav) .app-nav-links a.active::before { left: -1px; top: 7px; bottom: 7px; width: 3px; }
.nav-layout-side .app-nav-admin:not(.super-nav) .app-nav-user {
  margin-top: auto; display: flex; flex-wrap: wrap; align-items: center; gap: 0.2rem;
  padding-top: 0.7rem; border-top: 1px solid var(--admin-side-line);
}
.nav-layout-side .app-nav-admin:not(.super-nav) .admin-tools-panel { bottom: 100%; top: auto; left: 0; margin-bottom: 6px; max-height: 70vh; overflow-y: auto; }
.nav-layout-side .app-nav-admin:not(.super-nav) ~ .app-main,
.nav-layout-side .app-nav-admin:not(.super-nav) ~ .app-footer { margin-left: 268px; }

/* ── “TOP” LAYOUT (floating top bar) ───────────────────────────────────────── */
.nav-layout-top .app-nav-admin:not(.super-nav) {
  position: sticky; top: 12px; margin: 12px 16px 0; border-radius: var(--radius-xl, 18px); z-index: 1000;
}
.nav-layout-top .app-nav-admin:not(.super-nav) .app-nav-links a.active::before { left: 9px; right: 9px; bottom: 1px; height: 3px; }

/* ── Mobile fallback: both layouts → simple top bar ────────────────────────── */
@media (max-width: 900px) {
  .nav-layout-side .app-nav-admin:not(.super-nav) {
    position: static; width: auto; height: auto; margin: 0; border-radius: 0;
    border: none !important; border-bottom: 1px solid var(--admin-side-line) !important;
  }
  .nav-layout-side .app-nav-admin:not(.super-nav) .app-nav-inner { flex-direction: row; align-items: center; height: auto; padding: 0.5rem 0.8rem; }
  .nav-layout-side .app-nav-admin:not(.super-nav) ~ .app-main,
  .nav-layout-side .app-nav-admin:not(.super-nav) ~ .app-footer { margin-left: 0; }
  .nav-layout-side .app-nav-admin:not(.super-nav) .app-nav-user { margin-top: 0; border-top: none; padding-top: 0; }
}
