/* ===========================================================================
   front.css — the member-facing layer. Prefix `tc-`.

   SCOPE RULE: every rule in this file is scoped under `.tc`, so nothing here can
   reach the back office. The front never loads shell.css or ixt.css.

   Breakpoints (front only, all min-width — mobile first):
     sm  30em / 480   two-up cards
     md  48em / 768   the grid becomes a matrix; .tc-sheet renders as a .modal
     lg  62em / 992   the tab bar becomes a top nav; content caps at 970px
   `md` is 48em on purpose: it is the design system's OWN breakpoint, so our layout
   change and its coarse-pointer button rule can never disagree by 8px.

   `max-width: 900px` is DS-owned (the Record page's density switch). Never author a
   rule at that width.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   DEVIATION D5 — front density.

   The design system sets --base-size:14px for a mouse-driven admin. The front is
   read one-handed, standing, outdoors. The DS already does exactly this switch on
   its own Record page (`@media (max-width:900px){.od{--od-fs:16px}}`); this
   generalises its precedent rather than inventing a rule.

   Also load-bearing: iOS Safari force-zooms any <input> whose computed font-size is
   under 16px, which would break every form on the front.

   --base-size itself is NOT redefined: ds-parity.mjs asserts it.
   --------------------------------------------------------------------------- */
.tc {
  --tc-fs:      16px;
  --tc-fs-sm:   14px;
  --tc-lh:      24px;
  --tc-tabbar-h: 56px;
  --tc-header-h: 56px;
  --tc-pad:     16px;
  --tc-max:     970px;   /* the DS Record frame width, reused rather than invented */

  font-size: var(--tc-fs);
  line-height: var(--tc-lh);
  color: var(--foreground);
  background: var(--surface);
}

/* DEVIATION D7 — 100svh, not 100vh. Mobile browser chrome makes 100vh taller than
   the visible viewport, which would park the grid's sticky court header permanently
   under the URL bar. */
.tc-app {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
}
@supports not (min-height: 100svh) {
  .tc-app { min-height: 100vh; }
}

.tc-main {
  flex: 1 1 auto;
  width: 100%;
  max-width: var(--tc-max);
  margin: 0 auto;
  padding: var(--tc-pad) var(--tc-pad)
           calc(var(--tc-tabbar-h) + env(safe-area-inset-bottom) + 24px);
}
@media (min-width: 62em) {
  .tc-main { padding-bottom: 48px; }
}

/* ---------------------------------------------------------------------------
   DEVIATION D1 / D1b — touch-target floor.

   The design system's stated floor is 24px, measured on a desktop admin driven by a
   mouse. WCAG 2.2 SC 2.5.8 sets 24 CSS px as the MINIMUM; 2.5.5 sets 44 as the
   target. The front is used in a car park with one thumb.

   D1b is the sharper point: the DS's own query is
     `(hover) and (pointer:fine), (min-width:48em)`
   — fine-pointer OR >= 768px. A TOUCH TABLET at 768-1024px matches the second
   clause and therefore gets the SMALLEST targets on the LARGEST touch device. That
   is a genuine bug in the system, not a preference, so this block re-grows them
   after the DS band rather than fighting it at a narrower width.

   Only the HIT BOX grows. No token, geometry or type value changes, so the visual
   system is untouched.
   --------------------------------------------------------------------------- */
@media (hover: none) and (pointer: coarse) {
  .tc .btn,
  .tc .btn-xs,
  .tc .btn-2xs,
  .tc .btn-icon,
  .tc .btn-icon-sm,
  .tc .btn-icon-xs {
    min-height: 44px;
    min-width: 44px;
  }

  /* Where the visual size must stay small (a chip's remove button, a link inside a
     sentence), grow the pointer box instead of the geometry. */
  .tc .hit-44 { position: relative; }
  .tc .hit-44::after {
    content: "";
    position: absolute;
    inset: -10px;
  }
}

/* ---------------------------------------------------------------------------
   DEVIATION D2 — mobile navigation.

   §17 ships a 240px sidebar with no collapse, no hamburger and no breakpoint: on a
   390px viewport that is 61% of the screen. It is explicitly a BACK-OFFICE shell.
   The front uses five fixed bottom tabs within thumb reach; at `lg` the same five
   links become a top nav, in the SAME ORDER, so the mental model survives the
   breakpoint.

   Real <a> elements with aria-current="page" — §2's accessibility contract:
   interactive is a <button> or an <a>, never a div.
   --------------------------------------------------------------------------- */
.tc-tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 900;
  display: flex;
  height: calc(var(--tc-tabbar-h) + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--card);
  border-top: 1px solid var(--border);
}

.tc-tab {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-width: 0;
  padding: 6px 4px;
  font-size: 11px;
  font-weight: 500;
  line-height: 14px;
  color: var(--foreground-subdued);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.tc-tab svg { width: 22px; height: 22px; flex: 0 0 auto; }
.tc-tab span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tc-tab[aria-current="page"] { color: var(--foreground); font-weight: 650; }
.tc-tab:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; border-radius: var(--radius); }

.tc-topnav { display: none; }

@media (min-width: 62em) {
  .tc-tabbar { display: none; }

  .tc-topnav {
    position: sticky;
    top: 0;
    z-index: 900;
    display: flex;
    align-items: center;
    gap: 4px;
    height: var(--tc-header-h);
    padding: 0 var(--tc-pad);
    background: var(--card);
    border-bottom: 1px solid var(--border);
  }
  .tc-topnav .tc-brand {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-weight: 700;
    font-size: 15px;
    margin-right: 16px;
    text-decoration: none;
  }
  /* Capped by HEIGHT, not width: club logos are square, wide or tall, and a width cap
     lets a tall one push the nav bar open. */
  .tc-topnav .tc-brand-logo { height: 24px; width: auto; max-width: 96px; object-fit: contain; }
  .tc-topnav .tc-tab {
    flex: 0 0 auto;
    flex-direction: row;
    gap: 6px;
    padding: 8px 12px;
    font-size: 13px;
    border-radius: var(--radius);
  }
  .tc-topnav .tc-tab svg { width: 16px; height: 16px; }
  .tc-topnav .tc-tab[aria-current="page"] { background: var(--fill-tertiary); }
  .tc-topnav .tc-spacer { flex: 1 1 auto; }
}

/* Mobile header — the page title and one optional action. */
.tc-header {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 40px;
  margin-bottom: 16px;
}
.tc-header h1 {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-size: 22px;
  line-height: 28px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
@media (min-width: 62em) {
  .tc-header h1 { font-size: 26px; line-height: 32px; }
}

/* ---------------------------------------------------------------------------
   Cards and lists — DEVIATION D4.

   The front never instantiates the ixt-* engine. It is nowrap, hover-driven,
   horizontally scrolling, with a sticky header clone and 20px bulk-bar controls. On
   a touch device hover does not exist, so peek chevrons, sort arrows and row actions
   are unreachable; and a horizontally scrolling table inside a vertically scrolling
   page is the classic scroll trap.

   "My bookings" is therefore a list of rows: an identity line, one status badge, two
   facts, and one committing action. Anything else opens a sheet.

   Scope note: the back office keeps the real engine and stays desktop-only. That is
   a product decision, not a deviation.
   --------------------------------------------------------------------------- */
.tc-card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--tc-pad);
}
.tc-card + .tc-card { margin-top: 12px; }
.tc-card-title { margin: 0 0 4px; font-size: 15px; font-weight: 650; line-height: 20px; }
.tc-card-sub   { margin: 0; font-size: var(--tc-fs-sm); color: var(--foreground-subdued); }

/* « Installer l'application » (views/partials/pwa-install.php). La carte est un .tc-card ;
   seules les étapes iPhone ont une forme à elles : une liste numérotée, et le pictogramme
   du bouton à toucher à côté de son nom, parce que « Partager » n'est écrit nulle part
   dans Safari. */
.tc-install-steps { margin: 16px 0 0; padding-left: 22px; font-size: var(--tc-fs-sm); line-height: 22px; }
.tc-install-steps li + li { margin-top: 6px; }
.tc-install-glyph { display: inline-flex; vertical-align: -3px; margin-left: 4px; color: var(--ring); }

.tc-list { display: flex; flex-direction: column; gap: 8px; }

.tc-listrow {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px var(--tc-pad);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  text-align: left;
  width: 100%;
}
a.tc-listrow, button.tc-listrow {
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
a.tc-listrow:focus-visible, button.tc-listrow:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}
.tc-listrow-body { flex: 1 1 auto; min-width: 0; }
.tc-listrow-title { font-weight: 600; font-size: var(--tc-fs); line-height: 22px; }
.tc-listrow-facts {
  margin-top: 2px;
  font-size: var(--tc-fs-sm);
  line-height: 20px;
  color: var(--foreground-subdued);
}

/* DEVIATION D6 — under (hover:none), any affordance the DS reveals on hover gets a
   persistent equivalent. A (hover:none) device never reaches a hover-only control.
   Front only: the back office is a mouse surface and keeps the quiet affordance,
   which is the point of it. */
.tc-listrow-chevron { flex: 0 0 auto; margin-top: 2px; color: var(--foreground-subdued); }

/* ---------------------------------------------------------------------------
   DEVIATION D3 — bottom sheet.

   §9 ships `.modal{width:480px}` and `.sheet{width:420px; anchored right}`. On a
   390px viewport the sheet is a full-screen overlay with a hairline of page showing
   — it reads as a broken modal, and its close affordance lands in the least
   reachable corner of a phone. Neither accounts for a soft keyboard covering the
   lower 45% of the screen.

   ONE component, TWO presentations: below `md` it is a bottom sheet; at `md` and
   above the identical markup renders as the DS `.modal`, centred at 480px. So the
   PHP partial is single-sourced.

   §2's dialog contract is unchanged: role="dialog" aria-modal="true", focus moves in
   on open, Escape closes, focus returns to the trigger.
   --------------------------------------------------------------------------- */
.tc-sheet-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, .35);
  backdrop-filter: blur(2px);
}

.tc-sheet {
  width: 100%;
  max-height: 88svh;
  display: flex;
  flex-direction: column;
  background: var(--card);
  border-top: 1px solid var(--border);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--shadow-lg);
  animation: tcSheetUp .22s cubic-bezier(.32, .72, 0, 1);
}
@supports not (max-height: 88svh) {
  .tc-sheet { max-height: 88vh; }
}
@keyframes tcSheetUp { from { transform: translateY(100%); } to { transform: translateY(0); } }

/* The grab handle is the affordance for drag-to-dismiss. Escape and a real Close
   button exist too — a gesture is never the only way out. */
.tc-sheet-grab { padding: 8px 0 4px; display: flex; justify-content: center; touch-action: none; cursor: grab; }
.tc-sheet-grab::before {
  content: "";
  width: 36px; height: 4px;
  border-radius: 2px;
  background: var(--fill-tertiary);
}

.tc-sheet-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 4px var(--tc-pad) 12px;
}
.tc-sheet-title { flex: 1 1 auto; margin: 0; font-size: 18px; line-height: 24px; font-weight: 700; }
.tc-sheet-body  { flex: 1 1 auto; overflow-y: auto; padding: 0 var(--tc-pad) 12px; }
.tc-sheet-foot {
  display: flex;
  gap: 8px;
  padding: 12px var(--tc-pad) calc(12px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--border-soft);
  background: var(--card);
}
.tc-sheet-foot .btn { flex: 1 1 auto; justify-content: center; }

@media (min-width: 48em) {
  .tc-sheet-overlay { align-items: center; padding: 24px; }
  .tc-sheet {
    width: 480px;
    max-width: 95vw;
    max-height: 85vh;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    animation: tcSheetIn .18s ease;
  }
  .tc-sheet-grab { display: none; }
  .tc-sheet-foot { padding-bottom: 12px; justify-content: flex-end; }
  .tc-sheet-foot .btn { flex: 0 0 auto; }
  @keyframes tcSheetIn { from { opacity: 0; transform: scale(.97); } to { opacity: 1; transform: scale(1); } }
}

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

/* ---------------------------------------------------------------------------
   DEVIATION D8 — toast position.
   §8 anchors #toast-container bottom-right. On the front that puts every completion
   message underneath the tab bar, which is the one place it must not be.
   --------------------------------------------------------------------------- */
.tc #toast-container {
  bottom: calc(var(--tc-tabbar-h) + env(safe-area-inset-bottom) + 12px);
  left: 12px;
  right: 12px;
}
.tc #toast-container .toast { width: auto; max-width: 100%; }

@media (min-width: 62em) {
  .tc #toast-container { left: auto; right: 20px; bottom: 20px; }
  /* max-width à lever : hérité du mobile, « 100 % » d'un conteneur sans largeur réduisait
     le message à une colonne de 34 px. */
  .tc #toast-container .toast { width: 340px; max-width: none; }
}

/* ---------------------------------------------------------------------------
   Forms
   --------------------------------------------------------------------------- */
.tc .form-label { font-size: var(--tc-fs-sm); font-weight: 550; }
.tc .form-input,
.tc .form-select,
.tc .form-textarea {
  /* 16px so iOS does not zoom on focus. See D5. */
  font-size: var(--tc-fs);
  height: 44px;
  width: 100%;
}
.tc .form-textarea { height: auto; min-height: 88px; padding: 10px 12px; }
.tc .form-item + .form-item { margin-top: 16px; }
/* Deux champs côte à côte (.form-row) sont voisins dans la grille, pas empilés :
   l'espacement vertical des frères ne s'applique pas. */
.form-row > .form-item + .form-item { margin-top: 0; }

.tc-form-actions { display: flex; gap: 8px; margin-top: 24px; }
.tc-form-actions .btn { flex: 1 1 auto; justify-content: center; }
@media (min-width: 48em) {
  .tc-form-actions { justify-content: flex-end; }
  .tc-form-actions .btn { flex: 0 0 auto; }
}

/* Two fields on one line, but only once there is room for two. Below `sm` they
   stack, because a 390px viewport split in two gives each field ~185px — narrower
   than "Prénom" plus its padding, and the label wraps onto three lines. */
.tc-two { display: grid; gap: 0 12px; align-items: start; }
@media (min-width: 30em) {
  .tc-two { grid-template-columns: 1fr 1fr; }
  /* Côte à côte, les deux champs sont voisins dans la grille, pas empilés : sans cette
     ligne, `.form-item + .form-item` décalait le second de 16px et chaque paire
     (Ville / Téléphone, Prénom / Nom, Mot de passe / Confirmation) boitait. */
  .tc .tc-two > .form-item + .form-item { margin-top: 0; }
}
/* Une paire de champs est un bloc comme un autre : même espace avant et après. */
.tc .tc-two + .form-item, .tc .form-item + .tc-two, .tc .tc-two + .tc-two { margin-top: 16px; }
/* … sauf à l'intérieur d'une paire, où les deux moitiés sont côte à côte. */
@media (min-width: 30em) { .tc .tc-two > .form-item + .tc-two, .tc .tc-two > .tc-two + .form-item { margin-top: 0; } }

/* Le champ fichier : le bouton du navigateur, gris et à sa taille système, dans un
   cadre de 44px, jurait avec le reste du formulaire. */
.tc .form-file { height: auto; padding: 6px; font-size: 14px; color: var(--foreground-subdued); }
.tc .form-file::file-selector-button {
  margin-right: 12px; padding: 7px 12px; border-radius: var(--radius);
  border: 1px solid var(--border); background: var(--card); color: var(--foreground);
  font: inherit; font-weight: 600; cursor: pointer;
}
.tc .form-file::file-selector-button:hover { background: var(--fill-tertiary); }

/* Créer un club en deux étapes : l'indicateur, et le compte rappelé à l'étape 2. */
.signup-steps { list-style: none; display: flex; gap: 8px; margin: 0 0 16px; padding: 0; }
.signup-steps li {
  display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px 6px 6px;
  border-radius: 999px; font-size: 14px; color: var(--foreground-subdued); background: var(--fill-tertiary);
}
.signup-steps li span {
  width: 24px; height: 24px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 13px; background: var(--card); color: var(--foreground);
}
.signup-steps li[aria-current="step"] { background: var(--foreground); color: var(--card); font-weight: 600; }
.signup-steps li.is-done span { background: var(--success-fill); color: #fff; }
.signup-identity {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; margin: 0 0 16px; padding: 10px 12px;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg); font-size: 14px;
}
.signup-identity span { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.signup-identity form { margin: 0; }

/* Segmented choice — §2: "pick 1 of 2-4 visible options" is a radio/segmented
   control, not a select. Used for match type and for the winning side. */
.tc-seg { display: flex; gap: 6px; }
.tc-seg input { position: absolute; opacity: 0; pointer-events: none; }
.tc-seg label {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 8px 10px;
  font-size: var(--tc-fs-sm);
  font-weight: 550;
  text-align: center;
  background: var(--card);
  border: 1px solid var(--input);
  border-radius: var(--radius);
  cursor: pointer;
}
.tc-seg input:checked + label {
  background: var(--foreground);
  border-color: var(--foreground);
  color: var(--background);
}
.tc-seg input:focus-visible + label { outline: 2px solid var(--ring); outline-offset: 2px; }

/* Player chips on the confirm sheet. */
.tc-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.tc-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px 6px 10px;
  font-size: var(--tc-fs-sm);
  background: var(--fill-tertiary);
  border-radius: var(--radius);
}
.tc-chip button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px; height: 20px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--foreground-subdued);
  cursor: pointer;
  border-radius: 4px;
}
.tc-chip button:hover { color: var(--foreground); }

/* Member search results inside the sheet. */
.tc-search-results {
  margin-top: 6px;
  max-height: 220px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.tc-search-results:empty { display: none; }
.tc-search-result {
  display: block;
  width: 100%;
  padding: 12px;
  min-height: 44px;
  font: inherit;
  font-size: var(--tc-fs-sm);
  text-align: left;
  background: var(--card);
  border: 0;
  border-bottom: 1px solid var(--border-soft);
  cursor: pointer;
}
.tc-search-result:last-child { border-bottom: 0; }
.tc-search-result:hover, .tc-search-result:focus-visible { background: var(--accent); outline: none; }

/* Star rating for lesson feedback — real radios, so it works without JavaScript. */
.tc-rating { display: flex; gap: 8px; }
.tc-rating input { position: absolute; opacity: 0; pointer-events: none; }
.tc-rating label {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px; height: 48px;
  font-size: 18px;
  font-weight: 650;
  background: var(--card);
  border: 1px solid var(--input);
  border-radius: var(--radius);
  cursor: pointer;
}
.tc-rating input:checked + label {
  background: var(--foreground);
  border-color: var(--foreground);
  color: var(--background);
}
.tc-rating input:focus-visible + label { outline: 2px solid var(--ring); outline-offset: 2px; }

/* ---------------------------------------------------------------------------
   Public pages — sign in, tariffs, the follow-up response page
   --------------------------------------------------------------------------- */
.tc-narrow { width: 100%; max-width: 420px; margin: 0 auto; }

.tc-auth {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100svh;
  padding: 24px var(--tc-pad) calc(24px + env(safe-area-inset-bottom));
}
@supports not (min-height: 100svh) { .tc-auth { min-height: 100vh; } }

.tc-auth-brand { margin: 0 0 24px; font-size: 20px; font-weight: 700; text-align: center; }

.tc-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 20px 0;
  font-size: 12px;
  color: var(--foreground-subdued);
}
.tc-divider::before, .tc-divider::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: var(--border);
}

.tc-plan {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: var(--tc-pad);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.tc-plan-price { font-size: 24px; font-weight: 700; font-variant-numeric: tabular-nums; }
.tc-plan-grid { display: grid; gap: 12px; }
@media (min-width: 30em) { .tc-plan-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 62em) { .tc-plan-grid { grid-template-columns: repeat(3, 1fr); } }

/* Prose from the editable content blocks. */
.tc-prose { font-size: var(--tc-fs); line-height: var(--tc-lh); }
.tc-prose p  { margin: 0 0 12px; }
.tc-prose ul { margin: 0 0 12px; padding-left: 22px; }
.tc-prose li { margin-bottom: 6px; }
.tc-prose :last-child { margin-bottom: 0; }

/* Empty states — §19: illustration, heading, description, one CTA. */
.tc-empty { padding: 40px 20px; text-align: center; }
.tc-empty-icon  { color: var(--foreground-disabled); margin-bottom: 12px; }
.tc-empty-title { font-size: 16px; font-weight: 650; margin-bottom: 4px; }
.tc-empty-desc  { font-size: var(--tc-fs-sm); color: var(--foreground-subdued); margin: 0 auto 20px; max-width: 280px; }

/* ---------------------------------------------------------------------------
   Le passage vers le back-office, sur téléphone.

   Flottant plutôt que sixième onglet : .tc-tabbar partage sa largeur en cinq parts
   égales, et un élément de plus rognerait les libellés de TOUT LE MONDE — y compris
   ceux des membres, qui n'ont jamais accès à l'administration. Le coût d'une commande
   réservée à trois personnes ne doit pas être payé par les trois cents autres.

   Ancré à gauche : la main droite tient le téléphone et le pouce couvre le côté droit,
   où se trouvent déjà « Famille » et « Profil ». À gauche, il ne recouvre rien.
   --------------------------------------------------------------------------- */
.tc-adminfab {
  position: fixed;
  left: 12px;
  bottom: calc(var(--tc-tabbar-h) + env(safe-area-inset-bottom) + 12px);
  z-index: 901;              /* au-dessus de la barre, qui est en 900 */
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 44px;              /* cible au doigt, pas 32 */
  padding: 0 16px;
  border-radius: 999px;
  background: var(--foreground);
  color: var(--background);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  box-shadow: 0 4px 16px rgba(0, 0, 0, .22);
}
.tc-adminfab:active { transform: translateY(1px); }
.tc-adminfab svg { width: 16px; height: 16px; flex: 0 0 auto; }

/* À partir de 62em la barre du bas disparaît au profit de .tc-topnav, qui porte déjà
   son propre lien vers l'administration : deux chemins visibles en même temps vers le
   même endroit sont une hésitation, pas une commodité. */
@media (min-width: 62em) {
  .tc-adminfab { display: none; }
}

/* Le bouton flottant est en position:fixed : il passe donc au-dessus de ce qui finit
   en bas de page, et il recouvrait « Annuler » sur l'écran de confirmation. On réserve
   sa hauteur dans le flux, et seulement quand il existe — la classe est posée par le
   gabarit pour les administrateurs, plutôt que par :has(), qui ferait dépendre une
   collision de bouton du support du navigateur. */
@media (max-width: 61.99em) {
  .has-adminfab .tc-main { padding-bottom: 96px; }
}

/* Les résultats de recherche sont des <button> : ils ne prennent donc PAS la couleur de
   texte de la page, mais celle que le navigateur — ou une règle globale sur button —
   leur donne, ici du blanc sur un fond blanc. Le nom était bien écrit dans le DOM et
   parfaitement illisible ; deux bugs se cachaient l'un l'autre, puisque la recherche
   excluait par ailleurs celui qui cherchait et ne renvoyait donc presque jamais rien.
   :not(.muted) pour laisser « aucun résultat » garder son gris. */
.tc-search-result:not(.muted) { color: var(--foreground); }

/* ---------------------------------------------------------------------------
   L'écran de confirmation, sur téléphone.

   C'est l'écran le plus utilisé du staff, et le seul où le clavier s'ouvre : dès qu'il
   monte, il mange la moitié basse et la liste des membres se retrouve sous le pouce,
   hors de vue. Chaque respiration qu'on lui retire ici est une ligne de résultat qu'on
   gagne. On resserre donc les cartes, pas la taille du texte : réduire l'échelle
   typographique ferait payer la densité aux yeux plutôt qu'aux marges.

   Les cibles tactiles ne bougent pas : .tc-search-result garde ses 44 px.
   --------------------------------------------------------------------------- */
@media (max-width: 47.99em) {
  .tc-confirm .tc-card { padding: 12px; margin-bottom: 8px; }
  .tc-confirm .tc-card + .tc-card { margin-top: 0; }
  .tc-confirm .form-item { margin-bottom: 8px; }
  .tc-confirm .form-item:last-child { margin-bottom: 0; }
  .tc-confirm .form-label { margin-bottom: 4px; }

  /* Quatre lignes visibles, le reste défile DANS la liste plutôt que de pousser
     « Ajouter un invité » hors de l'écran. */
  .tc-confirm .tc-search-results { max-height: 180px; margin-top: 4px; }

  /* Les jetons se serrent : c'est une liste de noms, pas une galerie. */
  .tc-confirm .tc-chips { gap: 6px; margin-bottom: 8px; }

  /* L'en-tête de page reprend la hauteur d'une carte à lui tout seul. */
  .tc-confirm .tc-header { margin-bottom: 8px; }
}

/* ---------------------------------------------------------------------------
   Les deux actions restent sous le pouce.

   Sur un téléphone, « Confirmer » se trouvait tout en bas d'un formulaire qui grandit
   avec chaque joueur ajouté : on remplissait, puis on cherchait le bouton. Il est
   désormais collé au bas de la zone visible tant que le formulaire est à l'écran.

   `sticky` et non `fixed` : l'élément garde sa place dans le flux, donc il ne recouvre
   jamais la fin du formulaire et aucune hauteur n'est à réserver à la main — deux
   défauts que `fixed` aurait apportés avec lui. Il se décolle naturellement quand on
   atteint le bas de la page.

   Elle prend TOUTE la largeur et floute ce qui passe dessous. Un fond limité à la
   colonne de contenu laissait la carte déborder autour et en dessous : la barre semblait
   couper le formulaire en deux plutôt que flotter par-dessus. Et un fond transparent
   laisserait défiler du texte à travers les boutons, illisibles au moment de les viser.
   --------------------------------------------------------------------------- */
@media (max-width: 61.99em) {
  .tc-confirm .tc-form-actions {
    position: sticky;
    bottom: calc(var(--tc-tabbar-h) + env(safe-area-inset-bottom));
    z-index: 5;

    /* PLEINE LARGEUR, en sortant de la colonne de contenu.
       Un fond limité à la colonne laissait voir la carte déborder autour et en dessous :
       la barre avait l'air de couper le formulaire en deux au lieu de flotter par-dessus.
       Le 100vw ramené au centre échappe au padding du parent sans avoir à le connaître. */
    width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    padding: 10px 16px calc(10px + env(safe-area-inset-bottom));

    /* Le flou plutôt qu'un aplat : on voit que du contenu passe dessous, donc qu'il
       reste des choses à lire, sans que ce contenu gêne la lecture des deux boutons.
       Le fond translucide est le repli pour les navigateurs sans backdrop-filter — sans
       lui, le texte défilerait à travers les boutons. */
    background: color-mix(in srgb, var(--background) 82%, transparent);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border-top: 1px solid var(--border);
  }

  /* Les vieux moteurs ne connaissent ni color-mix ni backdrop-filter : ils reçoivent un
     aplat opaque, moins joli mais jamais illisible. */
  @supports not (backdrop-filter: blur(1px)) {
    .tc-confirm .tc-form-actions { background: var(--background); }
  }

}

/* ---------------------------------------------------------------------------
   Le classement (front/leaderboard). Podium, tableau, derniers matchs.
   --------------------------------------------------------------------------- */
.lb-filters { display: grid; gap: 12px; margin-bottom: 12px; }
@media (min-width: 36em) { .lb-filters { grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); align-items: end; } }
.lb-facts { margin: 0 0 16px; font-size: 13px; color: var(--foreground-subdued); }

.lb-podium { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-bottom: 16px; }
.lb-step {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: 14px 10px 12px; text-align: center; min-width: 0;
}
.lb-step.is-me { border-color: var(--foreground); }
.lb-medal {
  width: 36px; height: 36px; margin: 0 auto 8px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 16px; font-variant-numeric: tabular-nums;
  background: var(--secondary); color: var(--foreground);
}
/* Or, argent, bronze : les trois seules couleurs de la page, et elles disent le rang. */
.lb-gold   .lb-medal { background: #f5c542; color: #3d2e00; }
.lb-silver .lb-medal { background: #d4d6db; color: #2b2d31; }
.lb-bronze .lb-medal { background: #d9a27a; color: #3b2112; }
.lb-step-name { font-weight: 650; font-size: 14px; line-height: 1.25; overflow-wrap: anywhere; }
.lb-step-stat { margin-top: 4px; font-size: 12.5px; font-variant-numeric: tabular-nums; }

.lb-card { padding: 4px 0; overflow-x: auto; }
.lb-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.lb-table th {
  font-size: 12px; font-weight: 500; color: var(--foreground-subdued);
  text-align: left; padding: 10px 8px; border-bottom: 1px solid var(--border);
}
.lb-table td { padding: 10px 8px; border-bottom: 1px solid var(--border-soft); }
.lb-table tr:last-child td { border-bottom: 0; }
.lb-table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.lb-table .lb-rank { width: 28px; color: var(--foreground-subdued); padding-left: 16px; }
.lb-table .lb-name { font-weight: 550; }
.lb-table .lb-name .badge { margin-left: 6px; vertical-align: 1px; }
.lb-table tr.is-me td { background: var(--secondary); }
/* Sur téléphone : rang, joueur, victoires, défaites, pourcentage. Le reste en plus large. */
@media (max-width: 30em) { .lb-table .lb-wide { display: none; } }

/* La carte « Classement de la saison » de l'accueil. */
.lb-home { display: block; text-decoration: none; color: inherit; }
.lb-home .tc-card-title { display: inline-flex; align-items: center; gap: 6px; }
.lb-home-list { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 8px; }
.lb-home-list li { display: flex; align-items: center; gap: 10px; min-width: 0; font-size: 14px; }
.lb-home-list .lb-medal { width: 26px; height: 26px; margin: 0; font-size: 13px; flex-shrink: 0; }

/* ---------------------------------------------------------------------------
   Les photos de la page publique d'un club (migration 011) : la première en grand,
   les suivantes en vignettes. Défilement horizontal sur téléphone plutôt qu'une grille
   qui repousserait les tarifs trois écrans plus bas.
   --------------------------------------------------------------------------- */
.tc-gallery {
  display: grid; grid-auto-flow: column; grid-auto-columns: 78%; gap: 8px;
  overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
}
.tc-gallery > a { display: block; position: relative; scroll-snap-align: start; border-radius: var(--radius-lg); overflow: hidden; background: var(--fill-tertiary); }
.tc-gallery > a[hidden] { display: none; }
/* height: auto, sinon l'attribut height de la balise (la taille déclarée, pas toujours
 * celle du fichier) fixe la hauteur et l'aspect-ratio ne s'applique plus. */
.tc-gallery img { width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; display: block; }
/* Une seule photo : toute la largeur, en paysage, sans bande de défilement. */
.tc-gallery[data-count="1"] { grid-auto-columns: 100%; overflow: visible; }
.tc-gallery[data-count="1"] img { aspect-ratio: 16 / 9; }
@media (min-width: 48em) {
  .tc-gallery { grid-auto-flow: row; grid-template-columns: repeat(4, 1fr); overflow: visible; }
  .tc-gallery > a:first-child { grid-column: 1 / 3; grid-row: 1 / 3; }
  .tc-gallery > a:first-child img { aspect-ratio: auto; height: 100%; }
  /* Une, deux ou trois photos : la mosaïque à quatre colonnes laisserait des trous. */
  .tc-gallery[data-count="1"] { grid-template-columns: 1fr; }
  .tc-gallery[data-count="1"] > a:first-child { grid-column: auto; grid-row: auto; }
  .tc-gallery[data-count="1"] > a:first-child img { aspect-ratio: 21 / 9; height: auto; }
  .tc-gallery[data-count="2"] { grid-template-columns: repeat(2, 1fr); }
  .tc-gallery[data-count="2"] > a:first-child { grid-column: auto; grid-row: auto; }
  .tc-gallery[data-count="2"] > a:first-child img { aspect-ratio: 4 / 3; height: auto; }
  .tc-gallery[data-count="3"] { grid-template-columns: 2fr 1fr; }
  .tc-gallery[data-count="3"] > a:first-child { grid-column: 1; grid-row: 1 / 3; }
}

/* ---------------------------------------------------------------------------
   La visionneuse de photos ([data-lightbox], front.js) : une photo en grand, les
   flèches, le glissé sur téléphone, Échap pour fermer. Pour l'annuaire et la page
   publique d'un club.
   --------------------------------------------------------------------------- */
[data-lightbox] > a { cursor: zoom-in; }
[data-lightbox] > a[data-more]::after {
  content: attr(data-more); position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,.45); color: #fff; font-size: 22px; font-weight: 700;
}
.lb { position: fixed; inset: 0; z-index: 1000; background: rgba(10,10,12,.97); display: flex; flex-direction: column; color: #fff; }
.lb[hidden] { display: none; }
.lb-bar { display: flex; align-items: center; gap: 12px; padding: 10px 12px; font-size: 14px; }
.lb-bar .lb-count { opacity: .75; }
.lb-bar .lb-title { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 600; }
.lb-stage { position: relative; flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center; padding: 0 8px; touch-action: pan-y; }
.lb-stage img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: 6px; user-select: none; -webkit-user-drag: none; }
.lb-btn {
  width: 44px; height: 44px; border-radius: 50%; border: 0; cursor: pointer;
  background: rgba(255,255,255,.14); color: #fff; display: inline-flex; align-items: center; justify-content: center;
}
.lb-btn:hover { background: rgba(255,255,255,.24); }
.lb-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.lb-prev, .lb-next { position: absolute; top: 50%; transform: translateY(-50%); }
.lb-prev { left: 12px; } .lb-next { right: 12px; }
.lb-caption { text-align: center; font-size: 12px; opacity: .7; padding: 8px 12px 14px; min-height: 18px; }
@media (max-width: 47.99em) { .lb-prev, .lb-next { display: none; } }

/* Plateforme → Tournois : une finale par ligne dans le formulaire de résultat. */
.tn-admin-row { display: grid; gap: 6px; grid-template-columns: 1fr; margin-bottom: 8px; }
@media (min-width: 62em) { .tn-admin-row { grid-template-columns: 1.1fr 2fr .6fr 2fr .6fr 1.2fr; } }
