/* Fontes auto-hébergées identiques au site vitrine (yhdigitalfr.com) —
     aucune dépendance à Google Fonts ou toute autre CDN tierce. */
  @font-face {
    font-family: "Archivo";
    font-style: normal;
    font-weight: 400 800;
    font-stretch: 100% 125%;
    font-display: swap;
    src: url("/static/fonts/archivo-latin.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
      U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
      U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  @font-face {
    font-family: "IBM Plex Sans";
    font-style: normal;
    font-weight: 400 500;
    font-display: swap;
    src: url("/static/fonts/plex-latin.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
      U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
      U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }

  :root{
    /* Tokens identiques à yhdigitalfr.com/styles.css à l'origine — depuis la
       personnalisation (thème clair/sombre + couleur d'accent au choix,
       2026-08-16), --ink-* est redéfini par [data-theme="light"] ci-dessous
       et --rouge par [data-accent="..."] : tout composant qui lit ces
       variables suit automatiquement le choix de l'utilisateur sans qu'on
       ait à toucher un seul autre endroit du fichier. */
    --ink-950:#0e0c0c;
    --ink-900:#151212;
    --ink-800:#1b1717;
    --ink-700:#251f1d;
    --ink-500:#3e3532;
    --ink-300:#a9a09b;
    --ink-050:#f2eeec;

    --rouge:#d6402d;
    --rouge-soft:#7e4038;

    /* Danger/avertissement (bouton "supprimer", badge de risque, ÉTAT
       "dépassé" de la barre d'heures) — reste TOUJOURS rouge, quelle que
       soit la couleur d'accent choisie : ce sont de vraies alertes ("tu as
       dépassé ta base contractuelle"), pas une déco de marque, donc jamais
       personnalisables. Tout le reste qui utilisait le rouge par simple
       cohérence visuelle (intensité du calendrier, ÉTAT NORMAL de la barre
       d'heures) suit l'accent choisi via --rouge/--rouge-soft/--heat-* —
       retour Younes/Dylan 2026-08-16 : "je veux que la barre soit bleue si
       je choisis bleu", une visualisation doit être jolie dans la couleur
       choisie, seule une alerte réellement déclenchée doit rester rouge. */
    --color-danger:#d6402d;
    --color-danger-soft:#7e4038;

    /* Intensité du calendrier, 3 paliers — rgba() en dur (pas var(--rouge))
       car CSS ne permet pas d'extraire les canaux R/G/B d'une couleur
       hexadécimale ; chaque [data-accent] ci-dessous redéfinit ces 4
       variables avec les canaux de SA couleur. Valeurs par défaut = rouge. */
    --heat-1:rgba(214,64,45,.14);
    --heat-1-border:rgba(214,64,45,.45);
    --heat-2:rgba(214,64,45,.26);
    --heat-3:rgba(214,64,45,.42);

    --color-bg:var(--ink-950);
    --color-bg-alt:var(--ink-900);
    --color-text:var(--ink-050);
    --color-text-muted:var(--ink-300);
    --color-accent:var(--rouge);
    --color-rule:var(--ink-500);

    /* Ombre des cartes — aucune en thème sombre (une ombre portée ne se
       voit quasi pas sur fond déjà noir, et la bordure suffit à détacher
       la carte) ; une vraie ombre douce apparaît en thème clair, voir
       [data-theme="light"] ci-dessous, pour donner du relief sur fond
       quasi blanc. */
    --card-shadow:none;

    --font-display:"Archivo","Helvetica Neue",Helvetica,Arial,sans-serif;
    --font-text:"IBM Plex Sans","Helvetica Neue",Helvetica,Arial,sans-serif;

    --dur:.5s;
    --ease-out:cubic-bezier(0.16,0.84,0.32,1);
  }

  /* Thème clair — ramp --ink-* inversée en conservant les mêmes rôles
     (950=fond de page, 900=fond carte, 500=bordures, 300=texte atténué,
     050=texte principal) pour que tout le reste du CSS s'applique sans
     modification. Contrastes vérifiés : ink-300 (#6b615c) sur blanc ≈ 6:1,
     ink-050 (#1b1717) sur blanc ≈ 16:1 — largement au-dessus du seuil AA.
     --ink-500 (bordures/séparateurs) assombri le 2026-08-17 — la première
     valeur (#c3b8b1) était trop proche du blanc des cartes, l'app paraissait
     plate/austère sans l'ambiance que le fond noir donne gratuitement au
     thème sombre (retour Younes/Dylan). */
  :root[data-theme="light"]{
    --ink-950:#faf8f7;
    --ink-900:#ffffff;
    --ink-800:#f0ece9;
    --ink-700:#e4ddd9;
    --ink-500:#a89890;
    --ink-300:#6b615c;
    --ink-050:#1b1717;
    --card-shadow:0 1px 3px rgba(30,20,15,.08), 0 4px 10px rgba(30,20,15,.05);
  }

  /* Couleur d'accent — palette restreinte (pas de sélecteur libre) pour
     garantir un rendu propre : chaque option redéfinit --rouge (bordures,
     focus, bouton principal au survol, total du calendrier...), --rouge-soft
     (état normal de la barre d'heures) ET les 4 variables --heat-*
     (intensité du calendrier, mêmes canaux R/G/B que --rouge). --rouge-soft
     est une version assombrie/désaturée de --rouge, même logique que
     l'oxyde du rouge par défaut (#7e4038 pour #d6402d) — pas une science
     exacte, juste "moins vif, toujours identifiable comme la même teinte".
     Le rouge par défaut n'a pas besoin de bloc, c'est déjà la valeur de
     :root. Le danger/risque (--color-danger*) n'est jamais touché ici —
     voir le commentaire dans :root. */
  :root[data-accent="bleu"]{
    --rouge:#2f6fd6; --rouge-soft:#2f4368;
    --heat-1:rgba(47,111,214,.14); --heat-1-border:rgba(47,111,214,.45);
    --heat-2:rgba(47,111,214,.26); --heat-3:rgba(47,111,214,.42);
  }
  :root[data-accent="vert"]{
    --rouge:#2e8f52; --rouge-soft:#28553a;
    --heat-1:rgba(46,143,82,.14); --heat-1-border:rgba(46,143,82,.45);
    --heat-2:rgba(46,143,82,.26); --heat-3:rgba(46,143,82,.42);
  }
  :root[data-accent="violet"]{
    --rouge:#7c4fd1; --rouge-soft:#4e3d70;
    --heat-1:rgba(124,79,209,.14); --heat-1-border:rgba(124,79,209,.45);
    --heat-2:rgba(124,79,209,.26); --heat-3:rgba(124,79,209,.42);
  }
  :root[data-accent="orange"]{
    --rouge:#c96a1f; --rouge-soft:#764527;
    --heat-1:rgba(201,106,31,.14); --heat-1-border:rgba(201,106,31,.45);
    --heat-2:rgba(201,106,31,.26); --heat-3:rgba(201,106,31,.42);
  }
  :root[data-accent="turquoise"]{
    --rouge:#1f8f8f; --rouge-soft:#1c5252;
    --heat-1:rgba(31,143,143,.14); --heat-1-border:rgba(31,143,143,.45);
    --heat-2:rgba(31,143,143,.26); --heat-3:rgba(31,143,143,.42);
  }
  *{box-sizing:border-box;}
  :focus-visible{ outline:2px solid var(--rouge); outline-offset:2px; }
  body{
    margin:0;
    background:var(--color-bg);
    color:var(--color-text);
    font-family:var(--font-text);
    font-weight:400;
    -webkit-font-smoothing:antialiased;
    min-height:100vh;
    min-height:100dvh;
  }
  a{ color:inherit; }
  header{
    max-width:640px;
    margin:0 auto;
    /* max() avec env(safe-area-inset-top) : sur un iPhone à encoche/île
       dynamique, quand la page tourne en PWA installée plein écran
       (viewport-fit=cover, employee_form.html/employee_select.html), le
       contenu passe SOUS la barre de statut par défaut — sans cette
       marge de sécurité, le wordmark se retrouve visuellement collé/
       chevauché par l'heure et les icônes système. Sans effet sur les
       pages sans viewport-fit=cover (env() y vaut 0, max() retombe sur
       le plancher fixe) ni sur desktop.
       Plancher remonté de 28px à 54px le 08/08/2026 : chevauchement réel
       constaté par Younes sur iPhone (capture à l'appui) malgré cette
       règle — `env(safe-area-inset-top)` ne remonte pas toujours la
       vraie hauteur de la barre de statut dans tous les contextes iOS
       (ex: Safari avec barre d'adresse repliée au scroll, hors vraie PWA
       standalone), donc `env()` peut renvoyer 0 alors que la barre de
       statut est bien visible à l'écran. 54px couvre la hauteur d'une
       île dynamique (~59pt) même quand env() est à 0 — ne dépend plus
       uniquement de env() pour être correct. */
    padding:max(54px, calc(env(safe-area-inset-top, 0px) + 18px)) 20px 16px 20px;
    border-bottom:1px solid var(--color-rule);
    display:flex;
    justify-content:space-between;
    align-items:center;
    flex-wrap:wrap;
    gap:12px;
  }
  header.wide{ max-width:1040px; }

  /* Bannière d'installation PWA (écran employé) — masquée par défaut,
     affichée par JS uniquement si pertinent (pas déjà installée, pas
     déjà fermée). Toujours au-dessus du header : jamais affichée en PWA
     standalone (pas de conflit avec le padding "encoche" du header,
     réservé à ce contexte-là). */
  .install-banner{
    display:none; align-items:center; gap:10px;
    background:var(--ink-900); border-bottom:1px solid var(--rouge);
    padding:10px 16px; font-size:13px; line-height:1.4;
  }
  .install-banner.open{ display:flex; }
  .install-banner span{ flex:1; }
  .install-banner .btn{ width:auto; padding:8px 14px; font-size:11px; flex-shrink:0; }
  .install-banner-close{
    background:none; border:none; color:var(--ink-300); font-size:20px;
    line-height:1; cursor:pointer; padding:2px 4px; flex-shrink:0;
  }

  /* Mini-tuto "Ajouter à l'écran d'accueil" (iPhone) — ouvert depuis le
     lien "Comment faire ?" du bandeau d'installation. */
  .install-tutorial-step{ margin-top:16px; font-size:13px; color:var(--ink-300); }
  .install-tutorial-step p{ margin:0 0 8px 0; line-height:1.5; }
  .install-tutorial-step strong{ color:var(--ink-050); }
  .install-tutorial-target{
    display:flex; align-items:center; gap:10px;
    border:2px solid var(--rouge); border-radius:8px;
    padding:10px 12px; color:var(--ink-050); font-size:13px;
  }
  .header-left{ display:flex; align-items:center; gap:12px; }
  /* Wordmark repris tel quel du site vitrine : Archivo gras, majuscules,
     tracking large, point carré rouge — pas de logo réinventé. */
  h1.wordmark{
    font-family:var(--font-display);
    font-weight:700;
    font-stretch:115%;
    font-size:1.375rem;
    letter-spacing:.18em;
    line-height:1;
    color:var(--color-text);
    text-transform:uppercase;
    margin:0;
  }
  .wordmark-dot{
    display:inline-block;
    width:.34em; height:.34em;
    background:var(--rouge);
    margin-left:.16em;
    vertical-align:.06em;
  }
  header .subtitle{
    font-family:var(--font-display);
    font-size:10px;
    letter-spacing:.22em;
    text-transform:uppercase;
    color:var(--color-text-muted);
    margin-top:6px;
  }
  main{ padding:24px 20px 60px 20px; max-width:640px; margin:0 auto; }
  main.wide{ max-width:1040px; }

  h2{
    font-family:var(--font-display);
    font-weight:700;
    font-stretch:112%;
    letter-spacing:.01em;
  }

  /* Système d'icônes SVG (_icons.html) — remplace les emoji : rendu
     identique sur tout OS/navigateur, un seul trait (stroke 1.75),
     hérite de currentColor pour matcher le texte autour. Les titres qui
     combinent icône+texte utilisent .h-icon (display:flex) — pas toutes
     les h2 par défaut, pour ne pas casser le text-align:center hérité
     des h2 sans icône (ex. cartes de pricing/modals centrées). */
  .icon{ flex-shrink:0; }
  .h-icon{ display:flex; align-items:center; gap:8px; }
  /* Icône en couleur d'accent dans les titres de carte (icon+texte) — le
     texte du titre reste dans la couleur normale, seule l'icône hérite de
     --rouge (elle seule lit currentColor via ce sélecteur, pas le h2
     parent). Ajouté suite au retour "ça manque de couleur en thème clair"
     — le fond quasi blanc n'a pas l'ambiance gratuite du thème sombre,
     donc l'accent doit se montrer un peu plus qu'un simple filet. */
  .h-icon .icon{ color:var(--rouge); }

  /* Boutons — repris de .btn-cta (yhdigitalfr.com) : fond clair sur fond
     sombre, bordure, bascule vers transparent + bordure rouge au survol.
     Pas de boutons pleins colorés. */
  .btn{
    display:inline-flex; align-items:center; justify-content:center; gap:8px;
    width:100%;
    padding:16px 18px;
    font-family:var(--font-display);
    font-size:.8125rem;
    font-weight:700;
    font-stretch:112%;
    letter-spacing:.12em;
    line-height:1;
    text-transform:uppercase;
    text-decoration:none;
    background:var(--ink-050);
    color:var(--ink-950);
    border:1px solid var(--ink-050);
    cursor:pointer;
    transition:background var(--dur) var(--ease-out), color var(--dur) var(--ease-out),
               border-color var(--dur) var(--ease-out);
  }
  .btn:hover{ background:transparent; color:var(--ink-050); border-color:var(--rouge); }
  .btn:active{ transform:scale(0.99); }
  .btn.secondary{ background:transparent; color:var(--ink-300); border:1px solid var(--ink-500); }
  .btn.secondary:hover{ color:var(--ink-050); border-color:var(--ink-050); }
  .btn.danger{ background:transparent; color:var(--color-danger); border:1px solid var(--color-danger-soft); }
  .btn.danger:hover{ background:var(--color-danger); color:var(--ink-050); border-color:var(--color-danger); }

  .ghost-btn{
    padding:11px 16px;
    border:1px solid var(--ink-500);
    background:transparent; color:var(--ink-300);
    font-family:var(--font-display); font-weight:700; font-stretch:112%;
    font-size:11px; text-transform:uppercase; letter-spacing:.1em;
    cursor:pointer; transition:.15s; text-decoration:none;
    display:inline-flex; align-items:center; gap:6px;
  }
  .ghost-btn:hover{ border-color:var(--ink-050); color:var(--ink-050); }

  /* Cible tactile ≥44px (padding, pas de marge visuelle ajoutée au texte) —
     les .link-btn étaient trop petits/collés entre eux sur mobile. */
  .link-btn{
    display:inline-flex; align-items:center; gap:5px;
    background:none; border:none; color:var(--ink-300); font-size:13px;
    font-family:var(--font-text);
    cursor:pointer; text-decoration:underline;
    padding:12px 8px; min-height:44px;
  }
  .link-btn:hover{ color:var(--ink-050); }
  .link-btn.danger{ color:var(--color-danger); }
  .link-btn.danger:hover{ color:#ff6b56; }

  .action-group{ display:flex; align-items:center; flex-wrap:wrap; gap:2px; }

  .tile{
    display:flex; align-items:center; gap:14px;
    background:var(--ink-900); border:1px solid var(--color-rule);
    padding:18px 16px; margin-bottom:10px; text-decoration:none; color:var(--color-text);
    transition:.15s; cursor:pointer; width:100%; text-align:left;
  }
  .tile:hover, .tile:active{ border-color:var(--rouge); background:var(--ink-800); }
  .avatar{
    width:44px; height:44px; flex-shrink:0;
    background:var(--ink-800); border:1px solid var(--ink-500);
    color:var(--ink-300);
    display:flex; align-items:center; justify-content:center;
    font-family:var(--font-display); font-weight:700; font-size:15px;
  }
  .tile-name{ font-weight:600; font-size:16px; font-family:var(--font-text); }
  .tile-role{ font-size:12px; color:var(--ink-300); margin-top:2px; }
  .tile-badges{ margin-left:auto; display:flex; gap:6px; flex-shrink:0; }

  /* Badges d'alerte : un seul accent rouge, rationné, réservé à ce qui est
     vraiment urgent (risque de requalification). Le reste reste neutre
     (ink-300 sur ink-800) pour ne pas diluer le signal. --color-danger-soft
     en fond garantit un contraste élevé (~6.8:1) avec du texte ink-050 —
     vérifié pour rester lisible en plein soleil, contrairement à du texte
     rouge sur fond sombre (~4.3:1, plus fragile). Toujours rouge fixe, même
     si l'accent de marque est personnalisé — voir --color-danger dans :root. */
  /* display:inline-block + white-space:nowrap : sans ça, un badge a deux
     mots (ex. "Hors horaire") peut se couper au milieu sur une colonne
     etroite comme "Jour concerne" de l'Historique — l'espace interne au
     badge se comporte alors comme un retour a la ligne normal, ce qui
     coupe le badge en deux lignes au lieu de le faire simplement passer
     entier a la ligne suivante (signale par Younes, 2026-08-19). */
  .badge{
    display:inline-block; white-space:nowrap;
    font-family:var(--font-display);
    font-size:10px; font-weight:700; font-stretch:112%;
    padding:4px 8px;
    text-transform:uppercase; letter-spacing:.06em;
    border:1px solid var(--ink-500); color:var(--ink-300);
  }
  .badge.overtime, .badge.complementary{ border-color:var(--ink-500); color:var(--ink-050); }
  .badge.risk{ background:var(--color-danger-soft); border-color:var(--color-danger-soft); color:var(--ink-050); }

  label{
    display:block; font-family:var(--font-display); font-size:11px; color:var(--ink-300);
    margin:16px 0 6px 0; font-weight:700; font-stretch:110%;
    text-transform:uppercase; letter-spacing:.08em;
  }
  input, select{
    width:100%; padding:13px 12px; border:1px solid var(--ink-500);
    background:var(--ink-900); color:var(--color-text); font-size:16px; font-family:var(--font-text);
  }
  input:focus, select:focus{ border-color:var(--rouge); }

  /* Chevron custom (remplace la flèche native du système, incohérente
     entre navigateurs/OS) — SVG en data-URI, couleur ink-300 figée car
     ce thème n'a pas de variante claire. */
  select{
    appearance:none; -webkit-appearance:none; -moz-appearance:none;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23a9a09b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat:no-repeat;
    background-position:right 12px center;
    padding-right:36px;
    cursor:pointer;
  }
  select::-ms-expand{ display:none; }

  .quick-choice-row{ display:flex; gap:8px; margin-top:6px; }
  .chip-btn{
    flex:1; padding:10px; min-height:44px; border:1px solid var(--ink-500);
    background:transparent; color:var(--ink-300);
    font-family:var(--font-display); font-size:12px; font-weight:700; letter-spacing:.04em;
    text-transform:uppercase;
    cursor:pointer;
    display:flex; align-items:center; justify-content:center;
  }
  .chip-btn:hover{ border-color:var(--ink-050); color:var(--ink-050); }
  .chip-btn.active{ border-color:var(--rouge); color:var(--ink-050); }

  /* Personnalisation d'apparence (thème/accent) — voir theme.js. Les
     pastilles de couleur sont la seule fois où ce fichier pose une couleur
     "en dur" en dehors d'un token : c'est le but exact de l'écran (montrer
     chaque option telle qu'elle sera), donc pas de var() ici. */
  .appearance-row{ display:flex; gap:10px; margin-top:6px; flex-wrap:wrap; }
  .appearance-swatches{ margin-top:14px; }
  .appearance-swatch{
    width:36px; height:36px; border-radius:50%; border:2px solid transparent;
    padding:0; cursor:pointer; box-shadow:inset 0 0 0 1px rgba(0,0,0,.15);
  }
  .appearance-swatch.active{ border-color:var(--ink-050); }
  .appearance-swatch:hover{ transform:scale(1.08); }

  /* Sélecteur "Autre date" (jour/mois/année) — remplace un
     <input type="date"> natif qui débordait de l'écran sur iPhone en
     PWA (2026-08-08). Mêmes selects stylés que les heures, jamais un
     contrôle natif non maîtrisé pour la saisie de date. */
  .date-select-row{ display:flex; gap:8px; margin-top:10px; }
  .date-select-row select{ flex:1; min-width:0; }

  /* Plus de cadre autour de ce bloc (créait un double-cadre avec la carte
     du formulaire elle-même) — la séparation entre "Date" et "Service
     midi/soir" se fait par l'espacement (margin-top) et le libellé en
     majuscules ci-dessous, pas par une seconde bordure. */
  .shift-section{ margin-top:28px; }
  .shift-section-title{
    font-family:var(--font-display); font-weight:700; font-stretch:112%;
    font-size:13px; text-transform:uppercase; letter-spacing:.05em;
    display:flex; justify-content:space-between; align-items:center;
  }
  .manual-time-row{ display:flex; gap:12px; margin-top:8px; }
  .manual-time-row > div{ flex:1; min-width:0; }
  .field-label-row{ display:flex; justify-content:space-between; align-items:baseline; gap:8px; }
  .field-label-row .link-btn{ font-size:11px; }
  .time-picker{ display:flex; align-items:center; gap:6px; min-width:0; }
  /* Padding réduit par rapport aux selects standard (36px de marge pour
     le chevron, pensés pour du texte long comme "Janvier") — ces selects
     ne contiennent jamais que 2 chiffres, le chevron generic laissait
     trop peu de place aux 4 selects d'une ligne arrivée/départ sur un
     petit écran (débordement de carte observé à 320px). */
  .time-picker select{
    text-align:center; flex:1; min-width:0;
    padding-left:2px; padding-right:18px;
    background-position:right 2px center;
  }

  /* Éditeur d'horaire habituel (Équipe → Ajouter/Modifier un employé) —
     une ligne compacte par jour, les heures n'apparaissent que si le jour
     est coché ; empile en colonne sous 380px pour ne jamais répéter le
     débordement des time-pickers sur petit écran. */
  .schedule-editor{ display:flex; flex-direction:column; gap:8px; }
  .schedule-day-row{ border:1px solid var(--color-rule); padding:8px 10px; }
  .schedule-day-row.error{ border-color:var(--color-danger); }
  .schedule-day-toggle{ display:flex; align-items:center; gap:8px; font-size:13px; text-transform:none; letter-spacing:normal; font-weight:400; margin:0; cursor:pointer; }
  .schedule-day-toggle input{ width:auto; margin:0; }
  .schedule-day-times{ align-items:center; gap:8px; margin-top:8px; }
  .schedule-day-times .time-picker{ flex:1; }

  /* Messages : bordure rouge à gauche (motif repris du site — citations en
     border-left rouge) plutôt que du texte rouge, pour un contraste
     maximal (texte ink-050 sur surface sombre) quelles que soient les
     conditions de lecture. */
  .result-msg{
    display:flex; align-items:center; gap:7px;
    margin-top:14px; padding:12px 14px; font-size:14px;
    background:var(--ink-900); border-left:3px solid var(--ink-500);
  }
  .result-msg.error{ border-left-color:var(--color-danger); }
  .result-msg.ok{ border-left-color:var(--ink-050); }

  .feedback-overlay{
    display:none; position:fixed; inset:0; background:rgba(14,12,12,.88);
    align-items:center; justify-content:center; z-index:50; padding:20px;
  }
  .feedback-overlay.open{ display:flex; }
  /* max-height + overflow-y : même correctif que .modal-box (voir plus bas)
     — cette boîte sert aussi à "Ajouter un employé" (dashboard.php), un
     formulaire long (nom/poste/heures/panier repas/horaire habituel) qui
     débordait de l'écran sans rien à scroller, bouton "Ajouter" inatteignable
     (retour Younes, 2026-08-17). Sans effet sur les feedbacks courts
     (confirmation "Enregistré." côté employé) qui ne remplissent jamais la
     hauteur disponible. */
  .feedback-box{
    background:var(--ink-900); border:1px solid var(--color-rule);
    padding:32px; text-align:center; max-width:340px;
    max-height:calc(100vh - 40px); overflow-y:auto;
  }
  .feedback-icon{ display:flex; align-items:center; justify-content:center; }
  .feedback-icon .icon{ width:40px; height:40px; }
  .feedback-icon.ok .icon{ color:var(--ink-050); }
  .feedback-icon.error .icon{ color:var(--color-danger); }
  .feedback-name{ font-family:var(--font-display); font-weight:700; font-stretch:115%; font-size:22px; margin-top:10px; text-transform:uppercase; letter-spacing:.02em; }
  .feedback-status{ font-family:var(--font-display); font-weight:700; letter-spacing:.08em; text-transform:uppercase; font-size:11px; color:var(--ink-300); margin-top:8px; }
  .feedback-message{ font-size:13px; color:var(--ink-300); margin-top:8px; }

  /* Modals maison — remplacent prompt()/confirm() natifs du navigateur
     (illisibles, non stylables, incohérents avec la charte). Réutilisent
     le même overlay plein écran que .feedback-overlay. */
  .modal-overlay{
    display:none; position:fixed; inset:0; background:rgba(14,12,12,.88);
    align-items:center; justify-content:center; z-index:60; padding:20px;
  }
  /* #confirm-overlay peut maintenant s'ouvrir PAR-DESSUS un autre modal deja
     ouvert (ex. "Supprimer" depuis la modale d'edition de service du
     Planning, 2026-09-13) — a z-index egal, tous les .modal-overlay partagent
     le meme empilement et c'est l'ordre DANS LE HTML qui tranche, jamais
     l'ordre d'ouverture ; confirm-overlay etant declare AVANT la plupart des
     autres modales dans dashboard.php, il se retrouvait rendu EN DESSOUS
     d'une modale ouverte apres lui — bouton "Confirmer" invisible et
     inatteignable. Bug reel trouve en testant le Planning en local. */
  #confirm-overlay{ z-index:70; }
  .modal-overlay.open{ display:flex; }
  /* max-height + overflow-y : sans ça, une modale au contenu long (ex.
     plusieurs jours cochés dans l'éditeur d'horaire habituel) débordait
     purement et simplement de l'écran, sans rien à scroller nulle part —
     le bouton "Enregistrer" devenait inatteignable. calc(100vh - 40px)
     laisse la marge des 20px de padding haut/bas de .modal-overlay. */
  .modal-box{
    background:var(--ink-900); border:1px solid var(--color-rule);
    padding:24px; width:100%; max-width:360px;
    max-height:calc(100vh - 40px); overflow-y:auto;
  }
  .modal-title{
    font-family:var(--font-display); font-weight:700; font-stretch:112%;
    font-size:15px; text-transform:uppercase; letter-spacing:.04em;
    display:flex; align-items:center; gap:8px; margin:0;
  }
  .modal-body{ font-size:13px; color:var(--ink-300); margin-top:10px; line-height:1.5; }
  .modal-box label{ margin:16px 0 6px 0; }
  /* flex-wrap + min-width : sur un petit écran, "ENREGISTRER" (mot
     insécable, majuscules, letter-spacing) ne peut pas rétrécir sous sa
     propre largeur — empile les deux boutons plutôt que de les laisser
     déborder de la modale (débordement observé à 320px). */
  .modal-actions{ display:flex; flex-wrap:wrap; gap:10px; margin-top:20px; }
  .modal-actions .btn{ width:auto; flex:1; min-width:120px; padding:12px 14px; min-height:44px; }
  .modal-close{
    position:absolute; top:12px; right:12px; background:none; border:none;
    color:var(--ink-300); cursor:pointer; padding:10px; display:flex;
    min-width:44px; min-height:44px; align-items:center; justify-content:center;
  }
  .modal-close:hover{ color:var(--ink-050); }
  .modal-box{ position:relative; }

  /* Champ code à 4 chiffres — partagé entre le code employé
     (employee_form.php) et le verrouillage rapide du tableau de bord
     gérant (dashboard.php), même apparence dans les deux cas. */
  .pin-input{ font-size:28px; text-align:center; letter-spacing:0.5em; padding:16px 12px; }

  /* Verrouillage rapide du tableau de bord (dashboard.php uniquement) —
     recouvre tout, y compris l'écran de démarrage (z-index 300), tant que
     le code local n'a pas été saisi. Ce n'est PAS la vraie protection du
     compte (le mot de passe + la session l'assurent déjà) : juste un
     confort pour rouvrir l'app sans retaper le mot de passe à chaque fois,
     propre à cet appareil (jamais transmis au serveur, voir dashboard.php). */
  .dash-lock-overlay{
    display:none; position:fixed; inset:0; z-index:350;
    background:var(--ink-950); align-items:center; justify-content:center; padding:20px;
  }
  .dash-lock-overlay.open{ display:flex; }
  .dash-lock-box{ max-width:360px; width:100%; }

  .card{ background:var(--ink-900); border:1px solid var(--color-rule); padding:18px; margin-bottom:16px; box-shadow:var(--card-shadow); }
  .card h2{ font-size:15px; margin:0 0 12px 0; }

  /* Revue de disposition 2026-08-08, puis 2026-09-13 (retour Younes,
     capture a l'appui — voir le commentaire dans dashboard.php) : sous
     860px, les 4 cartes restent simplement empilees pleine largeur dans
     leur ordre naturel (.overview-col devient display:contents, invisible
     pour la mise en page — l'ordre de lecture mobile reste inchange :
     semaine, alertes, mois, notes). Au-dela de 860px, DEUX COLONNES
     INDEPENDANTES (chacune empile ses 2 cartes a SA propre hauteur, sans
     dependre de l'autre colonne) — corrige le vide qui apparaissait sous
     "Heures cette semaine" quand "Heures ce mois-ci" (plus haute, une
     ligne "Reste XXh" en plus par employe) forcait toute la ligne de
     grille a s'etirer, un ancien design en grille 2 colonnes/2 lignes ne
     marchait plus une fois les listes trop dissemblables en hauteur. */
  .overview-grid{ display:flex; flex-direction:column; gap:16px; }
  .overview-grid > .card{ margin-bottom:0; }
  .overview-col{ display:contents; }
  @media (min-width:860px){
    .overview-grid{ flex-direction:row; align-items:flex-start; }
    .overview-col{ display:flex; flex-direction:column; gap:16px; flex:1; min-width:0; }
    .overview-col:first-child{ flex:1.4; }
  }

  /* Navigation latérale du tableau de bord gérant — un vrai panneau à
     gauche en permanence sur desktop. Sous 860px, ce n'est plus
     converti en barre d'onglets horizontale (défilement peu
     découvrable, "Mon compte"/"Export" invisibles sans scroller) : le
     MÊME panneau devient un tiroir qui glisse depuis la gauche,
     déclenché par un bouton menu dans l'en-tête — reste un panneau de
     gauche, homogène avec le desktop, juste caché par défaut. */
  .dash-layout{ display:flex; gap:28px; align-items:flex-start; }
  .dash-sidebar{
    width:220px; flex-shrink:0; position:sticky; top:24px;
    display:flex; flex-direction:column; gap:2px;
  }
  .sidebar-link{
    display:flex; align-items:center; gap:10px;
    padding:12px 14px; min-height:44px; width:100%;
    background:none; border:none; border-left:3px solid transparent;
    color:var(--ink-300); font-family:var(--font-text); font-size:14px;
    text-align:left; cursor:pointer; transition:.15s;
  }
  .sidebar-link:hover{ color:var(--ink-050); background:var(--ink-900); }
  .sidebar-link.active{ border-left-color:var(--rouge); color:var(--ink-050); background:var(--ink-900); }
  .dash-main{ flex:1; min-width:0; }
  .dash-section[hidden]{ display:none; }

  .dash-menu-toggle{ display:none; }
  .dash-sidebar-backdrop{ display:none; }
  /* Visible seulement en tiroir mobile (voir règle plus bas) — sur
     desktop le panneau est fixe et permanent, un bouton "fermer" dessus
     n'aurait rien à rouvrir puisque .dash-menu-toggle y est lui-même
     masqué. */
  .dash-sidebar-close{ display:none; }

  @media (max-width:860px){
    .dash-menu-toggle{
      display:inline-flex; align-items:center; justify-content:center;
      width:44px; height:44px; flex-shrink:0;
      border:1px solid var(--color-rule); background:transparent; color:var(--ink-050);
      cursor:pointer;
    }
    .dash-menu-toggle:hover{ border-color:var(--ink-050); }

    /* Sans ce bouton, la seule façon de refermer le tiroir était de
       cliquer le fond assombri en dehors du panneau — pas du tout
       intuitif (signalé par Younes), surtout que le panneau occupe déjà
       82% de la largeur sur un petit écran. */
    .dash-sidebar-close{
      display:flex; align-items:center; justify-content:center;
      position:absolute; top:calc(env(safe-area-inset-top, 0px) + 14px); right:10px;
      width:40px; height:40px; z-index:1;
      background:none; border:none; color:var(--ink-300); cursor:pointer;
    }
    .dash-sidebar-close:hover{ color:var(--ink-050); }

    .dash-sidebar-backdrop{
      display:block; position:fixed; inset:0; z-index:199;
      background:rgba(0,0,0,.6); opacity:0; pointer-events:none;
      transition:opacity .2s var(--ease-out);
    }
    .dash-sidebar-backdrop.open{ opacity:1; pointer-events:auto; }

    .dash-sidebar{
      position:fixed; top:0; bottom:0; left:0; z-index:200;
      width:min(82vw, 300px);
      background:var(--ink-950); border-right:1px solid var(--color-rule);
      padding:calc(env(safe-area-inset-top, 0px) + 20px) 0 20px 0;
      overflow-y:auto;
      transform:translateX(-100%);
      transition:transform .25s var(--ease-out);
      box-shadow:0 0 40px rgba(0,0,0,.5);
    }
    .dash-sidebar.open{ transform:translateX(0); }
    .sidebar-link{ padding:13px 22px; }
  }
  @media (max-width:860px) and (prefers-reduced-motion:reduce){
    .dash-sidebar, .dash-sidebar-backdrop{ transition:none; }
  }

  table{ width:100%; border-collapse:collapse; font-size:13px; font-family:var(--font-text); }
  th, td{ text-align:left; padding:8px 6px; border-bottom:1px solid var(--color-rule); }
  th{
    font-family:var(--font-display); color:var(--ink-300); font-weight:700;
    text-transform:uppercase; font-size:10px; letter-spacing:.06em;
  }

  .alert-row{ display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:4px 10px; padding:10px 0; border-bottom:1px solid var(--color-rule); font-size:13px; }
  .alert-row:last-child{ border-bottom:none; }
  /* Sous 480px, deux lignes de contenu (ex: "Corinne · Polyvalent") + le
     groupe de boutons ("Modifier"/"Réinitialiser code"/"Retirer") ne
     tiennent plus toujours sur une seule ligne — mais flex-wrap seul
     bascule ce point de rupture au cas par cas selon la longueur exacte
     du nom/poste de CHAQUE employé, donc certaines lignes restaient sur
     une ligne et d'autres non : résultat visuellement incohérent d'une
     ligne à l'autre (signalé par Younes). Empile TOUJOURS les deux
     dessous ce seuil, pour que toutes les lignes s'alignent pareil quel
     que soit le nom. */
  @media (max-width:480px){
    .alert-row{ flex-direction:column; align-items:flex-start; gap:6px; }
  }
  .empty-state{ color:var(--ink-300); font-size:13px; padding:12px 0; }

  /* Messagerie SAV en bulles façon messagerie instantanée, plutôt que
     des lignes rectangulaires façon tableau (signalé par Younes). */
  .chat-thread{ display:flex; flex-direction:column; gap:10px; padding:6px 2px; max-height:420px; overflow-y:auto; }
  .chat-bubble-row{ display:flex; }
  .chat-bubble-row.mine{ justify-content:flex-end; }
  .chat-bubble-row.theirs{ justify-content:flex-start; }
  .chat-bubble{ max-width:75%; padding:9px 13px; border-radius:16px; font-size:13px; line-height:1.45; word-break:break-word; }
  .chat-bubble.mine{ background:var(--rouge); color:#fff; border-bottom-right-radius:4px; }
  .chat-bubble.theirs{ background:var(--ink-800); border:1px solid var(--color-rule); border-bottom-left-radius:4px; }
  .chat-bubble-sender{ font-size:10px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; opacity:.7; margin-bottom:3px; }
  .chat-bubble-meta{ font-size:10px; opacity:.65; margin-top:4px; text-align:right; }
  @media (max-width:480px){
    .chat-bubble{ max-width:88%; }
  }

  /* Aperçu visuel des heures de la semaine — carte d'accueil du tableau
     de bord (section "Vue d'ensemble"), pour qu'un gérant voie l'essentiel
     d'un coup d'œil sans avoir à naviguer, au lieu de tomber sur une
     carte d'alertes souvent vide. */
  .week-hours-row{ padding:10px 0; border-bottom:1px solid var(--color-rule); }
  .week-hours-row:last-child{ border-bottom:none; }
  .week-hours-row-top{ display:flex; justify-content:space-between; font-size:13px; margin-bottom:6px; }
  .week-hours-bar{ height:6px; background:var(--ink-800); overflow:hidden; }
  /* État normal = version atténuée de l'accent choisi (--rouge-soft, voir
     [data-accent] plus haut) — une barre de progression n'est pas une
     alerte, elle doit refléter la couleur choisie. .over bascule sur
     --color-danger (rouge vif FIXE) au dépassement : un changement de
     TEINTE (accent → rouge) se remarque bien plus qu'une simple variation
     d'intensité, y compris quand l'accent est déjà rouge par défaut
     (--rouge-soft y reste l'ancien "oxyde" atténué, --color-danger le rouge
     vif — la distinction normal/dépassé reste donc visible dans tous les cas). */
  .week-hours-bar-fill{ height:100%; background:var(--rouge-soft); }
  .week-hours-bar-fill.over{ background:var(--color-danger); }

  form.inline{ display:flex; gap:8px; flex-wrap:wrap; align-items:flex-end; }
  form.inline > div{ flex:1; min-width:120px; }
  form.inline label{ margin:0 0 4px 0; }

  .qr-box{ text-align:center; }
  .qr-box img{ width:180px; height:180px; background:#fff; padding:8px; }
  .share-link{ display:flex; gap:8px; margin-top:12px; }
  .share-link input{ flex:1; font-size:13px; }

  .topbar{ display:flex; justify-content:space-between; align-items:center; margin-bottom:16px; }

  .calendar-controls{ display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
  .calendar-controls select{ flex:1; min-width:140px; }
  .calendar-header-row{ display:flex; justify-content:space-between; align-items:center; margin-top:16px; }
  .calendar-nav-btn{
    background:transparent; border:1px solid var(--color-rule); color:var(--ink-050);
    width:44px; height:44px; cursor:pointer; font-family:inherit;
    display:inline-flex; align-items:center; justify-content:center;
  }
  .calendar-nav-btn:hover{ border-color:var(--rouge); }
  .calendar-month-label{
    font-family:var(--font-display); font-weight:700; font-stretch:110%;
    text-transform:uppercase; letter-spacing:.05em; font-size:13px;
  }
  .calendar-summary{ font-size:13px; color:var(--ink-300); margin-top:10px; }
  /* minmax(0, 1fr), pas juste 1fr : sans le "0", chaque colonne garde un
     plancher de largeur = son contenu minimal (min-content), et un
     libellé comme "8h30" force alors TOUTE la grille à déborder du cadre
     sur un petit écran (ex. iPhone X ~375px) — invisible sur un écran
     large ou desktop où 1/7 de la largeur suffit déjà, ce qui explique
     que ça n'avait jamais été repéré avant (signalé par Younes via une
     capture du téléphone d'Aline, 2026-08-19). Les deux grilles (en-têtes
     ET jours) doivent rester identiques pour que les colonnes s'alignent. */
  .calendar-weekdays{
    display:grid; grid-template-columns:repeat(7, minmax(0, 1fr)); gap:4px;
    margin-top:16px; font-size:10px; text-transform:uppercase; color:var(--ink-300); text-align:center;
  }
  .calendar-grid{ display:grid; grid-template-columns:repeat(7, minmax(0, 1fr)); gap:4px; margin-top:6px; }
  .calendar-cell{
    aspect-ratio:1; border:1px solid var(--color-rule); background:var(--ink-900);
    color:var(--ink-050); display:flex; flex-direction:column; align-items:center; justify-content:center;
    font-family:inherit; cursor:pointer; padding:2px; gap:2px; position:relative;
    transition:transform .12s var(--ease-out), border-color .12s var(--ease-out);
    min-width:0;
  }
  .calendar-cell:hover{ border-color:var(--ink-050); transform:translateY(-1px); }
  .calendar-cell:active{ transform:translateY(0); }
  .calendar-cell.empty{ border:none; background:none; cursor:default; }
  .calendar-cell.empty:hover{ transform:none; }
  .calendar-daynum{ font-size:11px; }
  .calendar-hours{
    font-size:9px; color:var(--ink-300);
    max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  @media (max-width:380px){
    .calendar-grid, .calendar-weekdays{ gap:2px; }
    .calendar-daynum{ font-size:10px; }
    .calendar-hours{ font-size:8px; }
  }

  /* Intensité par jour — 3 paliers dans la couleur d'accent choisie
     (--heat-*, suit --rouge/[data-accent], voir :root) : c'est une
     visualisation ("combien d'heures ce jour-là"), pas une alerte, donc
     jamais un dégradé multicolore type heatmap classique mais bien
     personnalisable — contrairement à --color-danger (badges/boutons
     "supprimer"/dépassement) qui reste toujours rouge, lui. */
  .calendar-cell.heat-1{ background:var(--heat-1); border-color:var(--heat-1-border); }
  .calendar-cell.heat-2{ background:var(--heat-2); border-color:var(--rouge); }
  .calendar-cell.heat-3{ background:var(--heat-3); border-color:var(--rouge); }
  .calendar-cell.heat-2 .calendar-hours, .calendar-cell.heat-3 .calendar-hours{ color:var(--ink-050); }

  /* Congé payé — ni l'échelle de chaleur (pas des heures travaillées) ni
     --color-danger (pas une alerte) : un traitement neutre à part, avec
     --ink-700/--ink-050 qui s'inversent déjà correctement entre thème
     sombre et clair (voir :root/[data-theme="light"]), sans avoir besoin
     d'une couleur dédiée en plus. */
  .calendar-cell.leave-day{ background:var(--ink-700); border-color:var(--ink-500); }
  .calendar-cell.leave-day .calendar-daynum, .calendar-cell.leave-day .calendar-hours{ color:var(--ink-050); font-weight:700; }

  /* Jour courant : repère indépendant de l'intensité (contour interne,
     ne casse pas la couleur de fond/bordure déjà utilisée par le heat). */
  .calendar-cell.today{ outline:1.5px solid var(--ink-050); outline-offset:-1.5px; }

  /* Week-end légèrement estompé — repère visuel classique de calendrier,
     purement décoratif (aucune règle métier n'en dépend). */
  .calendar-cell.weekend .calendar-daynum{ color:var(--ink-300); }

  .calendar-detail-card{ margin-top:14px; animation:calDetailIn .25s var(--ease-out); }
  .calendar-detail-header{ display:flex; justify-content:space-between; align-items:baseline; margin-bottom:8px; }
  .calendar-detail-total{ font-family:var(--font-display); font-weight:700; font-stretch:112%; color:var(--rouge); font-size:15px; }
  @keyframes calDetailIn{ from{ opacity:0; transform:translateY(-6px); } to{ opacity:1; transform:translateY(0); } }
  @media (prefers-reduced-motion:reduce){
    .calendar-cell{ transition:none; }
    .calendar-detail-card{ animation:none; }
  }

  /* Planning des services (2026-09-13, redesign demande Younes : vue par
     poste/generale, plusieurs services par jour bien visibles, ergonomie).
     Reste dans la meme charte que le Calendrier ci-dessus (--ink-*,
     --rouge) — jamais une palette categorielle arc-en-ciel par poste,
     contraire au principe etabli avec Dylan/Pizzamilia (2026-08-17) :
     seule une alerte reelle reste rouge fixe, le reste suit l'accent
     choisi ; un poste n'est pas une alerte. La distinction par poste passe
     par le TEXTE (sous le nom) et le filtre de vue, jamais par une couleur
     arbitraire en plus. */
  .planning-toolbar{
    display:flex; justify-content:space-between; align-items:flex-end;
    gap:12px; flex-wrap:wrap; margin:14px 0 16px 0;
  }
  .planning-filter-group{ min-width:180px; }
  .planning-filter-group label{ margin:0 0 6px 0; }
  .planning-filter-group select{ min-width:180px; }

  .planning-table{ border-collapse:separate; border-spacing:0; width:100%; min-width:720px; }
  .planning-table th, .planning-table td{ border-right:1px solid var(--color-rule); border-bottom:1px solid var(--color-rule); }
  .planning-th-corner, .planning-th-day{
    padding:10px 8px; font-size:12px; font-weight:600; text-align:center;
    background:var(--ink-800); white-space:nowrap; position:sticky; top:0; z-index:2;
  }
  .planning-th-corner{ left:0; z-index:3; text-align:left; }
  /* Week-end estompe — meme idiome que .calendar-cell.weekend ci-dessus,
     purement decoratif (aucune regle metier n'en depend). */
  .planning-th-day.weekend{ color:var(--ink-300); }
  .planning-employee-cell{
    padding:10px 12px; font-size:13px; font-weight:600; white-space:nowrap;
    position:sticky; left:0; z-index:1; background:var(--ink-900);
  }
  .planning-employee-role{ display:block; font-size:11px; font-weight:400; color:var(--ink-300); margin-top:2px; }
  .planning-row:nth-child(even) .planning-employee-cell, .planning-row:nth-child(even) .planning-day-cell{ background:var(--ink-800); }
  .planning-day-cell{
    padding:6px; vertical-align:top; min-width:110px; background:var(--ink-900);
  }
  .planning-day-cell.weekend{ background:color-mix(in srgb, var(--ink-800) 55%, var(--ink-900)); }
  .planning-row:nth-child(even) .planning-day-cell.weekend{ background:color-mix(in srgb, var(--ink-700) 55%, var(--ink-800)); }

  .planning-chip{
    background:var(--rouge); color:#fff; border-radius:8px; padding:6px 8px;
    font-size:12px; font-weight:600; margin-bottom:5px; cursor:pointer; text-align:center;
    transition:filter .12s var(--ease-out);
  }
  .planning-chip:hover{ filter:brightness(1.12); }
  /* Service en cours d'echange (2026-09-14) — jamais la couleur d'accent
     pleine (deja utilisee pour "service normal"), pour rester reperable
     d'un coup d'oeil dans la grille sans dependre uniquement de l'icone
     (accessibilite : jamais la couleur seule qui porte l'info). */
  .planning-chip.open{ background:var(--ink-500); border:1px dashed var(--ink-300); }
  .planning-chip.claimed{ background:var(--ink-700); border:2px solid var(--rouge); }
  .planning-chip-swap-icon{ margin-right:4px; }
  /* Bouton "+ Service" toujours visible (pas juste une zone vide cliquable
     "invisible") — clarte demandee par Younes : que ce soit evident qu'on
     peut ajouter un 2e service (coupure midi/soir) le meme jour, sans
     deviner qu'il faut cliquer a cote d'un service deja present. */
  .planning-add-btn{
    width:100%; min-height:32px; border:1px dashed var(--ink-500); background:transparent;
    color:var(--ink-300); font-family:inherit; font-size:16px; line-height:1; cursor:pointer;
    display:flex; align-items:center; justify-content:center;
    transition:border-color .12s var(--ease-out), color .12s var(--ease-out);
  }
  .planning-add-btn:hover{ border-color:var(--rouge); color:var(--rouge); }
  /* Case vide (aucun service) : le bouton "+" prend toute la hauteur
     disponible de la cellule plutot qu'une simple ligne fine — reste
     confortable au clic/tap meme si legerement sous 44px sur une grille
     dense destinee surtout a un usage bureau/tablette (voir revue UX
     2026-09-13). */
  .planning-day-cell:not(:has(.planning-chip)) .planning-add-btn{ min-height:44px; }

  /* Repere entre "ce poste" et le reste de l'equipe quand un poste est
     choisi dans "Vue" (2026-09-13, demande Younes : jamais un vrai
     blocage — n'importe qui peut remplacer n'importe qui). Purement
     informatif, la ligne separatrice n'est ni cliquable ni sticky. */
  .planning-group-separator td{
    padding:8px 12px; font-size:11px; color:var(--ink-300); text-transform:uppercase;
    letter-spacing:.05em; background:var(--ink-800); border-right:none;
  }

  /* Écran de chargement animé — logo YH Digital, ~3s, montré une fois par
     session juste après la connexion (gérant) ou après déverrouillage par
     code (employé). Le contenu derrière est déjà rendu ; l'overlay masque
     juste la transition pour un rendu plus "pro" qu'un affichage brut. */
  .splash-overlay{
    position:fixed; inset:0; z-index:300;
    background:var(--ink-950);
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    gap:20px;
    transition:opacity .5s var(--ease-out);
  }
  .splash-overlay.splash-hidden{ display:none; }
  .splash-overlay.closing{ opacity:0; pointer-events:none; }
  .splash-wordmark{
    font-family:var(--font-display); font-weight:700; font-stretch:115%;
    font-size:clamp(1.5rem, 5vw, 2.2rem); letter-spacing:.16em; text-transform:uppercase;
    color:var(--color-text); text-align:center;
    opacity:0; transform:translateY(10px);
    animation:splashIn .7s var(--ease-out) .15s forwards;
  }
  .splash-caption{
    font-family:var(--font-display); font-size:10px; letter-spacing:.22em; text-transform:uppercase;
    color:var(--ink-300); text-align:center; margin-top:8px;
    opacity:0;
    animation:splashIn .6s var(--ease-out) .5s forwards;
  }
  .splash-bar-track{
    width:180px; height:2px; background:var(--ink-500); overflow:hidden;
    opacity:0; animation:splashIn .4s var(--ease-out) .5s forwards;
  }
  .splash-bar-fill{ height:100%; width:0%; background:var(--rouge); animation:splashFill 2.3s cubic-bezier(.4,0,.2,1) .6s forwards; }
  @keyframes splashIn{ to{ opacity:1; transform:translateY(0); } }
  @keyframes splashFill{ to{ width:100%; } }
  @media (prefers-reduced-motion:reduce){
    .splash-wordmark, .splash-caption, .splash-bar-track{ animation:none; opacity:1; transform:none; }
    .splash-bar-fill{ animation:none; width:100%; }
    .splash-overlay{ transition:none; }
  }

  /* Notifications d'activité (polling du tableau de bord gérant, voir
     dashboard.html pollActivity) — au centre de l'écran, difficile à
     manquer, disparaissent seules ou au clic, jamais bloquantes (pas
     d'overlay derrière, on peut continuer à cliquer ailleurs). */
  .toast-stack{
    position:fixed; top:50%; left:50%; transform:translate(-50%, -50%);
    z-index:250; display:flex; flex-direction:column; gap:10px; align-items:center;
    width:min(92vw, 440px); pointer-events:none;
  }
  .toast{
    display:flex; align-items:center; gap:12px; width:100%;
    background:var(--ink-900); border:1px solid var(--rouge);
    padding:18px 22px; font-size:15px; font-weight:600; color:var(--ink-050);
    cursor:pointer; pointer-events:auto;
    box-shadow:0 12px 40px rgba(0,0,0,.55);
    animation:toastIn .35s var(--ease-out);
  }
  .toast .icon{ color:var(--rouge); flex-shrink:0; }
  @keyframes toastIn{ from{ opacity:0; transform:scale(.92); } to{ opacity:1; transform:scale(1); } }
  @media (prefers-reduced-motion:reduce){
    .toast{ animation:none; }
  }