/* tts-tokens.css — design system du module TikTok Shop.
 *
 * POURQUOI un fichier séparé et POURQUOI tout est porté par `.tts-scope` :
 * le reste de Vikky ne doit pas changer. Les tokens ci-dessous sont déclarés
 * sur le conteneur du module (`.tts-scope`, posé par src/sections/tts.js), pas
 * sur `:root` — une déclaration globale aurait fuité sur le BAT, le CRM et les
 * pages publiques dès le premier écran repris.
 *
 * Direction : minimal, sobre. Pas de dégradé décoratif, pas d'icône colorée,
 * pas de badge multicolore, pas de carte bordée. Les séparations sont des
 * hairlines, jamais des bordures pleines autour des blocs.
 *
 * Contrat d'usage et exemples de markup : docs/tts/DESIGN_SYSTEM.md
 */

.tts-scope {
  /* ── Surfaces & encres ─────────────────────────────────────────────── */
  --tts-bg: #F7F7F5;
  --tts-surface: #FFFFFF;
  --tts-ink: #111111;
  --tts-ink-2: #55555A;
  /* #8A8A8F mesuré par le banc de captures à 3,44:1 sur blanc et 3,07:1 sur le
     fond d'en-tête de tableau hérité de Vikky (#F0F2F8) — très en dessous du
     4,5:1 exigé, et c'est l'encre des LIBELLÉS de tuile, des méta de carte, des
     en-têtes de tableau et des pastilles « i ». Autrement dit : la moitié du
     texte de chaque écran.

     #6B6B70 : 5,30:1 sur blanc, 4,94:1 sur --tts-bg, 4,74:1 sur #F0F2F8. Le
     minimum strict était #6E6E73 (4,53:1 sur le pire fond) ; on garde 0,2 de
     marge pour que le seuil ne dépende pas du fond exact d'un écran qu'on
     n'a pas encore écrit. Au-delà, ce gris se confondrait avec --tts-ink-2
     (6,62:1 au pire) et la hiérarchie à trois encres du module disparaîtrait. */
  --tts-muted: #6B6B70;
  --tts-hairline: #E8E8E4;

  /* Accent : UNE seule couleur, celle de Vikky. Référencée et non recopiée,
     pour que le switch de thème existant (body.dark dans src/styles.css) la
     bascule automatiquement — sinon il y aurait deux vérités à maintenir. */
  --tts-accent: var(--accent);

  /* ── Sémantique ────────────────────────────────────────────────────── */
  /* #1B7F5C tenait 5,11:1 sur blanc mais 4,43:1 sur l'en-tête de tableau
     hérité de Vikky (#F0F2F8) — sous le seuil sur le seul fond où le banc ne
     l'avait pas encore photographié. Quatre points de moins suffisent : 5,23:1
     sur blanc, 4,67:1 au pire. Le vert ne change pas d'identité, il cesse
     d'être conforme par chance. */
  --tts-pos: #1A7B58;
  --tts-neg: #B3261E;   /* 6,54:1 sur blanc, 5,84:1 au pire */
  /* #B26A00 mesuré à 4,24:1 sur blanc — sous le seuil AA, et appliqué à du
     texte de 12 px. Assombri à 5,43:1. */
  --tts-warn: #9A5B00;

  /* ── Espacements : grille de 8px, sans exception ────────────────────── */
  --tts-s1: 8px;
  --tts-s2: 16px;
  --tts-s3: 24px;
  --tts-s4: 32px;
  --tts-s5: 40px;
  --tts-s6: 48px;

  /* ── Forme ─────────────────────────────────────────────────────────── */
  --tts-radius: 12px;
  --tts-shadow: 0 1px 2px rgba(0, 0, 0, .04);
  --tts-rule: 1px solid var(--tts-hairline);
  --tts-row-h: 44px;

  /* Police : celle que Vikky charge déjà (src/styles.css → --font-body,
     'DM Sans' en clair / 'Inter' en sombre). On la référence pour ne pas
     introduire une seconde famille sur un même écran. */
  --tts-font: var(--font-body);

  font-family: var(--tts-font);
  color: var(--tts-ink);
  font-size: 14px;          /* corps */
  line-height: 1.5;
}

/* ── Mode sombre ──────────────────────────────────────────────────────────
 * Aucun troisième mécanisme : on hérite du switch existant, qui pose la
 * classe `dark` sur <body> (src/theme.js, src/styles.css). Ni [data-theme],
 * ni media query — sinon un utilisateur qui force le thème clair sur une
 * machine en préférence sombre verrait ce module rester sombre.
 */
body.dark .tts-scope {
  --tts-bg: #030014;
  --tts-surface: #060317;
  --tts-ink: #F4F0FF;
  --tts-ink-2: #A8A6B7;
  --tts-muted: #918EA0;
  --tts-hairline: rgba(255, 255, 255, .08);
  /* Une ombre portée ne se voit pas sur un fond sombre : Vikky utilise un
     liseré interne, on fait pareil plutôt que d'empiler du noir sur du noir. */
  --tts-shadow: rgba(255, 255, 255, .04) 0 0 24px 0 inset;
  /* COULEURS SÉMANTIQUES, redéfinies ici et pas seulement à la racine.

     Elles ne l'étaient pas, et les trois étaient donc lues sur fond sombre
     avec des valeurs choisies pour le blanc. Mesuré au pixel sur une capture :
     « Critique » à 3,11:1 et les variations vertes à 4,10:1, sous le seuil
     AA de 4,5. Le mot « Critique » est le texte le plus important du bandeau
     d'alertes.

     Le banc de captures le signalait à chaque exécution ; il était non
     bloquant, et personne n'en avait rien fait. Un avertissement qu'on
     n'exploite pas vaut un contrôle absent. */
  --tts-pos: #4ADE9B;    /* 11,8:1 sur le fond sombre */
  --tts-neg: #FF6B63;    /*  7,3:1 */
  --tts-warn: #F0A64A;   /*  9,9:1 */
}

/* BOUTON ACTIF DE LA BARRE DE PÉRIODE, en mode sombre. `periodBar()` émet les
   boutons de Vikky (`.btn.btn-sm.btn-p`), dont `styles.css` fixe le texte en
   BLANC. L'accent de Vikky en sombre est un violet CLAIR (#9382FF) : le banc a
   mesuré « 28 jours » à 3,05:1, sur les sept écrans — c'est le libellé qui dit
   quelle fenêtre on lit.
   La règle n'est pas inversée dans styles.css mais ICI, et seulement sous
   `.tts-scope` : `.btn-p` sert tout le produit, et lui changer sa couleur de
   texte repeindrait le BAT, le CRM et les pages publiques depuis une PR qui ne
   regarde que TikTok Shop.
   `--tts-bg` plutôt qu'un noir littéral : #030014 sur #9382FF = 6,78:1, et
   5,29:1 sur l'accent de survol (#7C6AFF). En clair l'accent est foncé
   (#4F46E5, blanc à 6,29:1) : rien à changer, donc rien n'est changé. */
body.dark .tts-scope .btn-p { color: var(--tts-bg); }

/* ══ Carte ═══════════════════════════════════════════════════════════════
 * Surface, SANS bordure, rayon 12, ombre d'1px. L'en-tête est séparé par une
 * hairline — c'est la seule ligne autorisée dans une carte.
 */
.tts-scope .tts-card {
  background: var(--tts-surface);
  border: 0;
  border-radius: var(--tts-radius);
  box-shadow: var(--tts-shadow);
  overflow: hidden;
  margin-bottom: var(--tts-s2);
}
.tts-scope .tts-card-hd {
  display: flex;
  align-items: center;
  gap: var(--tts-s1);
  padding: var(--tts-s2);
  border-bottom: var(--tts-rule);
}
.tts-scope .tts-card-title {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--tts-ink);
}
.tts-scope .tts-card-meta {   /* valeur secondaire alignée à droite de l'en-tête */
  margin-left: auto;
  font-size: 12px;
  color: var(--tts-muted);
  font-variant-numeric: tabular-nums;
}
.tts-scope .tts-card-body { padding: var(--tts-s2); }

/* ══ Libellé ═════════════════════════════════════════════════════════════ */
.tts-scope .tts-label {
  display: block;
  font-size: 12px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--tts-muted);
}

/* ══ Chiffre-clé ═════════════════════════════════════════════════════════
 * tabular-nums est indispensable, pas cosmétique : sans lui les chiffres
 * d'une colonne ne s'alignent pas d'une ligne à l'autre et l'oeil ne peut
 * plus comparer deux montants.
 */
.tts-scope .tts-kpi {
  display: block;
  font-size: 32px;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--tts-ink);
  margin-top: var(--tts-s1);
}
.tts-scope .tts-kpi-lg { font-size: 40px; }
.tts-scope .tts-kpi-sub {   /* précision sous le chiffre, jamais un paragraphe */
  display: block;
  font-size: 12px;
  color: var(--tts-ink-2);
  margin-top: var(--tts-s1);
  font-variant-numeric: tabular-nums;
}

/* Bloc chiffre-clé complet : carte + libellé + valeur */
.tts-scope .tts-metric {
  background: var(--tts-surface);
  border: 0;
  border-radius: var(--tts-radius);
  box-shadow: var(--tts-shadow);
  padding: var(--tts-s2);
}

/* ══ Hairline ════════════════════════════════════════════════════════════ */
.tts-scope .tts-hairline {
  border: 0;
  border-top: var(--tts-rule);
  margin: var(--tts-s2) 0;
}

/* ══ Tableau ═════════════════════════════════════════════════════════════
 * Lignes de 44px, en-têtes en muted, ZÉBRURE NULLE : l'alternance de fonds
 * ajoute du bruit là où une hairline suffit à guider l'oeil.
 */
.tts-scope .tts-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
.tts-scope .tts-table th {
  height: var(--tts-row-h);
  padding: 0 var(--tts-s2);
  text-align: left;
  font-size: 12px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--tts-muted);
  border-bottom: var(--tts-rule);
  white-space: nowrap;
}
.tts-scope .tts-table td,
.tts-scope .tts-row > td {
  height: var(--tts-row-h);
  padding: 0 var(--tts-s2);
  font-size: 14px;
  color: var(--tts-ink);
  border-bottom: var(--tts-rule);
  vertical-align: middle;
}
.tts-scope .tts-table tbody tr:last-child > td { border-bottom: 0; }
.tts-scope .tts-table tbody tr:nth-child(even) > td { background: transparent; } /* pas de zébrure */
.tts-scope .tts-table tbody tr:hover > td { background: var(--tts-bg); }
/* Conteneur du bandeau de fraîcheur. Il n'a pas d'apparence propre — il
   existe pour que la repeinture du CHROME SEUL puisse le remplacer sans
   toucher à `#tts-screen`. Sans ce point d'accroche stable, replier le rail
   réécrivait tout le squelette et vidait l'écran. */
.tts-scope .tts-shell-banner { display: block; }

.tts-scope .tts-table-scroll { overflow-x: auto; }

/* Un tableau LARGE dans une carte étroite doit pouvoir défiler.

   Le P&L du Dashboard n'est volontairement pas enveloppé dans
   `.tts-table-scroll` : ses cinq colonnes tiennent dans une carte sur un
   écran de bureau, et trois tableaux indépendants empêchaient justement de
   comparer les fenêtres d'un coup d'œil. Ce raisonnement vaut à 1440 px.

   À 390 px il ne vaut plus : les cinq colonnes demandent 968 px, la carte en
   fait 358, et `overflow-x: hidden` les COUPE. « 7 derniers jours » et « Mois
   en cours » devenaient totalement inatteignables sur téléphone — pas réduits,
   pas tronqués : absents, sans la moindre barre de défilement.

   Relevé par le banc de captures, dont le contrôle de contenu coupé a été
   ajouté le même jour, précisément parce qu'il n'aurait pas vu ce défaut-là
   avant. */
.tts-scope .tts-card-body:has(> .tts-table) { overflow-x: auto; }

/* BARRE D'OUTILS D'UNE CARTE, à 390 px. `.row` de Vikky est un `flex` SANS
   `wrap` : la barre de « Produits » demande 439 px dans un corps de carte de
   326, et `.tts-card { overflow: hidden }` COUPE le surplus. « Export CSV » et
   la pastille d'aide étaient donc hors d'atteinte sur téléphone — pas
   réduits : absents, et sans barre de défilement.

   Ce défaut était INVISIBLE jusqu'ici parce que « Produits » et « Créateurs »
   se photographiaient vides (graine du banc périmée, corrigée dans la même
   PR) : sans ligne, pas de carte assez large pour couper quoi que ce soit.
   `wrap` et non `overflow-x: auto` : une barre de quatre boutons n'est pas un
   tableau large, et un contrôle qu'il faut faire défiler pour trouver est un
   contrôle qu'on ne trouve pas. */
.tts-scope .tts-card-body > .row { flex-wrap: wrap; }

/* PREMIÈRE COLONNE FIGÉE au défilement horizontal. L'écran Produits porte
   treize colonnes : passé la moitié, on lit des chiffres sans savoir de quel
   produit ils parlent — et on remonte à gauche à chaque ligne.
   `background` est OBLIGATOIRE : sans fond opaque, les colonnes défilantes
   se superposent au texte figé. Le fond de survol est repris à l'identique
   pour que la ligne survolée ne se coupe pas en deux. */
.tts-scope .tts-table .tts-col1 {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--tts-surface);
}
.tts-scope .tts-table tbody tr:hover > .tts-col1 { background: var(--tts-bg); }

/* Nom de produit sur DEUX lignes au plus, puis ellipse. Les libellés TikTok
   dépassent 80 caractères et poussaient toutes les colonnes de chiffres hors
   de l'écran. `title` porte le nom entier — l'ellipse ne doit jamais perdre
   de l'information, seulement la replier. */
.tts-scope .tts-prod-name {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-width: 220px;
  line-height: 1.25;
}
/* Identifiant de SKU sous le nom : nécessaire pour un recoupement avec
   l'export, inutile à la lecture — donc petit et discret, jamais absent. */
.tts-scope .tts-prod-id {
  display: block;
  font-size: 11px;
  color: var(--tts-muted);
  font-variant-numeric: tabular-nums;
}
.tts-scope .tts-td-empty {   /* état vide d'un tableau */
  text-align: center;
  color: var(--tts-muted);
}

/* ══ Variation vs période précédente ═════════════════════════════════════
 * ▲/▼ + %, 12px, en couleur de texte seulement. JAMAIS de fond coloré : un
 * tableau de 12 lignes en pastilles vertes et rouges devient illisible.
 */
.tts-scope .tts-delta {
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  background: none;
  padding: 0;
  white-space: nowrap;
}
/* `.tts-pos`, `.tts-neg` et `.tts-est` vivaient dans src/styles.css avec des
   couleurs CODÉES EN DUR, hors du design system — et ce sont elles que
   `deltaHtml()` et les marqueurs d'estimation émettent. Le jeton de mode sombre
   ne les atteignait donc jamais : les variations restaient mesurées à 4,10:1
   alors que le jeton, lui, était corrigé. Un premier correctif les a
   raccrochées par une SURCHARGE ici, ce qui marchait mais laissait deux
   définitions de la même chose — donc la garantie qu'elles divergent.

   Elles sont maintenant définies ICI et NULLE PART AILLEURS. Vérifié avant de
   les retirer de styles.css : les trois classes ne sont émises que par
   src/sections/tts-*.js, aucun écran hors module ne les porte (c'est
   `tests/tts/palette.test.mjs` qui le tient désormais).

   `tabular-nums` est conservé, et ce n'est pas décoratif : ce sont des colonnes
   de pourcentages et de montants, qui doivent s'aligner d'une ligne à l'autre. */
.tts-scope .tts-pos,
.tts-scope .tts-neg { font-variant-numeric: tabular-nums; }
.tts-scope .tts-pos { color: var(--tts-pos); }
.tts-scope .tts-neg { color: var(--tts-neg); }
/* Marqueur « est. » : 10px, donc le texte le plus petit du module. #B26A00 y
   était mesuré à 4,24:1 sur blanc — sous le seuil, et sur la plus petite
   graisse de l'écran. `--tts-warn` (#9A5B00) le porte à 5,43:1 sur blanc et
   4,85:1 sur le pire fond relevé, et le mode sombre l'atteint enfin. */
.tts-scope .tts-est { font-size: 10px; margin-left: 4px; color: var(--tts-warn); }

.tts-scope .tts-delta-up { color: var(--tts-pos); }
.tts-scope .tts-delta-down { color: var(--tts-neg); }
.tts-scope .tts-delta-flat { color: var(--tts-muted); }

/* ══ Pastille d'aide « i » ═══════════════════════════════════════════════
 * Tout texte explicatif va ici, pas sur l'écran. Émise par un SEUL endroit du
 * code : `helpIcon()` de src/sections/tts-ui.js.
 *
 * SURVOL ⇒ le `title` natif. CLIC ⇒ le popover, qui s'affiche sur
 * `aria-expanded="true"` et non sur `:hover` / `:focus-visible` : un popover
 * qui s'ouvre au survol se referme dès que la souris part, donc on ne peut
 * ni le relire ni y sélectionner un nom de fonction SQL. C'est un `<button>`,
 * donc Entrée et Espace l'ouvrent sans une ligne de script — `title` seul
 * n'est atteignable à aucun clavier.
 */
.tts-scope .tts-help {
  position: relative;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tts-s2);
  height: var(--tts-s2);
  border-radius: 50%;
  border: var(--tts-rule);
  background: none;
  color: var(--tts-muted);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}
.tts-scope .tts-help:hover,
.tts-scope .tts-help:focus-visible { color: var(--tts-ink); outline: none; }
.tts-scope .tts-help-text {
  position: absolute;
  bottom: calc(100% + var(--tts-s1));
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  width: max-content;
  max-width: 260px;
  padding: var(--tts-s1);
  border-radius: var(--tts-radius);
  background: var(--tts-surface);
  box-shadow: 0 4px 16px rgba(0, 0, 0, .10);
  border: var(--tts-rule);
  color: var(--tts-ink-2);
  font-size: 12px;
  font-weight: 400;
  line-height: 1.5;
  text-transform: none;
  letter-spacing: normal;
  text-align: left;
  white-space: normal;
  display: none;
}
/* Ouvert au CLIC uniquement. `openHelp()` repasse l'élément en
 * `position: fixed` avec des coordonnées calculées, parce qu'un popover
 * `absolute` posé dans un `.tts-table-scroll` est rogné par l'overflow du
 * conteneur — donc inatteignable là où on en a le plus besoin. */
.tts-scope .tts-help[aria-expanded="true"] .tts-help-text { display: block; }

/* ══ Mises en page ═══════════════════════════════════════════════════════ */
.tts-scope .tts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--tts-s2);
}
.tts-scope .tts-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--tts-s2);
  margin-top: var(--tts-s2);
}
.tts-scope .tts-chart { height: 200px; }
.tts-scope .tts-spark { height: 40px; }

/* ══ Reprise des éléments existants du module ════════════════════════════
 * Ces classes vivent dans src/styles.css et servaient des fonds colorés.
 * On les ramène au système ICI, dans le périmètre du module uniquement :
 * texte coloré + hairline, aucun aplat.
 */
.tts-scope .tts-pass,
.tts-scope .tts-fail,
.tts-scope .tts-wait {
  background: none;
  padding: var(--tts-s1) 0;
  font-size: 14px;
  font-weight: 500;
}
.tts-scope .tts-pass { color: var(--tts-pos); }
.tts-scope .tts-fail { color: var(--tts-neg); }
.tts-scope .tts-wait { color: var(--tts-warn); }
.tts-scope .tts-warn { color: var(--tts-warn); font-size: 12px; }
.tts-scope .tts-row-ko > td { background: none; color: var(--tts-neg); }
.tts-scope .tts-status {
  background: none;
  padding: 0;
  font-size: 12px;
  color: var(--tts-ink-2);
}
.tts-scope .tts-status.tts-done { background: none; color: var(--tts-pos); }
.tts-scope .tts-status.tts-failed { background: none; color: var(--tts-neg); }
.tts-scope .tts-status.tts-running { background: none; color: var(--tts-warn); }
.tts-scope .tts-note { font-size: 12px; color: var(--tts-ink-2); line-height: 1.5; margin: 0 0 var(--tts-s1); }
.tts-scope .tts-busy { font-size: 12px; color: var(--tts-muted); align-self: center; }
.tts-scope .tts-log {
  background: var(--tts-bg);
  border-radius: var(--tts-radius);
  padding: var(--tts-s1);
  font-size: 12px;
  line-height: 1.6;
  max-height: 260px;
  overflow: auto;
  white-space: pre-wrap;
  margin: var(--tts-s2) 0 0;
}
/* Barre de progression de l'objectif : accent uni, pas de dégradé. */
.tts-scope .tts-bar { height: 4px; border-radius: 999px; background: var(--tts-hairline); overflow: hidden; margin: 0 var(--tts-s2) var(--tts-s2); }
.tts-scope .tts-bar-fill { height: 100%; background: var(--tts-accent); }

@media (max-width: 860px) {
  .tts-scope .tts-grid { grid-template-columns: 1fr 1fr; }
  .tts-scope .tts-cols { grid-template-columns: 1fr; }
  .tts-scope .tts-kpi { font-size: 28px; }
}

/* ── Rail du module ───────────────────────────────────────────────────────
   Le module porte son propre menu latéral plutôt que d'ajouter sept entrées au
   menu général de Vikky. Hairline de séparation, jamais de bordure pleine ;
   l'élément actif se signale par l'encre, pas par un fond coloré. */
.tts-scope.tts-shell {
  display: flex;
  gap: var(--tts-s3);
  align-items: flex-start;
}
/* ── Repli en icônes : l'état REPLIÉ est l'état de BASE ───────────────────
   DÉFAUT FERMÉ : à 390 px, les sept libellés du rail ne tenaient pas. La
   règle était `.tts-rail-list { display: flex; overflow-x: auto; }` —
   « Clients », « Expenses & Rebates » et « Imports » étaient coupés net au
   bord droit, sans dégradé ni barre de défilement visible. Rien ne signalait
   qu'il restait trois entrées, dont celle qui ALIMENTE le module.

   POURQUOI le replié est la base et le déplié une surcharge au-dessus de
   860 px : sous 860 px le rail doit être replié QUOI QU'AIT MÉMORISÉ
   l'utilisateur. Écrit dans l'autre sens, la media query mobile aurait dû
   redéclarer tout l'état replié — deux jeux de déclarations à tenir alignés,
   donc la garantie qu'ils divergent. Ici le repli imposé sur mobile découle
   de l'absence de surcharge, il n'est pas réécrit. */
.tts-scope .tts-rail {
  flex: 0 0 48px;
  border-right: 1px solid var(--tts-hairline);
}
.tts-scope .tts-rail-shop-wrap {
  position: relative;
  margin-bottom: var(--tts-s2);
}
/* Rond d'initiales. Il ne REMPLACE pas le sélecteur : le `<select>` natif est
   superposé, transparent, et garde donc le clic, le clavier et la liste
   complète. Un rond seul aurait supprimé le changement de boutique sur
   téléphone, où le repli est imposé. */
/* FOCUS VISIBLE sur le sélecteur superposé. Il est en `opacity: 0` : l'anneau
   de focus du navigateur est donc rendu sur un élément invisible, et un
   utilisateur au clavier n'a AUCUN repère. Le commentaire du dessus justifie
   la superposition par « garder le clic ET le clavier » — sans cette règle,
   le clavier était à moitié perdu. On déporte l'indication sur le rond, qui
   est l'élément réellement vu. L'état replié étant la base partout et IMPOSÉ
   sous 860 px, le défaut touchait tout le monde sur téléphone. */
/* `:has()` et non `+` : dans le balisage le ROND PRÉCÈDE le sélecteur, et CSS
   ne sélectionne pas vers l'arrière. Écrit avec `+`, cette règle n'aurait
   jamais rien stylé — un correctif d'accessibilité silencieusement inerte. */
.tts-scope .tts-rail-shop-wrap:has(.tts-rail-shop:focus-visible) .tts-rail-shop-badge,
.tts-scope .tts-rail-shop-wrap:has(.tts-rail-shop:focus) .tts-rail-shop-badge {
  outline: 2px solid var(--tts-accent);
  outline-offset: 2px;
}

.tts-scope .tts-rail-shop-badge {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  margin: 0 auto;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--tts-ink);
  background: var(--tts-bg);
  border: 1px solid var(--tts-hairline);
  border-radius: 50%;
}
.tts-scope .tts-rail-shop {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  font: inherit;
  font-size: 13px;
  color: var(--tts-ink);
  background: var(--tts-surface);
  border: 0;
  border-radius: 50%;
  opacity: 0;
  cursor: pointer;
}
.tts-scope .tts-rail-list { list-style: none; margin: 0; padding: 0; }
.tts-scope .tts-rail-item,
.tts-scope .tts-rail-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--tts-s1);
  width: 100%;
  padding: 8px 0;
  text-align: left;
  font: inherit;
  font-size: 13px;
  color: var(--tts-ink-2);
  background: none;
  border: 0;
  border-radius: 8px;
  cursor: pointer;
}
.tts-scope .tts-rail-ico { display: inline-flex; flex: 0 0 16px; }
/* Masqué, pas absent : le libellé reste dans le DOM et les boutons portent de
   toute façon `title` ET `aria-label` — `title` seul n'est pas atteignable au
   clavier. */
.tts-scope .tts-rail-label { display: none; }
.tts-scope .tts-rail-item:hover,
.tts-scope .tts-rail-toggle:hover { color: var(--tts-ink); background: var(--tts-bg); }
.tts-scope .tts-rail-item.is-active { color: var(--tts-ink); font-weight: 600; }
/* EN BAS du rail : au-dessus de la liste, il déplacerait les sept entrées à
   chaque clic. */
.tts-scope .tts-rail-toggle {
  margin-top: var(--tts-s1);
  padding-top: var(--tts-s1);
  border-top: 1px solid var(--tts-hairline);
  border-radius: 0;
  /* `--tts-muted` aurait été le choix naturel pour un bouton secondaire, mais
     le banc l'a mesuré à 3,15:1 sur ce fond en clair — sous le 4,5:1 exigé.
     `--tts-ink-2`, la même encre que les entrées du rail, passe. */
  color: var(--tts-ink-2);
}

/* État DÉPLIÉ : réservé aux écrans larges ET au choix de l'utilisateur. */
@media (min-width: 860.01px) {
  .tts-scope .tts-rail:not(.is-collapsed) { flex: 0 0 186px; padding-right: var(--tts-s2); }
  .tts-scope .tts-rail:not(.is-collapsed) .tts-rail-shop-badge { display: none; }
  .tts-scope .tts-rail:not(.is-collapsed) .tts-rail-shop {
    position: static;
    opacity: 1;
    padding: 7px 9px;
    border: 1px solid var(--tts-hairline);
    border-radius: 8px;
  }
  .tts-scope .tts-rail:not(.is-collapsed) .tts-rail-item,
  .tts-scope .tts-rail:not(.is-collapsed) .tts-rail-toggle {
    justify-content: flex-start;
    padding: 8px 9px;
  }
  .tts-scope .tts-rail:not(.is-collapsed) .tts-rail-toggle { padding-top: var(--tts-s1); }
  .tts-scope .tts-rail:not(.is-collapsed) .tts-rail-label { display: inline; }
}
.tts-scope .tts-shell-main { flex: 1 1 auto; min-width: 0; }
.tts-scope .tts-shell-hd {
  display: flex;
  align-items: center;
  gap: var(--tts-s2);
  flex-wrap: wrap;
  padding-bottom: var(--tts-s2);
  margin-bottom: var(--tts-s2);
  border-bottom: 1px solid var(--tts-hairline);
}
.tts-scope .tts-shell-title {
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--tts-ink);
}
.tts-scope .tts-shell-period { margin-left: auto; }

/* ── Période personnalisée ────────────────────────────────────────────────
   Les deux champs date sont RÉUNIS dans un cadre. Posés nus au milieu des sept
   boutons de préréglage, ils se lisaient comme deux contrôles indépendants :
   rien ne disait qu'ils forment UNE période, ni à quel bouton ils se
   rattachent. Le cadre le dit sans une ligne de texte.

   `inline-flex` et non `flex` : la barre est en `flex-wrap`, et un bloc aurait
   occupé toute la ligne restante à 1440px. */
.tts-scope .tts-period-custom {
  display: inline-flex;
  align-items: center;
  gap: var(--tts-s1);
  padding: 4px var(--tts-s1);
  border: var(--tts-rule);
  border-radius: var(--tts-radius);
  background: var(--tts-surface);
}
/* La flèche ne réutilise pas `.tts-note`, qui porte une marge basse de 10px
   destinée à un paragraphe : dans un conteneur centré verticalement, elle
   décalerait la flèche au-dessus des deux champs. */
.tts-scope .tts-period-sep { font-size: 13px; color: var(--tts-muted); }
/* Les bornes et le message de refus, dans leur propre conteneur : c'est lui
   qu'on rafraîchit pendant une saisie, pour ne JAMAIS réécrire les champs date
   sous les doigts de qui les remplit (voir periodStatus() dans tts-ui.js). */
.tts-scope .tts-period-status { display: inline-flex; align-items: center; gap: var(--tts-s1); }
/* Actions de l'écran, à droite de la barre de période. `:empty { display:none }`
 * n'est pas cosmétique : six des sept écrans n'ont aucune action, et le `gap`
 * de `.tts-shell-hd` leur réserverait sinon un blanc qui décale la barre de
 * période vers la gauche sur tous ces écrans. */
.tts-scope .tts-shell-actions { display: flex; gap: var(--tts-s1); }
.tts-scope .tts-shell-actions:empty { display: none; }

/* Sous 860px le rail passe au-dessus, en ligne : un rail de 186px sur un
   téléphone ne laisse rien à l'écran.

   Et il y reste REPLIÉ d'office — l'état déplié n'a aucune surcharge ici, donc
   aucune règle à écrire pour l'imposer. Les sept entrées deviennent sept
   icônes qui SE PARTAGENT la largeur disponible (`flex: 1 1 0`, plafonnées à
   44px) : elles tiennent toutes, sans défilement, donc sans entrée coupée au
   bord droit. C'est exactement le défaut qu'on ferme, et il se relit sur la
   capture `shell-*-390.png`. */
@media (max-width: 860px) {
  .tts-scope.tts-shell { display: block; }
  .tts-scope .tts-rail {
    display: flex;
    align-items: center;
    gap: var(--tts-s1);
    flex: none;
    border-right: 0;
    border-bottom: 1px solid var(--tts-hairline);
    padding: 0 0 var(--tts-s2);
    margin-bottom: var(--tts-s2);
  }
  .tts-scope .tts-rail-shop-wrap { flex: 0 0 32px; margin-bottom: 0; }
  .tts-scope .tts-rail-list { display: flex; gap: 2px; flex: 1 1 auto; min-width: 0; }
  .tts-scope .tts-rail-list > li { flex: 1 1 0; min-width: 30px; max-width: 44px; }
  /* Le bouton de repli n'a plus de sens : l'état est imposé par la largeur.
     Le laisser aurait offert un bouton sans effet visible. */
  .tts-scope .tts-rail-toggle { display: none; }
}
