:root {
  /* ===== Roadcase Dense (P1) — warm dark metal, amber LED, pro-tool density.
     Anti "AI look": no indigo, no glow. Light mode is kept (papier chaud). */
  --bg: #141310;
  --bg-elevated: #1b1a16;
  --surface: #211f1a;
  --surface-hover: #2a281f;
  --surface-active: #302d24;
  --card: #1e1c17;
  --card-hover: #26241d;

  --accent: #e0a44c;
  --accent-hover: #ecb463;
  --accent-muted: #e0a44c26;
  --accent-glow: rgba(224,164,76,0.30);
  /* P2a — amber family extras (gradient partner, ink-on-amber, subtle tints)
     so no component needs a hardcoded hex/rgba again. */
  --accent-deep: #c88a2f;
  --on-accent: #141310;
  --accent-tint: rgba(224, 164, 76, 0.07);
  --accent-tint-strong: rgba(224, 164, 76, 0.12);
  --accent-line: rgba(224, 164, 76, 0.22);
  /* Legacy alias: `var(--primary, #6366f1)` used to fall back to INDIGO in ~10
     places. One alias re-tints them all to the Roadcase accent. */
  --primary: var(--accent);

  --text: #eae7dd;
  --text-dim: #a7a193;
  --text-muted: #948c7e;

  --border: #2e2c25;
  --border-light: #3a372e;
  --divider: #28261f;
  /* U2h — LE trait de séparation des champs (filet de rangée ET frontière de
     section) : UNE seule source de couleur, une valeur PAR THÈME (hairline clair
     sur le métal sombre, sombre sur le papier clair). Mesuré sur la carte :
     --divider ne donnait que 1,12:1 (quasi invisible), --border 1,22:1 et
     servait de bord de cadre — d'où DEUX traits de deux couleurs à la même
     frontière. Ici : 1,77:1 (sombre) / 1,56:1 (clair). */
  --ui-rule: rgba(234, 231, 221, 0.20);

  --success: #84b06a;
  --warning: #d99a3d;
  --danger: #dd7a63;
  --info: #7fa8c9;
  /* LOT U1b — jetons d'INK : le texte posé sur une couleur pleine ne doit plus
     être écrit `#fff` en ligne. Valeurs mesurées (scripts/qa-ui-density.cjs) :
     --on-danger (ink sombre) = 6.6:1 sur --danger, --overlay-text = 7.66:1 sur
     le fond des écrans sombres (Show Time). */
  --on-danger: #141310;
  --on-success: #141310;
  --on-warning: #141310;
  --chip-bg: var(--surface);
  --chip-text: var(--text-dim);
  --overlay-text: #f2f2f2;

  --font: 'Inter', 'SF Pro Display', system-ui, -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', 'Fira Code', monospace;

  /* Typography scale (12 → 20px). All UI font sizes map to these tokens so
     every page/component stays uniform. */
  --font-xs: 12px;   /* smallest: badges, tiny aux labels */
  --font-sm: 13px;   /* help text, small labels */
  --font-md: 14px;   /* body / form inputs / most labels */
  --font-lg: 16px;   /* sub-headings, buttons, emphasised text */
  --font-xl: 20px;   /* section titles */

  /* Shadows stay sober (pro-tool): tight and short, no wide glows. */
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.35);
  --shadow-md: 0 3px 10px rgba(0,0,0,0.4);
  --shadow-lg: 0 8px 26px rgba(0,0,0,0.45);
  --shadow-glow: 0 0 24px var(--accent-glow);

  /* Small radii (pro-tool density): 4/7/10/14 — was 6/10/16/24. */
  --radius-sm: 4px;
  --radius: 7px;
  --radius-lg: 10px;
  --radius-xl: 14px;

  /* ===== Densité UI (socle U1, 2026-11-02) ==============================
     UNE seule échelle pour tout le chrome : padding de carte, écart entre
     champs, hauteur de contrôle, hauteur de ligne de tableau, et surtout la
     LARGEUR FIXE du libellé — c'est elle qui aligne tous les contrôles sur
     la même position x. Aucun composant ne doit réécrire ces valeurs en dur. */
  --ui-pad: 14px;      /* padding de carte (avant : 24px) */
  --ui-gap-y: 6px;     /* écart vertical entre champs (avant : 16px) */
  --ui-gap-x: 8px;     /* écart libellé ↔ contrôle */
  --ui-gap-field: 8px; /* U2f — ESPACE SYMÉTRIQUE autour d'un contrôle de
                          formulaire : 8px au-dessus (libellé ↔ contrôle) et
                          8px en dessous, dans la rangée. Consommé par les
                          pages `.config-page` (index.css §U2f). */
  --ui-h-ctl: 26px;    /* hauteur d'un contrôle (desktop) */
  --ui-h-btn: 28px;    /* U2g — hauteur UNIQUE d'un élément CLIQUABLE (bouton,
                          pilule, repli de section). 28 ≥ cible tactile 24px, et
                          c'est la même valeur que --ui-h-row : une seule échelle
                          d'INTERACTION dans toute l'app. */
  --ui-h-row: 28px;    /* hauteur d'une ligne de tableau */
  --ui-label-w: 118px; /* largeur FIXE du libellé — la clé de l'alignement */

  --transition: 150ms cubic-bezier(0.4, 0, 0.2, 1);
  --transition-slow: 300ms cubic-bezier(0.4, 0, 0.2, 1);

  /* Native form controls (checkbox/radio/switch) follow the accent instead of
     the browser blue — inherited by every control, no per-input rule needed. */
  accent-color: var(--accent);

  font-family: var(--font);
  font-size: 15px;
}

/* ===== Light theme =====
   Activated by <html data-theme="light"> (ThemeToggle sets it). Re-tints the
   same variable names so every component using var(--*) switches automatically. */
:root[data-theme='light'] {
  /* Warm paper (papier chaud) — the light mode is KEPT and re-tinted to match
     the Roadcase family. Accent #b07a1e keeps AA contrast on the light bg. */
  --bg: #f4f1ea;
  --bg-elevated: #ebe7dd;
  --surface: #fffdf8;
  --surface-hover: #f1ede4;
  --surface-active: #e7e2d6;
  --card: #fffdf8;
  --card-hover: #f7f4ec;

  /* U1 — jetons d'ACCESSIBILITÉ du thème clair (valeurs CALCULÉES puis
     MESURÉES sur les trois surfaces réelles : --bg page, --card, sidebar
     --bg-elevated, et sur un badge teinté) :
       --text-muted #645c4c → 5.86 / 6.50 / 5.35 / 4.59   (avant 3.33–3.64)
       --text-dim   #5c564a → 6.45 / 7.16 / 5.89
       --accent     #7a4f0d → 6.90 page, 4.87 en texte sur fond teinté
     Ne pas les « ré-éclaircir » à l'œil : scripts/qa-ui-density.cjs les mesure. */
  /* U1 — accent du thème clair : 6.90:1 sur la page, 4.87:1 en TEXTE accent
     sur un fond teinté (--accent-tint-strong), 7.78:1 en blanc sur accent
     (bouton primaire). #8a5a14 n'atteint que 4.10 sur le fond teinté. */
  --accent: #7a4f0d;
  --accent-hover: #6a4309;
  --accent-muted: #b07a1e1a;
  --accent-glow: rgba(176,122,30,0.22);
  /* P2a — same amber family as the dark root, re-tinted for paper. */
  --accent-deep: #8f5f14;
  --on-accent: #fffdf8;
  --accent-tint: rgba(176, 122, 30, 0.07);
  --accent-tint-strong: rgba(176, 122, 30, 0.12);
  --accent-line: rgba(176, 122, 30, 0.22);
  --primary: var(--accent);

  --text: #26231d;
  --text-dim: #5c564a;     /* U1 — 6.45:1 sur --bg, 5.89:1 sur la sidebar */
  /* U1 — 5.86 page / 6.50 carte / 5.35 sidebar / 4.59 sur un badge teinté.
     #6f685b (proposition du brief) ne donne que 4.47 sur la sidebar
     (--bg-elevated) et 3.83 sur un badge teinté : un cran plus sombre pour que
     le seuil tienne sur TOUTES les surfaces, pas seulement sur --bg. */
  --text-muted: #645c4c;

  --border: #e2ddd0;
  --border-light: #eae5d9;
  --divider: #ebe7dd;
  /* U2h — même jeton que la racine sombre, valeur CLAIRE adaptée : un hairline
     sombre translucide sur le papier (1,56:1 sur --card). */
  --ui-rule: rgba(38, 35, 29, 0.22);

  /* U1b — les quatre couleurs sémantiques étaient trop CLAIRES pour du TEXTE en
     thème clair (mesuré : --success 3.88, --warning 3.99, --info 4.24 sur --card,
     --danger 4.18 sur la sidebar, et toutes < 4.5 sur leur propre badge teinté à
     15 %). Valeurs recalculées pour tenir 4.5:1 sur --card/--bg/--bg-elevated ET
     sur le badge teinté (voir la table de la ref ui-contrast-2026). */
  --success: #2f7048;
  --warning: #855a0d;
  --danger: #a83e2b;
  --info: #3d6b8a;
  --danger-hover: #963623;
  --success-hover: #255e3d;
  /* U1b — ink sur couleur pleine (voir le :root sombre). */
  --on-danger: #fffdf8;
  --on-success: #fffdf8;
  --on-warning: #fffdf8;
  --chip-bg: var(--surface);
  --chip-text: var(--text-dim);
  /* Les écrans sombres volontaires (Show Time) ne suivent PAS les thèmes : leur
     texte reste clair dans les deux — c'est un jeton, plus un littéral. */
  --overlay-text: #f2f2f2;

  --shadow-sm: 0 1px 2px rgba(60, 50, 30, 0.08);
  --shadow-md: 0 3px 10px rgba(60, 50, 30, 0.1);
  --shadow-lg: 0 8px 26px rgba(60, 50, 30, 0.14);
  --shadow-glow: 0 0 24px var(--accent-glow);

  accent-color: var(--accent);
}
html {
  line-height: 1.55;
  color: var(--text);
  background: var(--bg);
  color-scheme: dark;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

html[data-theme='light'] {
  color-scheme: light;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
}

#root {
  min-height: 100vh;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* ::selection */
::selection {
  background: var(--accent);
  color: var(--on-accent);
}

/* Scrollbar */
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
::-webkit-scrollbar-track {
  background: transparent;
}
::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 4px;
  border: 2px solid var(--bg);
}
::-webkit-scrollbar-thumb:hover {
  background: var(--border-light);
}
::-webkit-scrollbar-corner {
  background: transparent;
}

/* Focus visible */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Animations */
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes slideIn {
  from { opacity: 0; transform: translateY(-8px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}
@keyframes spin {
  to { transform: rotate(360deg); }
}
@keyframes shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

.animate-fade-in { animation: fadeIn var(--transition) ease-out; }
.animate-slide-in { animation: slideIn var(--transition-slow) ease-out; }
.animate-pulse { animation: pulse 2s ease-in-out infinite; }

/* Layout */
.page {
  padding: 24px;
  max-width: 1400px;
  margin: 0 auto;
  /* Dense inner tables (tracks, backline) scroll inside their own containers
     instead of forcing a horizontal page scroll on narrow/mobile screens.
     `clip` (not `hidden`) so the element still clips horizontal overflow but
     does NOT become a scroll container — `overflow-x:hidden` computes to
     `overflow-y:auto`, which breaks position:sticky on descendants (e.g. the
     rider/daysheet/tourbook layout editor PDF preview). */
  overflow-x: clip;
}

@media (max-width: 768px) {
  .page { padding: 16px; }
}

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 28px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--divider);
}

.page-header h1 {
  font-size: 1.75rem;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.02em;
  background: linear-gradient(135deg, var(--text) 0%, var(--accent) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.page-header-actions {
  display: flex;
  gap: 12px;
}

/* Transport mode selector bar — P3c: it now rides in the shared `.rc-header`
   (Roadcase) as the header's ACTIONS row, so it carries no margin of its own:
   the header's padding + hairline carry the rhythm. Kept as its own class so
   existing selectors keep matching. */
.config-transport-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  flex-wrap: wrap;
}

/* Inline per-field "Populate from" label layout */
.config-field-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
/* Groups the inline per-field buttons ("Use example" + "Populate from") on
   the right side of the label, keeping them together. */
.config-field-actions {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  margin-left: auto;
}
.section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--divider);
  padding-bottom: 8px;
}
.collapsible-section .section-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  color: var(--text);
}
.collapsible-section .section-toggle h2 {
  margin: 0;
  font-size: 1.1rem;
}
.collapsible-section .chevron {
  display: inline-block;
  font-size: var(--font-xs);
  transition: transform 0.15s ease;
  color: var(--text-muted);
}
.collapsible-section .chevron.open {
  transform: rotate(90deg);
}
.section-body {
  padding-top: 4px;
}
.section-header-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 4px 0 12px;
  padding-bottom: 4px;
}
.section-footer {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid var(--divider);
}
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 0.875rem;
  font-weight: 600;
  border-radius: var(--radius);
  padding: 10px 20px;
  border: none;
  cursor: pointer;
  transition: all var(--transition);
  text-decoration: none;
  white-space: nowrap;
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-primary {
  /* Roadcase: amber, no more amber→red (was #d0344d). Ink-on-accent keeps AA. */
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent-deep) 100%);
  color: var(--on-accent);
  box-shadow: 0 2px 8px var(--accent-glow);
}

.btn-primary:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: 0 6px 20px var(--accent-glow);
}

.btn-primary:active:not(:disabled) {
  transform: translateY(0);
}

.btn-secondary {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
}

.btn-secondary:hover:not(:disabled) {
  background: var(--surface-hover);
  border-color: var(--border-light);
}

.btn-ghost {
  background: transparent;
  color: var(--text-dim);
  border: 1px solid transparent;
}

.btn-ghost:hover:not(:disabled) {
  background: var(--surface);
  color: var(--text);
}

.btn-danger {
  background: var(--danger);
  color: var(--on-danger);
}

.btn-danger:hover:not(:disabled) {
  background: #e83b48;
}

.btn-small {
  padding: 6px 12px;
  font-size: 0.8125rem;
}

.btn-large {
  padding: 14px 28px;
  font-size: 1rem;
}

.toggle-group {
  display: inline-flex;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 2px;
}

.toggle-btn {
  padding: 8px 16px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-dim);
  background: transparent;
  border: none;
  border-radius: calc(var(--radius) - 2px);
  cursor: pointer;
  transition: all var(--transition);
}

.toggle-btn:hover { color: var(--text); }
.toggle-btn.active {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: 0 2px 8px var(--accent-glow);
}

/* Inputs */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.form-field label {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

.form-field input[type="text"],
.form-field input[type="number"],
.form-field input[type="color"],
.form-field select,
.form-field textarea {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 12px;
  font-size: 0.875rem;
  color: var(--text);
  font-family: var(--font);
  transition: all var(--transition);
}

/* Auto-growing textarea — mirrors .form-field inputs but expands to fit content */
.auto-textarea {
  width: 100%;
  display: block;
  resize: none;
  overflow: hidden;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 12px;
  font-size: 0.875rem;
  line-height: 1.4;
  color: var(--text);
  font-family: var(--font);
  transition: border-color var(--transition), box-shadow var(--transition);
}
.auto-textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-muted);
}

/* WYSIWYG with the rider PDF (2026-08-09): the PDF body is A4 minus 40pt
   margins = 515pt usable, Roboto 10pt, line-height ~1.4. To keep the wrap
   identical while staying readable on screen, we scale font AND width by the
   same factor: 10px font @ 686px width ≈ 13.5px font @ 926px width — same
   width/font ratio, so one line typed in the config = one line in the rider.
   13.5px matches the sidebar nav links for a consistent UI. */
.config-page .auto-textarea {
  font-size: 13.5px;
  line-height: 1.4;
  padding: 8px 10px;
}

.form-field input:focus,
.form-field select:focus,
.form-field textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-muted);
}

/* Standalone form inputs (Show / Setlist pages) — match .form-field inputs */
.form-input {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 12px;
  font-size: 0.875rem;
  color: var(--text);
  font-family: var(--font);
  transition: all var(--transition);
}
.form-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-muted);
}
.form-input::placeholder {
  color: var(--text-muted);
}
select.form-input {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2394a3b8' d='M6 8L2 4h8z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 32px;
  cursor: pointer;
}

/* Uniform height for every control — native date/time inputs render taller
   than selects/text inputs otherwise (DATE field looked bigger than STATUS).
   Neutralize the native picker chrome so the box is exactly 40px everywhere. */
.form-input {
  height: 40px;
  box-sizing: border-box;
}
textarea.form-input {
  height: auto;
}
input.form-input[type="date"],
input.form-input[type="time"] {
  height: 40px;
  padding: 0 12px;
  line-height: 1;
  overflow: hidden;
  -webkit-appearance: none;
  appearance: none;
}
input.form-input[type="date"]::-webkit-datetime-edit,
input.form-input[type="time"]::-webkit-datetime-edit {
  line-height: 38px;
  padding: 0;
}
input.form-input[type="date"]::-webkit-calendar-picker-indicator,
input.form-input[type="time"]::-webkit-calendar-picker-indicator {
  margin: 0;
}
/* Hide the native clock/calendar icon so time fields are a compact bare text
   input (still editable via typing / arrow keys / the picker on click). */
input.form-input.no-picker::-webkit-calendar-picker-indicator {
  display: none;
  -webkit-appearance: none;
}
input.form-input.no-picker {
  text-align: center;
  padding: 0 4px;
}

/* Password field with a show/hide eye toggle (src/components/PasswordInput.tsx).
   The wrapper is position:relative and full-width so it slots into the same
   block/flex/grid slots the bare <input> used to occupy; the button is
   absolutely positioned so the layout width never changes. */
.password-field {
  position: relative;
  display: block;
  width: 100%;
}
.password-field > input {
  width: 100%;
  padding-right: 40px; /* keep typed text clear of the eye button */
}
/* Same override for the auth cards, whose `.login-card input` rule is more
   specific than `.password-field > input` (and may load after it). */
.login-card .password-field > input {
  padding-right: 40px;
}
.password-toggle {
  position: absolute;
  top: 50%;
  right: 4px;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--transition), background var(--transition);
}
.password-toggle:hover {
  color: var(--text);
  background: var(--surface-hover);
}
.password-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.password-toggle[aria-pressed="true"] {
  color: var(--text);
}
.password-toggle:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.password-toggle svg {
  width: 18px;
  height: 18px;
  display: block;
}

/* Compact color input — mirrors .form-field input[type="color"] */
input.form-input[type="color"] {
  width: 48px;
  height: 40px;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

input.form-input[type="color"]::-webkit-color-swatch-wrapper {
  padding: 0;
}

input.form-input[type="color"]::-webkit-color-swatch {
  border: none;
  border-radius: var(--radius-sm);
}

.form-field input::placeholder,
.form-field textarea::placeholder {
  color: var(--text-muted);
}

.form-field input[type="color"] {
  width: 48px;
  height: 40px;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.form-field input[type="color"]::-webkit-color-swatch-wrapper {
  padding: 0;
}

.form-field input[type="color"]::-webkit-color-swatch {
  border: none;
  border-radius: var(--radius-sm);
}

.checkbox-label {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  color: var(--text);
  font-size: 0.875rem;
}

.checkbox-label input[type="checkbox"] {
  width: 20px;
  height: 20px;
  accent-color: var(--accent);
  cursor: pointer;
}

.toggle-group {
  display: inline-flex;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 2px;
}

.toggle-btn {
  padding: 8px 16px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-dim);
  background: transparent;
  border: none;
  border-radius: calc(var(--radius) - 2px);
  cursor: pointer;
  transition: all var(--transition);
}

.toggle-btn:hover { color: var(--text); }
.toggle-btn.active {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: 0 2px 8px var(--accent-glow);
}

/* Cards */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  /* U1 — densité : le padding de carte vient de l'échelle (--ui-pad, 14px),
     plus de 24px codé en dur. Les zones qui ont besoin d'air (aperçus PDF,
     papier) gardent leur propre padding localement. */
  padding: var(--ui-pad);
  box-shadow: var(--shadow-sm);
  transition: all var(--transition);
}

/* Row/ITEM card INSIDE a CardStack card body (Account documents, visas,
   airlines, availability, song charts). Same FRAME as .card but NO 24px
   padding — each item brings its compact padding inline. A distinct class so
   the QA harness (scripts/qa-double-cards.cjs) can prove that no card FRAME is
   nested inside another one. */
.rc-item-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

/* ---- Foldable cards (UI homogeneity, 2026-10-24) --------------------------
   Every page folds its large sections with the SAME pattern: a <details.card>
   whose <summary> carries the .rc-card-head chrome (mono uppercase title +
   dim sub). The native disclosure marker is hidden — the rc-head IS the
   affordance; a ▸ chevron is drawn via ::before and rotates when open. */
details.card > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: flex-start;
  gap: 10px;
}
details.card > summary::-webkit-details-marker { display: none; }
details.card > summary > div:first-child { flex: 1; }
details.card > summary h3 {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 8px;
}
details.card > summary h3::before {
  content: '▸';
  display: inline-block;
  color: var(--text-dim);
  font-size: 0.85em;
  transition: transform var(--transition);
}
details.card[open] > summary h3::before { transform: rotate(90deg); }
details.card > summary + * { margin-top: 12px; }

@media (hover: hover) and (pointer: fine) {
  .card:hover {
    border-color: var(--border-light);
    box-shadow: var(--shadow-md);
  }
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--divider);
}

.card-title {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--text);
}

/* Grid */
.grid {
  display: grid;
  gap: 16px;
}

.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 1024px) {
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
  .grid-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .grid-4, .grid-3, .grid-2 { grid-template-columns: 1fr; }
}

/* ─── Setlists/Checklists: single-column layout (list above editor) ─── */
.setlists-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

/* Band settings two-pane stays 2-up on desktop, stacks on mobile. The pages
   use an inline `gridTemplateColumns: '1fr 1fr'` (surcharges media queries), so
   the mobile rule needs `!important` to win. */
.settings-row { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
@media (max-width: 768px) {
  .settings-row { grid-template-columns: 1fr !important; }
}

/* ─── Backline (shared) — used by the config Audio-Backline read-only summary
       (backline-list + backline-row grid) AND the musician/crew editor. The
       editor table uses its OWN .bl-* classes so the summary layout is
       untouched. (2026-08-14 — the editor was refactored into a tracks-style
       table; the shared classes below keep the Audio-Backline summary correct.) */
.backline-list { display: flex; flex-direction: column; gap: 6px; }
.backline-row {
  display: grid;
  /* Default for rows that don't set their own gridTemplateColumns inline
     (e.g. the "Add Backline Item" row in ConfigAudioBacklinePage). The summary
     rows (IEM/Lights/Audio-Backline) override this inline. */
  grid-template-columns: 70px 60px 130px minmax(0,1fr) minmax(0,1fr) 130px 32px;
  gap: 6px;
  align-items: center;
  font-size: var(--font-xs);
}
.backline-type, .backline-label, .backline-qty, .backline-notes {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 6px 8px;
  border-radius: var(--radius);
  font-size: var(--font-xs);
  min-width: 0;
}
.backline-qty { text-align: center; }
/* Actions cell of the Bandz Backline "Items List" (✏️ / 🗑️ per row). The
   Items List reuses the summary's row pattern (asked by user 2026-10-15). */
.backline-actions {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  white-space: nowrap;
}
/* The NumberPicker wrapper must fill its grid cell (it renders inline-block,
   which shrinks to content and breaks the backline grid alignment). Used by
   the shared summary rows (ConfigLightsPage, ConfigAudioBacklinePage). */
.backline-row .number-picker { display: block; width: 100%; }
.backline-row .number-picker input { width: 100%; }

/* Mobile: the audio-backline "Add Backline Item" editor and its read-only
   summary reflow so the TYPE sits on its own line, with the rest below —
   instead of a wide 5-column row that overflows the viewport. (2026-08-14) */
@media (max-width: 767px) {
  .backline-edit-grid,
  .backline-summary-grid,
  .backline-items-grid {
    grid-template-columns: 1fr 1fr !important;
  }
  /* The three blocks (Add/Edit form, Items List, summary) share the SAME 8-track
     grid — BACKLINE_GRID in ConfigBacklinePage — so every column lines up. On
     narrow screens everything below the qty takes a full line; the Items List
     row actions close the last line. Only the track COUNT/ORDER matters here:
     the `1fr 1fr !important` above replaces the desktop template. */
  .backline-edit-grid > :nth-child(3),
  .backline-edit-grid > :nth-child(4),
  .backline-edit-grid > :nth-child(5),
  .backline-edit-grid > :nth-child(6),
  .backline-edit-grid > :nth-child(7),
  .backline-summary-grid > :nth-child(3),
  .backline-summary-grid > :nth-child(4),
  .backline-summary-grid > :nth-child(5),
  .backline-summary-grid > :nth-child(6),
  .backline-summary-grid > :nth-child(7),
  .backline-items-grid > :nth-child(3),
  .backline-items-grid > :nth-child(4),
  .backline-items-grid > :nth-child(5),
  .backline-items-grid > :nth-child(6),
  .backline-items-grid > :nth-child(7) { grid-column: 1 / -1; }
  .backline-items-grid > :nth-child(8) { grid-column: 2; justify-self: end; }
}

/* ─── Backline EDITOR table (musician/crew edit) ───
   A TABLE with column headers, same pattern as the instrument tracks: one
   shared grid where every row is display:contents. On narrow screens the table
   scrolls horizontally in its .bl-section container (mirroring .tracks-section).
   Uses .bl-* (not .backline-*) so it never collides with the shared summary
   classes above. (2026-08-14) */
.bl-section {
  overflow-x: auto;
}
.bl-table {
  display: grid;
  grid-template-columns: 84px 56px 140px minmax(0,1fr) minmax(0,1fr) 120px 110px 34px;
  gap: 2px 6px;
  align-items: center;
  min-width: 760px;
}
.bl-row { display: contents; }
.bl-header {
  font-weight: 600;
  color: var(--text-muted);   /* U1 — était #aaa : 2.1:1 en thème clair */
  font-size: var(--font-xs);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.bl-header > span {
  padding: 4px 2px 2px;
  display: block;
  width: 100%;
  box-sizing: border-box;
  overflow: hidden;
  border-bottom: 1px solid var(--divider);
}
.bl-data { display: contents; }
.bl-data > div {
  padding: 3px 0;
  box-sizing: border-box;
}
.bl-handle {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  white-space: nowrap;
}
.bl-qty { text-align: center; }
.bl-qty .number-picker { display: block; width: 100%; }
.bl-qty .number-picker input { width: 100%; text-align: center; }
.bl-img { display: flex; align-items: center; }
.bl-dragging .bl-type,
.bl-dragging .bl-label,
.bl-dragging .bl-notes { opacity: 0.5; }

/* Mobile: reflow the backline editor into a 2-line layout — line 1 is the Type
   (full width), line 2 holds the rest (handle, qty, description, notes, image,
   delete). Hide the column header (it no longer matches a 2-line row). Drop
   display:contents so each row becomes its own grid; the shared-grid table
   look only applies ≥768px. (2026-08-14) */
@media (max-width: 767px) {
  .bl-header { display: none; }
  .bl-data {
    display: grid;
    grid-template-columns: 44px 48px 1fr 1fr 30px;
    gap: 6px;
    align-items: center;
    padding: 8px;
    border: 1px solid var(--border, #2a2a3e);
    border-radius: var(--radius, 8px);
    margin-bottom: 8px;
  }
  .bl-data .bl-type { grid-column: 1 / -1; }
  .bl-data .bl-label { grid-column: 1 / -1; }
  .bl-data .bl-notes { grid-column: 1 / -1; }
  .bl-data .bl-provider { grid-column: 1 / -1; }
  .bl-data .bl-img { grid-column: 1 / -1; }
  .bl-data .bl-handle { grid-column: 1 / 2; }
  .bl-data .bl-qty { grid-column: 2 / 3; }
  .bl-data .bl-actions { grid-column: 5 / 6; justify-self: end; }
  .bl-section { overflow-x: visible; }
  .bl-table { min-width: 0; display: block; }
}
/* Reuse the track table input style for a consistent "table" look */
.bl-data .td-input {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 4px 8px;
  border-radius: var(--radius);
  font-size: var(--font-xs);
  width: 100%;
  box-sizing: border-box;
}
.bl-data .td-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-muted);
}
.bl-data textarea.td-input {
  resize: none;
  overflow: hidden;
  line-height: 1.4;
}

/* Tables */
.table-wrapper {
  overflow-x: auto;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}

th {
  text-align: left;
  font-weight: 600;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  background: var(--surface);
  padding: 12px 16px;
  border-bottom: 1px solid var(--divider);
  white-space: nowrap;
}

td {
  padding: 12px 16px;
  border-bottom: 1px solid var(--divider);
  color: var(--text);
}

tr:last-child td { border-bottom: none; }
tr:hover td { background: var(--surface-hover); }

/* Songbook (repertoire) table — reorderable rows with a grab handle cell */
.sb-table td { vertical-align: middle; }
.sb-table tbody tr.dragging { opacity: 0.5; }
.sb-drag-handle {
  display: inline-block;
  cursor: grab;
  color: var(--text-muted);
  font-size: 1.1rem;
  line-height: 1;
  padding: 4px 6px;
  border-radius: 4px;
  user-select: none;
}
.sb-drag-handle:hover { background: var(--border); color: var(--text); }
.sb-drag-handle:active { cursor: grabbing; }

/* Users & Access — elegant expandable list */
.u-avatar {
  width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-weight: 600; font-size: 0.95rem; color: var(--on-accent);
  background: var(--accent); flex-shrink: 0;
}
.u-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 11px; border-radius: 999px;
  font-size: 0.75rem; font-weight: 600; white-space: nowrap; line-height: 1.3;
}
.u-pill--super { background: var(--accent-tint-strong); color: var(--accent); }
.u-pill--user { background: color-mix(in srgb, var(--text-muted) 14%, transparent); color: var(--text-dim); }
.u-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.u-dot--on { background: var(--success); }
.u-dot--off { background: var(--text-muted); }
.u-chevr {
  border: none; background: transparent; color: var(--text-muted);
  cursor: pointer; font-size: 0.85rem; padding: 6px 8px; border-radius: 6px; line-height: 1;
}
.u-chevr:hover { background: var(--surface-hover); color: var(--text); }
.u-detail { background: var(--surface-hover); }
.u-detail td { padding: 18px 20px; }
.u-bandchip {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 8px; padding: 4px 6px 4px 10px; font-size: 0.8rem;
}
.u-bandchip select {
  border: none; background: transparent; color: var(--text);
  font-size: 0.78rem; outline: none; cursor: pointer; padding: 0 2px;
}
.u-bandchip__x {
  border: none; background: transparent; color: var(--text-muted);
  cursor: pointer; font-size: 1rem; padding: 0 2px; line-height: 1;
}
.u-bandchip__x:hover { color: var(--danger); }
.u-rowactions { display: flex; gap: 6px; flex-wrap: wrap; }
.u-bandtag {
  font-size: 0.68rem; font-weight: 600; padding: 1px 7px; border-radius: 999px;
  background: color-mix(in srgb, var(--text-muted) 14%, transparent); color: var(--text-dim);
  white-space: nowrap; line-height: 1.4;
}
.u-sectionlabel {
  font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-muted); font-weight: 600; margin-bottom: 8px;
}

/* Forms */
.input-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.input-row {
  display: flex;
  gap: 12px;
}

.input-row > * { flex: 1; }

/* Tags */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  font-size: 0.75rem;
  font-weight: 500;
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-dim);
  border: 1px solid var(--border);
}

.tag-accent {
  background: var(--accent-muted);
  color: var(--accent);
}

/* Badges */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  font-size: 0.6875rem;
  font-weight: 600;
  border-radius: 999px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

/* LOT U1b — les teintes de badge étaient des rgba() littérales (elles ne suivaient
   donc ni l'accent ni le thème) et la couleur du texte était celle du jeton, ce
   qui tombait sous 4.5:1 en thème clair. Le fond est maintenant dérivé DU MÊME
   jeton (color-mix) : le badge et son texte restent solidaires dans les 2 thèmes. */
.badge-warning { background: color-mix(in srgb, var(--warning) 15%, transparent); color: var(--warning); }
.badge-danger { background: color-mix(in srgb, var(--danger) 15%, transparent); color: var(--danger); }
.badge-success { background: color-mix(in srgb, var(--success) 15%, transparent); color: var(--success); }
.badge-info { background: var(--chip-bg); color: var(--chip-text); border: 1px solid var(--border); }

/* Conflicts */
.conflict-banner {
  background: linear-gradient(135deg, rgba(255, 184, 0, 0.1) 0%, rgba(255, 184, 0, 0.05) 100%);
  border: 1px solid var(--warning);
  border-radius: var(--radius);
  padding: 16px;
  margin-bottom: 24px;
  animation: slideIn var(--transition-slow) ease-out;
}

.conflict-banner strong { color: var(--warning); }
.conflict-banner ul { margin: 8px 0 0; padding-left: 20px; }
.conflict-banner li { color: var(--text-dim); font-size: 0.875rem; }

/* Conflict indicators on cards */
.conflict-ring {
  border-color: var(--warning) !important;
  box-shadow: 0 0 0 1px var(--warning), 0 0 0 3px rgba(255, 184, 0, 0.1);
}

/* Empty states */
.empty-state {
  text-align: center;
  padding: 48px 24px;
  color: var(--text-muted);
}

.empty-state svg {
  width: 64px;
  height: 64px;
  margin-bottom: 16px;
  opacity: 0.4;
}

/* Read-only "Mic stands (venue-provided)" — rendered as a TABLE with column
   headers, matching the backline editor (.bl-*). Dedicated .ms-* classes so
   the shared .bl-* grid (8 fixed columns) is never touched. (2026-09-02) */
.ms-section {
  margin-top: 12px;
}
.ms-title {
  margin: 0 0 6px;
  font-size: var(--font-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.ms-table {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  gap: 2px 6px;
  align-items: center;
  min-width: 320px;
}
.ms-row { display: contents; }
.ms-header {
  font-weight: 600;
  color: var(--text-muted);
  font-size: var(--font-xs);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.ms-header > span {
  padding: 4px 2px 2px;
  display: block;
  width: 100%;
  box-sizing: border-box;
  overflow: hidden;
  border-bottom: 1px solid var(--divider);
}
.ms-data { display: contents; }
.ms-data > div {
  padding: 3px 0;
  box-sizing: border-box;
}
.ms-qty { text-align: center; }

/* Modals */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.7);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  z-index: 1000;
  animation: fadeIn var(--transition) ease-out;
}

.modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  max-width: 480px;
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
  animation: slideIn var(--transition-slow) ease-out;
}

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 24px;
  border-bottom: 1px solid var(--divider);
}

.modal-title {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--text);
}

.modal-close {
  width: 32px;
  height: 32px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all var(--transition);
}

.modal-close:hover {
  background: var(--surface-hover);
  color: var(--text);
}

.modal-body {
  padding: 24px;
}

.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  padding: 16px 24px;
  border-top: 1px solid var(--divider);
}

/* Tooltips */
.tooltip {
  position: relative;
}

.tooltip::after {
  content: attr(data-tip);
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-bottom: 8px;
  padding: 8px 12px;
  background: var(--surface-active);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 0.75rem;
  color: var(--text);
  white-space: nowrap;
  opacity: 0;
  visibility: hidden;
  transition: all var(--transition);
  z-index: 100;
}

.tooltip:hover::after {
  opacity: 1;
  visibility: visible;
}

/* Loading */
.loading {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 48px;
  color: var(--text-muted);
}

.spinner {
  width: 32px;
  height: 32px;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

/* Drag and drop */
.dragging {
  opacity: 0.5;
  transform: scale(1.02);
  box-shadow: var(--shadow-lg);
  z-index: 100;
}

.drag-over {
  border-color: var(--accent) !important;
  background: var(--accent-muted);
}

/* Conflict indicator pulse */
@keyframes conflictPulse {
  0%, 100% { box-shadow: 0 0 0 1px var(--warning), 0 0 0 3px rgba(255,184,0,0.1); }
  50% { box-shadow: 0 0 0 2px var(--warning), 0 0 0 6px rgba(255,184,0,0.2); }
}

.conflict-ring {
  animation: conflictPulse 2s ease-in-out infinite;
}

/* Drag preview */
.drag-preview {
  transform: rotate(3deg);
  box-shadow: var(--shadow-lg);
  opacity: 0.9;
}

/* Loading skeleton */
.skeleton {
  background: linear-gradient(90deg, var(--surface) 25%, var(--surface-hover) 50%, var(--surface) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s ease-in-out infinite;
  border-radius: var(--radius);
}

@keyframes shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

/* Drag handle */
.drag-handle {
  cursor: grab;
  color: var(--text-muted);
  padding: 4px;
  border-radius: var(--radius-sm);
  transition: all var(--transition);
}

.drag-handle:hover {
  color: var(--text);
  background: var(--surface);
}

.dragging .drag-handle {
  cursor: grabbing;
  color: var(--accent);
}

/* Print styles */
@media print {
  .page-header-actions,
  .btn,
  .modal-overlay,
  .page-header {
    display: none !important;
  }
  .page { padding: 0; }
  .card { border: 1px solid #ccc; }
  body { background: white; color: black; }
}
/* ─── Instrument Editor — compact track layout ─── */
.tracks-section {
  padding: 8px 12px;
  overflow-x: auto;
}
.tracks-list {
  /* ONE shared grid for the header row AND every track row — each .track-row
     is display: contents, so ALL rows share the exact same column tracks.
     (Previously each row was its own grid: fr columns were re-sized per row
     from that row's min-content — header "Name" 108px vs data 103px — which
     shifted every column from Rack onward.) (2026-08-09) */
  display: grid;
  /* U2 (retour utilisateur 2026-11-02) : la colonne NAME est la SEULE à
     pouvoir rétrécir en dernier — minmax(140px, 1fr) la protège, tandis que
     Mic et Notes (minmax(40/58px, …)) ont un PLANCHER lisible et cèdent leur
     trois `fr` se partageaient la réduction et Name devenait illisible avant
     les colonnes secondaires. */
  grid-template-columns: 26px minmax(120px, 1fr) 92px 46px 46px 46px 34px 34px minmax(40px, 0.5fr) 82px 88px 50px 82px 100px minmax(58px, 0.8fr) 28px;
  gap: 2px 4px;
  align-items: center;
  /* Narrow enough to fit the page without horizontal scroll — the section
     that hosts the table is ~888px wide on the musician edit page. Selects
     still show their values fully (Rack "Stagerack", Mic From/From
     "The Band"). (2026-08-12: Connection + Transmitter columns removed —
     wireless now lives per instrument, not per track.) */
  min-width: 894px;
}
.track-row {
  display: contents;
}
.track-header {
  font-weight: 600;
  color: var(--text-muted);
  font-size: var(--font-xs);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 0;
  border-bottom: none;
}
.track-header > span {
  padding: 4px 2px 2px;
  /* Each header cell fills its grid column (shared with data rows via
     display: contents on .track-row). Bottom border replaces the old
     .track-header border-bottom which is lost with display: contents. */
  display: block;
  width: 100%;
  box-sizing: border-box;
  overflow: hidden;
  border-bottom: 1px solid var(--divider);
}
.track-data {
  display: contents;
}
.td-track-n {
  text-align: center;
  font-weight: 600;
  color: var(--text-dim);
  font-size: var(--font-sm);
}
.td-input {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 4px 8px;
  border-radius: var(--radius);
  font-size: var(--font-xs);
  width: 100%;
  /* Match the header cells (border-box) so fr columns size identically
     between header and data rows. (2026-08-09) */
  box-sizing: border-box;
}
.td-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-muted);
}
.td-input-num {
  text-align: center;
}
.td-select {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 4px 22px 4px 8px;
  border-radius: var(--radius);
  font-size: var(--font-xs);
  width: 100%;
  box-sizing: border-box;
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath fill='%23999' d='M0 0l5 6 5-6z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 7px center;
  cursor: pointer;
}
.td-select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-muted);
}
.td-boom {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  justify-content: center;
  color: var(--text-dim);
  font-size: var(--font-xs);
}
.td-boom input {
  accent-color: var(--accent);
  cursor: pointer;
}
.td-boom-label {
  white-space: nowrap;
}
/* "Shared" column — tick when the channel is reused by a replacement/guest. */
.td-shared {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.td-shared input {
  accent-color: var(--accent);
  cursor: pointer;
}
/* Light tint on the microphone columns (MIC → MIC FROM) so the input-list
   table reads more easily as a group. */
.td-mic,
.td-mic-from {
  background: var(--accent-tint);
  border-radius: var(--radius);
}
.track-header > .th-mic,
.track-header > .th-mic-from {
  background: var(--accent-tint-strong);
  border-radius: var(--radius);
  padding: 3px 6px;
  /* U1 — un libellé sur fond TEINTÉ garde --text-muted hérité du th → 4.0:1.
     Le cran --text-dim passe AA sur ce fond dans les deux thèmes. */
  color: var(--text-dim);
}
.td-remove {
  background: none;
  border: none;
  color: var(--text-muted);   /* U1 — était #666 : 2.9:1 en thème sombre */
  cursor: pointer;
  font-size: var(--font-md);
  padding: 2px;
}
.td-remove:hover {
  color: var(--danger);
}
.tracks-footer {
  padding-top: 6px;
}

/* ─── Instrument editor (musician edit page) ─── */
.instrument-editor {
  display: flex;
  align-items: stretch;
  gap: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.instrument-color-bar {
  width: 4px;
  flex: 0 0 auto;
  background: var(--accent);
}
.instrument-editor-header {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
}
.instrument-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.instrument-editor-title {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
}
.instrument-editor-actions {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 0 0 auto;
}
.instrument-name-input {
  background: transparent;
  border: none;
  color: var(--text);
  font-weight: 500;
  font-size: 0.9rem;
  flex: 1;
  min-width: 0;
  padding: 4px 6px;
  border-radius: var(--radius-sm);
}
.instrument-name-input:focus {
  outline: none;
  background: var(--bg);
}
.instrument-name-input::placeholder { color: var(--text-muted); }
.track-count-label {
  font-size: 0.7rem;
  color: var(--text-muted);
  font-family: var(--font-mono);
  white-space: nowrap;
  flex: 0 0 auto;
}
.conflict-warning { color: var(--warning); font-size: 0.85rem; }
.btn-icon {
  background: none;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  padding: 2px;
  display: inline-flex;
  align-items: center;
}
.btn-icon:hover { color: var(--text); }
.chevron { width: 18px; height: 18px; transition: transform var(--transition); }
.chevron.open { transform: rotate(90deg); }
.has-conflict { border-color: var(--warning); }
.instrument-list { display: flex; flex-direction: column; gap: 8px; }
.tracks-section { padding: 0 12px 12px; border-top: 1px solid var(--divider); overflow-x: auto; }
.tracks-footer { margin-top: 8px; }

/* ─── Crew summary (rider page) ─── */
.crew-summary { display: flex; flex-wrap: wrap; gap: 8px; }
.crew-item {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: 6px;
  background: var(--accent-tint); border: 1px solid var(--accent-line);
  font-size: var(--font-sm);
}
.crew-role { font-weight: 500; }
.crew-count { color: var(--accent); font-weight: bold; }

/* ─── Stage plot thumbnails ─── */
.stageplot-thumbnails {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}
.stageplot-thumb {
  position: relative;
  width: 200px;
  height: 200px;
  border-radius: 6px;
  overflow: hidden;
  border: 2px solid var(--border);
  cursor: pointer;
}
.stageplot-thumb.selected {
  border-color: var(--accent);
}
.stageplot-thumb img {
  width: 100%;
  height: 165px;
  object-fit: cover;
}
.stageplot-thumb-name {
  display: block;
  font-size: var(--font-xs);
  color: var(--text-dim);
  text-align: center;
  padding: 3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.stageplot-thumb-remove {
  position: absolute;
  top: 2px;
  right: 2px;
  background: rgba(0,0,0,0.7);
  border: none;
  color: var(--danger);
  cursor: pointer;
  font-size: var(--font-xs);
  padding: 2px 4px;
  border-radius: 4px;
  line-height: 1;
}
.stageplot-thumb-remove:hover {
  background: var(--danger);
  color: var(--bg);
}
.stageplot-thumb-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  cursor: pointer;
  outline: none;
  border-radius: 6px;
}
.stageplot-thumb-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.stageplot-thumb-card .stageplot-thumb-name {
  width: 200px;
}
.stageplot-add-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 200px;
  height: 200px;
  border: 2px dashed var(--border);
  border-radius: 6px;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  font-size: var(--font-sm);
  font-family: inherit;
  padding: 8px;
  text-align: center;
}
.stageplot-add-card:hover {
  border-color: var(--accent);
  color: var(--text);
}
.stageplot-add-icon {
  font-size: 1.6rem;
  line-height: 1;
}
.stageplot-preview {
  margin-top: 12px;
}
.stageplot-preview img {
  max-width: 100%;
  max-height: 300px;
  border-radius: 8px;
  border: 1px solid var(--border);
}
.stageplot-clear-btn {
  margin-top: 4px;
}

/* ─── Instrument tags on musician cards ─── */
.instrument-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 4px;
}
.instrument-tag {
  font-size: var(--font-xs);
  padding: 2px 8px;
  border-radius: 4px;
  background: var(--accent-tint);
  border: 1px solid var(--accent-line);
  color: var(--accent);
}

/* ---- Save error banner (global persistence-failure warning) ---- */
.save-error-banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  background: rgba(255, 71, 87, 0.12);
  border: 1px solid var(--danger);
  border-radius: var(--radius, 8px);
  padding: 12px 14px;
  margin-bottom: 18px;
  color: var(--text);
}
.save-error-banner-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
  min-width: 0;
  font-size: 0.9rem;
}
.save-error-banner-body strong { color: var(--danger); }
.save-error-banner-hint {
  color: var(--text-dim);
  font-size: 0.82rem;
}
.save-error-banner-close {
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
}
.save-error-banner-close:hover { color: var(--text); }

/* ---- Trial banner (14-day self-service trial — L3, 2026-09-24) ---- */
.trial-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  border-radius: var(--radius, 8px);
  padding: 8px 12px;
  margin-bottom: 14px;
  font-size: 0.85rem;
  color: var(--text);
}
/* Discreet line while the trial runs. */
.trial-banner-active {
  background: rgba(84, 160, 255, 0.08);
  border: 1px solid rgba(84, 160, 255, 0.35);
  color: var(--text-dim);
  padding: 6px 12px;
}
/* Loud red banner once it has expired (writing is blocked server-side). */
.trial-banner-expired {
  background: rgba(255, 71, 87, 0.12);
  border: 1px solid var(--danger);
}
.trial-banner-text { flex: 1; min-width: 0; }
.trial-banner-expired strong { color: var(--danger); margin-right: 4px; }
.trial-banner-cta {
  flex-shrink: 0;
  background: var(--danger);
  color: var(--on-danger);
  border-radius: 6px;
  padding: 5px 10px;
  font-weight: 600;
  font-size: 0.8rem;
  text-decoration: none;
  white-space: nowrap;
}
.trial-banner-cta:hover { filter: brightness(1.08); }

/* ---- Offline banner (top of main content, full width) ---- */
.offline-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  border: 1px solid;
  border-radius: 8px;
  margin-bottom: 14px;
  font-size: 0.85rem;
  color: var(--text, #f0f0f5);
}
.offline-banner-offline {
  background: rgba(255, 184, 0, 0.12);
  border-color: var(--warning, #ffb800);
}
.offline-banner-syncing {
  background: rgba(84, 160, 255, 0.1);
  border-color: var(--info);
}
.offline-banner-success {
  background: rgba(0, 212, 126, 0.12);
  border-color: var(--success, #00d47e);
}
.offline-banner-icon { font-size: 1rem; line-height: 1; flex-shrink: 0; }
.offline-banner-body { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.offline-banner-body strong { font-size: 0.88rem; }
.offline-banner-sub { color: var(--text-dim, #a0a0b0); }
.offline-banner-actions { display: flex; gap: 6px; flex-shrink: 0; align-items: center; }
.offline-badge-sync {
  background: var(--warning, #ffb800);
  color: #1a1a1a;
  border: none;
  border-radius: 6px;
  padding: 4px 10px;
  font-weight: 700;
  font-size: 0.78rem;
  cursor: pointer;
  white-space: nowrap;
}
.offline-badge-sync:hover { filter: brightness(1.1); }
.offline-badge-sync:disabled { opacity: 0.6; cursor: default; }
.offline-badge-clear {
  background: transparent;
  color: var(--text-dim, #a0a0b0);
  border: 1px solid var(--border, #2a2a3e);
}

/* ---- "Import your rider (AI)" modal (2026-08) ---- */

.ai-import-modal {
  max-width: 560px;
}

.ai-import-body {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.ai-drop-zone {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 92px;
  padding: 16px;
  border: 1px dashed var(--border, #2a2a3e);
  border-radius: var(--radius, 8px);
  background: var(--surface, #1e1e2a);
  color: var(--text-dim, #a0a0b0);
  font-size: var(--font-sm);
  text-align: center;
  cursor: pointer;
  transition: border-color var(--transition, .15s ease), background var(--transition, .15s ease);
}

.ai-drop-zone:hover {
  border-color: var(--info);
  background: var(--surface-hover, #242433);
}

.ai-drop-zone-over {
  border-color: var(--info);
  background: rgba(84, 160, 255, 0.1);
}

.ai-drop-file strong {
  color: var(--text, #f0f0f5);
}

.ai-import-textarea {
  width: 100%;
  resize: vertical;
  font-size: var(--font-md);
  font-family: inherit;
}

.ai-import-actions {
  display: flex;
  justify-content: flex-end;
}

.ai-import-error {
  border: 1px solid var(--danger, #ff5470);
  background: rgba(255, 84, 112, 0.1);
  color: var(--danger, #ff5470);
  border-radius: var(--radius, 8px);
  padding: 10px 14px;
  font-size: var(--font-sm);
}

.ai-import-ocr-banner {
  border: 1px solid var(--accent, #e0a44c);
  background: rgba(224, 164, 76, 0.12);
  color: var(--text, #f2ede4);
  border-radius: var(--radius, 8px);
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: var(--font-sm);
}

.ai-ocr-lang {
  margin-top: 12px;
}
.ai-ocr-lang select {
  max-width: 260px;
}

.ai-import-success {
  border: 1px solid var(--success, #00d47e);
  background: rgba(0, 212, 126, 0.12);
  color: var(--success, #00d47e);
  border-radius: var(--radius, 8px);
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: var(--font-sm);
}

.ai-import-success strong {
  color: var(--success, #00d47e);
  font-size: var(--font-md);
}

.ai-import-success span {
  color: var(--text, #f0f0f5);
}

.ai-import-review {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.ai-import-banner {
  border: 1px solid var(--warning, #ffb800);
  background: rgba(255, 184, 0, 0.12);
  color: var(--warning, #ffb800);
  border-radius: var(--radius, 8px);
  padding: 10px 14px;
  font-size: var(--font-md);
  font-weight: 600;
}

.ai-import-meta {
  color: var(--text-dim, #a0a0b0);
  font-size: var(--font-xs);
}

.ai-section {
  border: 1px solid var(--border, #2a2a3e);
  border-radius: var(--radius, 8px);
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.ai-section-title {
  margin: 0;
  font-size: var(--font-md);
  font-weight: 600;
  color: var(--text, #f0f0f5);
}

.ai-transport {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.ai-transport-badge {
  align-self: flex-start;
  font-size: var(--font-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim, #a0a0b0);
  background: var(--surface-hover, #242433);
  border-radius: 999px;
  padding: 2px 10px;
}

.ai-fields {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.ai-field {
  display: grid;
  grid-template-columns: minmax(96px, 140px) 1fr;
  gap: 10px;
  align-items: baseline;
  font-size: var(--font-sm);
  min-width: 0;
}

.ai-field-key {
  color: var(--text-dim, #a0a0b0);
  word-break: break-word;
}

.ai-field-value {
  color: var(--text, #f0f0f5);
  min-width: 0;
  overflow-wrap: anywhere;
}

.ai-import-footer {
  justify-content: space-between;
}

/* Under 768px the two-column field grid stacks so long values never overflow
   a 390px viewport. */
@media (max-width: 768px) {
  .ai-import-modal {
    max-width: 100%;
  }
  .ai-field {
    grid-template-columns: 1fr;
    gap: 2px;
  }
}

/* ---- AI personnel import (musicians + crew) ---- */
.ai-personnel-block {
  margin-top: 20px;
  border-top: 1px solid var(--border, #2a2a3e);
  padding-top: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.ai-personnel-review {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.ai-personnel-group {
  border: 1px solid var(--border, #2a2a3e);
  border-radius: var(--radius, 8px);
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.ai-personnel-group-title {
  margin: 0;
  font-size: var(--font-sm);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim, #a0a0b0);
}

.ai-personnel-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.ai-personnel-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: var(--font-sm);
  min-width: 0;
}

.ai-personnel-check {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  flex: 0 1 auto;
}

.ai-personnel-name {
  font-weight: 600;
  color: var(--text, #f0f0f5);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ai-personnel-badge {
  flex: 0 0 auto;
  font-size: var(--font-xs);
  font-weight: 700;
  border-radius: 999px;
  padding: 2px 10px;
  white-space: nowrap;
}

.ai-badge-new {
  color: var(--success, #00d47e);
  background: rgba(0, 212, 126, 0.12);
}

.ai-badge-enrich {
  color: var(--warning, #ffb800);
  background: rgba(255, 184, 0, 0.12);
}

.ai-personnel-fields {
  color: var(--text-dim, #a0a0b0);
  min-width: 0;
  overflow-wrap: anywhere;
  flex: 1 1 auto;
}

.ai-personnel-conflicts {
  flex: 0 0 auto;
  font-size: var(--font-xs);
  color: var(--text-dim, #a0a0b0);
  border: 1px dashed var(--border, #2a2a3e);
  border-radius: 6px;
  padding: 2px 8px;
  white-space: nowrap;
}

/* ---- AI stage plot recovered from a PDF drawing (LOT E) ---- */
.ai-stageplot-block {
  margin-top: 20px;
  border-top: 1px solid var(--border, #2a2a3e);
  padding-top: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.ai-stageplot-previews {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.ai-stageplot-preview {
  max-width: 220px;
  max-height: 160px;
  border: 1px solid var(--border, #2a2a3e);
  border-radius: var(--radius, 8px);
  object-fit: contain;
  background: var(--surface, #1a1a2e);
}

/* ---- AI assistant (read-only chat) ---- */
.ai-assistant-subtitle {
  margin: -8px 0 20px;
  color: var(--text-muted);
  font-size: var(--font-md);
}

.ai-assistant-band {
  color: var(--text-muted);
  font-size: var(--font-sm);
  margin-right: 8px;
}

.ai-credit-badge {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--divider);
  color: var(--text);
  font-size: var(--font-sm);
  font-weight: 600;
  white-space: nowrap;
}

.ai-credit-badge.ai-credit-empty {
  color: var(--danger);
  border-color: var(--danger);
}

/* Two-pool credit chips inside the badge (monthly allowance + persistent top-up). */
.ai-credit-badge .ai-credit-pool-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border: 1px solid var(--divider);
  margin: 0 2px;
  white-space: nowrap;
}

.ai-chat {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 260px);
  min-height: 320px;
  border: 1px solid var(--divider);
  border-radius: 12px;
  background: var(--bg-elevated);
  overflow: hidden;
}

.ai-chat-scroll {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.ai-chat-empty {
  margin: auto;
  color: var(--text-muted);
  text-align: center;
  max-width: 460px;
  font-size: var(--font-md);
}

.ai-msg {
  display: flex;
}

.ai-msg-user {
  justify-content: flex-end;
}

.ai-msg-assistant {
  justify-content: flex-start;
}

.ai-msg-bubble {
  max-width: 78%;
  padding: 10px 14px;
  border-radius: 12px;
  white-space: pre-wrap;
  word-break: break-word;
  font-size: var(--font-md);
  line-height: 1.45;
}

.ai-msg-user .ai-msg-bubble {
  background: var(--accent);
  color: var(--on-accent);
  border-bottom-right-radius: 4px;
}

.ai-msg-assistant .ai-msg-bubble {
  background: var(--surface);
  border: 1px solid var(--divider);
  color: var(--text);
  border-bottom-left-radius: 4px;
}

.ai-msg-thinking .ai-msg-bubble {
  color: var(--text-muted);
  font-style: italic;
}

.ai-msg-error .ai-msg-bubble {
  border-color: var(--danger);
  color: var(--danger);
}

.ai-chat-input {
  display: flex;
  gap: 8px;
  padding: 12px;
  border-top: 1px solid var(--divider);
  background: var(--bg-elevated);
}

.ai-chat-input .form-input {
  flex: 1;
}

/* ---- AI proposal card (Apply/Cancel) ---- */
.ai-action-card {
  max-width: 100%;
  padding: 14px;
  border-left: 3px solid var(--accent);
}
.ai-action-card-head {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  flex-wrap: wrap;
}
.ai-action-badge {
  flex-shrink: 0;
  font-family: var(--font-mono, monospace);
  font-size: var(--font-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  white-space: nowrap;
}
.ai-action-summary {
  flex: 1;
  min-width: 0;
  font-weight: 600;
}
.ai-action-changes {
  margin-top: 8px;
  padding: 8px 10px;
  border-radius: 8px;
  background: var(--bg-elevated);
  border: 1px solid var(--divider);
  color: var(--text-muted);
  font-family: var(--font-mono, monospace);
  font-size: var(--font-xs);
  word-break: break-word;
}
.ai-action-actions {
  display: flex;
  gap: 8px;
  margin-top: 12px;
}
.ai-action-status {
  margin-top: 12px;
  font-weight: 600;
}
.ai-action-ok {
  color: var(--success, #2e7d32);
}
.ai-action-error {
  color: var(--danger);
}

@media (max-width: 768px) {
  .ai-chat {
    height: calc(100vh - 320px);
    min-height: 280px;
  }
  .ai-msg-bubble {
    max-width: 90%;
  }
}


/* ===== Cookie consent banner (RGPD/nLPD) =====
   Informative bottom banner; does NOT block the app. Uses theme variables. */
.cookie-consent {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 1500;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 12px 20px;
  background: var(--card);
  border-top: 1px solid var(--border);
  box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.18);
  font-size: var(--font-sm);
  color: var(--text);
}
.cookie-consent-text {
  margin: 0;
  flex: 1 1 320px;
  min-width: 0;
  line-height: 1.5;
}
.cookie-consent-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
}
.cookie-consent-link {
  color: var(--accent);
  text-decoration: none;
  font-weight: 600;
}
.cookie-consent-link:hover {
  text-decoration: underline;
}
@media (max-width: 768px) {
  .cookie-consent {
    flex-direction: column;
    align-items: flex-start;
    padding: 12px 16px;
    /* P2a: sit ABOVE the mobile bottom tab bar instead of covering it. */
    bottom: calc(52px + env(safe-area-inset-bottom, 0px));
  }
  .cookie-consent-actions {
    width: 100%;
    justify-content: flex-end;
  }
}

/* ── Page Itinerary : aperçu d'un jour, déplié SOUS sa ligne (v0.600) ──
   Le tableau défile horizontalement sur mobile (.table-wrapper) ; on donne
   donc au panneau une largeur mini confortable au lieu de le laisser
   s'écraser dans la cellule. */
.itinerary-preview-row > td.itinerary-preview-cell {
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding: 12px 12px 16px;
}
.itinerary-preview-caption {
  margin: 0 0 10px;
  font-size: var(--font-sm);
  color: var(--text-dim);
}
.itinerary-preview-body {
  min-width: 620px;
  max-width: 860px;
}
@media (max-width: 768px) {
  .itinerary-preview-body {
    min-width: 0;
  }
}

/* ── Access panel (Band Settings → Members) — matrice de capacités (chantier C, 2026-09-25) ──
   Même pattern que la table des pistes (.tracks-list) : UNE seule grille
   partagée par l'en-tête et toutes les lignes, min-width + wrapper scrollable
   pour ne pas casser la page en mobile (< 768px). */
.access-panel {
  padding: 8px 0 4px;
}
.access-matrix-wrap {
  overflow-x: auto;
}
.access-matrix {
  display: grid;
  /* The first column holds the LEVEL SELECTOR — three buttons (— / 👁 / ✏️), not a
     single checkbox. It was 26px wide (the checkbox era): the three buttons spilled
     over the capability labels and the header overlapped the level legend. Its width
     is now the width of the control it actually contains (2026-10-08). */
  grid-template-columns: 118px minmax(170px, 1fr) minmax(150px, 1fr);
  gap: 4px 10px;
  align-items: center;
  min-width: 560px;   /* défile horizontalement dans son wrapper sur mobile */
  padding-bottom: 4px;
}
.access-head {
  white-space: nowrap;   /* an upper-case legend must not wrap into the next column */
  font-weight: 600;
  color: var(--text-muted);
  font-size: var(--font-xs);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.access-group {
  grid-column: 1 / -1;
  font-weight: 600;
  color: var(--text-muted);
  font-size: var(--font-xs);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding-top: 6px;
}
.access-label {
  cursor: pointer;
  font-size: var(--font-sm);
  /* Never let a long capability name push the level selector out of its column. */
  min-width: 0;
  overflow-wrap: anywhere;
}
.access-presets {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 8px 0 4px;
}
@media (max-width: 768px) {
  .access-matrix {
    /* The selector keeps its width; the wrapper scrolls horizontally instead of
       squeezing the controls into an unreadable pile. */
    grid-template-columns: 108px minmax(150px, 1fr) minmax(130px, 1fr);
    min-width: 480px;
  }
}

/* ---- Account page: one stacked column of same-width sections -------------
   Every page section (My Team card first, then credits/password, sessions,
   export, delete) lives in this single flex column: same max width (1000px)
   and a small 16px gap between cards instead of being glued edge-to-edge. */
.account-sections {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* CardStack (draggable cards, 2026-10-24): the cards are wrapped in a
   [data-card-id] div each, so the section's gap must be reproduced inside. */
.card-stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.card-stack > [data-card-id] > .card {
  margin: 0 !important; /* wrappers replaced the old sibling margins */
}

/* Discreet notice shown ONLY on the shared read-only demo (showcase) account —
   the app-wide <ShowcaseBanner/> (App.tsx) already carries this message on every
   page, so the Account page does NOT repeat it. */

/* Rider-config anti-data-loss banner (2026-10-07) — refuses a save silently
   never: 409 `stale` (conflict) or a value the server kept (preserved). */
.config-guard-banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  border-radius: var(--radius, 8px);
  padding: 10px 14px;
  margin-bottom: 18px;
  background: rgba(255, 176, 32, 0.10);
  border: 1px solid rgba(255, 176, 32, 0.55);
  color: var(--text);
}
.config-guard-banner-body { display: flex; flex-direction: column; gap: 6px; min-width: 0; flex: 1; }
.config-guard-notice { display: flex; align-items: flex-start; gap: 8px; font-size: 0.9rem; }
.config-guard-notice-text { min-width: 0; }
.config-guard-notice-icon { flex: 0 0 auto; }
.config-guard-notice-preserved .config-guard-notice-icon { color: var(--accent); }
.config-guard-notice-close,
.config-guard-banner-close {
  background: none;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: 0 4px;
}
.config-guard-notice-close:hover,
.config-guard-banner-close:hover { color: var(--text); }


/* ===== Option C (2026-10-09) → P2f (2026-10-09): show cards on EVERY
   viewport + read-first day summary ===== */

/* P2f — the Shows LIST is one card stack (Atlas / Roadcase language) at every
   width: the dense <table> is gone and so is the mobile-only split. A single
   markup source (`.shows-cards` > `.show-card`) is always rendered; only the
   LAYOUT changes per breakpoint, so there is never a duplicate render. */
.shows-cards {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.show-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color .15s ease;
}
.show-card:hover { border-color: var(--accent); }
.show-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Date block — mono, tabular figures, uppercase (`.atlas-row .dt` language). */
.show-card-date {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  white-space: nowrap;
}
.show-card-icon { font-size: 1.15rem; line-height: 1; flex: 0 0 auto; }
.show-card-body { flex: 1 1 auto; min-width: 0; }
.show-card-name {
  font-weight: 600;
  font-size: var(--font-md);
  line-height: 1.25;
  overflow-wrap: anywhere;
}
.show-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 10px;
  margin-top: 2px;
  font-size: var(--font-sm);
  color: var(--text-dim);
}
.show-card-meta span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* Status tag — `.atlas-tag` language: mono chip, colour carried by the token
   injected inline from the status palette (no hex in this stylesheet). */
.show-card-status {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 3px 7px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  white-space: nowrap;
}
.show-card .u-chevr { flex: 0 0 auto; }
.show-card-chevron { flex: 0 0 auto; color: var(--text-dim); font-size: 1.2rem; }

/* Desktop: Atlas row proportions — a wide mono date block first, roomier gaps. */
@media (min-width: 769px) {
  .show-card { gap: 16px; padding: 11px 16px; }
  .show-card-date { min-width: 96px; font-size: 13px; }
}

/* Mobile: the SAME markup, wrapped — date + icon + status on the first line,
   name/meta and the actions on the second. */
@media (max-width: 768px) {
  .show-card { flex-wrap: wrap; row-gap: 6px; }
  .show-card-date { order: 1; }
  .show-card-icon { order: 2; }
  .show-card-status { order: 3; margin-left: auto; }
  .show-card-body { order: 4; flex: 1 1 55%; }
  .show-card-delete { order: 5; }
  .show-card-chevron { order: 6; }
}

/* List head: date sort + status legend (the table header went with the table). */
.shows-list-head {
  display: flex;
  gap: 16px;
  align-items: center;
  margin-bottom: 10px;
  flex-wrap: wrap;
}
.shows-sort {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: none;
  cursor: pointer;
  font-size: var(--font-xs);
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.shows-sort:hover { color: var(--text); border-color: var(--accent); }

/* Consolidated read-only daysheet viewer (DaysheetViewer). */
.daysheet-viewer { padding: 18px 20px; }
.daysheet-viewer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.daysheet-viewer-header { margin-bottom: 8px; }
.daysheet-viewer-subtitle { font-size: var(--font-md, 14px); color: var(--text-dim); margin: 2px 0 6px; }
.daysheet-viewer-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  font-size: var(--font-sm, 13px);
  color: var(--text-dim);
}
.daysheet-viewer-section {
  margin-top: 18px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.daysheet-viewer-section-title {
  margin: 0 0 8px;
  font-size: var(--font-sm, 13px);
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-dim);
}
.daysheet-viewer-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 20px;
}
.daysheet-viewer-item { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.daysheet-viewer-label {
  font-size: var(--font-xs, 12px);
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-dim);
}
.daysheet-viewer-value { font-size: var(--font-md, 14px); font-weight: 500; word-break: break-word; }
.daysheet-viewer-empty { color: var(--text-dim); font-size: var(--font-sm, 13px); margin: 0; }
.daysheet-viewer-note {
  margin: 0;
  font-size: var(--font-sm, 13px);
  white-space: pre-wrap;
  color: var(--text);
}
.daysheet-viewer-list { display: flex; flex-direction: column; gap: 8px; }
.daysheet-viewer-table { width: 100%; border-collapse: collapse; font-size: var(--font-sm, 13px); }
.daysheet-viewer-table th,
.daysheet-viewer-table td {
  text-align: left;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
  word-break: break-word;
}
.daysheet-viewer-table th {
  font-size: var(--font-xs, 12px);
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-dim);
  font-weight: 600;
}

@media (max-width: 768px) {
  .daysheet-viewer-grid { grid-template-columns: 1fr; }
}

/* ===== Public promo page — design "Mailerlite Sandro" (variant B) ==========
   Markup/CSS only: the blob stays the single source (promo-content.js untouched),
   downloads keep the SAME guarded URLs. Theme variables everywhere; the only
   hardcoded colors are the hero gradient + the light pill face + the photo/clip
   tile faces, which the validated mockup (promo-preview-maquette.html, variant
   B) fixes on purpose — they sit inside the page card, not on the app chrome. */
.sand-hero {
  background-color: #111;
  background-image: linear-gradient(160deg, #111, #2a2a2e);
  background-size: cover;
  background-position: center;
  border-radius: 10px;
  color: #fff;
  padding: 34px 20px;
  text-align: center;
  margin-bottom: 18px;
}
/* Full-bleed photo hero: cover image behind a dark veil (set inline) —
   text reads over the gradient overlay baked into the background-image. */
.sand-hero-photo {
  min-height: 300px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .55);
}
.sand-hero-logo {
  max-height: 96px;
  max-width: 60%;
  object-fit: contain;
  margin: 0 auto 14px;
  display: block;
}
.sand-hero-artist {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  line-height: 1.15;
}
.sand-hero-tour {
  font-size: 13px;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: #cfcfcf;
  margin: 8px 0 0;
}
.sand-hero-kit {
  font-size: var(--font-xs, 12px);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #9a9aa0;
  margin: 10px 0 0;
}
.sand-pill {
  display: block;
  width: 100%;
  max-width: 420px;
  margin: 10px auto;
  background: #f0f0f2;
  border: 1px solid #e4e4e7;
  border-radius: 999px;
  padding: 13px 18px;
  font-size: 13.5px;
  font-weight: 600;
  color: #1c1c1e;
  text-align: center;
  text-decoration: none;
  overflow-wrap: anywhere;
}
.sand-pill:hover { background: #e6e6ea; }
.sand-sec {
  font-size: var(--font-sm, 13px);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin: 26px 0 10px;
  font-weight: 600;
}
.sand-strip {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 6px 2px 12px;
  scrollbar-width: thin;
}
.sand-mini {
  position: relative;
  flex: 0 0 130px;
  width: 130px;
  border-radius: 8px;
  overflow: hidden;
  text-decoration: none;
  display: block;
  color: var(--text);
}
.sand-mini:focus-visible {
  outline: 2px solid var(--accent, #6c8cff);
  outline-offset: 2px;
}
.sand-mini img {
  width: 130px;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  display: block;
  /* gradient face = the mockup tile, visible while the real thumb loads
     (loading=lazy) or if the guarded URL ever fails */
  background: linear-gradient(135deg, #d9c8b4, #8a7460 60%, #3c332b);
}
.sand-mini-video {
  background: linear-gradient(135deg, #1c1c1e, #3a3a3e);
  aspect-ratio: 3 / 2;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 18px;
  position: relative;
}
/* VIDEO TILE FIX (2026-10-20): the thumbnail is the file's own first frame
   (<video preload="metadata">, muted, playsInline, no autoplay). The element
   paints over the dark gradient above when the browser can decode a frame;
   when it cannot (codecs), the gradient stays = the old fallback tile.
   pointer-events:none keeps the click on the enclosing download <a>. */
.sand-mini-video video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: transparent;
  pointer-events: none;
}
.sand-mini-video-play {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  font-size: 14px;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
  pointer-events: none;
}
.sand-mini-file {
  background: linear-gradient(135deg, #2a281f, #4a463a 60%, #2a281f);
  aspect-ratio: 3 / 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  color: var(--text);
  font-size: 16px;
  text-align: center;
  overflow-wrap: anywhere;
  padding: 6px;
}
.sand-mini-size {
  position: absolute;
  right: 4px;
  bottom: 4px;
  font-size: 10px;
  background: rgba(10, 10, 12, .72);
  color: #fff;
  border-radius: 999px;
  padding: 2px 7px;
  pointer-events: none;
}
.sand-bio {
  text-align: center;
  max-width: 640px;
  margin: 28px auto 0;
  font-size: var(--font-md, 14px);
  line-height: 1.65;
}
.sand-quote {
  text-align: center;
  max-width: 560px;
  margin: 10px auto;
  font-style: italic;
  font-size: var(--font-sm, 13px);
  color: var(--text-dim);
  border: 0;
  padding: 0;
}
.sand-quote-src { font-style: normal; }
.sand-embeds { max-width: 640px; margin: 14px auto 0; }
/* ===== Sandro v2 (2026-10-19) ============================================ */
/* #1 Photo hero: the big image ALONE — full width, ~16/7, cover, rounded
   corners; the name/tour/kit text lives in the LIGHT block below. */
.sand-hero-img {
  width: 100%;
  aspect-ratio: 16 / 7;
  border-radius: 12px;
  background-size: cover;
  background-position: center;
  background-color: #111;
  margin-bottom: 18px;
}
.sand-head {
  text-align: center;
  margin: 4px 0 22px;
}
.sand-artist-light {
  color: var(--text);
  font-size: 28px;
}
.sand-tour-light {
  color: var(--text-dim);
}
.sand-kit-light {
  font-size: var(--font-xs, 12px);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin: 10px 0 0;
}
/* #2 Social icons: inline SVG, text color, accent on hover. */
.sand-socials {
  display: flex;
  gap: 14px;
  justify-content: center;
  align-items: center;
  margin: 26px 0 0;
}
.sand-socials-compact {
  margin: 14px 0 0;
}
.sand-social {
  color: var(--text);
  display: inline-flex;
  opacity: .85;
}
.sand-social:hover { color: var(--accent, #6c8cff); opacity: 1; }
/* #5 The ONE full-pack pill at the bottom of the page. */
.sand-pack {
  display: block;
  width: 100%;
  max-width: 420px;
  margin: 34px auto 6px;
  background: #1c1c1e;
  border: 1px solid #1c1c1e;
  border-radius: 999px;
  padding: 14px 18px;
  font-size: 14px;
  font-weight: 700;
  color: #fff;
  text-align: center;
  text-decoration: none;
}
.sand-pack:hover { background: #33333a; }
@media (max-width: 480px) {
  .sand-hero { padding: 26px 14px; }
  .sand-hero-artist { font-size: 21px; }
  .sand-hero-tour { letter-spacing: .18em; }
  .sand-hero-img { aspect-ratio: 16 / 9; }
  .sand-artist-light { font-size: 22px; }
}

/* ---- Foldable sub-sections INSIDE a card (UI homogeneity, 2026-10-24) ----
   Same affordance as details.card but for sections WITHIN a big card: the
   rc-section-title becomes the summary, marker hidden, chevron rotates. */
details.rc-section-fold > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 8px;
}
details.rc-section-fold > summary::-webkit-details-marker { display: none; }
details.rc-section-fold > summary::before {
  content: '▸';
  display: inline-block;
  color: var(--text-dim);
  font-size: 0.85em;
  transition: transform var(--transition);
}
details.rc-section-fold[open] > summary::before { transform: rotate(90deg); }

/* =====================================================================
   U1 — SOCLE DE DENSITÉ (2026-11-02)
   Une échelle (--ui-*) + UNE grille de formulaire + UN tableau dense +
   les règles mobile de la skill `mobile-native`. Portée VOLONTAIREMENT
   limitée : la grille ne s'applique qu'aux pages qui portent
   `data-density="socle"` (les pages migrées), pour ne pas recomposer les
   écrans hors périmètre (P2/P3 s'en chargent).
   ===================================================================== */

/* ---- 1. La grille d'alignement -------------------------------------
   `.form-row` = grid [libellé FIXE] [contrôle qui remplit]. Le `<label>`
   est le 1er enfant, le contrôle le 2e. C'est la largeur FIXE (--ui-label-w)
   qui met tous les contrôles sur la même position x : un libellé en largeur
   auto produit une position x par libellé (14 positions mesurées avant).
   Les lignes de champ existantes (`.form-group`, `.form-field`) consomment
   la MÊME déclaration — mais SEULEMENT au premier niveau de la grille
   (`> .form-group` / `> .form-row`) : une ligne IMBRIQUÉE garde son ancien
   layout, sinon elle se décale de la colonne du parent (mesuré : positions x
   parasites à 254 / 506 / 632 px). */
.page[data-density='socle'] .form-grid > .form-group,
.page[data-density='socle'] .form-grid > .form-field,
.page[data-density='socle'] .rc-field-grid > .form-row,
/* U2 — LA LIGNE DE CHAMP EST UNIVERSELLE (2026-11-02) : un bloc qui n'est pas
   dans un .form-grid (monitoring, sous-éditeurs, blocs legacy) doit tomber sur
   le MÊME axe que les autres. On cible donc la ligne par sa STRUCTURE (un
   groupe dont l'enfant direct est un libellé), à n'importe quelle profondeur :
   sinon chaque bloc garde son axe et la page n'en a aucun (28 positions x
   mesurées sur l'éditeur de personne, contre 2 dans les blocs migrés).
   `:has(> label)` évite d'attraper un CONTENEUR de lignes (fieldset de
   monitoring, .form-row) — seuls les groupes qui PORTENT un libellé sont des
   lignes de champ. */
.page[data-density='socle'] :is(.form-group, .form-field):has(> label:not(.checkbox-label)),
.page[data-density='socle'] .rc-form-row:has(> label) {
  display: grid;
  grid-template-columns: var(--ui-label-w) minmax(0, 1fr);
  align-items: center;
  column-gap: var(--ui-gap-x);
  row-gap: 2px;
  min-height: var(--ui-h-row);
  /* U2h — LE FILET DE RANGÉE DOIT AVOIR DE L'AIR (retour utilisateur du 03.11 :
     « dans identity les champs sont collés aux lignes »). La rangée peignait son
     filet 2 px sous le contrôle : il touchait le champ. Désormais 8 px entre le
     bas du champ et le trait (`--ui-gap-field`, la valeur de référence), et les
     8 px du `margin-bottom` ci-dessous entre le trait et la rangée suivante.
     Mesuré par scripts/qa-u2h-section-lines.cjs (fieldToRule / ruleToField). */
  padding: 0 0 var(--ui-gap-field);
  border-bottom: 1px solid var(--ui-rule);
  margin: 0 0 var(--ui-gap-field);
}
/* U2h — L'AIR APRÈS LE TRAIT (8 px jusqu'au champ suivant). Deux rangées
   voisines peuvent vivre dans DEUX conteneurs empilés (des `.form-row`
   successifs) qui n'ont AUCUNE marge entre eux : le filet de la première
   tombait alors à 0 px du champ de la suivante (mesuré sur /tour/team/new).
   Le conteneur de rangées porte donc le même --ui-gap-field. Hors config : les
   pages de config n'ont pas de filet de rangée et gardent leur rythme U2f
   (scripts/qa-u2f-spacing.cjs). */
.page[data-density='socle']:not(.config-page) :is(.form-grid, .form-row, .rc-form-row):has(> :is(.form-group, .form-field)) {
  margin-bottom: var(--ui-gap-field);
}
.page[data-density='socle'] :is(.form-grid, .form-row) > :is(.form-group, .form-field),
.page[data-density='socle'] .rc-form-row:has(> :is(.form-group, .form-field)) > :is(.form-group, .form-field) {
  margin-bottom: 0;
}
/* U2h — UNE SEULE LIGNE, et c'est CELLE QUI A DE L'AIR AUTOUR (retour
   utilisateur du 03.11). Deux familles de pages, deux traits, jamais les deux :
   A) PAGES DE CONFIG (`.config-page`) : le trait est celui de la SECTION
      (`border-top` de `.form-section`, espacé par margin-top/padding-top
      1.5rem) ; le filet de rangée y est SUPPRIMÉ (règle U2e/U2h plus bas,
      `border-bottom: 0`). Il ne reste donc qu'un trait, loin des champs.
   B) AUTRES PAGES DE FORMULAIRE (édition People, identité…) : le trait est
      celui de la RANGÉE (`border-bottom`), espacé de 8 px au-dessus ET en
      dessous (`--ui-gap-field`) ; la section n'en ajoute un QUE si elle ne
      porte aucune rangée (tableau, texte, chips) — sinon deux traits se
      peignaient à ~22-24 px l'un de l'autre. Ce trait de section est posé en
      BAS et non en haut, pour ne pas retomber sous le filet de la dernière
      rangée de la section précédente.
   Une seule couleur pour les deux : le jeton --ui-rule (mesuré avant :
   --divider pour la rangée contre --border pour la section, soit
   rgb(235,231,221) et rgb(38,35,29) à la MÊME frontière).
   Vérifié par scripts/qa-u2h-section-lines.cjs (0 paire < 30 px, 0 trait à
   moins de 8 px d'un champ, une seule couleur de filet). */
.page[data-density='socle']:not(.config-page) .form-section:has(.form-group, .form-field, .rc-form-row) {
  border-top: 0;
  border-bottom: 0;
}
.page[data-density='socle']:not(.config-page) .form-section:not(:has(.form-group, .form-field, .rc-form-row)) {
  border-top: 0;
  border-bottom: 1px solid var(--ui-rule);
  /* Le trait ne doit pas toucher le dernier contrôle de la section (un
     input sans libellé, un fichier) : 8 px d'air, même règle que les rangées. */
  padding-bottom: var(--ui-gap-field);
}
/* Le libellé est aligné À DROITE contre le contrôle (colonne de lecture). */
.page[data-density='socle'] .form-grid > .form-group > label,
.page[data-density='socle'] .form-grid > .form-field > label,
.page[data-density='socle'] .rc-field-grid > .form-row > label,
.page[data-density='socle'] :is(.form-group, .form-field):has(> label:not(.checkbox-label)) > label,
.page[data-density='socle'] .rc-form-row:has(> label) > label {
  text-align: right;
  justify-self: end;
  align-self: center;
  margin: 0;
  font-size: var(--font-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.25;
}
/* Un indice sous le champ (baseRoleHint…) reste dans la COLONNE du contrôle. */
.page[data-density='socle'] .form-grid > .form-group > small,
.page[data-density='socle'] .form-grid > .form-field > small,
.page[data-density='socle'] .rc-field-grid > .form-row > small,
.page[data-density='socle'] :is(.form-group, .form-field):has(> label:not(.checkbox-label)) > small,
.page[data-density='socle'] .rc-form-row:has(> label) > small {
  grid-column: 2;
  color: var(--text-dim);
}
/* =====================================================================
   U2e (2026-11-03) — LES PAGES DE CONFIG DU RIDER EMPILENT :
   libellé (phrase d'explication) AU-DESSUS, contrôle PLEINE LARGEUR dessous.

   POURQUOI une exception à la gouttière : sur `config/sound`,
   `config/hospitality`… le libellé n'est pas un mot court (« Name », « Diet »)
   mais une phrase (« Details about allergies », « Catering items (one per
   line) », « Monitor requirements »). Dans la gouttière de 118px il était
   écrasé / tronqué — l'utilisateur demande explicitement l'empilement qu'il
   avait avant U2. AILLEURS la gouttière reste la règle : les libellés y sont
   courts et l'alignement des contrôles est ce qui fait la densité.

   Spécificité : (0,5,1) — elle bat la règle de ligne universelle U2
   `.page[data-density='socle'] .rc-form-row:has(> label)` (0,3,1) sans
   dépendre de l'ordre des feuilles (`App.css` est chargée après `index.css`).
   Densité CONSERVÉE : padding de carte `--ui-pad`, écart `--ui-gap-y`, champ
   ~26px — seule la disposition change. Prouvé par
   `scripts/qa-u2e-titles-config.cjs` (EMPILÉ=true par rangée + non-régression
   `118px …` sur `/tour/venues/new`). */
.page.config-page[data-density='socle'] .rc-form-row:has(> label:not(.checkbox-label)),
.page.config-page[data-density='socle'] :is(.form-group, .form-field):has(> label:not(.checkbox-label)) {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  /* U2f — ESPACE SYMÉTRIQUE : le même écart au-dessus du contrôle (entre le
     libellé et le champ) et en dessous (dans la rangée). Mesuré avant :
     avant = 2px, après = 5px (4px de padding + le filet 1px). Le `- 1px` du
     padding bas, c'est le filet de la rangée : le vide visible sous le contrôle
     vaut donc EXACTEMENT --ui-gap-field. Le padding HAUT reste à 4px pour ne
     pas déplacer l'écart entre blocs (il est mesuré par le harnais). */
  row-gap: var(--ui-gap-field);
  column-gap: 0;
  min-height: 0;
  /* U2h — ICI, LA SEULE LIGNE EST CELLE DE LA SECTION. Retour utilisateur du
     03.11 : « dans les pages de config j'ai l'impression que tu as supprimé la
     mauvaise ligne » → le bon trait est celui qui A DE L'AIR AUTOUR (le
     `border-top` de `.form-section`, espacé par margin-top/padding-top 1.5rem),
     pas celui qui collait au champ. Le filet de rangée est donc SUPPRIMÉ dans
     les pages de config, et l'écart sous le contrôle reste `--ui-gap-field` (le
     `-1px` du filet n'a plus lieu d'être : sans trait, 8 px pleins). */
  padding: 4px 0 var(--ui-gap-field);
  border-bottom: 0;
  /* U2g — les rangées de config gardent leur rythme d'origine (l'écart entre
     blocs y est mesuré par scripts/qa-u2f-spacing.cjs) : pas de marge ajoutée. */
  margin: 0;
}
/* Le libellé reprend la ligne entière (ses boutons « Use example » /
   « Populate from » restent à droite via `.config-field-actions`) et se lit
   à GAUCHE : un libellé aligné à droite au-dessus de son champ se lit comme
   un sous-titre du champ précédent. */
.page.config-page[data-density='socle'] .rc-form-row:has(> label:not(.checkbox-label)) > label,
.page.config-page[data-density='socle'] :is(.form-group, .form-field):has(> label:not(.checkbox-label)) > label {
  text-align: left;
  justify-self: stretch;
  align-self: start;
}
/* Une seule colonne ⇒ un indice éventuel reste sous le contrôle (colonne 1). */
.page.config-page[data-density='socle'] .rc-form-row:has(> label:not(.checkbox-label)) > small,
.page.config-page[data-density='socle'] :is(.form-group, .form-field):has(> label:not(.checkbox-label)) > small {
  grid-column: 1;
}
/* Il n'y a plus de colonne de libellé à réserver : un champ SANS libellé
   (règle U2 « le h2 du bloc fait office de libellé ») ne doit pas démarrer
   126px à droite des champs empilés. */
.page.config-page[data-density='socle'] .form-section > :is(div, fieldset):has(> :is(input, select, textarea)):not(:has(> label)) {
  padding-left: 0;
}
/* U2f — `ProviderSelector` porte un margin NÉGATIF inline (`-4px 0 10px`) pour
   se tasser sous le libellé dans les blocs NON empilés. Dans une rangée de
   config, l'écart vient de la rangée : on neutralise (8px au-dessus / 8px en
   dessous, mesuré par `scripts/qa-u2f-spacing.cjs`). Le margin d'origine reste
   la valeur par défaut de `.provider-select` (aucune autre page ne change). */
.provider-select {
  margin: -4px 0 10px;
}
.page.config-page[data-density='socle'] .rc-form-row > .provider-select {
  margin: 0;
}
/* `.form-grid` = DEUX colonnes de largeur utile sur desktop (au lieu d'une
   colonne unique de cartes), une seule sous 720px. Deux colonnes et non
   « auto-fit » : chaque colonne porte SA position x, donc 2 positions de
   contrôle au total (une ligne pleine largeur retombe sur celle de la
   colonne 1) — c'est ce qui rend l'alignement mesurable.
   U2g — l'écart VERTICAL d'une grille de rangées est --ui-gap-field (8px), comme
   l'écart entre deux rangées hors grille : sinon la même page aurait 8px ici et
   6px là (mesuré à 390 sur l'éditeur de personne : rowGaps [6, 8]). */
.page[data-density='socle'] .form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--ui-gap-field) 24px;
}
/* U2 — un `.form-row` (groupe de 2-3 champs côte à côte, ex. monitoring) reçoit
   EXACTEMENT la même grille que `.form-grid` : c'est ce qui fait tomber son
   2ᵉ champ sur l'ancre de la 2ᵉ colonne de la page. Un 3ᵉ champ passe à la
   ligne suivante, colonne 1 — donc aucune position x nouvelle. */
.page[data-density='socle'] .form-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--ui-gap-field) 24px;
}
/* U2 — même chose pour le conteneur Roadcase `.rc-form-row` QUAND il groupe des
   champs (`> .form-group`). Un `.rc-form-row` qui porte LUI-MÊME son libellé
   reste une ligne de champ (règle `.rc-form-row:has(> label)` ci-dessus). */
.page[data-density='socle'] .rc-form-row:has(> :is(.form-group, .form-field)) {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--ui-gap-field) 24px;
  /* Le padding 8px de `.rc-form-row` (App.css) et son filet sont portés par les
     LIGNES de champ à l'intérieur : les garder ici décalerait toute la colonne
     de 8px par rapport aux `.form-grid` de la page (mesuré : 380 vs 388). */
  padding: 0;
  border-bottom: 0;
}
/* U2 — une rangée qui ne porte qu'UN champ (ex. « Name » de la fiche crew) le
   laisse pleine largeur : la forcer dans une demi-colonne rétrécirait un champ
   qui était large, sans rien aligner de plus. */
.page[data-density='socle'] :is(.form-row, .rc-form-row):has(> :is(.form-group, .form-field):only-child) {
  grid-template-columns: minmax(0, 1fr);
}
/* U2 — un champ SANS libellé (le titre `h2` du bloc sert de libellé, ex. Band
   Settings › Identity) démarre QUAND MÊME sur la colonne de contrôle : sinon la
   page a un axe par bloc (mesuré 270 px pour le nom du groupe, 396 px pour les
   champs libellés). Aucun libellé n'est inventé : on aligne, on n'ajoute rien. */
.page[data-density='socle'] .form-section > :is(div, fieldset):has(> :is(input, select, textarea)):not(:has(> label)) {
  padding-left: calc(var(--ui-label-w) + var(--ui-gap-x));
}
/* ≤720px : ce retrait mangerait la largeur d'un écran de téléphone (le libellé
   passe au-dessus, il n'y a plus de colonne à réserver). */
@media (max-width: 720px) {
  .page[data-density='socle'] .form-section > :is(div, fieldset):has(> :is(input, select, textarea)):not(:has(> label)) {
    padding-left: 0;
  }
}
/* Une ligne « case à cocher » n'a PAS de colonne de libellé (le libellé EST
   la case) : elle occupe la largeur entière, donc la case tombe toujours sur le
   bord gauche de la page — une seule position, jamais une par colonne.
   `grid-column: 1 / -1` neutralise aussi les `style={{display:'flex'}}` inline
   hérités des sous-éditeurs (une règle CSS ne bat pas un style inline, la
   réserve de colonne oui). */
.page[data-density='socle'] :is(.form-group, .form-field):has(> label.checkbox-label) {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: var(--ui-h-row);
  padding: 3px 0 var(--ui-gap-field);
  border-bottom: 1px solid var(--ui-rule);
  margin: 0;
}
/* U2b — BLOCS RÉPÉTEURS (Run of show, Distances, Contact persons) : ils suivent
   la GRILLE DE PAGE. Un bloc de rangées en <div> démarrait au bord de la carte
   (x269) alors que la colonne de contrôle de la page est à x395 : trois blocs,
   trois axes, et un day sheet à 7 positions x. Le bloc prend donc le retrait de
   la grille commune, et chaque rangée est une grille à pistes EXPLICITES — les
   mêmes pour toutes les rangées, donc les colonnes s'alignent verticalement
   comme dans un tableau, sans <table> (canon .rc-list/.rc-card de la refonte :
   on ne remplace pas une liste gérée par un tableau). */
/* Le retrait est calculé pour que le PREMIER CONTRÔLE tombe sur l'ancre de la
   grille (396 à 1440) : la rangée porte son propre cadre (padding 8px), d'où le
   -8px. Sans ça, le bloc décalait ses champs de 8px sous les champs de la page. */
.page[data-density='socle'] .rc-data-block {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--ui-gap-y);
  padding-left: calc(var(--ui-label-w) + var(--ui-gap-x) - 8px);
  min-width: 0;
}
.page[data-density='socle'] .rc-data-block > * { min-width: 0; }
/* Run of show — ↑ ↓ | From | To | Category | Activity | ＋ | × */
.page[data-density='socle'] .roadmap-list .rc-card-fields {
  display: grid;
  grid-template-columns: 30px 30px 96px 96px minmax(130px, 150px) minmax(140px, 1fr) 30px 30px;
  gap: 6px;
  align-items: center;
  min-width: 0;
}
/* La catégorie « Other… » ajoute un champ : il reste DANS la cellule Category,
   sinon il décalerait toutes les pistes suivantes de la rangée. */
.page[data-density='socle'] .roadmap-list .rc-cell-cat {
  display: flex;
  gap: 4px;
  align-items: center;
  min-width: 0;
}
.page[data-density='socle'] .roadmap-list .rc-cell-cat > * { min-width: 0; }
.page[data-density='socle'] .roadmap-list .rc-cell-cat > select { flex: 1 1 auto; }
.page[data-density='socle'] .roadmap-list .rc-cell-cat > input { flex: 1 1 90px; }
/* Deuxième rangée (responsable / téléphone / lieu) : mêmes pistes partout. */
.page[data-density='socle'] .roadmap-list [data-row-secondary] {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  align-items: center;
  min-width: 0;
}
/* Distances — From → To | Mode | Dist. | Durée | Notes | × */
.page[data-density='socle'] .distance-list > .rc-card {
  display: grid;
  grid-template-columns: minmax(100px, 1fr) 20px minmax(100px, 1fr) 92px 84px 100px minmax(110px, 1fr) 30px;
  gap: 6px;
  align-items: center;
  min-width: 0;
}
/* Contact persons — Role | Name | Phone | Email | Notes | × */
.page[data-density='socle'] .contact-rows > .contact-row {
  display: grid;
  grid-template-columns: 150px minmax(110px, 1fr) 150px minmax(130px, 1fr) minmax(100px, 1fr) 30px;
  gap: 6px;
  align-items: center;
  min-width: 0;
}
/* ≤720px : ces rangées repassent en pile (le retrait de libellé n'a plus de sens
   et une grille à 8 pistes n'entre pas dans 390px). */
@media (max-width: 720px) {
  .page[data-density='socle'] .rc-data-block { padding-left: 0; }
  .page[data-density='socle'] .roadmap-list .rc-card-fields,
  .page[data-density='socle'] .distance-list > .rc-card,
  .page[data-density='socle'] .contact-rows > .contact-row,
  .page[data-density='socle'] .roadmap-list [data-row-secondary] {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* Contrôles compacts : hauteur d'échelle, padding resserré, largeur nulle
   au minimum (sinon une option longue pousse la colonne). */
.page[data-density='socle'] .form-input,
.page[data-density='socle'] .form-group select,
.page[data-density='socle'] .form-group input,
.page[data-density='socle'] .form-field select,
.page[data-density='socle'] .form-field input,
.page[data-density='socle'] .form-row select,
.page[data-density='socle'] .form-row input {
  min-height: var(--ui-h-ctl);
  height: var(--ui-h-ctl);
  padding: 2px 8px;
  font-size: var(--font-md);
  min-width: 0;
  width: 100%;
}
.page[data-density='socle'] textarea,
.page[data-density='socle'] .auto-textarea {
  height: auto;
  min-height: calc(var(--ui-h-ctl) + 12px);
  padding: 4px 8px;
}
/* Un bouton/chip inline garde sa taille : il n'est pas un contrôle de saisie. */
.page[data-density='socle'] .rc-pill { height: auto; }

/* ---- 2. Tableau dense (.tbl-dense) ---------------------------------
   En-tête collant, ligne à --ui-h-row, colonnes numériques à droite en
   monospace tabulaire, contrôles inline à 21px, hover de ligne. AUCUN
   contrôle existant n'est remplacé : on ne change que la métrique.

   ⚠️ MÉDIA ÉCRAN SEULEMENT (lot U3). `.tbl-dense` est une densification
   d'INTERFACE : elle ne doit jamais atteindre l'IMPRESSION. `DaysheetViewer`
   alimente la day sheet lue ET la day sheet imprimée (Ctrl+P) — une hauteur
   de ligne forcée ou un en-tête collant y rognerait la sortie papier. Les
   règles sont donc sous `@media screen` : à l'impression le tableau garde
   sa métrique d'origine, sans exception à maintenir. */
@media screen {
  table.tbl-dense {
    border-collapse: collapse;
    font-size: var(--font-md);
    font-variant-numeric: tabular-nums;
  }
  table.tbl-dense thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    height: var(--ui-h-row);
    padding: 2px 8px;
    background: var(--bg-elevated);
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
  }
  table.tbl-dense tbody td {
    height: var(--ui-h-row);
    padding: 2px 8px;
    border-bottom: 1px solid var(--divider);
    vertical-align: middle;
  }
  /* Colonnes numériques : `data-num` posé sur le th ET le td (ou via `th.num`). */
  table.tbl-dense th[data-num],
  table.tbl-dense td[data-num],
  table.tbl-dense th.num,
  table.tbl-dense td.num {
    text-align: right;
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
  }
  /* Contrôles inline d'un tableau dense : 24px. U1 les avait à 21px ; le lot
     U3 impose un plancher de CIBLE CLIQUABLE de 24px (une ligne de 28px moins
     4px de respiration) — 21px passait sous la cible tactile. Aucun contrôle
     n'est remplacé ni masqué, seule la métrique change. */
  table.tbl-dense select,
  table.tbl-dense input:not([type='checkbox']):not([type='radio']),
  table.tbl-dense textarea {
    height: 24px;
    min-height: 24px;
    padding: 0 6px;
    font-size: var(--font-sm);
    background: var(--bg);
    color: var(--text);            /* jamais la couleur par défaut du navigateur */
    -webkit-text-fill-color: var(--text);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
  }
  table.tbl-dense input[type='checkbox'],
  table.tbl-dense input[type='radio'] {
    width: 14px;
    height: 14px;
    margin: 0;
  }
  /* CIBLES CLIQUABLES : densifier la LIGNE ne doit pas rétrécir le bouton.
     24px est le plancher (une ligne de 28px moins 4px de respiration) ; un
     bouton déjà plus haut garde sa hauteur naturelle — min-height ne rabote
     jamais. Aucun bouton n'est masqué ni remplacé. */
  table.tbl-dense :is(button, .btn, a.btn) { min-height: 24px; }
}
@media screen and (hover: hover) and (pointer: fine) {
  table.tbl-dense tbody tr:hover td { background: var(--surface-hover); }
}

/* En-tête collant EFFECTIF (lot U3). `position: sticky` ne colle que dans un
   ancêtre DÉFILANT : `.table-wrapper` porte `overflow-x: auto` (indispensable
   aux tableaux larges) et devient donc cet ancêtre — mais sans hauteur bornée
   il ne défile jamais verticalement, et le `<th>` ne collait pas (mesuré :
   Δ = 260 px sur un défilement de page de 260 px = aucune adhérence).
   On BORNE la hauteur du cadre : le tableau défile DANS son cadre et l'en-tête
   reste visible. Réservé à ≥ 721 px — sous 720 px le tableau est déjà une
   carte par ligne et un cadre défilant gênerait le geste. */
@media screen and (min-width: 721px) {
  .table-wrapper:has(> table.tbl-dense) {
    max-height: min(72vh, 680px);
    overflow: auto;
  }
}

/* ---- 3. Thème : <option> lisibles (les options ne suivent pas les tokens
   par défaut sur Windows/Linux : sans cette règle elles sortent noires sur
   fond sombre).) ---- */
option {
  background: var(--bg-elevated);
  color: var(--text);
}

/* ---- 4. Règles MOBILE (skill mobile-native) ------------------------
   Appliquées globalement : ce sont des tells « site web » sur téléphone. */
html {
  -webkit-tap-highlight-color: transparent;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior: none;
}
body { overscroll-behavior: none; }

/* iOS zoome dès qu'un champ fait moins de 16px — on corrige la CAUSE,
   jamais avec user-scalable=no. */
@media (pointer: coarse) {
  input, select, textarea { font-size: 16px; }
  table.tbl-dense select,
  table.tbl-dense input:not([type='checkbox']):not([type='radio']) { font-size: 16px; height: 28px; }
}

/* Contrôles = pas de sélection de texte, pas de callout, pas de délai de tap. */
button, a, [role='button'], .btn, .mtab, .rc-pill, .toggle-btn, .chip,
input[type='checkbox'], input[type='radio'], select {
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
}
/* Le TEXTE de contenu reste sélectionnable (jamais user-select:none sur body). */
input[type='text'], input[type='number'], input[type='email'], input[type='password'],
textarea, .form-input, .auto-textarea {
  -webkit-user-select: text;
  user-select: text;
}

/* ---- 5. ≤ 720px : le libellé passe AU-DESSUS du contrôle, et un tableau
   dense devient UNE CARTE PAR LIGNE (libellé de colonne à gauche via
   `data-l`, contrôle/valeur à droite) — aucune colonne perdue, aucun
   débordement horizontal. ÉCRAN SEULEMENT (U3) : sous un format papier
   étroit, un tableau imprimé doit rester un tableau. */
@media screen and (max-width: 720px) {
  .page[data-density='socle'] .form-grid > .form-group,
  .page[data-density='socle'] .form-grid > .form-field,
  .page[data-density='socle'] .rc-field-grid > .form-row,
  .page[data-density='socle'] :is(.form-group, .form-field):has(> label:not(.checkbox-label)),
  .page[data-density='socle'] .rc-form-row:has(> label) {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 2px;
    padding: 5px 0;
    min-height: 0;
  }
  .page[data-density='socle'] .form-grid > .form-group > label,
  .page[data-density='socle'] .form-grid > .form-field > label,
  .page[data-density='socle'] .rc-field-grid > .form-row > label,
  .page[data-density='socle'] :is(.form-group, .form-field):has(> label:not(.checkbox-label)) > label,
  .page[data-density='socle'] .rc-form-row:has(> label) > label {
    text-align: left;
    justify-self: start;
  }
  .page[data-density='socle'] .form-grid > .form-group > small,
  .page[data-density='socle'] .form-grid > .form-field > small,
  .page[data-density='socle'] .rc-field-grid > .form-row > small,
  .page[data-density='socle'] :is(.form-group, .form-field):has(> label:not(.checkbox-label)) > small,
  .page[data-density='socle'] .rc-form-row:has(> label) > small { grid-column: 1; }
  .page[data-density='socle'] .form-grid { grid-template-columns: minmax(0, 1fr); }
  .page[data-density='socle'] .form-row,
  .page[data-density='socle'] .rc-form-row:has(> :is(.form-group, .form-field)) { grid-template-columns: minmax(0, 1fr); }

  table.tbl-dense,
  table.tbl-dense tbody,
  table.tbl-dense tr,
  table.tbl-dense td { display: block; width: 100%; }
  table.tbl-dense thead { display: none; }
  table.tbl-dense tr {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--card);
    margin-bottom: var(--ui-gap-y);
    padding: 2px 8px;
  }
  table.tbl-dense tbody td {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    height: auto;
    min-height: var(--ui-h-row);
    padding: 3px 0;
    border-bottom: 1px solid var(--divider);
    text-align: right;
  }
  table.tbl-dense tbody tr td:last-child { border-bottom: 0; }
  table.tbl-dense tbody td::before {
    content: attr(data-l);
    flex: 0 0 auto;
    margin-right: auto;
    text-align: left;
    font-size: var(--font-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
  }
  table.tbl-dense tbody td:empty,
  table.tbl-dense tbody td[data-l='']:empty { display: none; }
}

/* =====================================================================
   U2i (2026-11-03) — CHAMP COURT = CELLULE DE RANGÉE GROUPÉE
   « dans la page general config, les champs des temps (show duration,
   installation, soundcheck, changeover, breakdown) prennent 1 ligne chacun.
   Possible de tout faire passer sur 1 ligne ? on ne fera jamais plus du 999
   minutes. » (user, 03.11)

   RÈGLE GÉNÉRALISABLE (cf. ui-densite-2026.md §17) : un contrôle dont la
   valeur tient en 2-3 chiffres n'a jamais besoin d'une rangée PLEINE LARGEUR —
   il devient une CELLULE d'une rangée groupée. La page DÉCLARE le groupe dans
   son schéma (`rowGroup: 'times'` dans GENERAL_LAYOUT_SECTIONS) et cette règle
   le rend ; aucune des cinq largeurs n'est codée en dur.

   Pourquoi `repeat(5, minmax(0, 1fr))` et non `minmax(160px, 1fr)` : à 768 px
   un plancher de 160 px déborde (5×160 + 4×16 = 864 px > zone de contenu). Le
   plancher est donc 0 : la cellule rétrécit, le libellé se replie, JAMAIS de
   débordement horizontal. La cible (~200 px par cellule ≈ 1/5 d'une rangée de
   1000 px) vient du `1fr`, pas d'une constante.
   Repli : 2 colonnes sous 768 px, 1 colonne sous 480 px.
   ===================================================================== */
.page.config-page[data-density='socle'] .config-times-row {
  display: grid;
  /* 5 cellules égales : la répartition demandée (≈200 px dans 1000 px). */
  grid-template-columns: repeat(5, minmax(0, 1fr));
  /* DEUX rangées PARTAGÉES (libellés / contrôles) : c'est ce qui garantit le
     MÊME `y` pour les cinq champs même quand un libellé se replie sur deux
     lignes (« Changeover Duration (minutes) » vs « Soundcheck »). Mesuré sans
     ces rangées partagées : deux valeurs de `y` à 24 px d'écart. */
  grid-template-rows: auto auto;
  column-gap: 16px;
  row-gap: var(--ui-gap-field);
  align-items: start;
  /* Même respiration que les rangées de champ empilées (U2f/U2h) : l'air sous
     le contrôle vaut --ui-gap-field, et AUCUN filet (en config le trait est
     celui de la SECTION, cf. §16). */
  padding: 4px 0 var(--ui-gap-field);
  margin: 0;
}
.page.config-page[data-density='socle'] .config-times-cell {
  display: grid;
  /* `subgrid` : la cellule EMPRUNTE les deux rangées de la rangée groupée —
     libellé en rangée 1, contrôle en rangée 2, pour les cinq cellules à la
     fois. Un navigateur sans subgrid retombe sur deux rangées locales (mise en
     page identique, alignement des champs non garanti) : aucune casse. */
  grid-template-rows: subgrid;
  grid-row: span 2;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  min-width: 0;
}
/* Libellé AU-DESSUS (règle des pages de config, §13.2) ; ses boutons
   (« Use example » / « Populate from ») restent DANS la cellule, TOUJOURS à
   droite du libellé (pas de repli du bouton) : c'est le TEXTE qui se replie
   dans sa colonne. Mesuré avant : un libellé sur deux lignes faisait descendre
   son bouton dans la rangée des champs, alors que les autres restaient en
   haut — cinq cellules lues comme cinq hauteurs. */
.page.config-page[data-density='socle'] .config-times-cell > .config-field-label {
  flex-wrap: nowrap;
  align-items: flex-start;
  gap: 2px 6px;
  min-width: 0;
}
.page.config-page[data-density='socle'] .config-times-cell > .config-field-label > span:first-child {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}
/* LE CONTRÔLE EST COURT : 90 px ; l'unité « min » est un SUFFIXE lisible à
   côté du champ, jamais dans la valeur. `max-width: 100%` + retour à la ligne
   de l'unité ⇒ aucun débordement quand la cellule descend sous ~120 px. */
.page.config-page[data-density='socle'] .config-times-ctl {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  min-width: 0;
}
.page.config-page[data-density='socle'] .config-times-ctl > input[type='number'] {
  width: 90px;
  max-width: 100%;
  min-width: 0;
  height: var(--ui-h-ctl);
}
.page.config-page[data-density='socle'] .config-times-unit {
  flex: 0 0 auto;
  color: var(--text-dim);
  font-size: var(--font-sm);
}
/* La note du groupe (Show Duration) reste sous la rangée, sur sa largeur. */
.page.config-page[data-density='socle'] .config-times-note {
  margin: var(--ui-gap-field) 0 0;
  font-size: 0.8rem;
}
/* U2i — EN-TÊTE de la rangée groupée. Même classe que les titres de
   sous-section (`.rc-section-title`) : une marche EN DESSOUS du titre de section
   de la page (h2 de config = 12,8 px), donc l'échelle reste décroissante — un
   `h4` nu à 13,5 px serait plus gros que le h2. Le `h4` garde sinon son margin
   de base du navigateur (1.33em ≈ 18 px au-dessus) : on le neutralise pour que
   la rangée respire comme les autres blocs (--ui-gap-y sous le titre). */
.page.config-page[data-density='socle'] .config-times-title {
  margin: 0 0 var(--ui-gap-y);
  color: var(--text-dim);
}
/* REPLI — 5 colonnes dès 768 px (seuil du brief), 2 sous 768, 1 sous 480. */
@media (max-width: 767px) {
  .page.config-page[data-density='socle'] .config-times-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 479px) {
  .page.config-page[data-density='socle'] .config-times-row {
    grid-template-columns: minmax(0, 1fr);
  }
}
/* ===== CSS Variables ===== */
/* NOTE: index.css is the single source of truth for the theme palette
   (dark :root + [data-theme='light']). This block only carries structural /
   legacy tokens that live here; color values are aligned to the Roadcase
   dark palette so shared names resolve consistently regardless of load order. */
:root {
  --bg: #141310;
  --surface: #211f1a;
  --accent: #e0a44c;
  --accent-hover: #ecb463;
  --text: #eae7dd;
  --text-muted: #948c7e;
  --border: #2e2c25;
  --border-light: #3a372e;
  /* U2h — jeton du trait de séparation des champs, IDENTIQUE à src/index.css
     (racine sombre ; la valeur claire vit dans :root[data-theme='light'] de
     index.css, plus spécifique). */
  --ui-rule: rgba(234, 231, 221, 0.20);
  --danger: #dd7a63;
  --danger-hover: #e88d78;
  --success: #84b06a;
  --success-hover: #90b879;
  --warning: #d99a3d;
  /* U1b — ink sur couleur pleine + jetons de chip/overlay, IDENTIQUES à
     src/index.css (les deux racines doivent rester alignées : App.css est chargé
     après, donc ses valeurs SOMBRES gagnent ; les surcharges claires vivent dans
     :root[data-theme='light'] de index.css, plus spécifique). */
  --on-danger: #141310;
  --on-success: #141310;
  --on-warning: #141310;
  --chip-bg: var(--surface);
  --chip-text: var(--text-dim);
  --overlay-text: #f2f2f2;
  /* P2a — kept IDENTICAL to src/index.css (roots must stay aligned): amber
     family extras + the legacy `--primary` alias (kills indigo fallbacks). */
  --accent-deep: #c88a2f;
  --on-accent: #141310;
  --accent-tint: rgba(224, 164, 76, 0.07);
  --accent-tint-strong: rgba(224, 164, 76, 0.12);
  --accent-line: rgba(224, 164, 76, 0.22);
  --primary: var(--accent);
  /* U1 — échelle de densité, IDENTIQUE à src/index.css (les deux racines
     doivent rester alignées : App.css est chargé après). */
  --ui-pad: 14px;
  --ui-gap-y: 6px;
  --ui-gap-x: 8px;
  --ui-gap-field: 8px; /* U2f — espace symétrique autour d'un contrôle (voir index.css) */
  --ui-h-ctl: 26px;
  --ui-h-btn: 28px; /* U2g — hauteur unique d'un élément cliquable (voir index.css) */
  --ui-h-row: 28px;
  --ui-label-w: 118px;
  --radius: 7px;
  --radius-sm: 4px;
  --radius-lg: 10px;
  --sidebar-width: 200px;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
  --shadow-lg: 0 8px 26px rgba(0, 0, 0, 0.45);
  --font: 'Inter', system-ui, -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', 'Fira Code', monospace;
  --transition: 150ms cubic-bezier(0.4, 0, 0.2, 1);
  accent-color: var(--accent);
}

/* ===== Reset & Base ===== */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  min-height: 100vh;
}

a {
  color: var(--accent);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

h1, h2, h3, h4, h5, h6 {
  font-weight: 600;
  color: var(--text);
  line-height: 1.3;
}

h1 { font-size: 1.75rem; margin-bottom: 0.5rem; }
h2 { font-size: 1.25rem; margin-bottom: 0.5rem; }
h3 { font-size: 1.1rem; margin-bottom: 0.25rem; }
/* U2e — un `h4` n'a pas de taille propre dans la feuille de base : il retombait
   sur le défaut du navigateur (1em = 15px ici), donc PLUS GROS que le titre de
   la carte qui le contient dès que celui-ci descend à 14px. On fixe la marche
   intermédiaire de l'échelle (page 16 · carte 14 · sous-carte 13,5 · section
   11,7) : la hiérarchie reste monotone décroissante, mesurée par
   `scripts/qa-u2e-titles-config.cjs`. Les `h4` qui portent leur propre classe
   de taille (`.daysheet-viewer-section-title`, `.ai-section-title`…) ne sont
   pas touchés : une classe bat un sélecteur de type. */
h4 { font-size: 13.5px; margin-bottom: 0.25rem; }

p { margin-bottom: 0.5rem; }

input, textarea, select, button {
  font-family: inherit;
  font-size: inherit;
}

/* ===== App Layout ===== */
.app-layout {
  display: flex;
  flex-direction: column;
  /* U1 — 100dvh : la coque suit la zone VISIBLE quand la barre d'URL se
     replie (100vh = la plus grande hauteur → un bouton collé en bas passe
     sous la barre du navigateur). */
  min-height: 100dvh;
}

/* New-version banner — appears when a deploy is detected and the auto-reload
   hasn't fired yet, so the user never has to hard-refresh every tab. */
.update-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 8px 16px;
  /* Was #1d4e89 (Backstage blue) — Roadcase: amber strip, themed text. */
  background: var(--accent-muted);
  color: var(--text);
  border-bottom: 1px solid var(--accent);
  font-size: 14px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}

/* Showcase (demo) banner — read-only sample-data notice for the demo account.
   Sits at the very top of every page, under the new-version banner. */
.showcase-banner {
  position: sticky;
  top: 0;
  z-index: 1500;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 8px 16px;
  /* Was purple stripes (#3a2b56/#443366) — Roadcase caution-tape in tokens. */
  background: repeating-linear-gradient(45deg, var(--accent-tint-strong), var(--accent-tint-strong) 12px, var(--surface) 12px, var(--surface) 24px);
  color: var(--text);
  font-size: 14px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}
.showcase-banner-badge {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 12px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--accent-muted);
  border: 1px solid var(--accent);
  color: var(--accent);
}

/* ===== P4a (2026-10-10) — the demo banner must not swallow the hamburger ====
   BUG (user, demo account, 390): `.showcase-banner` is `position: sticky;
   top: 0; z-index: 1500` while `.mobile-menu-btn` is `position: fixed;
   top: .75rem; z-index: 200` — the strip covers the CENTRE of the button
   (`document.elementFromPoint` at 390 returns the banner, or its badge, on
   every locale) so the menu cannot be opened any more.
   FIX (CSS only): the banner stays at the very top — sticky untouched — and
   the hamburger is OFFSET UNDER it, only while the banner is a direct child
   of `.app-layout` (App.tsx:370, `:has()`), so a normal account keeps
   `top: .75rem` untouched.
   MEASURED headless/dark over 320·360·375·390·414·430·479 in EN/FR/ES:
     96px worst case (ES at ≤390 and FR at ≤360 — the notice needs 2 lines)
     · 73.6px (EN at ≤360, FR at 375-430) · 41.2px (every locale from 479
     up, and EN from 375 up) — the notice is NEVER clipped (scrollHeight ==
     clientHeight). So: 100px (worst case, rounded UP, covers 320→479)
     below 480px, 44px from 480 to 900 — inside the 900px breakpoint where
     the hamburger exists at all (button top 11.25px + 44 = 55.25 > 41.2).
   `.update-banner` (fixed, z 2000, 45px measured at 390) is the same class
   of bug: same offset, declared FIRST so that when both strips are up the
   later showcase rule wins (button top 56px / 112px > 45px → still clear). */
.app-layout:has(> .update-banner) .mobile-menu-btn {
  top: calc(0.75rem + 48px);
}
@media (max-width: 900px) {
  .app-layout:has(> .showcase-banner) .mobile-menu-btn {
    top: calc(0.75rem + 44px);
  }
}
@media (max-width: 479px) {
  .app-layout:has(> .showcase-banner) .mobile-menu-btn {
    top: calc(0.75rem + 100px);
  }
}

/* ===== Sidebar (P2a Roadcase restyle) =====
   Reference: maquette 006-vision-atlas `.side` — mono uppercase section
   labels, compact 6px/9px links, amber-soft active state with a left amber
   rule. The collapse mechanism (`bandz.sidebar.section.<id>` + chevron) is
   untouched: only presentation changed. */
.sidebar {
  width: var(--sidebar-width);
  height: 100vh;
  /* Darker than the content panels so the amber-soft active state reads. */
  background: var(--bg-elevated);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: fixed;
  left: 0;
  top: 0;
  bottom: 0;
  z-index: 100;
  overflow-y: auto;
  transition: transform var(--transition), visibility var(--transition);
}

.sidebar-header {
  padding: 1.25rem 1rem 0.9rem;
  border-bottom: 1px solid var(--border);
}

/* ===== Bandz logo (inline SVG, LOGO T2) =====
   `BandzLogo` paints itself with the theme tokens so it re-tints with
   light/dark AND with the accent/text picked in ThemeToggle. The colours are
   declared here as real rules (not only as the paths' presentation
   attributes): CSS wins over those attributes, so this block is the palette
   contract, and `currentColor` on the two mount points keeps a visible
   fallback through the inherited text colour if a token ever fails to
   resolve. Never hardcode a hex and never filter the mark. */
svg[data-logo='bandz'] .bandz-logo-card,
svg[data-logo='bandz'] .bandz-logo-word {
  fill: var(--text, currentColor);
}
svg[data-logo='bandz'] .bandz-logo-lanyard {
  stroke: var(--accent, currentColor);
}
svg[data-logo='bandz'] .bandz-logo-accent {
  fill: var(--accent, currentColor);
}

/* Bandz brand logo at the top of the sidebar, above the band selector. */
.sidebar-brand-logo {
  display: block;
  width: 100%;
  max-width: 96px;
  height: auto;
  margin: 0 auto 0.9rem;
  /* Keep a local text colour so `currentColor` above never depends on a
     distant ancestor when the theme is overridden. */
  color: var(--text, inherit);
}

.sidebar-header h2 {
  font-size: 1.3rem;
  color: var(--accent);
  margin: 0;
}

.sidebar-subtitle {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin: 0.25rem 0 0;
}

.sidebar-nav {
  display: flex;
  flex-direction: column;
  padding: 0.25rem 0 0.75rem;
  /* No flex:1 — navs must only take their own content height so collapsed
     sections don't spread the remaining labels to the middle of the page.
     Content stays anchored at the top. */
}

/* A collapsible sidebar section: a styled divider + header, then the links. */
.sidebar-section {
  border-top: 1px solid var(--border);
}
.sidebar-section:first-of-type {
  border-top: none;
}

.nav-section-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 0.85rem 9px 0.3rem 11px;
  background: none;
  border: none;
  color: var(--text-muted);
  /* Mono, small, widely tracked uppercase — the Roadcase section label.
     11px floor (root is 15px, so rem rounding landed at 10.31px): functional
     label, not decoration. */
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color var(--transition);
}
.nav-section-label:hover {
  color: var(--text);
}

/* Section header label ellipsis: only the sidebar renders a <span> child
   (label + chevron); the layout editors use .nav-section-label as a plain
   span, so this child selector never affects them. */
.nav-section-label > span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-section-chevron {
  flex-shrink: 0;
  color: var(--text-muted);
  transition: transform var(--transition);
}
.nav-section-chevron.open {
  transform: rotate(180deg);
}

.nav-link {
  display: block;
  padding: 6px 9px;
  margin: 1px 0;
  color: var(--text-dim);
  text-decoration: none;
  font-size: 12.5px;
  font-family: var(--font);
  font-weight: 500;
  /* Robust ellipsis: the sidebar is now narrower, so long menu labels must
     never wrap to a second line or spill past the fixed sidebar width. The
     nav-links are single text nodes, so display:block makes text-overflow
     apply reliably (display:flex would clip without an ellipsis glyph). */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
  border-left: 2px solid transparent;
  border-radius: var(--radius-sm);
}

.nav-link:hover {
  background: var(--surface);
  text-decoration: none;
  color: var(--text);
}

/* Active = amber-soft fill + amber text + amber left rule (Roadcase; the
   Backstage indigo state is gone for good). */
.nav-link.active {
  background: var(--accent-muted);
  color: var(--accent);
  border-left-color: var(--accent);
  font-weight: 600;
}

/* Nav links with a label + subtitle (People / Musicians / Crew under the
   "People & Roles" section): stack the two lines vertically instead of the
   single-line ellipsis of a plain .nav-link. */
.nav-link-with-sub {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  gap: 1px;
}
.nav-link-label {
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.nav-link-subtitle {
  max-width: 100%;
  font-size: 0.72rem;
  font-weight: 400;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* U1 — sur l'item ACTIF la sidebar pose --accent-muted (ambre 15%) : le cran
   --text-muted n'y donne que 4.0:1 en thème sombre. Le cran --text-dim passe
   AA sur ce fond teinté, dans les deux thèmes. */
.nav-link.active .nav-link-subtitle {
  color: var(--text-dim);
}

/* ===== Main Content ===== */
.main-content {
  flex: 1;
  margin-left: var(--sidebar-width);
  padding: 2rem;
  max-width: 1200px;
  width: calc(100% - var(--sidebar-width));
}

/* ===== Footer ===== */
.app-footer {
  margin-left: var(--sidebar-width);
  padding: 0 2rem 2rem;
  max-width: 1200px;
  width: calc(100% - var(--sidebar-width));
  box-sizing: border-box;
}
.app-footer-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 14px 20px;
  border-top: 1px solid var(--border);
  border-radius: 0 0 var(--radius-xl, 12px) var(--radius-xl, 12px);
  background: linear-gradient(180deg, transparent, var(--accent-muted));
  color: var(--text-muted);
  font-size: 0.8rem;
}
.app-footer-brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.9rem;
}
.app-footer-logo {
  width: 22px;
  height: 22px;
  border-radius: 5px;
}
.app-footer-brand strong { color: var(--text); }
.app-footer-tagline { color: var(--text-muted); }
.app-footer-ver {
  font-family: var(--font-mono);
  color: var(--text-muted);
}
.app-footer-links {
  display: inline-flex;
  align-items: center;
  gap: 16px;
}
.app-footer-links a {
  color: var(--text-muted);
  text-decoration: none;
  transition: color 0.2s;
}
.app-footer-links a:hover {
  color: var(--accent);
}

/* ===== Page ===== */
.page {
  animation: fadeIn 0.2s ease;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

.page-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.page-header h1 {
  margin: 0;
}

/* ===== Buttons ===== */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 500;
  transition: all var(--transition);
  white-space: nowrap;
}

.btn:hover {
  background: var(--border);
  border-color: var(--border-light);
}

.btn:active {
  transform: scale(0.97);
}

.btn-primary {
  /* Same amber gradient as src/index.css (the two .btn-primary rules must not
     diverge: whichever CSS file loads last would win). */
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent-deep) 100%);
  color: var(--on-accent);
  border-color: var(--accent);
}

.btn-primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}

.btn-danger {
  background: transparent;
  color: var(--danger);
  border-color: var(--danger);
}

.btn-danger:hover {
  background: var(--danger);
  color: var(--on-danger);
}

.btn-small {
  padding: 0.3rem 0.6rem;
  font-size: 0.8rem;
}

.btn-large {
  padding: 0.75rem 1.5rem;
  font-size: 1rem;
}

.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: none;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: all var(--transition);
  font-size: 0.85rem;
}

.btn-icon:hover {
  background: var(--border);
  color: var(--text);
}

.btn-danger-icon {
  color: var(--danger);
}

.btn-danger-icon:hover {
  background: rgba(233, 69, 96, 0.15);
  color: var(--danger);
}

/* ===== Form Elements ===== */
.edit-form {
  max-width: 700px;
}

.form-group {
  margin-bottom: 1rem;
}

.form-group label {
  display: block;
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--text-muted);
  margin-bottom: 0.35rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.form-group input[type='text'],
.form-group input[type='number'],
.form-group textarea,
.form-group select {
  width: 100%;
  padding: 0.6rem 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font-size: 0.9rem;
  transition: border-color var(--transition);
}

.form-group input:focus,
.form-group textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-muted);
}

.form-group textarea {
  resize: vertical;
  min-height: 60px;
}

.form-group input::placeholder,
.form-group textarea::placeholder {
  color: var(--text-muted);
  opacity: 0.6;
}

.form-row {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}

.form-row .form-group {
  flex: 1;
  min-width: 150px;
}

/* Keep selects/inputs inside the flex row from overflowing on long options
   (e.g. "drum_hardware") — shrink below intrinsic content width. */
.form-row .form-group select,
.form-row .form-group input[type='number'],
.form-row .form-group input[type='text'] {
  width: 100%;
  min-width: 0;
}

/* U2h — une SECTION n'a le trait du haut QUE si elle ne porte aucune rangée de
   champ : sinon c'est le filet de la rangée qui porte la frontière, et deux
   traits se peignaient à ~24 px l'un de l'autre (défaut signalé par
   l'utilisateur). La règle qui retire le trait est dans index.css (portée
   `[data-density='socle']`, plus spécifique) car elle vise les pages migrées ;
   ici on tient le DÉFAUT, avec le jeton unique --ui-rule (même couleur que le
   filet de rangée). Une section qui n'a qu'un tableau/un texte garde donc sa
   frontière sans qu'aucune règle ne l'ajoute. */
.form-section {
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--ui-rule);
}

.form-section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

.form-section-header h2 {
  margin: 0;
}

.form-actions {
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
  display: flex;
  gap: 1rem;
  justify-content: flex-end;
}

.checkbox-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  font-size: 0.9rem;
}

.checkbox-label input[type='checkbox'] {
  accent-color: var(--accent);
  width: 16px;
  height: 16px;
}

.checkbox-group-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

/* Rider page: musicians/crew checkboxes flow inline, wrapping to the
   available width with a double-space gap between items. */
.musician-inline-list {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 1rem;
}

.musician-inline-list .musician-checkbox {
  width: auto;
}

.input-with-save {
  display: flex;
  gap: 0.5rem;
}

.input-with-save input {
  flex: 1;
}

/* ===== Toggle Group ===== */
.toggle-group {
  display: flex;
  gap: 0;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--border);
}

.toggle-btn {
  padding: 0.45rem 0.9rem;
  border: none;
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  font-size: 0.85rem;
  transition: all var(--transition);
  border-right: 1px solid var(--border);
}

.toggle-btn:last-child {
  border-right: none;
}

.toggle-btn:hover {
  background: var(--border);
  color: var(--text);
}

.toggle-btn.active {
  background: var(--accent);
  color: var(--on-accent);
}

/* ===== Instrument Editor ===== */
.instrument-editor {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem;
  margin-bottom: 0.75rem;
}

.instrument-editor-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 0.75rem;
  font-weight: 500;
  font-size: 0.9rem;
}

.instrument-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem;
}

.instrument-fields .form-group {
  margin-bottom: 0;
}

.instrument-fields .form-group:nth-child(5),
.instrument-fields .form-group:nth-child(6),
.instrument-fields .form-group:nth-child(7) {
  grid-column: 1 / -1;
}

/* ===== Musician List ===== */
.musician-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1rem;
}

/* Section label between base-role groups (main / session / guest) */
.musician-section-label {
  grid-column: 1 / -1;
  margin-top: 0.5rem;
  padding: 8px 12px;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--text-dim);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.musician-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  transition: all var(--transition);
  position: relative;
  cursor: default;
}

.musician-drag-handle {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  cursor: grab;
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-size: 1rem;
  line-height: 1;
  padding: 4px 6px;
  border-radius: 4px;
  user-select: none;
}

.musician-drag-handle:hover {
  background: var(--border);
  color: var(--text);
}

.musician-drag-handle:active {
  cursor: grabbing;
}

.musician-card:hover {
  border-color: var(--border-light);
  box-shadow: var(--shadow-md);
}

.musician-card.dragging {
  opacity: 0.5;
  border-color: var(--accent);
}

.musician-color-bar {
  height: 4px;
  width: 100%;
}

.musician-card-body {
  padding: 1rem;
}

.musician-card-body h3 {
  margin-bottom: 0.15rem;
  font-size: 1.05rem;
}

.musician-role {
  font-size: 0.85rem;
  color: var(--text-muted);
  margin-bottom: 0.5rem;
}

.musician-details {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-bottom: 0.5rem;
}

.instrument-count {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-bottom: 0.75rem;
}

.musician-card-actions {
  display: flex;
  gap: 0.5rem;
}

.empty-state {
  grid-column: 1 / -1;
  text-align: center;
  padding: 3rem 1rem;
  color: var(--text-muted);
}

.empty-hint {
  color: var(--text-muted);
  font-style: italic;
  font-size: 0.85rem;
  padding: 0.5rem 0;
}

/* ===== Conflict Banner ===== */
.conflict-banner {
  background: rgba(233, 69, 96, 0.1);
  border: 1px solid var(--danger);
  border-radius: var(--radius);
  padding: 0.75rem 1rem;
  margin-bottom: 1rem;
}

.conflict-banner strong {
  color: var(--danger);
  font-size: 0.9rem;
}

.conflict-banner ul {
  margin: 0.5rem 0 0;
  padding-left: 1.25rem;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.conflict-banner li {
  margin-bottom: 0.15rem;
}

/* ===== Modal ===== */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  animation: fadeIn 0.15s ease;
}

.modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.5rem;
  min-width: 320px;
  max-width: 90vw;
  box-shadow: var(--shadow-lg);
}

.modal h2 {
  margin-bottom: 0.5rem;
}

.modal p {
  color: var(--text-muted);
  margin-bottom: 1.25rem;
}

.modal-actions {
  display: flex;
  gap: 0.75rem;
  justify-content: flex-end;
}

/* ===== Rider Page ===== */
.rider-actions {
  display: flex;
  gap: 0.5rem;
}

.config-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.25rem;
  margin-top: 1.5rem;
}

.config-section {
  margin-bottom: 1.25rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--border);
}

.config-section:last-child {
  margin-bottom: 0;
  padding-bottom: 0;
  border-bottom: none;
}

.config-section h2 {
  font-size: 1rem;
  margin-bottom: 0.75rem;
}

.musician-checkbox {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  font-size: 0.9rem;
  padding: 0.3rem 0;
}

.musician-checkbox input[type='checkbox'] {
  accent-color: var(--accent);
}

.musician-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
}

.musician-role-tag {
  font-size: 0.75rem;
  /* U1b — --text-muted sur --border tombait à 4.2:1 en sombre : le chip porte
     désormais les jetons de chip (fond --surface, texte --text-dim, 6.4:1). */
  color: var(--chip-text);
  background: var(--chip-bg);
  padding: 1px 6px;
  border-radius: 10px;
  margin-left: 0.35rem;
}

/* ===== Rider Card (new) ===== */
.rider-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.25rem;
  margin-bottom: 1.5rem;
}

.rider-card-section {
  margin-bottom: 1rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--border);
}

.rider-card-section:last-child {
  margin-bottom: 0;
  padding-bottom: 0;
  border-bottom: none;
}

.rider-card-section h2 {
  font-size: 1rem;
  margin-bottom: 0.75rem;
}

/* ===== Rider read-only view (L2, 2026-10-12) =====
   L'écran LECTURE d'un `viewer` : aucune affordance de formulaire. Les valeurs sont du
   texte (transport), des listes (line-up) et des images (stage plot). */
.rider-readonly-value {
  margin: 0;
  font-size: 1rem;
}

.rider-readonly-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.rider-readonly-list li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.95rem;
}

.rider-readonly-thumb {
  cursor: default;
}

/* ===== Rider Preview (real-time PDF) ===== */
.rider-preview-container {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.25rem;
  margin-bottom: 1.5rem;
}

.rider-preview-container h2 {
  font-size: 1rem;
  margin-bottom: 0.75rem;
}

/* ===== Rider PDF Editor (admin WYSIWYG) ===== */
.rider-editor-scope {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
  flex-wrap: wrap;
}

.rider-editor-scope .toggle-group {
  display: flex;
  gap: 0.5rem;
}

.rider-editor-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: 1.5rem;
  align-items: start;
}

.rider-editor-panel {
  min-width: 0;
}

.rider-editor-panel .form-section {
  margin-bottom: 1.25rem;
}

/* P3d — the layout editors' section titles speak the same Roadcase language
   as `.config-page .form-section > h2` (P3c): mono, uppercase, tracked, dim.
   Presentation only — it never touches the section ORDER (useLayoutOrder) nor
   the drag/drop affordances. */
.rider-editor-panel .form-section h2,
.rider-editor-preview h2 {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 0.6rem;
}

.section-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border);
}

.section-row:last-child {
  border-bottom: none;
}

.section-row-reorder {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
}

.section-row-reorder .btn-small {
  padding: 0 0.4rem;
  line-height: 1;
}

.section-row-check {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  white-space: nowrap;
  font-size: 0.8rem;
}

/* Inside a .form-group (layout editors' Style panels), the checkbox hint can
   be long — let it WRAP instead of being clipped (user 2026-10-18: the Rider
   Layout editor's top panel read as a truncated blob). Scoped to .form-group
   so the section-row contract (nowrap) is untouched. */
.form-group .section-row-check {
  white-space: normal;
  align-items: flex-start;
}
.form-group .section-row-check input[type='checkbox'] {
  flex-shrink: 0;
  margin-top: 2px;
}
/* A .form-group that spans the WHOLE row of a .form-row grid — for the
   long-hint checkbox groups in the Style panel. */
.form-row .form-group--wide {
  flex: 1 1 100%;
  min-width: 0;
}

.section-row-title {
  flex: 1;
  min-width: 0;
}

/* Section card: control row + collapsible content details (mirrors the PDF). */
.section-card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 0.6rem;
  background: var(--surface);
  overflow: hidden;
}

.section-card > .section-row {
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface) 96%, var(--text) 4%);
}

.section-card-body {
  padding: 0.5rem 0.6rem 0.6rem 2.4rem;
  font-size: 0.85rem;
}

/* Per-section style override (Rider Layout editor): "Aa" toggle on the
   section row + the inline style block under it. */
.section-style-toggle {
  margin-left: auto;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.section-style-toggle-on {
  border-color: var(--accent);
  color: var(--accent);
}

.section-style-override {
  padding: 0.5rem 0.6rem 0.6rem 2.4rem;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface) 92%, var(--text) 8%);
  font-size: 0.85rem;
}

.section-style-override-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 0.4rem;
}

.section-style-override-title {
  font-weight: 600;
  font-size: 0.85rem;
}

.section-style-override-head .btn-small {
  margin-left: auto;
}

.section-style-override .form-group {
  min-width: 130px;
}

.section-style-override-input {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.section-style-override-input .form-input {
  min-width: 0;
}

.section-detail-list {
  margin: 0 0 0.4rem;
  padding-left: 1.1rem;
  color: var(--text-dim);
  display: grid;
  gap: 2px;
}

.section-detail-list li {
  line-height: 1.4;
}

.section-text-inline {
  margin-top: 0.4rem;
  max-width: 560px;
}

.section-text-inline .form-field-label {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-dim);
  display: block;
  margin-bottom: 2px;
}

/* The "Show tour name" checkbox lives in a .section-row-check (nowrap by
   default) — allow the long label to wrap instead of overflowing. */
.section-text-inline .section-row-check {
  white-space: normal;
  flex-wrap: wrap;
  cursor: pointer;
}

.section-card:has(> .section-row > .section-row-check input:not(:checked)) .section-detail-list {
  display: none;
}

/* Deep-link focus flash (2026-08-11): the Layout Editor links "edit" fields
   with ?focus=<fieldId>; the target element flashes to draw the eye.
   P1.5: the ring is amber (was indigo rgba(99,102,241)). */
.field-focus-flash {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 8px;
  animation: field-focus-pulse 1.8s ease;
}

@keyframes field-focus-pulse {
  0% { box-shadow: 0 0 0 4px var(--accent-glow); }
  70% { box-shadow: 0 0 0 8px transparent; }
  100% { box-shadow: 0 0 0 4px transparent; }
}

/* Field-level rows inside a section card. */
.field-list {
  margin: 0.4rem 0 0.2rem;
  border-top: 1px dashed var(--border);
  padding-top: 0.4rem;
}

.field-list-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 0.3rem;
}

.field-list-head .field-spacer-add,
.field-list-add .field-spacer-add {
  opacity: 0.8;
}

.field-list-head .field-spacer-add:hover,
.field-list-add .field-spacer-add:hover {
  opacity: 1;
}

.field-list-add {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 0.3rem;
}

.field-text-editor {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
  min-width: 0;
}

/* (Le champ texte n'a plus de barre de mise en page inline : gras/italique/
   taille/couleur/alignement passent par le bloc « Aa » de la ligne.) */

.field-row-text {
  background: color-mix(in srgb, var(--surface) 96%, var(--text) 4%);
  border-radius: 6px;
  padding: 2px 4px;
  align-items: flex-start;
}

.field-row-dragging {
  opacity: 0.45;
}

.field-row[draggable='true'] {
  cursor: grab;
}

.field-row[draggable='true']:active {
  cursor: grabbing;
}

.field-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.2rem 0;
  font-size: 0.85rem;
}

.field-row .section-row-reorder {
  flex-direction: row;
}

.field-row .section-row-reorder .btn-small {
  padding: 0 0.35rem;
  font-size: 0.75rem;
}

/* Per-FIELD style override (v0.558): the "Aa" button on every field row (right
   aligned, same affordance as the section rows) + the inline block that opens
   under THAT field. The block reuses the section block's layout; it lives in
   the field list, so its own left padding/underline are trimmed. */
.field-style-toggle {
  margin-left: auto;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.field-style-override {
  border-bottom: none;
  border-radius: 6px;
  margin: 0.15rem 0 0.35rem;
}

/* Per-COLUMN width control (v0.644): a small numeric field + ↺ on each column
   row of the table sections (input-list / output-list / rack-usage / backline).
   The ↺ clears the override (column back to its default width). */
.field-width-input {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin-left: 0.6rem;
}

.field-width-input .field-width-num {
  width: 62px;
  min-width: 0;
  padding: 0.15rem 0.3rem;
  font-size: 0.8rem;
  text-align: center;
}

/* Dedicated drag handle — only THIS grab-area starts a reorder drag, so the
   ↑/↓/✕ buttons inside the row keep receiving plain clicks. */
.field-drag-handle {
  cursor: grab;
  user-select: none;
  font-size: 0.8rem;
  letter-spacing: -2px;
  color: var(--text-dim);
  padding: 0 4px;
  border-radius: 4px;
}

.field-drag-handle:hover {
  background: color-mix(in srgb, var(--surface) 88%, var(--text) 12%);
  color: var(--text);
}

.field-drag-handle:active {
  cursor: grabbing;
}

.section-card-dragging {
  opacity: 0.45;
  outline: 2px dashed var(--accent);
  outline-offset: 2px;
}
.backline-row-dragging {
  opacity: 0.45;
  outline: 2px dashed var(--accent);
  outline-offset: 2px;
}

.field-row-spacer {
  background: color-mix(in srgb, var(--surface) 96%, var(--text) 4%);
  border-radius: 6px;
  padding: 2px 4px;
}

/* A field that has no value set (would emit nothing in the PDF) — shown with
   an unchecked box and a small "empty" tag so gaps are visible at a glance. */
.field-row-empty .field-label {
  opacity: 0.55;
}

.field-empty-hint {
  margin-left: auto;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-dim);
  background: color-mix(in srgb, var(--surface) 88%, var(--text) 12%);
  border-radius: 4px;
  padding: 1px 6px;
}

.field-row-spacer .field-spacer-size {
  width: 56px;
  padding: 1px 4px;
  font-size: 0.78rem;
}

.field-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.field-link {
  font-size: 0.78rem;
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap;
}

.field-link:hover {
  text-decoration: underline;
}

.rider-editor-preview {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.25rem;
  position: sticky;
  top: 1rem;
  /* Keep the preview pinned while the edit panel scrolls, without exceeding
     the viewport: cap its height and let it scroll internally. */
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
}

/* P3d: title typography comes from the shared mono/uppercase rule above. */
.rider-editor-preview h2 {
  margin-bottom: 0.9rem;
}

.preview-scope-badge {
  margin-left: 8px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-dim);
  background: color-mix(in srgb, var(--surface) 86%, var(--text) 14%);
  border-radius: 6px;
  padding: 2px 8px;
  vertical-align: middle;
}

.save-status-ok {
  color: var(--success);
  margin-left: 0.75rem;
  font-size: 0.9rem;
}

.save-status-err {
  color: var(--danger);
  margin-left: 0.75rem;
  font-size: 0.9rem;
}

@media (max-width: 1100px) {
  .rider-editor-grid {
    grid-template-columns: 1fr;
  }
  .rider-editor-preview {
    position: static;
    /* Single column: let the preview flow naturally below the edit panel,
       no sticky pin, no internal scroll cap. */
    max-height: none;
    overflow: visible;
  }
}

.rider-preview-iframe {
  width: 100%;
  height: 600px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: #fff;
}

.rider-preview-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 200px;
  background: var(--bg);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  color: var(--text-muted);
  font-size: 0.9rem;
  font-style: italic;
}

/* ===== Add Item Row ===== */
.add-item-row {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

.add-item-row input {
  flex: 1;
  padding: 0.5rem 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font-size: 0.9rem;
}

.add-item-row input:focus {
  outline: none;
  border-color: var(--accent);
}

/* ===== Item List ===== */
.item-list {
  list-style: none;
  padding: 0;
}

.item-list li {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.9rem;
}

.item-list li:last-child {
  border-bottom: none;
}

.item-list li:hover {
  background: rgba(255, 255, 255, 0.02);
}

.item-list .empty-hint {
  color: var(--text-muted);
  font-style: italic;
  font-size: 0.85rem;
}

/* ===== Config Page ===== */
/* Config pages match the shows page form width (ShowDetailPage uses
   max-width:1000) for uniform field widths across the site (2026-08-13). */
.config-page .edit-form {
  max-width: 1000px;
}

/* P3c — section titles follow the Roadcase header language (mono, uppercase,
   tracked, dim) so a config section reads like the rest of the app's pro-tool
   density. Scoped to `.config-page`: every other page keeps its own h2. */
.config-page .form-section > h2 {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* P3d — same language for a sub-heading that lives INSIDE a card (TechTab's
   "Backline providers" / "Roles for this show"). Reusable: any component may
   add `className="rc-section-title"`. */
.rc-section-title {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* ===== Mobile Menu Button ===== */
.mobile-menu-btn {
  display: none;
  position: fixed;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 200;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.5rem;
  cursor: pointer;
}

.hamburger {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 22px;
  height: 16px;
  justify-content: center;
}

.hamburger span {
  display: block;
  height: 2px;
  background: var(--text);
  border-radius: 2px;
  transition: all 0.3s ease;
}

.hamburger.open span:nth-child(1) {
  transform: rotate(45deg) translate(4px, 4px);
}

.hamburger.open span:nth-child(2) {
  opacity: 0;
}

.hamburger.open span:nth-child(3) {
  transform: rotate(-45deg) translate(4px, -4px);
}

.sidebar-overlay {
  display: none;
}

/* ===== Responsive: 900px ===== */
@media (max-width: 900px) {
  .mobile-menu-btn {
    display: block;
  }

  .sidebar {
    transform: translateX(-100%);
    visibility: hidden;
  }

  .sidebar.open {
    transform: translateX(0);
    visibility: visible;
  }

  .sidebar-overlay {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 99;
  }

  .main-content {
    margin-left: 0;
    width: 100%;
    padding: 1.5rem;
    padding-top: 3.5rem;
  }

  .musician-grid {
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  }

  .form-row {
    flex-direction: column;
  }

  .form-row .form-group {
    min-width: unset;
  }

  .instrument-fields {
    grid-template-columns: 1fr;
  }

  .rider-preview-iframe {
    height: 400px;
  }

  .app-footer {
    margin-left: 0;
    width: 100%;
    padding: 0 1.5rem 1.5rem;
    max-width: none;
  }

  .page-header {
    flex-direction: column;
    align-items: flex-start;
  }

  .rider-actions {
    width: 100%;
  }

  .rider-actions .btn {
    flex: 1;
    justify-content: center;
  }
}

/* ===== Responsive: 480px ===== */
@media (max-width: 480px) {
  .main-content {
    padding: 1rem;
    padding-top: 3rem;
  }

  h1 {
    font-size: 1.35rem;
  }

  .musician-grid {
    grid-template-columns: 1fr;
  }

  .modal {
    min-width: unset;
    width: calc(100% - 2rem);
    padding: 1.25rem;
  }

  .rider-preview-iframe {
    height: 350px;
    border-radius: var(--radius-sm);
  }

  .rider-preview-container {
    padding: 1rem;
  }

  .toggle-btn {
    padding: 0.35rem 0.6rem;
    font-size: 0.8rem;
  }

  .add-item-row {
    flex-direction: column;
  }

  .input-with-save {
    flex-direction: column;
  }

  .form-actions .btn-large {
    width: 100%;
    justify-content: center;
  }
}

/* ===== Utility ===== */
input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {
  opacity: 1;
}

::selection {
  background: var(--accent);
  color: var(--on-accent);
}

/* ===== Scrollbar ===== */
::-webkit-scrollbar {
  width: 8px;
}

::-webkit-scrollbar-track {
  background: var(--bg);
}

::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 4px;
}

::-webkit-scrollbar-thumb:hover {
  background: var(--border-light);
}

/* ===== Profile Selector ===== */
.profile-selector {
  position: relative;
  width: 100%;
  max-width: 200px;
}

.profile-selector-trigger {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.6rem 0.5rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  cursor: pointer;
  font-size: 0.85rem;
  font-weight: 500;
  transition: all var(--transition);
}

.profile-selector-trigger:hover {
  border-color: var(--border-light);
  background: var(--bg-elevated);
}

/* Row under the logo: band name + chevron. */
.profile-trigger-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  width: 100%;
}

/* Fixed-size logo slot. The band logo (or the band initial fallback) always
   renders inside THIS exact box, so switching bands never shifts the layout. */
.profile-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: var(--radius);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  overflow: hidden;
  flex-shrink: 0;
}

.profile-logo-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 4px;
  display: block;
}

.profile-logo .profile-avatar {
  width: 100%;
  height: 100%;
  border-radius: inherit;
  font-size: 1.35rem;
  background: var(--accent);
}

.profile-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 0.8rem;
  font-weight: 700;
  flex-shrink: 0;
}

.profile-avatar.small {
  width: 24px;
  height: 24px;
  font-size: 0.7rem;
  border-radius: 4px;
}

/* Fixed-size thumbnail in the dropdown list: logo image or initial. */
.profile-dropdown-thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 4px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  overflow: hidden;
  flex-shrink: 0;
}

.profile-dropdown-thumb-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 2px;
  display: block;
}

.profile-trigger-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
}

.profile-chevron {
  flex-shrink: 0;
  color: var(--text-muted);
  transition: transform var(--transition);
}

.profile-chevron.open {
  transform: rotate(180deg);
}

.profile-selector-dropdown {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  z-index: 200;
  overflow: hidden;
  animation: fadeIn 0.15s ease;
}

.profile-dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.6rem 0.75rem;
  border: none;
  background: transparent;
  color: var(--text);
  font-size: 0.85rem;
  text-align: left;
  cursor: pointer;
  transition: background var(--transition);
}

.profile-dropdown-item:hover {
  background: var(--border);
}

.profile-dropdown-item.active {
  background: var(--accent-muted);
}

.profile-dropdown-item.manage {
  color: var(--accent);
  font-weight: 500;
  gap: 0.6rem;
}

.profile-dropdown-info {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.profile-dropdown-name {
  font-weight: 500;
  font-size: 0.85rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.profile-dropdown-meta {
  font-size: 0.7rem;
  color: var(--text-muted);
}

.profile-check {
  flex-shrink: 0;
  color: var(--accent);
}

.profile-dropdown-divider {
  height: 1px;
  background: var(--border);
  margin: 4px 0;
}

/* ===== Profile Grid (List Page) ===== */
.profile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1rem;
}

.profile-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: all var(--transition);
}

.profile-card:hover {
  border-color: var(--border-light);
  box-shadow: var(--shadow-md);
}

.profile-card-image {
  width: 100%;
  height: 120px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface);
  padding: 8px;
  box-sizing: border-box;
  overflow: hidden;
}

.profile-card-image img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 6px;
}

.profile-card-image-placeholder {
  width: 100%;
  height: 120px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.5rem;
  font-weight: 700;
  color: var(--accent);
  background: linear-gradient(135deg, var(--bg) 0%, var(--surface) 100%);
}

.profile-card-body {
  padding: 1rem;
}

.profile-card-name {
  font-size: 1.1rem;
  font-weight: 600;
  margin-bottom: 0.25rem;
  color: var(--text);
}

.profile-card-meta {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-bottom: 0.75rem;
}

.profile-card-actions {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.profile-card-actions .btn {
  font-size: 0.8rem;
  padding: 0.35rem 0.7rem;
}

/* ===== Landing / Home page ===== */

.home-page {
  max-width: 900px;
  margin: 0 auto;
  padding: 2rem 1rem 4rem;
}

.home-hero {
  text-align: center;
  padding: 3rem 1rem 2.5rem;
}

/* P4a — the hero mark is the REAL T2 logo (inline `<BandzLogo/>`, theme-aware
   via `svg[data-logo='bandz']`), not the 🎵 emoji ("the old logo"). The class
   now sizes the SVG instead of a font: the `full` variant is portrait
   (viewBox 471×543 ≈ 0.867) so the HEIGHT drives it and the width follows.
   Same recipe as `.sidebar-brand-logo` / `.login-logo` (block + auto width +
   local text colour so `currentColor` never depends on a distant ancestor). */
.home-logo {
  /* Shown ONLY while the sidebar is collapsed to a hamburger (<=900px):
     on desktop the sidebar header already carries the logo, and showing it
     twice on the same screen reads as a duplicate. */
  display: none;
  width: auto;
  height: 120px;
  max-width: 100%;
  margin: 0 auto 0.75rem;
  color: var(--text, inherit);
}

@media (max-width: 900px) {
  .home-logo {
    display: block;
  }
}

@media (max-width: 480px) {
  .home-logo {
    height: 84px;
  }
}

/* Screen-reader-only heading (e.g. the Home h1 whose visible twin was dropped
   because the logo wordmark already carries the name). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.home-subtitle {
  color: var(--text-muted);
  font-size: 1rem;
  margin: 0;
}

.home-section-label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin: 0 0 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
}

.home-band-card {
  text-align: left;
  cursor: pointer;
  padding: 0;
  font: inherit;
  color: inherit;
  width: 100%;
}

.home-band-card:hover {
  transform: translateY(-2px);
}

.home-open-btn {
  pointer-events: none;
  margin-top: 0.25rem;
}

.home-bands .profile-card-info {
  padding: 1rem;
}

/* ===== Transport-Dependent Config UI ===== */

.page-header-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.toggle-group-sm .toggle-btn {
  padding: 0.3rem 0.6rem;
  font-size: 0.8rem;
}

.config-preset-badge {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.6rem;
  border-radius: var(--radius);
  font-size: 0.78rem;
  font-weight: 500;
  white-space: nowrap;
}

.badge-van {
  background: color-mix(in srgb, var(--danger) 15%, transparent);
  color: var(--danger);
  border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent);
}

.badge-plane {
  background: color-mix(in srgb, var(--info) 15%, transparent);
  color: var(--info);
  border: 1px solid color-mix(in srgb, var(--info) 30%, transparent);
}

.badge-info {
  /* U1b — était rgba(255,255,255,.06) (un blanc littéral, faux en thème clair) :
     la teinte claire rendait --text-muted à 4.31:1 en sombre. Le fond vient
     maintenant du jeton de chip (--surface) et le texte de --chip-text. */
  background: var(--chip-bg);
  color: var(--chip-text);
  border: 1px solid var(--border);
  font-size: 0.72rem;
}

.transport-icon {
  display: inline-flex;
  align-items: center;
  font-size: 0.9em;
  opacity: 0.8;
  margin-right: 0.2em;
}

.form-hint {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin-top: 0.3rem;
  line-height: 1.4;
}

/* ===== Login Page ===== */
.login-page {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
}

.login-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
}

/* Login-page logo (inline SVG — palette rules: see `svg[data-logo='bandz']`
   above). Height drives the size; the width follows the viewBox ratio. Still
   shared by the <img> logo of the signup / verify-email pages, so nothing
   image-specific is removed here. */
.login-logo {
  height: 110px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  border-radius: 8px;
  color: var(--text, inherit);
}

.login-demo-note {
  max-width: 340px;
  color: var(--text-muted);
  font-size: 0.8rem;
  text-align: center;
  line-height: 1.45;
  margin-top: 0.25rem;
}

.login-card {
  width: 340px;
  max-width: 90vw;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 2rem;
  box-shadow: var(--shadow-lg);
  text-align: center;
}

.login-card h1 {
  font-size: 1.6rem;
  margin-bottom: 0.25rem;
}

.login-subtitle {
  color: var(--text-muted);
  font-size: 0.85rem;
  margin-bottom: 1.5rem;
}

.login-card form {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  text-align: left;
}

.login-card label {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}

.login-card input {
  width: 100%;
  padding: 0.6rem 0.75rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font-size: 0.9rem;
}

.login-card input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-muted);
}

.login-btn {
  margin-top: 0.5rem;
  padding: 0.65rem;
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  border-radius: var(--radius);
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition);
}

.login-btn:hover {
  background: var(--accent-hover);
}

.login-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.login-error {
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  color: var(--danger);
  border: 1px solid color-mix(in srgb, var(--danger) 40%, transparent);
  border-radius: var(--radius);
  padding: 0.5rem 0.7rem;
  font-size: 0.82rem;
  text-align: center;
}

/* ===== User panel (sidebar footer) ===== */
.user-panel {
  margin-top: 0;
  border-top: none;
  border-bottom: 1px solid var(--border);
  padding: 0.6rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}

.user-info {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.user-name {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Page × level grid (2026-10-08): three states per family, the unavailable ones
   disabled — a greyed button with a title says WHY, a missing button says nothing. */
.access-levels {
  display: inline-flex;
  gap: 2px;
  /* Three buttons must never shrink or wrap: a squeezed control is what made the
     level selector overlap the labels (2026-10-08). */
  flex: 0 0 auto;
  white-space: nowrap;
}
.access-level {
  flex: 0 0 auto;
  min-width: 26px;
  text-align: center;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  border-radius: 4px;
  padding: 1px 6px;
  font-size: var(--font-sm);
  line-height: 1.5;
  cursor: pointer;
}
.access-level-on {
  background: rgba(116, 185, 255, 0.18);
  border-color: var(--info);
  color: var(--text);
}
.access-level:disabled { opacity: 0.35; cursor: not-allowed; }
.user-role {
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  padding: 0.15rem 0.45rem;
  border-radius: 999px;
  font-weight: 700;
}

.role-admin { background: rgba(0, 184, 148, 0.18); color: var(--success); }
.role-manager { background: rgba(253, 203, 110, 0.18); color: var(--warning); }
.role-read-only { background: rgba(136, 136, 170, 0.18); color: var(--text-muted); }
/* Band ROLES (2026-10-08) — the badge shows what the person IS in the active band,
   never the technical `users.role` ceiling ("read-only" confused a real user). */
.role-owner { background: rgba(0, 184, 148, 0.18); color: var(--success); }
.role-editor { background: rgba(116, 185, 255, 0.18); color: var(--info); }
.role-tech { background: rgba(253, 203, 110, 0.18); color: var(--warning); }
.role-viewer { background: rgba(136, 136, 170, 0.18); color: var(--text-muted); }
.role-superadmin { background: var(--accent-muted); color: var(--accent); }
.role-demo { background: rgba(136, 136, 170, 0.18); color: var(--text-muted); }

.logout-btn {
  padding: 0.4rem;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text-muted);
  font-size: 0.8rem;
  cursor: pointer;
  transition: all var(--transition);
}

.logout-btn:hover {
  background: var(--border);
  color: var(--text);
}

/* ===== Theme settings (toggle + accent color) ===== */
.theme-settings {
  display: flex;
  gap: 6px;
  flex: 1;
  min-width: 0;
}
.theme-toggle-btn {
  flex: 1;
  min-width: 0;
}
.language-toggle-btn {
  flex: 1;
  min-width: 0;
  font-size: 0.8rem;
}
.theme-settings-popover {
  position: fixed;
  z-index: 1000;
  width: 236px;
  padding: 0.75rem;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.theme-settings-heading {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.theme-settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}
.theme-settings-label {
  font-size: 0.85rem;
  color: var(--text);
}
.theme-mode-btn {
  padding: 0.3rem 0.7rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface-hover);
  color: var(--text);
  font-size: 0.8rem;
  cursor: pointer;
  transition: all var(--transition);
}
.theme-mode-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.accent-presets {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  flex-wrap: wrap;
}
.accent-swatch {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 2px solid var(--border);
  cursor: pointer;
  padding: 0;
  transition: transform var(--transition), border-color var(--transition), box-shadow var(--transition);
}
.accent-swatch:hover {
  transform: scale(1.12);
  border-color: var(--text-muted);
}
.accent-swatch.active {
  border-color: var(--text);
  box-shadow: 0 0 0 2px var(--accent-glow);
}
.accent-custom {
  position: relative;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  overflow: hidden;
  cursor: pointer;
  border: 2px dashed var(--border-light);
  background:
    conic-gradient(red, yellow, lime, aqua, blue, magenta, red);
}
.accent-custom input[type='color'] {
  position: absolute;
  inset: -8px;
  width: 40px;
  height: 40px;
  border: none;
  padding: 0;
  opacity: 0;
  cursor: pointer;
}
.accent-reset {
  align-self: flex-start;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 0.78rem;
  cursor: pointer;
  padding: 0.1rem 0;
  transition: color var(--transition);
}
.accent-reset:hover:not(:disabled) {
  color: var(--accent);
  text-decoration: underline;
}
.accent-reset:disabled {
  opacity: 0.5;
  cursor: default;
}
.theme-settings-default {
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 0.78rem;
  cursor: pointer;
  padding: 0.1rem 0.3rem;
  border-radius: var(--radius-sm);
  transition: color var(--transition);
}
.theme-settings-default:hover:not(:disabled) {
  color: var(--accent);
  text-decoration: underline;
}
.theme-settings-default:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ===== Users page ===== */
.page-pad {
  padding: 1rem;
}

.users-form {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  align-items: flex-end;
  margin-bottom: 2rem;
}

.users-form input,
.users-form select {
  padding: 0.5rem 0.7rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font-size: 0.85rem;
}

.users-list table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
}

.users-list th,
.users-list td {
  text-align: left;
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--border);
}

.users-list select {
  padding: 0.3rem 0.4rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
}

.users-list button {
  padding: 0.3rem 0.6rem;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  cursor: pointer;
  font-size: 0.78rem;
}

.users-list button:hover:not(:disabled) {
  background: var(--border);
}

.users-list button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Layout preset list (unified scope, v0.559): every preset is listed with a
   scope badge (Global / band name) whatever the mode being edited. */
.layout-preset-list {
  list-style: none;
  margin: 0.5rem 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.layout-preset-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 6px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
}

.layout-preset-name {
  font-weight: 600;
}

.layout-preset-badge.is-band {
  color: var(--accent);
}

.layout-preset-actions {
  margin-left: auto;
  display: flex;
  gap: 6px;
}

.layout-preset-rename {
  flex: 1;
  min-width: 160px;
}

/* ---- Login / sign-up shared bits (L3 self-service signup, 2026-09-24) ---- */
/* Ghost button: the "back" 2FA action + "Resend verification email". */
.login-btn-ghost {
  background: transparent;
  color: var(--text-dim);
  border: 1px solid var(--border);
  margin-top: 0;
}
.login-btn-ghost:hover {
  color: var(--text);
  border-color: var(--text-dim);
}
/* Resend block shown under the form when the server answers
   `email_not_verified` on login. */
.login-resend {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-top: 0.2rem;
  padding-top: 0.8rem;
  border-top: 1px dashed var(--border);
}
.login-resend label {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-muted);
}
.login-resend input {
  width: 100%;
  padding: 0.6rem 0.75rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font-size: 0.9rem;
}
/* Small helper line under a field (password policy, display-name hint). */
.signup-note {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.75rem;
  line-height: 1.4;
  text-align: left;
}
.signup-alt {
  margin: 1rem 0 0;
  font-size: 0.85rem;
  color: var(--text-muted);
}
.signup-alt a { color: var(--accent); }
.signup-ok {
  margin: 0 0 0.5rem;
  padding: 0.45rem 0.6rem;
  background: color-mix(in srgb, var(--success) 12%, transparent);
  border: 1px solid var(--success);
  border-radius: var(--radius);
  color: var(--success);
  font-size: 0.82rem;
  text-align: center;
}


/* =====================================================================
   P2a — shared page header (<PageHeader/>, src/components/PageHeader.tsx)
   Maquette pattern: mono uppercase tracked title, sub/meta at the left,
   actions at the right. Scoped with the `rc-` prefix so the 55 pages still
   on the legacy `.page-header` are untouched until P3.
   ===================================================================== */
.rc-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 20px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--divider);
}
/* Sticky variant (2026-10-18, user): on the transport-selector config pages,
   the title + transport selector stay pinned at the top while scrolling —
   same model as the show page's sticky tab bar (top:0, zIndex, page bg). */
.rc-header--sticky {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--bg);
  padding: 8px 0 14px;
  scroll-margin-top: 12px;
}
.rc-header-title {
  margin: 0;
  font-family: var(--font-mono);
  /* U2e — échelle des titres : 14px = titre de CARTE / de section (« DAY SHEET »,
     « 📧 Daysheet reminder »). Avant : 1.15rem (17,25px avec la racine à 15px),
     jugé trop grand par l'utilisateur. Le titre de PAGE garde la marche du
     dessus (16px, voir `h1.rc-header-title` juste après) et les sous-cartes
     sont à 13,5px (`h4`). `letter-spacing` reste en `em`, donc il suit. */
  font-size: 14px;
  line-height: 1.3;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text);
}
/* U2e — titre de PAGE (`.rc-header-title` sur un `h1` : PageHeader,
   ConfigPageHeader, StagePlotEditorPage) : 16px, un cran au-dessus des cartes. */
h1.rc-header-title {
  font-size: 16px;
}
.rc-header-sub {
  margin: 5px 0 0;
  max-width: 72ch;
  font-size: var(--font-sm);
  color: var(--text-dim);
}
.rc-header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* =====================================================================
   P2a — mobile bottom tab bar (visible ONLY ≤768px, media query, no JS).
   Desktop keeps the sidebar. ≤900px the sidebar is ALREADY an off-canvas
   drawer (hamburger + overlay) — so this bar becomes the primary mobile
   navigation and its `More` tab opens that SAME drawer: one source of nav
   truth (all sections, all permissions, collapse state), nothing duplicated.
   ===================================================================== */
.mobile-tabbar {
  display: none;
}

.mtab {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 3px 0;
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-decoration: none;
  font-family: var(--font-mono);
  font-size: 8.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.mtab:hover {
  text-decoration: none;
  color: var(--text-dim);
}
.mtab-ic {
  font-family: var(--font);
  font-size: 15px;
  line-height: 1;
  opacity: 0.55;
}
.mtab.on,
.mtab.on:hover {
  color: var(--accent);
}
.mtab.on .mtab-ic {
  opacity: 1;
}

/* Center FAB — amber gradient, lifts above the bar (maquette `.p-tab.fab`). */
.mtab-fab {
  flex: 0 0 auto;
  align-self: flex-start;
  width: 48px;
  height: 48px;
  margin-top: -26px;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent-deep) 100%);
  color: var(--on-accent);
  font-family: var(--font);
  font-size: 22px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 8px 22px var(--accent-glow);
  transition: transform var(--transition);
}
.mtab-fab:active {
  transform: scale(0.94);
}

@media (max-width: 768px) {
  .mobile-tabbar {
    display: flex;
    align-items: stretch;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    /* Below .sidebar-overlay (99) and .sidebar (100): opening the More
       drawer covers the bar instead of fighting it. */
    z-index: 90;
    background: var(--surface);
    border-top: 1px solid var(--border);
    padding: 6px 4px calc(8px + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -6px 18px rgba(0, 0, 0, 0.25);
  }

  /* The fixed bar must never hide the end of the page (main AND footer). */
  .main-content {
    padding-bottom: 68px;
  }
  .app-footer {
    padding-bottom: 68px;
  }

  .rc-header {
    flex-direction: column;
    align-items: flex-start;
  }
  .rc-header-actions {
    width: 100%;
  }
}


/* ==========================================================================
   P2b — command palette ⌘K (maquette 006 : .pal / .pal-box / .pal-in /
   .pal-list / .pal-g / .pal-i / .pal-f). Tokens only (P1 Roadcase) — the
   backdrop keeps the same convention as .modal-overlay (neutral black veil).
   ========================================================================== */
.pal {
  position: fixed;
  inset: 0;
  background: rgba(10, 9, 8, 0.72);
  backdrop-filter: blur(3px);
  display: none;
  align-items: flex-start;
  justify-content: center;
  padding-top: 14vh;
  /* Above .modal-overlay/.theme-settings-popover (1000) so the palette is the
     top-most interactive surface, below the informational banners (1500/2000). */
  z-index: 1100;
}

.pal.open {
  display: flex;
}

.pal-box {
  width: 560px;
  max-width: 92vw;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-lg);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-lg), 0 0 0 1px var(--accent-line);
  overflow: hidden;
  animation: pal-drop 0.16s ease-out;
}

@keyframes pal-drop {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pal-box {
    animation: none;
  }
}

.pal-in {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
}

.pal-caret {
  font-family: var(--font-mono);
  font-size: var(--font-lg);
  line-height: 1;
  color: var(--accent);
}

.pal-q {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  outline: none;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: var(--font-md);
}

.pal-q::placeholder {
  color: var(--text-muted);
}

.pal-esc {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-sm);
  padding: 2px 6px;
  color: var(--text-muted);
}

.pal-list {
  max-height: 320px;
  overflow-y: auto;
  padding: 6px;
}

.pal-g {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 8px 11px 4px;
}

/* A palette row is a <button>: reset the UA chrome, keep the mockup's rhythm. */
.pal-i {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 9px 11px;
  border: none;
  background: none;
  border-radius: var(--radius);
  font-family: var(--font);
  font-size: var(--font-sm);
  color: var(--text-dim);
  text-align: left;
  cursor: pointer;
}

.pal-i .ic {
  flex: 0 0 auto;
  width: 22px;
  text-align: center;
  font-family: var(--font-mono);
  color: var(--text-muted);
}

/* Long entity names (a venue, a show title) must ellipsize, never widen. */
.pal-t {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pal-i .hint {
  margin-left: auto;
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  color: var(--text-muted);
}

/* Selected = amber-soft fill + amber ink (the mockup's `--amber-soft`). */
.pal-i.sel,
.pal-i:hover {
  background: var(--accent-muted);
  color: var(--accent);
}

.pal-i.sel .ic,
.pal-i:hover .ic,
.pal-i.sel .hint,
.pal-i:hover .hint {
  color: var(--accent);
}

.pal-loading,
.pal-empty {
  padding: 10px 12px;
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  color: var(--text-muted);
}

.pal-f {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  padding: 9px 16px;
  border-top: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  color: var(--text-muted);
}

.pal-f-brand {
  margin-left: auto;
  color: var(--text-dim);
}

/* Sidebar entry point (bottom of the sidebar, above Help). It reuses the
   .nav-link rhythm via its own class — a <button> needs the flex reset. */
.sidebar-search {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  background: none;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  text-align: left;
}

.sidebar-search:hover,
.sidebar-search:focus-visible {
  background: var(--surface);
  color: var(--text);
}

.sidebar-search-ic {
  flex: 0 0 auto;
}

.sidebar-search-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sidebar-search-kbd {
  margin-left: auto;
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  color: var(--text-muted);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-sm);
  padding: 1px 5px;
}

@media (max-width: 768px) {
  .pal {
    padding-top: 8vh;
  }

  .pal-list {
    max-height: 52vh;
  }
}


/* =====================================================================
   P3a — "LIST pages" patron (2026-10-10). One stacked-card language for
   every list the product renders, so Venues / Tours (was a dense <table>)
   and the Setlists / Checklists / Musicians / Crew pickers read like the
   Shows list (P2f, `.show-card`) and the Atlas rows. Tokens only.
   A grid of vignettes that was already clean (Contacts / Musicians /
   Crew `.musician-grid`) keeps its grid — only its accents are tokenised.
   ===================================================================== */

/* The stack itself (`.shows-cards` language, one markup at every width). */
.rc-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* An item may carry an expandable panel under its card (tour budget). */
.rc-list-item {
  display: flex;
  flex-direction: column;
}
.rc-list-item > .rc-card {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
.rc-list-item > .rc-card:last-child {
  border-radius: var(--radius);
}
.rc-panel {
  border: 1px solid var(--border);
  border-top: 0;
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--bg-elevated);
  padding: 12px 14px;
}

.rc-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: border-color var(--transition), background var(--transition);
}
.rc-card.clickable {
  cursor: pointer;
}
.rc-card.clickable:hover {
  border-color: var(--accent);
}
.rc-card.clickable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* Selected row in a picker column (setlists / checklists). */
.rc-card.on {
  border-color: var(--accent);
  background: var(--accent-tint);
}

.rc-card-ic {
  flex: 0 0 auto;
  font-size: 1.1rem;
  line-height: 1;
  color: var(--text-dim);
}
/* Deterministic per-venue colour dot (data-derived, never a hex literal). */
.rc-card-dot {
  flex: 0 0 auto;
  width: 10px;
  height: 10px;
  border-radius: 3px;
}
.rc-card-body {
  flex: 1 1 auto;
  min-width: 0;
}
.rc-card-name {
  font-weight: 600;
  font-size: var(--font-md);
  line-height: 1.25;
  overflow-wrap: anywhere;
}
.rc-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 10px;
  min-width: 0;
  margin-top: 2px;
  font-size: var(--font-sm);
  color: var(--text-dim);
}
.rc-card-meta > span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rc-card-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  flex: 0 0 auto;
  flex-wrap: wrap;
}

/* Mono chip — count / capacity / statut (`.atlas-tag` language). */
.rc-chip {
  display: inline-block;
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 7px;
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  color: var(--text-dim);
  white-space: nowrap;
}

/* Filter pill (base-role filters on Musicians / Crew). */
.rc-pill {
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 4px 12px;
  font-size: var(--font-xs);
  line-height: 1.5;
  cursor: pointer;
  background: transparent;
  color: var(--text-dim);
  transition: color var(--transition), border-color var(--transition),
    background var(--transition);
}
.rc-pill:hover {
  color: var(--text);
  border-color: var(--border-light);
}
.rc-pill.on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}
.rc-pill.on:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: var(--on-accent);
}

/* Mobile: the SAME markup, wrapped — body first, actions on their own line. */
@media (max-width: 768px) {
  .rc-card {
    flex-wrap: wrap;
    row-gap: 8px;
  }
  .rc-card-body {
    flex: 1 1 60%;
  }
  .rc-card-actions {
    flex: 1 1 100%;
    justify-content: flex-start;
  }
}

/* P3a — mobile fix for the two-pane list pages (Setlists / Checklists):
   a grid item defaults to `min-width: auto`, so the editor's fixed-width
   song/task rows blew the 1fr column out to ~494px at 390 and dragged the
   list pane with it (content wider than the viewport, silently clipped).
   `min-width: 0` on the panes + on their inputs lets the SAME rows shrink;
   `.rc-form-row` lets them wrap instead of squeezing. */
.setlists-layout > * {
  min-width: 0;
}
.rc-form-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
  row-gap: 6px;
}
.rc-form-row .form-input {
  min-width: 0;
}

/* P3b — editor pages: a FIELD row holds label+input COLUMNS, so it STRETCHES
   (the inputs of one row share a baseline — `center` stays for the P3a control
   rows) and the group drops its own bottom margin: the row's padding + hairline
   carry the rhythm (Roadcase density). */
.form-row.rc-form-row {
  align-items: stretch;
}
.rc-form-row .form-group {
  margin-bottom: 0;
}

/* P3c — CONFIG pages: a field is a ROW. `.rc-form-row` is a flex row by
   default; here it stacks label over control (column + stretch) so the row's
   padding + hairline carry the vertical rhythm instead of the `.form-group`
   1rem margin (Roadcase density). Scoped to `.config-page` so the editor
   pages (P3b) that use `.form-row.rc-form-row` side-by-side keep their
   columns. `data-field-id` / deep-link targets are untouched. */
.config-page .form-group.rc-form-row {
  flex-direction: column;
  align-items: stretch;
  row-gap: 6px;
  margin-bottom: 0;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.config-page .form-group.rc-form-row > label {
  margin-bottom: 0;
}
.config-page .form-group.rc-form-row:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

/* P3b — the venue lookup dropdown: the app's own surface/border tokens instead
   of a hardcoded dark box (was #1c1c1c / #333 / #eee inline). The wrapper
   stays `position: relative` on the page. */
.rc-suggest {
  position: absolute;
  z-index: 20;
  top: 100%;
  left: 0;
  right: 0;
  max-height: 240px;
  overflow-y: auto;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.rc-suggest button {
  display: block;
  width: 100%;
  padding: 6px 8px;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font-size: var(--font-sm);
  text-align: left;
  cursor: pointer;
}
.rc-suggest button:hover,
.rc-suggest button:focus-visible {
  background: var(--surface-hover);
}

/* =====================================================================
   P4a — DAY tab (ItinerarySection / TransportSection / ShowTasksSection /
   ShowReminderSettings), 2026-10-10. Same tokens, ONE markup at every
   width. Additions, all on the P3a/P3d language:
   - `.rc-card-head`   : a card's own title row (title + actions). It is
     DELIBERATELY not `.rc-header`: that one marks the PAGE header
     (ShowDetailPage already wears exactly one) and "exactly one
     .rc-header per page" is an asserted contract of qa-roadcase-p3e.
   - `.rc-form-row.col`: a STACKED field row (label over control) — the
     in-card twin of `.config-page .form-group.rc-form-row`, needed
     because `.rc-form-row` alone is a centre-aligned control row and
     would shrink stacked inputs to their content width.
   - `.rc-card.col`    : an item card that stacks its control rows
     (roadmap step, transport leg, task row) instead of the P3a
     single-line row.
   - `.rc-card-fields` : a cluster of controls that WRAPS, so the
     fixed-width schedule inputs (2×96 time + 110 category + activity)
     stop forcing a 540px row at 390.
   - `.rc-field-grid`  : the day sheet's 2-column field grid, 1 column
     under 768px (inline grid styles removed: a media query cannot
     override an inline `grid-template-columns`).
   ===================================================================== */
.rc-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px 12px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}
.rc-card-head .rc-header-title {
  margin: 0;
}

.rc-form-row.col {
  flex-direction: column;
  align-items: stretch;
  row-gap: 6px;
  margin: 0;
  padding: 10px 0;
}

.rc-card.col {
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
}
.rc-card.col > * {
  min-width: 0;
}

.rc-card-fields {
  display: flex;
  align-items: center;
  gap: 6px 8px;
  flex-wrap: wrap;
  row-gap: 6px;
  min-width: 0;
}

.rc-field-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 20px;
  min-width: 0;
  margin-bottom: 16px;
}

@media (max-width: 768px) {
  .rc-field-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .rc-card-head {
    align-items: flex-start;
  }
}

/* =====================================================================
   U2g (2026-11-03) — UNE SEULE ÉCHELLE POUR LES ÉLÉMENTS CLIQUABLES

   Retour utilisateur sur la page People : « les champs et l'espace entre eux
   ne sont pas uniformes ». Mesuré (1440, page People) :
       .btn 35px · .btn-small 28px · .rc-pill 28px · .section-toggle 21,4px
       .tag-pill 27px (padding inline, aucune règle CSS)
   soit QUATRE hauteurs pour des éléments de même nature, sur le même écran.

   Règle : un élément cliquable = --ui-h-btn (28px). 28 ≥ la cible tactile de
   24 px (contrat U3 §11.3) et c'est la valeur de --ui-h-row : les contrôles de
   formulaire (26px) restent la seule autre échelle, volontairement plus basse
   (un champ n'est pas une cible de clic, il se remplit).

   ⚠️ Ce bloc vit dans App.css parce que ce fichier est chargé APRÈS index.css :
   à spécificité égale c'est lui qui gagne (les .btn des deux feuilles
   divergeaient déjà — voir la note de .btn-primary). Ne pas le remonter dans
   index.css sans re-vérifier l'ordre des feuilles.

   `.btn-large` garde sa proéminence (34px) : c'est une action d'écran vide
   (créer le premier stage plot), pas un bouton de barre d'outils.
   ===================================================================== */
.btn,
.btn-small,
.rc-pill,
.tag-pill,
.section-toggle,
.btn-icon {
  box-sizing: border-box;
  min-height: var(--ui-h-btn);
}

.btn {
  height: var(--ui-h-btn);
  padding: 0 14px;
}

.btn-small {
  height: var(--ui-h-btn);
  padding: 0 10px;
}

.btn-large {
  height: 34px;
  min-height: 34px;
  padding: 0 20px;
}

.btn-icon {
  width: var(--ui-h-btn);
  height: var(--ui-h-btn);
}

/* Pilules de filtre de la page People : la classe était posée dans le JSX mais
   n'avait AUCUNE règle CSS (la hauteur venait d'un padding inline → 27px). On
   garde le padding/l'arrondi inline, on ne fixe que la hauteur de l'échelle. */
.tag-pill {
  display: inline-flex;
  align-items: center;
  height: var(--ui-h-btn);
}

/* Repli de section (`<button class="section-toggle">` qui porte le h2) : 21,4px
   parce que la hauteur venait du texte. Une cible de clic a une hauteur. */
.section-toggle {
  height: var(--ui-h-btn);
}

/* Écart entre les cartes de la liste People : le `.card-stack` vaut 16px, le
   `.musician-grid` valait 1rem (15px, la racine est à 15px). Une seule valeur
   désormais : 16px — mesuré `next.top - prev.bottom` = 16 sur les deux
   conteneurs, à 1440 comme à 390. */
.musician-grid {
  gap: 16px;
}
/* ===== Stage Plot Editor ===== */

.stageplot-editor {
  display: flex;
  height: 100%;
  min-height: 500px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  position: relative;
}

/* ── Toolbar / Palette (Left) ── */

.stageplot-toolbar {
  width: 220px;
  min-width: 220px;
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.stageplot-toolbar-actions {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 8px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.stageplot-toolbar-actions .btn-icon {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  border-radius: var(--radius-sm);
  transition: all var(--transition);
  font-size: 1rem;
}

.stageplot-toolbar-actions .btn-icon:hover:not(:disabled) {
  background: var(--surface-hover);
  color: var(--text);
}

.stageplot-toolbar-actions .btn-icon:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

.stageplot-toolbar-actions .btn-icon.active {
  color: var(--accent);
  background: var(--accent-muted);
}

.stageplot-toolbar-actions .btn-danger-icon {
  color: var(--danger);
}

.stageplot-toolbar-actions .btn-danger-icon:hover:not(:disabled) {
  background: color-mix(in srgb, var(--danger) 15%, transparent);
}

.stageplot-toolbar-divider {
  width: 1px;
  height: 20px;
  background: var(--border);
  margin: 0 4px;
}

.stageplot-toolbar-search {
  padding: 8px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.stageplot-toolbar-search input {
  width: 100%;
  padding: 6px 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 0.8rem;
}

.stageplot-toolbar-search input:focus {
  outline: none;
  border-color: var(--accent);
}

.stageplot-toolbar-categories {
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  max-height: 120px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.stageplot-category-tab {
  padding: 6px 12px;
  background: transparent;
  border: none;
  color: var(--text-dim);
  cursor: pointer;
  font-size: 0.8rem;
  text-align: left;
  transition: all var(--transition);
  border-left: 3px solid transparent;
}

.stageplot-category-tab:hover {
  background: var(--surface-hover);
  color: var(--text);
}

.stageplot-category-tab.active {
  background: var(--accent-muted);
  color: var(--accent);
  border-left-color: var(--accent);
  font-weight: 600;
}

.stageplot-toolbar-items {
  flex: 1;
  overflow-y: auto;
  padding: 4px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px;
  align-content: start;
}

.stageplot-palette-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  cursor: grab;
  border-radius: var(--radius-sm);
  transition: background var(--transition);
  user-select: none;
}

.stageplot-palette-item:hover {
  background: var(--surface-hover);
}

.stageplot-palette-item:active {
  cursor: grabbing;
  background: var(--surface-active);
}

.stageplot-palette-icon {
  font-size: 1.3rem;
  width: 28px;
  text-align: center;
  flex-shrink: 0;
  line-height: 1;
}

.stageplot-palette-label {
  font-size: 0.78rem;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.stageplot-palette-empty {
  padding: 16px;
  text-align: center;
  color: var(--text-muted);
  font-size: 0.8rem;
}

/* ── Canvas (Center) ── */

.stageplot-canvas-container {
  flex: 1;
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(ellipse at center, var(--surface) 0%, var(--bg) 100%);
}

.stageplot-canvas-container canvas {
  display: block;
}

/* ── Properties Sidebar (Right) ── */

.stageplot-properties {
  width: 260px;
  min-width: 260px;
  background: var(--surface);
  border-left: 1px solid var(--border);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.stageplot-properties-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.stageplot-properties-header h3 {
  margin: 0;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--text);
}

.stageplot-properties-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1;
  padding: 24px;
}

.stageplot-properties-empty p {
  color: var(--text-muted);
  font-size: 0.85rem;
  text-align: center;
  line-height: 1.5;
}

.stageplot-property-section {
  padding: 12px;
  border-bottom: 1px solid var(--border);
}

.stageplot-property-section h4 {
  margin: 0 0 8px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

.stageplot-property-section .form-field {
  margin-bottom: 8px;
}

.stageplot-property-section .form-field:last-child {
  margin-bottom: 0;
}

.stageplot-property-section .form-field label {
  font-size: 0.72rem;
  color: var(--text-muted);
  margin-bottom: 2px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.stageplot-property-section .form-field input[type="text"],
.stageplot-property-section .form-field input[type="number"],
.stageplot-property-section .form-field select {
  width: 100%;
  padding: 6px 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 0.82rem;
  transition: border-color var(--transition);
}

.stageplot-property-section .form-field input:focus,
.stageplot-property-section .form-field select:focus {
  outline: none;
  border-color: var(--accent);
}

.stageplot-property-section .form-field input[type="checkbox"] {
  accent-color: var(--accent);
}

.stageplot-property-row {
  display: flex;
  gap: 8px;
  margin-bottom: 8px;
}

.stageplot-property-row .form-field {
  flex: 1;
  margin-bottom: 0;
}

.stageplot-property-row .form-field input {
  width: 100%;
}

.stageplot-property-badge {
  display: inline-block;
  padding: 2px 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-muted);
}

.stageplot-properties .checkbox-label {
  font-size: 0.82rem;
  color: var(--text-dim);
  margin-top: 4px;
}

/* ── Responsive ── */

@media (max-width: 900px) {
  .stageplot-editor {
    flex-direction: column;
  }

  .stageplot-toolbar {
    width: 100%;
    min-width: 100%;
    max-height: 200px;
    border-right: none;
    border-bottom: 1px solid var(--border);
  }

  .stageplot-toolbar-categories {
    flex-direction: row;
    max-height: none;
    overflow-x: auto;
    padding: 4px;
  }

  .stageplot-category-tab {
    white-space: nowrap;
    padding: 4px 10px;
    border-left: none;
    border-bottom: 2px solid transparent;
  }

  .stageplot-category-tab.active {
    border-left-color: transparent;
    border-bottom-color: var(--accent);
  }

  .stageplot-toolbar-items {
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    max-height: 100px;
  }

  .stageplot-properties {
    width: 100%;
    min-width: 100%;
    max-height: 200px;
    border-left: none;
    border-top: 1px solid var(--border);
  }
}

/* ── Toolbar: stage size + colour + zoom ── */

.stageplot-toolbar-size,
.stageplot-toolbar-color {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.stageplot-toolbar-size label,
.stageplot-toolbar-color label {
  display: block;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  margin-bottom: 4px;
}

.stage-size-row {
  display: flex;
  align-items: center;
  gap: 6px;
}

.stage-size-row input {
  width: 100%;
  padding: 4px 6px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 0.8rem;
}

.stage-size-row span {
  color: var(--text-dim);
}

.swatch-row {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 6px;
}

.swatch {
  width: 20px;
  height: 20px;
  border-radius: 4px;
  border: 2px solid transparent;
  cursor: pointer;
  padding: 0;
  transition: transform var(--transition);
}

.swatch:hover {
  transform: scale(1.12);
}

.swatch.active {
  border-color: var(--text);
  box-shadow: 0 0 0 1px var(--surface);
}

.color-input {
  width: 100%;
  height: 28px;
  padding: 2px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

/* ── Canvas viewport / stage / elements ── */

.stageplot-canvas-viewport {
  flex: 1;
  min-width: 0;
}

.stageplot-canvas-wrap {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

.stageplot-zoom {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  flex-shrink: 0;
  font-size: 0.8rem;
  color: var(--text-dim);
}

.stageplot-zoom .btn-icon {
  width: 26px;
  height: 26px;
  border: 1px solid var(--border);
  background: var(--bg);
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--text);
}

.stageplot-zoom .stageplot-dim-label {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 0.72rem;
}

.stageplot-element {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  user-select: none;
  touch-action: none;
}

/* Keep the editable instrument name outside the icon/image box. */
.stageplot-element-graphic {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}

/* ── Canvas CONTENT (P3d exemption) ────────────────────────────────────────
   Everything drawn ONTO the stage sheet is document content, not UI chrome:
   the sheet is a white page (it exports to PNG/PDF on white), so its labels
   (#444 / #222), the translucent name input, the white handle ring and the
   drag handles keep their on-paper colours. The chrome AROUND the canvas
   (toolbar, panels, buttons, modal) is fully tokenized in this same file. */
.stageplot-element-label {
  font-size: 10px;
  line-height: 1.1;
  color: #444;
  text-align: center;
  pointer-events: none;
  margin-top: 2px;
  /* Let the label overflow the (narrow) icon width so the full name is
     readable under the image — a 10px label is wider than most icons. */
  max-width: 180px;
  overflow: visible;
  white-space: nowrap;
  /* ⚠️ flex-shrink:0 est CRITIQUE : le parent .stageplot-element a une
     hauteur fixe (el.height × STAGE_SCALE) et le graphic prend 100% de
     cette hauteur (flex:0 0 auto) → sans ça, le label est rétréci à 0px
     par le flex container et devient invisible dans le canvas. */
  flex-shrink: 0;
}

.stageplot-element-name-input {
  width: 100%;
  max-width: 100%;
  min-width: 0;
  margin-top: 3px;
  padding: 2px 4px;
  font-size: 10px;
  line-height: 1.2;
  text-align: center;
  color: #222;
  background: rgba(255, 255, 255, 0.92);
  border: 1px solid var(--border);
  border-radius: 4px;
  box-sizing: border-box;
  cursor: text;
  white-space: nowrap;
  flex-shrink: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.stageplot-element-name-input:focus {
  outline: 1.5px solid var(--accent);
  outline-offset: 1px;
}

.stageplot-element.selected {
  outline: 1.5px dashed var(--accent);
  outline-offset: 2px;
}

.stageplot-handle {
  position: absolute;
  width: 12px;
  height: 12px;
  background: var(--accent);
  border: 1.5px solid #fff;
  border-radius: 50%;
  z-index: 5;
}

.stageplot-handle.resize {
  right: -6px;
  bottom: -6px;
  cursor: nwse-resize;
}

.stageplot-handle.rotate {
  top: -16px;
  left: 50%;
  transform: translateX(-50%);
  cursor: grab;
  background: var(--text-dim);
}

.stageplot-palette-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  flex-shrink: 0;
}

/* ── Properties sidebar swatch reuse ── */
.stageplot-properties .swatch-row {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 6px;
}

.stageplot-properties .swatch {
  width: 22px;
  height: 22px;
  border-radius: 4px;
  border: 2px solid transparent;
  cursor: pointer;
  padding: 0;
}

.stageplot-properties .swatch.active {
  border-color: var(--text);
}

.stageplot-properties .color-input {
  width: 100%;
  height: 28px;
  padding: 2px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.stageplot-properties .stageplot-property-section h4 {
  margin: 0 0 8px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

/* ── Drum Kit editor modal ── */
.stageplot-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.stageplot-modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  width: min(720px, 92vw);
  max-height: 88vh;
  overflow: auto;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
}

.stageplot-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.stageplot-modal-header h3 {
  margin: 0;
  font-size: 1rem;
}

.modal-header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.modal-header-actions .btn-primary {
  height: 28px;
  padding: 0 14px;
  font-size: 0.85rem;
  line-height: 1;
}

.drumkit-body {
  display: flex;
  gap: 20px;
  padding: 16px;
  flex-wrap: wrap;
}

.drumkit-preview {
  flex: 1 1 240px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 16px;
}

.drumkit-preview svg {
  max-width: 100%;
  height: auto;
}

.drumkit-summary {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--text);
  letter-spacing: 0.04em;
}

.drumkit-hand-note {
  font-size: 0.72rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.drumkit-controls {
  flex: 1 1 320px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.drumkit-controls section h4 {
  margin: 0 0 8px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

.drumkit-hand-row,
.drumkit-presets {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.btn-toggle,
.btn-chip {
  padding: 6px 12px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.8rem;
  transition: all var(--transition);
}

.btn-toggle.active,
.btn-chip:hover {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--on-accent);
}

.drumkit-pieces {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px 16px;
}

.drumkit-piece {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.drumkit-piece label {
  font-size: 0.82rem;
  color: var(--text);
  flex: 1;
}

.stepper {
  display: flex;
  align-items: center;
  gap: 6px;
}

.stepper span {
  min-width: 18px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.82rem;
}

.stepper .btn-icon {
  width: 24px;
  height: 24px;
  border: 1px solid var(--border);
  background: var(--bg);
  border-radius: var(--radius-sm);
  cursor: pointer;
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  line-height: 1;
}

/* ── Alignment guides (symmetry / edge snapping) ── */
.stageplot-guide {
  z-index: 5;
  pointer-events: none;
}

/* ── Riser editor (uses site design tokens) ── */
.dk-preview {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 16px;
  margin: 16px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.dk-preview svg {
  max-width: 100%;
  height: auto;
}

.dk-summary {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--text);
  letter-spacing: 0.04em;
}

.dk-section {
  margin: 0 16px 18px;
}

.dk-section h4 {
  margin: 0 0 8px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

.dk-section > .btn {
  margin-right: 8px;
}

.dk-checkbox {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.86rem;
  color: var(--text);
  cursor: pointer;
}

.dk-checkbox input {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  cursor: pointer;
}

.dk-steppers {
  display: flex;
  align-items: center;
  gap: 10px;
}

.dk-steppers span {
  min-width: 22px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.9rem;
  color: var(--text);
}

.dk-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}

.dk-riser-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.dk-riser-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.dk-riser-idx {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--text-muted);
  padding-top: 6px;
}

.layering-actions {
  display: flex;
  gap: 6px;
}

.layering-actions .btn-icon {
  flex: 1;
  font-size: 1rem;
}
/* Stage Plot Editor Page Styles */

/* ── List mode ────────────────────────────── */

.stageplot-list-page .page-subtitle {
  font-size: 0.85rem;
  color: var(--text-muted);
  margin: 0;
}

.stageplot-loading,
.stageplot-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 64px 24px;
  color: var(--text-dim);
  font-size: 1rem;
}

.stageplot-error {
  color: var(--danger);
}

.stageplot-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 80px 24px;
  text-align: center;
}

.stageplot-empty-icon {
  font-size: 3.5rem;
  margin-bottom: 8px;
  opacity: 0.6;
  filter: grayscale(0.3);
}

.stageplot-empty h2 {
  font-size: 1.5rem;
  color: var(--text);
  margin: 0;
}

.stageplot-empty p {
  max-width: 420px;
  color: var(--text-dim);
  line-height: 1.6;
  margin: 0;
}

/* ── Card grid ────────────────────────────── */

.stageplot-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
}

.stageplot-card.card {
  display: flex;
  flex-direction: column;
  transition: all var(--transition);
}

.stageplot-card:hover {
  border-color: var(--border-light);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.stageplot-card .card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
  padding-bottom: 8px;
}

.stageplot-card .card-title {
  font-size: 1rem;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}


.stageplot-kind-badge {
  font-size: 0.7rem;
  background: var(--accent);
  color: var(--on-accent);
  padding: 2px 7px;
  border-radius: 999px;
  margin-left: 6px;
  white-space: nowrap;
}

.stageplot-card-info {
  display: flex;
  gap: 16px;
  font-size: 0.8rem;
  color: var(--text-dim);
  margin-bottom: 12px;
}

.stageplot-thumb {
  width: 100%;
  margin: 6px 0;
  border-radius: 6px;
  overflow: hidden;
  /* Document surface: the stage plot is a WHITE sheet (same paper as the
     PDF/PNG export) — this is content, not chrome, and stays white. */
  background: #fff;
  border: 1px solid var(--border-light);
}

.stageplot-thumb-inner svg {
  display: block;
  margin: 0 auto;
  max-height: 150px;
  height: auto;
  width: auto;
}

.stageplot-credit {
  padding: 10px 16px;
  font-size: 0.78rem;
  color: var(--text-dim);
  text-align: center;
  line-height: 1.4;
}

.stageplot-card-actions {
  display: flex;
  gap: 8px;
  margin-top: auto;
}

/* ── Editor mode (full page) ──────────────── */

.stageplot-editor-page {
  display: flex;
  flex-direction: column;
  height: calc(100vh - 32px); /* full viewport minus padding */
  overflow: hidden;
}

.editor-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.editor-header-left {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
  min-width: 0;
}

.editor-header-right {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
}

.editor-title-input {
  flex: 1;
  max-width: 400px;
  min-width: 120px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px 12px;
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
  transition: border-color var(--transition);
}

.editor-title-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-muted);
}

.editor-title-input::placeholder {
  color: var(--text-muted);
}

.editor-save-status {
  font-size: 0.8125rem;
  font-weight: 500;
  min-width: 80px;
  text-align: right;
}

.editor-save-status.success {
  color: var(--success);
}

.editor-save-status.error {
  color: var(--danger);
}

.editor-body {
  flex: 1;
  overflow: hidden;
}

.stageplot-generate-panel,
.stageplot-generate-report {
  margin: 8px 16px;
  padding: 12px 14px;
  border: 1px solid var(--border-light);
  border-radius: 8px;
  background: var(--bg-elevated, #fff);
  font-size: var(--font-sm);
}

.stageplot-generate-title {
  font-weight: 600;
  margin-bottom: 8px;
}

.stageplot-generate-row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 8px;
}

.stageplot-generate-row label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: var(--font-sm);
}

.stageplot-generate-row input,
.stageplot-generate-row select {
  padding: 4px 6px;
  border: 1px solid var(--border-light);
  border-radius: 6px;
  min-width: 90px;
}

.stageplot-generate-check {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
  font-size: var(--font-sm);
}

.stageplot-generate-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

.stageplot-generate-report ul {
  margin: 4px 0 8px 18px;
  padding: 0;
}

.stageplot-generate-unmapped {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px dashed var(--border-light);
}

.stageplot-generate-unmapped-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 6px;
}

.stageplot-ai-credits-out {
  margin-top: 6px;
  color: var(--danger, #c0392b);
  font-size: 0.85rem;
}

/* ── AI mapping panel (LOT B) ─────────────── */
.stageplot-ai-map-panel {
  margin-top: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border-light);
  border-radius: 8px;
  background: var(--surface, #fff);
}

.stageplot-ai-credits-badge {
  margin-left: 8px;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-dim, #666);
}

.stageplot-ai-hint {
  margin: 6px 0;
  font-size: 0.85rem;
  color: var(--text-dim, #666);
}

.stageplot-ai-map-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 8px;
}

.stageplot-ai-map-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  max-height: 240px;
  overflow-y: auto;
}

.stageplot-ai-map-row {
  padding: 4px 0;
  border-bottom: 1px solid var(--border-light);
}

.stageplot-ai-map-row label {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}

.stageplot-ai-map-name {
  font-weight: 500;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.stageplot-ai-map-icon {
  font-size: 0.85rem;
  color: var(--text-dim, #666);
}

.stageplot-ai-map-conf {
  font-size: 0.8rem;
  color: var(--text-dim, #666);
  min-width: 40px;
  text-align: right;
}

/* ── Placement assistant (LOT C) ──────────── */
.stageplot-assistant {
  margin-top: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border-light);
  border-radius: 8px;
  background: var(--surface, #fff);
}
.stageplot-assistant-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.stageplot-assistant-title {
  font-weight: 600;
  font-size: 0.9rem;
}
.stageplot-assistant-input-row {
  display: flex;
  gap: 8px;
  align-items: center;
}
.stageplot-assistant-input {
  flex: 1;
  min-width: 0;
  padding: 6px 8px;
  border: 1px solid var(--border-light);
  border-radius: 6px;
  background: var(--bg, #fff);
  color: var(--text, #222);
  font-size: 0.9rem;
}
.stageplot-assistant-input:disabled {
  opacity: 0.6;
}
.stageplot-assistant-suggestions {
  margin-top: 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.stageplot-assistant-suggestion {
  text-align: left;
  padding: 4px 8px;
  border: 1px dashed var(--border-light);
  border-radius: 6px;
  background: transparent;
  color: var(--text-dim, #666);
  font-size: 0.85rem;
  cursor: pointer;
}
.stageplot-assistant-suggestion:hover {
  border-color: var(--accent, #e0a44c);
  color: var(--accent, #e0a44c);
}
.stageplot-assistant-applied {
  margin: 6px 0 0;
  font-size: 0.85rem;
  color: var(--success, #27ae60);
}
.stageplot-assistant-history {
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
  max-height: 320px;
  overflow-y: auto;
}
.stageplot-assistant-entry {
  padding: 8px 0;
  border-top: 1px solid var(--border-light);
}
.stageplot-assistant-entry:first-child {
  border-top: none;
}
.stageplot-assistant-reply {
  margin: 0 0 6px;
  font-size: 0.9rem;
}
.stageplot-assistant-actions {
  list-style: none;
  margin: 0;
  padding: 0;
}
.stageplot-assistant-action {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 3px 0;
}
.stageplot-assistant-action-text {
  flex: 1;
  min-width: 0;
  font-size: 0.85rem;
  color: var(--text-dim, #666);
}
.stageplot-assistant-entry-actions {
  margin-top: 6px;
  display: flex;
  justify-content: flex-end;
}

/* ── Responsive ───────────────────────────── */

@media (max-width: 768px) {
  .editor-header {
    flex-direction: column;
    gap: 8px;
    padding: 8px 12px;
  }

  .editor-header-left,
  .editor-header-right {
    width: 100%;
  }

  .editor-title-input {
    max-width: none;
  }

  .editor-save-status {
    min-width: 60px;
    font-size: 0.75rem;
  }

  .stageplot-grid {
    grid-template-columns: 1fr;
  }
}

/* Read-only note — shown when the account lacks the `content.rider` capability.
   A suppressed write is never silent (see StagePlotEditorPage). */
.stageplot-readonly-note {
  margin: 0 0 12px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  color: var(--text-dim);
  font-size: var(--font-sm);
}
/* =========================================================================
   P2c / P2c-2 — Atlas / Route map (maquette 006 — sections .map / .rr / .rl).
   Roadcase tokens ONLY: no hex, no hardcoded colour, no new dependency.
   The map is a plain inline SVG (viewBox 0 0 100 100, preserveAspectRatio
   none) + absolutely positioned pins, exactly like the mockup.

   P2c-2 layout (user decisions 2026-10-09) — ONE column, top → bottom:
   hero (next show + countdown) → dates list → map (last, smaller).
   The right rail is gone: `.atlas-stack` is the single container.

   P2g (2026-10-09) — the map is a VIEWPORT, not a bbox: the projection frame
   is centred on the next show (see AtlasPage.tsx) and a Google-Maps-style
   control cluster (.atlas-mapctl, top-right) drives zoom / recenter /
   "all dates". The map keeps `overflow: hidden`, which is what CLIPS both the
   out-of-frame pins and the route segments crossing the frame border.
   ========================================================================= */

/* Header stats line (spec P2c « titre + stats ») — same string as the map badge. */
.atlas-headstats {
  display: inline-block;
  margin-left: 10px;
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.atlas-legend {
  display: flex;
  gap: 14px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  align-items: center;
}
.atlas-legend i {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 5px;
  vertical-align: -1px;
}
.atlas-legend .lg-done { background: var(--accent); }
.atlas-legend .lg-next { border: 2px solid var(--accent); }
.atlas-legend .lg-up { border: 2px solid var(--border-light); }

/* Single column: hero → list → map. */
.atlas-stack {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}

/* ============================== CARD SHELL ============================ */
.atlas-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.atlas-card-hd {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  padding: 11px 15px;
  border-bottom: 1px solid var(--border);
}
.atlas-card-hd .t {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 600;
}
.atlas-card-hd .a {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--accent);
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
}
.atlas-card-hd .a:hover { color: var(--accent-hover); }

/* ============================== 1 · HERO ============================= */
/* The next show (fallback: most recent) + its countdown, side by side on
   desktop and stacked on mobile. Without a countdown the body takes the
   whole width (flex, not grid — no empty trailing column). */
.atlas-hero {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.atlas-hero-body {
  flex: 1 1 auto;
  min-width: 0;
  padding: 15px 16px;
}
.atlas-hero-state {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
}
.atlas-hero-state .led {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
}
.atlas-hero-venue {
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.2;
  overflow-wrap: anywhere;
}
.atlas-hero-meta {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-dim);
  margin-top: 3px;
  overflow-wrap: anywhere;
}
/* Ghost country borders — context only (user 10-10: pins floating on an empty
   sheet read as "in the void"). Hairline in the theme border colour, never a
   fill, never competing with the route: the map stays a chart, not an atlas. */
/* A dark-on-dark hairline was INVISIBLE in practice (user 10-10: "je ne vois
   pas les pays"; measured 1/10 by vision). A LIGHT stroke at low alpha keeps
   the same filigrane intent but actually reads on the dark map. */
.atlas-borders {
  fill: none;
  stroke: var(--text-dim);
  stroke-width: 1;
  opacity: 0.28;
  vector-effect: non-scaling-stroke;
}

.atlas-hero-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 9px;
  margin-top: 13px;
}
.atlas-hero-grid .b {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 8px 10px;
  min-width: 0;
}
.atlas-hero-grid .g {
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.atlas-hero-grid .val {
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 600;
  margin-top: 2px;
  overflow-wrap: anywhere;
}
.atlas-hero-actions { display: flex; gap: 8px; margin-top: 13px; max-width: 320px; }
.atlas-hero-actions .btn { flex: 1; min-width: 0; }

/* countdown — lives INSIDE the hero (right column on desktop) */
.atlas-hero-cd {
  flex: 0 0 320px;
  min-width: 0;
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.atlas-capline {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 11px 16px 0;
  overflow-wrap: anywhere;
}
.atlas-cd {
  padding: 12px 16px 15px;
  display: flex;
  gap: 9px;
  background: linear-gradient(135deg, var(--accent-tint-strong), transparent 60%);
}
.atlas-cd .u {
  flex: 1;
  min-width: 0;
  text-align: center;
  background: var(--bg);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  padding: 8px 0;
}
.atlas-cd .n {
  font-family: var(--font-mono);
  font-size: 22px;
  font-weight: 700;
  color: var(--accent-hover);
  font-variant-numeric: tabular-nums;
}
.atlas-cd .l {
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: 3px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ============================== 2 · LIST ============================= */
.atlas-list { max-height: 340px; overflow-y: auto; }
.atlas-row {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  width: 100%;
  padding: 9px 14px;
  border: 0;
  border-bottom: 1px solid var(--divider);
  background: none;
  cursor: pointer;
  font-size: 12.5px;
  text-align: left;
  color: var(--text);
}
.atlas-row:last-child { border-bottom: none; }
.atlas-row:hover { background: var(--surface-hover); }
.atlas-row .dt {
  font-family: var(--font-mono);
  text-align: center;
  font-size: 11.5px;
  font-weight: 700;
}
.atlas-row .dt small {
  display: block;
  font-size: 8.5px;
  color: var(--text-muted);
  font-weight: 500;
  text-transform: uppercase;
}
.atlas-row .mid { display: block; min-width: 0; }
.atlas-row .v {
  display: block;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.atlas-row .c {
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.atlas-tag {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 7px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-dim);
  white-space: nowrap;
}
.atlas-tag.next { background: var(--accent-muted); color: var(--accent); }
.atlas-list-empty {
  padding: 16px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
}

/* ============================== 3 · MAP ============================== */
.atlas-map {
  position: relative;
  height: 280px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden; /* labels clip at the frame — they can never overflow the page */
  background:
    radial-gradient(ellipse 70% 60% at 50% 45%, var(--accent-tint), transparent 70%),
    repeating-linear-gradient(0deg, transparent 0 47px, var(--accent-tint) 47px 48px),
    repeating-linear-gradient(90deg, transparent 0 47px, var(--accent-tint) 47px 48px),
    var(--card);
}
.atlas-scan {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent, var(--accent-tint) 50%, transparent);
  animation: atlas-scan 7s linear infinite;
  pointer-events: none;
}
@keyframes atlas-scan {
  0% { transform: translateY(-100%); }
  100% { transform: translateY(100%); }
}

.atlas-map svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.atlas-seg { fill: none; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.atlas-seg-dim { stroke: var(--accent-line); stroke-width: 1.5; }
.atlas-seg-done {
  stroke: var(--accent);
  stroke-width: 2;
  filter: drop-shadow(0 0 4px var(--accent-glow));
}
.atlas-seg-next {
  stroke: var(--accent-hover);
  stroke-width: 2;
  stroke-dasharray: 7 9;
  animation: atlas-flow 1.1s linear infinite;
  filter: drop-shadow(0 0 5px var(--accent-glow));
}
/* Upcoming segments (after the next one): same flow animation, subtler, with a
   per-segment animation-delay (chronological `order`) so the pulses travel
   along the route in date order. (user 2026-10-22) */
.atlas-seg-up {
  stroke: var(--accent-line);
  stroke-width: 1.5;
  stroke-dasharray: 5 7;
  animation: atlas-flow 1.1s linear infinite;
}
@keyframes atlas-flow { to { stroke-dashoffset: -16; } }

/* pins — click = open the show (same model as the list rows) ----------- */
.atlas-pin {
  position: absolute;
  transform: translate(-50%, -50%);
  cursor: pointer;
  z-index: 2;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  line-height: 0;
}
.atlas-pin .dot {
  display: block;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--bg-elevated);
  border: 2px solid var(--border-light);
  margin: 0 auto;
  transition: var(--transition);
}
.atlas-pin.done .dot {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 8px var(--accent-glow);
}
.atlas-pin.next .dot {
  width: 15px;
  height: 15px;
  background: var(--bg);
  border-color: var(--accent);
  box-shadow: 0 0 12px var(--accent-glow);
  animation: atlas-pulse 1.6s infinite;
}
@keyframes atlas-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
.atlas-pin:hover .dot { transform: scale(1.3); }
.atlas-pin .lab {
  position: absolute;
  top: 50%;
  left: 14px;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 140px;
  background: var(--bg);
  opacity: 0.72;
  padding: 1px 5px;
  border-radius: var(--radius-sm);
  line-height: 1.4;
}
.atlas-pin.next .lab { color: var(--accent); opacity: 1; }
/* Labels are DECORATION: they must never steal a click meant for a dot (dense
   maps overlap — verified by QA: a label sitting over a neighbouring dot used
   to open the wrong show). */
.atlas-pin .lab { pointer-events: none; }
.atlas-pin.lab-left .lab { left: auto; right: 14px; }
.atlas-pin.lab-above .lab {
  top: auto;
  bottom: 14px;
  left: 50%;
  transform: translateX(-50%);
}
/* The active pin stays on top of the label layer. */
.atlas-pin.next { z-index: 4; }

/* badge + empty states ------------------------------------------------- */
.atlas-badge {
  position: absolute;
  left: 14px;
  top: 12px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--bg);
  opacity: 0.85;
  border: 1px solid var(--border);
  padding: 5px 9px;
  border-radius: var(--radius-sm);
  z-index: 3;
  pointer-events: none;
}
.atlas-badge b { color: var(--accent); font-weight: 600; }

.atlas-map-note {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 20px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  z-index: 1;
}
.atlas-empty {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--text-dim);
  border: 1px dashed var(--border-light);
  border-radius: var(--radius-lg);
  padding: 28px 20px;
  text-align: center;
}
.atlas-error { color: var(--danger); font-size: var(--font-sm); }

/* ========================= 3b · MAP CONTROLS (P2g) =================== */
/* Google-Maps-like overlay pinned to the TOP-RIGHT corner (the stats badge
   owns the top-left): zoom stack → recenter → "all dates" pill. Same four
   controls on mobile, just one notch smaller — they all stay inside the
   220px frame. Tokens only, no hex, no new dependency. */
.atlas-mapctl {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 6; /* above the pins (2/4) and the badge (3) */
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}
.atlas-mapctl button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: 16px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: var(--transition);
}
.atlas-mapctl button:hover {
  background: var(--surface-hover);
  border-color: var(--accent);
  color: var(--accent);
}
/* Zoom − / + read as ONE cell, like the maps control stack. */
.atlas-mapctl .grp {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.atlas-mapctl .grp button { border: 0; border-radius: 0; }
.atlas-mapctl .grp button + button { border-top: 1px solid var(--border); }
.atlas-mapctl .grp button:hover { background: var(--surface-hover); }
/* The pill carries a translated label — never a fixed width. */
.atlas-mapctl .pill {
  width: auto;
  height: auto;
  padding: 5px 9px;
  font-size: 9.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
}
.atlas-mapctl .pill:hover { padding: 5px 9px; }

/* ============================== MOBILE (≤768px) ====================== */
/* Same order as desktop: hero → list → map (DOM order, flex column). */
@media (max-width: 768px) {
  .atlas-hero { flex-direction: column; }
  .atlas-hero-cd {
    flex: 0 0 auto;
    border-left: 0;
    border-top: 1px solid var(--border);
  }
  .atlas-hero-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .atlas-hero-actions { max-width: none; }
  .atlas-map { height: 220px; }
  .atlas-list { max-height: none; }
  .atlas-pin .lab { font-size: 8px; max-width: 96px; }
  .atlas-pin .dot { width: 9px; height: 9px; }
  .atlas-pin.next .dot { width: 13px; height: 13px; }
  .atlas-legend { gap: 10px; }
  /* Same controls, smaller: 2 * 28 + 28 + pill ≈ 120px inside a 220px map. */
  .atlas-mapctl { top: 8px; right: 8px; gap: 5px; }
  .atlas-mapctl button { width: 28px; height: 28px; font-size: 15px; }
  .atlas-mapctl .pill { padding: 4px 8px; font-size: 11px; }
  .atlas-mapctl .pill:hover { padding: 4px 8px; }
}
/* =========================================================================
   P2d — Day of show / Run of show (maquette 005 — .mast / .ros / .nowbar / .cd).
   Roadcase tokens ONLY: no hex, no hardcoded colour, no new dependency, no
   weather widget (the masthead line is the STORED `weather` note, hidden empty).

   Two modes on the same page:
     · showday → hero (giant date + clock + doors countdown) → run-of-show;
     · before  → next-show hero + countdown → clickable upcoming dates.
   ========================================================================= */

.dayof-page .dayof-error {
  margin: 0 0 12px;
  padding: 9px 12px;
  border: 1px solid var(--danger);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  color: var(--danger);
  font-family: var(--font-mono);
  font-size: var(--font-xs);
}

/* P2e — tour-stats badge in the BEFORE mode: the SAME badge as the Atlas
   header (src/lib/tourStats.ts owns the numbers/strings), same look. */
.dayof-page .dayof-headstats {
  display: inline-block;
  margin-left: 10px;
  font-family: var(--font-mono);
  font-size: var(--font-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.dayof-empty,
.dayof-ros-empty,
.dayof-list-empty {
  padding: 18px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  text-align: center;
}

.dayof-stack {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}

/* ============================== HERO / MASTHEAD ======================== */
.dayof-hero {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}

.dayof-mast {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, var(--accent-tint), transparent 70%);
}
.dayof-mast-left { min-width: 0; }

.dayof-big {
  font-family: var(--font-mono);
  font-size: 40px;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  text-transform: uppercase;
}
.dayof-big .dnum { color: var(--accent); }
.dayof-big .dow,
.dayof-big .mon { color: var(--text); }

.dayof-sub {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-dim);
  margin-top: 8px;
  letter-spacing: 0.05em;
  overflow-wrap: anywhere;
}
.dayof-sub b { color: var(--text); font-weight: 700; }
.dayof-sub .lbl { text-transform: uppercase; letter-spacing: 0.1em; }
.dayof-sub .sep { color: var(--text-muted); }

.dayof-mast-right {
  text-align: right;
  font-family: var(--font-mono);
  flex: 0 0 auto;
}
.dayof-clock {
  font-size: 26px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.dayof-clock small {
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 500;
}
.dayof-wx {
  font-size: 11.5px;
  color: var(--text-dim);
  margin-top: 4px;
  max-width: 240px;
  overflow-wrap: anywhere;
}

/* doors countdown — INSIDE the hero (assertion `data-dayof-cdoors`) */
.dayof-doors {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 18px;
  background: linear-gradient(135deg, var(--accent-tint-strong), transparent 60%);
}
.dayof-doors .cap {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}
.dayof-doors .u {
  flex: 0 0 74px;
  text-align: center;
  background: var(--bg);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  padding: 7px 0;
  min-width: 0;
}
.dayof-doors .n {
  font-family: var(--font-mono);
  font-size: 21px;
  font-weight: 700;
  color: var(--accent-hover);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.dayof-doors .l {
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: 3px;
}

/* ============================== RUN OF SHOW =========================== */
.dayof-ros {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.dayof-ros-hd {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
}
.dayof-ros-hd .t {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 600;
}
.dayof-live {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--accent);
  display: flex;
  align-items: center;
  gap: 6px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dayof-live .led {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
  animation: dayof-pulse 2.4s infinite;
  flex: 0 0 auto;
}
@keyframes dayof-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.dayof-agenda { padding: 6px 0 8px; }

.dayof-step {
  display: grid;
  grid-template-columns: 74px 24px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 10px 16px;
  position: relative;
}
.dayof-step .t {
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.dayof-step .rail {
  position: relative;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
}
.dayof-step .rail::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--border-light);
}
.dayof-step:first-child .rail::before { top: 50%; }
.dayof-step:last-child .rail::before { bottom: 50%; }
.dayof-step .node {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--card);
  border: 2px solid var(--border-light);
  position: relative;
  z-index: 1;
}
.dayof-step.done .node { background: var(--success); border-color: var(--success); }
.dayof-step.done .rail::before { background: linear-gradient(180deg, var(--success), var(--border-light)); }
.dayof-step.future .node,
.dayof-step.plain .node { background: var(--card); border-color: var(--border-light); }
.dayof-step.now .node {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 10px var(--accent-glow, rgba(224, 164, 76, 0.8));
  animation: dayof-pulse 1.6s infinite;
}
.dayof-step.now .t,
.dayof-step.now .name { color: var(--accent); }

.dayof-step .body { min-width: 0; }
.dayof-step .name {
  font-size: 13.5px;
  font-weight: 600;
  overflow-wrap: anywhere;
}
.dayof-step .meta {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--text-muted);
  margin-top: 1px;
  overflow-wrap: anywhere;
}
.dayof-step .who { display: flex; gap: 5px; }
.dayof-step .who .c {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--surface);
  border: 1px solid var(--border-light);
  color: var(--text-dim);
  padding: 3px 7px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
}

/* NOW banner, inserted right above the current step */
.dayof-nowbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 2px 16px;
  padding: 8px 12px;
  background: linear-gradient(90deg, var(--accent-tint-strong), transparent 75%);
  border: 1px solid var(--accent-line, var(--accent));
  border-radius: 8px;
}
.dayof-nowbar .lbl {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.18em;
  color: var(--accent);
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
}
.dayof-nowbar .lbl .led {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
  animation: dayof-pulse 1.6s infinite;
}
.dayof-nowbar .txt {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-dim);
  min-width: 0;
  overflow-wrap: anywhere;
}
.dayof-nowbar .txt b { color: var(--text); }
.dayof-nowbar .prog {
  margin-left: auto;
  width: 110px;
  height: 5px;
  border-radius: 99px;
  background: var(--border-light);
  overflow: hidden;
  flex: 0 0 auto;
}
.dayof-nowbar .prog i {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--accent-hover));
  box-shadow: 0 0 8px var(--accent-glow, rgba(224, 164, 76, 0.6));
}

.dayof-ros-ft {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
}

/* ====================== BEFORE MODE · NEXT SHOW HERO ================== */
.dayof-next {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.dayof-next-body {
  flex: 1 1 auto;
  min-width: 0;
  padding: 15px 16px;
}
.dayof-next-state {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
}
.dayof-next-state .led {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
}
.dayof-next-venue {
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.2;
  overflow-wrap: anywhere;
}
.dayof-next-meta {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--text-dim);
  margin-top: 3px;
  overflow-wrap: anywhere;
}
.dayof-next-actions { display: flex; gap: 8px; margin-top: 13px; max-width: 320px; }
.dayof-next-actions .btn { flex: 1; min-width: 0; }

.dayof-next-cd {
  flex: 0 0 360px;
  min-width: 0;
  border-left: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.dayof-capline {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 11px 16px 0;
  overflow-wrap: anywhere;
}
.dayof-cd {
  padding: 12px 16px 15px;
  display: flex;
  gap: 9px;
  background: linear-gradient(135deg, var(--accent-tint-strong), transparent 60%);
}
.dayof-cd .u {
  flex: 1;
  min-width: 0;
  text-align: center;
  background: var(--bg);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  padding: 8px 0;
}
.dayof-cd .n {
  font-family: var(--font-mono);
  font-size: 22px;
  font-weight: 700;
  color: var(--accent-hover);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.dayof-cd .l {
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: 3px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ====================== BEFORE MODE · UPCOMING LIST =================== */
.dayof-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  overflow: hidden;
}
.dayof-card-hd {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  padding: 11px 15px;
  border-bottom: 1px solid var(--border);
}
.dayof-card-hd .t {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 600;
}
.dayof-list { max-height: 420px; overflow-y: auto; }
.dayof-row {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  width: 100%;
  padding: 9px 14px;
  border: 0;
  border-bottom: 1px solid var(--divider, var(--border));
  background: none;
  cursor: pointer;
  font-size: 12.5px;
  text-align: left;
  color: var(--text);
}
.dayof-row:last-child { border-bottom: none; }
.dayof-row:hover { background: var(--surface-hover, var(--surface)); }
.dayof-row .dt {
  font-family: var(--font-mono);
  text-align: center;
  font-size: 11.5px;
  font-weight: 700;
}
.dayof-row .dt small {
  display: block;
  font-size: 8.5px;
  color: var(--text-muted);
  font-weight: 500;
  text-transform: uppercase;
}
.dayof-row .mid { display: block; min-width: 0; }
.dayof-row .v {
  display: block;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dayof-row .c {
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dayof-tag {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 7px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-dim);
  white-space: nowrap;
}
.dayof-tag.next {
  background: var(--accent-muted, var(--accent-tint-strong));
  color: var(--accent);
}

/* ================================ MOBILE ============================== */
@media (max-width: 768px) {
  .dayof-mast { flex-direction: column; align-items: flex-start; gap: 12px; }
  .dayof-mast-right { text-align: left; }
  .dayof-wx { max-width: none; }
  .dayof-big { font-size: 30px; }
  .dayof-doors { flex-wrap: wrap; }
  .dayof-doors .cap { flex: 1 0 100%; }
  .dayof-doors .u { flex: 1 1 0; min-width: 0; }
  .dayof-step { grid-template-columns: 56px 18px minmax(0, 1fr); gap: 9px; padding: 9px 12px; }
  .dayof-step .who { display: none; }
  .dayof-nowbar { flex-wrap: wrap; }
  .dayof-nowbar .prog { width: 100%; margin-left: 0; }
  .dayof-next { flex-direction: column; }
  .dayof-next-cd { flex: 1 1 auto; border-left: 0; border-top: 1px solid var(--border); }
  .dayof-next-actions { max-width: none; }
  .dayof-ros-ft .btn { width: 100%; }
}
