/* =========================================================================
   Design tokens — grounded in badminton.lyonsportmetropole.org
   (theme "sections-lsm-2020"; logo: logo-blanc.png, brush-stroke red).

   Brand red sampled from the logo: #be1522 (dominant opaque pixel).
   The site's own theme also declares --lsm-red:#f10b32 and uses #e30613
   for the active menu item / hover underline; that brighter red is kept
   as --accent-bright for nav interactions, mirroring the site's menu.
   Navy #323c62 is the site's section-title color (.titre-bloc-client),
   used here for page titles and the wordmark — green is NOT part of the
   club identity (green was the previous app skin).
   ========================================================================= */
:root {
  /* Surfaces */
  --paper: #faf9f7;        /* warm off-white page ground */
  --card: #ffffff;
  --card-raised: #f5f4f2;  /* warm neutral panel: menu band, stat rows, hovers */

  /* Ink (tinted warm, never pure black — the site itself uses #333/#242424).
     --muted targets ≥4.5:1 on Card Raised (#f5f4f2) to clear WCAG AA. */
  --ink: #201a1a;
  --ink-soft: #453b3a;
  --muted: #6f6462;
  --line: #e4dfdd;
  --line-strong: #cfc7c5;

  /* Brand red ramp, anchored on the logo (#be1522) */
  --accent: #be1522;
  --accent-deep: #8f0f1a;      /* pressed/hover on solid red */
  --accent-bright: #e30613;    /* site's menu red: active/hover nav */
  --accent-pale: #faecec;      /* tint, e.g. responsablé rows */

  /* Section-tile navy from the site's titles */
  --navy: #323c62;

  /* Category segments — the statut/mixité bars.
     Statut: brand red (club's own status) vs teal — the classic
     red/teal diverging pair (ColorBrewer RdTe): ~180° apart in hue and
     clearly separated by lightness, so it works for the colorblind too.
     Mixité: rose/blue — the gender convention used across data
     visualizations (an 11-year review of gender figures: blue is the
     dominant color for men; rose/pink for women). The rose is set
     lighter than the brand red so Femme never reads like Ayant droit;
     if a gender-diverse category ever appears, violet is the standard
     third color in inclusive palettes. */
  --ad: #be1522;
  --ext: #2a9d8f;
  --mme: #e0719c;
  --msr: #2f6fc1;
  --warn: #c98a00;  /* fill-rate warning band (70–99 %); teal OK, red over */

  /* Error uses a separate warm tone (not the brand red) so a validation
     error and a branded button don't read as the same signal */
  --danger: #b3401f;
  --danger-bg: #fbe8de;

  /* Small radius scale; no shadows, hairline borders only */
  --radius-sm: 6px;
  --radius-md: 10px;

  --ease: cubic-bezier(0.4, 0, 0.2, 1); /* no bounce/elastic */
}

* { box-sizing: border-box; }

/* The `hidden` attribute must always win: .save-status sets display:flex,
   which would otherwise outrank the UA's [hidden]{display:none} and keep
   the empty toast floating at bottom-center of every page. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: -apple-system, "Segoe UI", ui-sans-serif, system-ui, "Helvetica Neue", sans-serif;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

/* =========================================================================
   Top bar — white ground, red logo lockup, quiet nav (plain white header
   like the club site; nav links go from gray ink to the menu red #e30613
   on hover/active, with the site's red underline bar on the active item).
   ========================================================================= */
.topbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  padding: 0.6rem 1.4rem;
  background: var(--card);
  border-bottom: 1px solid var(--line);
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--navy);
  text-decoration: none;
}
.brand-logo { height: 80px; width: auto; } /* 3x: the brush-stroke logo is unreadable at 32px */
.topbar nav { display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; }
.topbar a, .topbar .link {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 0.92rem;
  padding: 0.2rem 0;
  border-bottom: 2px solid transparent;
  transition: color 0.15s var(--ease), border-color 0.15s var(--ease);
}
.topbar a:hover, .topbar .link:hover { color: var(--accent-bright); }
.topbar a.active {
  color: var(--accent-bright);
  font-weight: 600;
  border-bottom-color: var(--accent-bright);
}
.inline { display: inline; }
.link {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--accent); font-size: inherit;
}
.link:hover { color: var(--accent-bright); }

.wrap { max-width: 1180px; margin: 0 auto; padding: 1.6rem 1.2rem 3rem; }

h1 {
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.2;
  margin: 0 0 0.25rem;
  color: var(--navy);
}
h2 {
  font-size: 1.05rem;
  font-weight: 700;
  margin: 0;
  color: var(--accent);
}
.muted { color: var(--muted); }
.error { color: var(--danger); font-weight: 600; }

/* =========================================================================
   Sections — flat panels with a hairline border, no drop shadows.
   ========================================================================= */
section {
  margin: 1.5rem 0;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: 1.1rem 1.2rem 1.3rem;
}

.session-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.8rem; }
.count { color: var(--muted); font-size: 0.85rem; }

/* Session section collapse (the session-head/toggle stays visible) */
.session-toggle {
  font: inherit;
  font-size: 0.78rem;
  color: var(--muted);
  background: none;
  border: none;
  padding: 0.2rem 0.35rem;
  cursor: pointer;
}
.session-toggle:hover { color: var(--accent); }
.session-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
section.collapsed .stats,
section.collapsed .rc-picker,
section.collapsed .table-scroll,
section.collapsed .rc-hint { display: none; }

/* Legend for the highlighted rows (tr.rc): the section's responsables créneau */
.rc-legend {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.78rem;
  color: var(--muted);
}
.rc-swatch {
  display: inline-block;
  width: 16px;
  height: 12px;
  background: var(--accent-pale);
  box-shadow: inset 3px 0 0 var(--accent);
  border-radius: 2px;
}

.stats {
  margin: 0.5rem 0 1rem;
  padding: 0.8rem 0.9rem;
  background: var(--card-raised);
  border-radius: var(--radius-sm);
}
.stat-line { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; margin: 0.3rem 0; }
.stat-line .label { width: 4.5rem; color: var(--muted); font-size: 0.78rem; }
/* The bar is a flex item inside a wrapping .stat-line: a greedy flex: 1
   would let a narrow legend share the row and starve the track to a
   sliver (Mixité at 375 was ~10px). A 120px floor makes the legend wrap
   instead, so the bar keeps the full leftover — both bars stay equal and
   legible on narrow viewports, while desktop (340px cap) is unchanged. */
.bar {
  flex: 1 1 120px; min-width: 120px; display: flex; height: 10px; overflow: hidden;
  border-radius: 5px; background: var(--line); max-width: 340px;
}
.seg { height: 100%; }
.seg.ad { background: var(--ad); }
.seg.ext { background: var(--ext); }
.seg.mme { background: var(--mme); }
.seg.msr { background: var(--msr); }
.legend { font-size: 0.78rem; color: var(--muted); }

/* =========================================================================
   Tables
   ========================================================================= */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* Sticky leading columns: the edit action and the member's identity
   (Nom + Prénom) stay co-visible while the wide sheet-parity table
   scrolls horizontally. Geometry is fixed because a sticky cell offsets
   from the scrollport, not from its neighbour: the pencil cell is
   --edit-w wide, the name columns are pinned at their own fixed widths,
   and every pin's `left` is the sum of the pins before it.
     left-zero      = first pin, flush (pencil on admin, Nom on respo/anon)
     left-edit      = Nom on admin, after the pencil
     left-prenom    = Prénom on admin (pencil + Nom)
     left-prenom-0  = Prénom on respo/anon (Nom)
   Backgrounds mirror the row states (hover / RC wash) so the pinned cells
   never look detached from the row they belong to. */
.table-scroll {
  --edit-w: 2.9rem;   /* pencil cell (pencil glyph + padding) */
  --name-w: 8rem;     /* Nom — fits the longest surnames in the store */
  --given-w: 7rem;    /* Prénom — fits the longest first names */
}
.table-scroll th.sticky-col,
.table-scroll td.sticky-col {
  position: sticky;
  z-index: 2;
  background: var(--card);
}
.table-scroll th.sticky-col { z-index: 3; }
.table-scroll .left-zero { left: 0; }
.table-scroll .left-edit { left: var(--edit-w); }
.table-scroll .left-prenom { left: calc(var(--edit-w) + var(--name-w)); }
.table-scroll .left-prenom-0 { left: var(--name-w); }
.table-scroll tr:hover td.sticky-col { background: var(--card-raised); }
.table-scroll tr.rc td.sticky-col,
.table-scroll tr.rc:hover td.sticky-col { background: var(--accent-pale); }
/* The pinned cells lock their own widths (min+max — `width` alone is
   only a preferred size and a squeezed auto-layout table shrinks it
   below the pinned offsets): the column is exactly --name-w /
   --given-w and an outlier name clips with an ellipsis instead of
   stretching its column and misaligning the pins. */
.table-scroll td.row-edit {
  width: var(--edit-w); min-width: var(--edit-w); max-width: var(--edit-w);
}
.table-scroll th.col-name, .table-scroll td.col-name {
  width: var(--name-w); min-width: var(--name-w); max-width: var(--name-w);
}
.table-scroll th.col-prenom, .table-scroll td.col-prenom {
  width: var(--given-w); min-width: var(--given-w); max-width: var(--given-w);
}
.table-scroll td.col-name, .table-scroll td.col-prenom {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.table-scroll td.sticky-col:not(.left-zero) { box-shadow: 1px 0 0 var(--line); }
.table-scroll tr.rc td.sticky-col:not(.left-zero) { box-shadow: 1px 0 0 var(--accent); }
/* Phones: pin Nom only. The full identity zone (pencil + Nom + Prénom
   ≈ 277px) would leave a ~50px scroll window on a 375px phone — the
   Prénom pin engages from 640px up, where the zone is affordable. */
@media (max-width: 640px) {
  .table-scroll th.col-prenom,
  .table-scroll td.col-prenom {
    position: static;
    box-shadow: none;
  }
}
table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
th, td { text-align: left; padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--line); }
th {
  color: var(--muted);
  font-weight: 600;
  font-size: 0.75rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
tr:last-child td { border-bottom: none; }
tr:hover td { background: var(--card-raised); }
tr.rc td { background: var(--accent-pale); }
tr.rc:hover td { background: var(--accent-pale); }
tr.rc td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
td.row-edit { width: 1%; white-space: nowrap; }
td.actions { white-space: nowrap; text-align: right; }
td.edit-cell { padding: 0.6rem; }

/* Icon-only row action (admin edit), compact, no label */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.2rem 0.35rem;
  line-height: 1;
  border-color: transparent;
  background: none;
  color: var(--ink-soft);
}
.icon-btn svg { display: block; }
.icon-btn:hover { background: var(--card-raised); border-color: var(--line-strong); color: var(--accent); }

/* =========================================================================
   Recap / choice picker
   ========================================================================= */
.rc-picker { margin: 0.5rem 0 1rem; }
.rc-picker form { display: flex; flex-wrap: wrap; align-items: center; gap: 0.7rem; }
.rc-picker .label { color: var(--muted); font-size: 0.8rem; }
.rc-hint { margin: 0 0 0.4rem; font-size: 0.8rem; color: var(--muted); }
.rc-choice { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.8rem; }
.rc-error { color: var(--danger); font-size: 0.8rem; }
.edit-error {
  color: var(--danger);
  font-size: 0.8rem;
  display: inline-block;
  margin-left: 0.6rem;
}
.edit-error:empty { display: none; }
.recap td { font-size: 0.8rem; }
.recap-hint { margin: 0 0 0.5rem; font-size: 0.8rem; color: var(--muted); }

/* Row-edit cell: the member's identity stays visible while choosing a
   session, so the admin never edits a nameless row. */
.edit-member {
  display: block;
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--ink);
  margin-bottom: 0.45rem;
}

/* Accessible-only label (the edit select has a visible role via context) */
.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;
}

/* Undo stays on the row's action line: inline, not a stacked block */
td.actions form { display: inline; }

.badge {
  display: inline-block; font-size: 0.7rem; padding: 0.15rem 0.5rem;
  border-radius: 999px; background: var(--card-raised); color: var(--ink-soft);
  border: 1px solid var(--line);
  margin-right: 0.4rem;
}

/* =========================================================================
   Buttons — solid brand fill for primary submit, quiet outline otherwise.
   ========================================================================= */
button {
  font: inherit;
  padding: 0.4rem 0.85rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  background: var(--card);
  color: var(--ink-soft);
  cursor: pointer;
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease), transform 0.1s var(--ease);
}
button:hover { background: var(--card-raised); border-color: var(--muted); }
button:active { transform: translateY(1px); }
button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
button:disabled { opacity: 0.6; cursor: wait; }
button[type="submit"]:not(.link) {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 600;
}
button[type="submit"]:not(.link):hover { background: var(--accent-deep); border-color: var(--accent-deep); }

select {
  font: inherit;
  padding: 0.4rem 0.6rem;
  max-width: 420px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--ink);
}
select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* =========================================================================
   Login form
   ========================================================================= */
.login-form { max-width: 340px; display: grid; gap: 0.9rem; margin-top: 1.2rem; }
.field { display: grid; gap: 0.3rem; }
.field input {
  font: inherit;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--ink);
  transition: border-color 0.15s var(--ease);
}
.field input:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-pale);
}

/* =========================================================================
   Guest landing + login panels — the roster sits behind roles, so the
   landing page is pure brand + CTA, and the login page splits the member
   flow (email + member password) from the staff flow (password only).
   ========================================================================= */
.home-hero {
  max-width: 520px;
  margin: 12vh auto 0;
  text-align: center;
  display: grid;
  justify-items: center;
  gap: 0.9rem;
}
.home-logo { width: 120px; height: auto; }
.home-hero h1 { margin: 0; color: var(--navy); }
.home-hero .cta {
  margin-top: 0.6rem;
  font-weight: 600;
  color: #fff;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 0.55rem 1.4rem;
  text-decoration: none;
}
.home-hero .cta:hover { background: var(--accent-deep); border-color: var(--accent-deep); }

/* Bureau block on the guest landing: public contact info (name + title
   from config.yaml), same card language as the login panels. */
.bureau {
  max-width: 520px;
  margin: 2.5rem auto 0;
  padding: 1.1rem 1.2rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.bureau h2 { margin: 0 0 0.6rem; font-size: 1.05rem; color: var(--navy); }
.bureau-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}
.bureau-name { font-weight: 600; margin-right: 0.6rem; }
.bureau-title { color: var(--muted); }

.login-panel {
  max-width: 480px;
  margin: 1.6rem 0 0;
  padding: 1.1rem 1.2rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.login-panel h2 { margin: 0 0 0.4rem; font-size: 1.05rem; color: var(--navy); }
.login-panel + .login-panel { margin-top: 1.1rem; }

/* =========================================================================
   Member toolbar (dashboard) — search input mirrors the .field focus
   treatment: no outline, accent border + pale ring on :focus-visible.
   ========================================================================= */
.member-toolbar { display: flex; margin: 0 0 1rem; }
.member-empty {
  margin: 0 0 1rem;
  padding: 0.8rem 0.9rem;
  background: var(--card-raised);
  border-radius: var(--radius-sm);
  color: var(--muted);
  font-size: 0.9rem;
}

/* Transient write-confirmation toast (role=status, auto-hidden by JS).
   Fixed to the bottom: the admin acts across a long page, so the "it
   worked" beat must land where the action happened. Flat per the system
   rule: solid card + strong hairline, no shadow. After a real move the
   toast also carries the two-click "Annuler" (ADR 0006), same intent beat
   as the recap — the flex row keeps message and action on one line. */
.save-status {
  position: fixed;
  left: 50%;
  bottom: 1.2rem;
  transform: translateX(-50%);
  z-index: 50;
  max-width: min(92vw, 420px);
  padding: 0.7rem 1.1rem;
  background: var(--card);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-md);
  color: var(--ink);
  font-size: 0.9rem;
  font-weight: 600;
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.8rem;
}
.undo-form { display: inline-flex; align-items: center; gap: 0; flex: none; }

/* Session lens chips: the table-of-contents for a 9-session page. The
   active chip uses the title navy (not the brand red — red stays the
   one action per surface). */
.session-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin: 0.9rem 0 1.1rem;
}
.session-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.8rem;
  padding: 0.3rem 0.65rem;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--card);
  color: var(--ink-soft);
}
.session-chip:hover { background: var(--card-raised); border-color: var(--muted); color: var(--accent); }
.session-chip .chip-count { color: var(--muted); font-size: 0.75rem; }
.session-chip.active {
  background: var(--navy);
  border-color: var(--navy);
  color: #fff;
  font-weight: 600;
}
.session-chip.active .chip-count { color: rgba(255, 255, 255, 0.7); }
/* The lens hides sections (search sets the hidden attribute separately;
   the two lenses compose: search only looks inside the visible lens). */
section.session-filtered { display: none; }

/* Undo two-click confirm: armed state reads as a pending action, not text */
.undo-confirm[aria-pressed="true"] { color: var(--danger); font-weight: 700; }

/* Recap action cell: the undo affordance lives beside the move it reverts */
.recap-actions { white-space: nowrap; text-align: right; }
.member-search {
  font: inherit;
  padding: 0.4rem 0.7rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--ink);
  transition: border-color 0.15s var(--ease);
  width: 100%;
  max-width: 420px;
}
.member-search:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-pale);
}

/* Standalone (non-panel) dashboard headings need breathing room:
   the global h2 margin is 0 (headings inside sections). */
.section-title { margin: 2.4rem 0 0.8rem; }

/* =========================================================================
   /stats — season dashboard: KPI cards, summary table, bar panels.
   Aggregate-only (no member names/emails), same flat card language as the
   member sections; numbers are the fact, bars are the glance (DESIGN.md
   rule — every bar carries its numeric label).
   ========================================================================= */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.8rem;
  margin: 2rem 0 0.3rem;
}
.kpi {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.85rem 1rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.kpi-label {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted);
}
.kpi-value {
  font-size: 1.9rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--navy);
  font-variant-numeric: tabular-nums;
  white-space: nowrap; /* a wrapping value clipped the trailing % on narrow cards */
}
.kpi-value small {
  font-size: 1rem;
  font-weight: 600;
  color: var(--muted);
  margin-left: 0.1rem;
  line-height: 1;
  vertical-align: baseline;
}
.kpi-sub { font-size: 0.78rem; color: var(--muted); }

/* Summary table: right-aligned numerics (tabular figures), sessions named
   in full, warning tints for over-capacity. */
.summary th.num, .summary td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap; /* "100 %" never wraps mid-value */
}
/* Subtle column rules: numeric cells in a 10-column table are hard to
   track without vertical guides. Half a step above the row hairlines. */
.summary th + th,
.summary td + td { border-left: 1px solid var(--line); }
.summary td.session-name { white-space: nowrap; }
.summary td.strong { font-weight: 700; }
.summary td.over { color: var(--danger); font-weight: 600; }
.summary .total-row td {
  border-top: 2px solid var(--line-strong);
  background: var(--card-raised);
  font-weight: 700;
}
.summary .total-row:hover td { background: var(--card-raised); }
.foot { font-size: 0.78rem; margin-top: 0.5rem; }

/* Three bar panels. The track keeps a floor (120px flex basis + min-width)
   so the Mixité bar cannot collapse to a sliver on a 375px phone — the
   lesson of the section bars (DESIGN.md). Labels truncate with a title
   tooltip; the number is always visible. */
/* minmax(0, 1fr): the default auto min-track lets a nowrap chart label
   blow the track past the container (min-content sizing); minmax(0) caps
   it, so the label ellipsizes instead and the page never scrolls wide. */
/* Observable Plot panels: server owns the data (JSON in the page), Plot
   owns the geometry. The .plot container gets the SVG at container width;
   text inherits the app font, all other colors come from the tokens. */
.plot-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
  margin-top: 1.4rem;
}
.plot-panel { margin: 0; }
.plot-wide { grid-column: 1 / -1; }
.plot { min-height: 220px; }
.plot svg { display: block; max-width: 100%; height: auto; }
.plot svg text { font-family: inherit; }
/* Chart legends (HTML, below the plot — the Plot legend ate 130px of the
   chart on phones, which is what made the mobile charts tiny). */
.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.9rem;
  margin-top: 0.5rem;
  font-size: 0.75rem;
  color: var(--muted);
}
.age-chip { display: inline-flex; align-items: center; gap: 0.35rem; }
.age-swatch { width: 10px; height: 10px; border-radius: 2px; flex: none; }
.age-swatch.mme { background: var(--mme); }
.age-swatch.msr { background: var(--msr); }
.age-swatch.age0 { background: #22315f; }
.age-swatch.age1 { background: #46548c; }
.age-swatch.age2 { background: #6d79ad; }
.age-swatch.age3 { background: #98a1c8; }
.age-swatch.age4 { background: #c3c9e1; }
.age-swatch.jour { background: var(--navy); }
.age-swatch.ad { background: var(--ad); }
.age-swatch.ext { background: var(--ext); }
.age-swatch.annulee { background: var(--msr); } /* Club Sky: distinct from the red/teal statut stack */
.age-swatch.mean { height: 3px; border-radius: 1px; background: var(--msr); }
/* Hover tooltips (Plot `tip` marks render g[aria-label="tip"]): flat per
   the design doc — card fill, hairline border, no drop-shadow (the lib
   ships one), ink text. */
.plot svg g[aria-label="tip"] path {
  filter: none;
  fill: var(--card);
  stroke: var(--line-strong);
}
.plot svg g[aria-label="tip"] text {
  font-size: 10.5px;
  font-weight: 600;
  fill: var(--ink);
}
.panel-note { font-size: 0.78rem; margin: 0.05rem 0 0.3rem; color: var(--muted); }

@media (max-width: 980px) {
  .plot-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  /* The label column is 130px on phones — the axis text scales down with it
     instead of overflowing the plot; charts get taller (their own height
     option) so bars stay readable. */
  .plot svg { font-size: 9px; }
}

/* "À retenir": computed season facts, as list items with a red rule. */
.insights {
  list-style: none;
  margin: 0.7rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.45rem;
}
.insights li {
  padding: 0.55rem 0.7rem 0.55rem 1.5rem;
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-size: 0.88rem;
}

@media (max-width: 980px) {
  .chart-grid { grid-template-columns: minmax(0, 1fr); }
}
