/* Nautelia: the single stylesheet. Tokens from the prototype, defined ONCE here
   (skill nautelia-ui-ux). Only use tokens that exist: lib/__tests__/styles.test.js
   fails on an undefined var(--x). Bump ?v= in the pages when this file changes. */

:root {
  --bg: #0B0F19;
  --panel: #131A2A;
  --panel-2: #1A2336;
  --activity: #9AA6BD;   /* an activity's colour, set per element from the API (safeColor); neutral here */
  --accent: var(--orange);    /* the eyebrow and the counts: a club may set its own (Henar, 13-oct) */
  --heading: var(--text);     /* the section title: likewise */
  --side: #0E1320;      /* the shell's side bar and tab bar (Claude Design, 28-sep) */
  --line: rgba(255, 255, 255, 0.10);
  --text: #F4F4F2;
  --text-dim: #9AA6BD;
  --orange: #FF4B12;
  --blue: #2979FF;
  --green: #28A96B;
  --amber: #E0A33E;
  --red: #E5484D;   /* a red, far from the brand orange (Estela, 2-oct: orange only for buttons and titles) */
  --ink: #0A0A0A;
  --radius: 8px;
  --tap: 48px;
  --tap-secondary: 44px;
  --font-body: 'DM Sans', system-ui, sans-serif;
  --font-display: 'Barlow', 'DM Sans', system-ui, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, monospace;
}

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

body {
  margin: 0;
  background-color: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: 740px; margin: 0 auto; padding: 0 16px 80px; }
/* The login and the club's page (Estela, 13-oct: «un form en condiciones»): a narrow centred card, the logo and the
   title above it, every way in one under the other, every button as wide and as tall as the others. */
.wrap.auth { max-width: 440px; margin: 0 auto; padding-top: 6vh; }
.auth .brand { justify-content: center; }
.auth h1 { text-align: center; margin: 8px 0 20px; }
.auth__card { display: flex; flex-direction: column; gap: 14px; padding: 24px; border: 1px solid var(--line);
  border-radius: 16px; background-color: var(--panel); }
.auth__card .meta { text-align: center; margin: 0; }
.auth .actions { display: block; margin: 0; }
.auth .btn { width: 100%; min-height: 52px; justify-content: center; }
.auth__form { display: flex; flex-direction: column; gap: 10px; margin: 0; }
.auth__or { display: flex; align-items: center; gap: 12px; margin: 4px 0 0; text-align: center; color: var(--text-dim);
  font-size: 13px; }
.auth__or::before, .auth__or::after { content: ""; flex: 1; border-top: 1px solid var(--line); }
h1, h2 { font-family: var(--font-display); font-weight: 900; text-transform: uppercase; margin: 0; }
h1 { font-size: 26px; }
h2 { font-size: 15px; letter-spacing: 0.04em; }
.meta { font-size: 14px; color: var(--text-dim); margin: 4px 0 0; }
.mono { font-family: var(--font-mono); }
[hidden] { display: none !important; }

/* Brand */
.brand { display: flex; align-items: center; gap: 10px; padding: 16px 0 12px; }
.brand__word { font-family: var(--font-display); font-weight: 900; font-size: 26px; line-height: 0.85; letter-spacing: -0.025em; }
.brand__word span { color: var(--orange); }
/* A club's logo (13-oct, ADR-0012) in the mark's place and box: the mark's 36 px high, its own width, never deformed */
.brand__logo { display: block; height: 64px; width: auto; max-width: 100%; object-fit: contain; }

/* Buttons: same base per level, only the colour changes */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; min-height: var(--tap); padding: 12px 16px;
  border: 1px solid transparent; border-radius: var(--radius);
  background-color: var(--orange); color: var(--ink);
  font-family: var(--font-body); font-size: 15px; font-weight: 700; cursor: pointer; text-decoration: none;
}
/* ONE component paints them, Action (app/views.js; plan buttons, Estela 6-oct), with four kinds: primary
   (.btn, orange filled), neutral (grey), danger (red, the same everywhere; it always asks first) and toggle
   (an orange border). Nothing that removes, cancels or deletes is orange. */
.btn--neutral {
  min-height: var(--tap-secondary); font-size: 14px;
  background-color: transparent; color: var(--text); border-color: var(--line);
}
.btn--neutral[aria-pressed="true"] { border-color: var(--blue); }   /* "Editar" while its card is open, like a pressed chip */
.btn--danger { background-color: transparent; color: var(--red); border-color: var(--red); }
.btn--toggle { background-color: transparent; color: var(--orange); border-color: var(--orange); }
/* With an icon (Ver, Editar, Quitar/Baja/Borrar): a phone shows the icon alone in 44 x 44 and keeps the word for
   the screen reader (visually hidden, never display: none); from 600 px the word alone (Estela, 6-oct). */
.btn__icon { flex: none; display: block; }
.btn--icon { min-width: var(--tap-secondary); min-height: var(--tap-secondary); padding-left: 0; padding-right: 0; }
.btn--icon .btn__label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
@media (min-width: 600px) {
  .btn--icon { min-width: 0; padding-left: 14px; padding-right: 14px; }
  .btn--icon .btn__label { position: static; width: auto; height: auto; overflow: visible; clip: auto; }
  .btn--icon .btn__icon { display: none; }
}
.btn[disabled] { opacity: 0.45; cursor: not-allowed; }
/* On its way: a pressed button keeps its own words or icon and its colour, only dimmed, until the
   action ends (Estela, 30-sep: the busy words laid over it looked blurred; one look for every button). */
.btn.is-busy, .btn.is-busy[disabled] { opacity: 0.5; cursor: progress; }
.field.is-busy { opacity: 0.6; cursor: progress; }
.actions { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.block__foot { display: flex; flex-direction: column; }   /* a block's last line: its text, then its button */
/* Estela, 6-oct: "esos botones tan grandes no los hagas, queda feísimo". Full width only on a phone; from 600 px a
   button takes its own width and the buttons of a block sit in a row (the side bar's "Salir" keeps its card's width). */
@media (min-width: 600px) {
  .btn { width: auto; }
  .actions { flex-direction: row; flex-wrap: wrap; align-items: center; }
  /* Mi perfil: the last line's text on the left and its button on the right, every button as wide (Estela, 7-oct). */
  .block__foot { flex-direction: row; justify-content: space-between; align-items: center; gap: 24px; }
  .block__foot .actions { margin-top: 0; flex: none; }
  .block__foot .btn { width: 13rem; }
  .side__user .btn { width: 100%; }
}

/* Chips (filters, person selector) */
.chips { position: relative; display: flex; gap: 8px; overflow-x: auto; padding: 12px 0 4px; }   /* relative: its chips' offsetLeft is within it */
.chip {
  flex: none; display: inline-flex; align-items: center; gap: 8px;
  min-height: var(--tap-secondary); min-width: var(--tap-secondary); justify-content: center; padding: 10px 14px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background-color: transparent; color: var(--text-dim);
  font-family: var(--font-body); font-size: 14px; cursor: pointer; text-decoration: none;
}
/* "Volver": a small link, not a box (Estela, 29-sep) */
.chip.back { border: none; background: transparent; background-color: transparent; padding: 4px 0; min-height: 0; font-size: 14px; color: var(--text-dim); }
.chip.back::before { content: "‹ "; }
.chip[aria-pressed="true"] { color: var(--text); border-color: var(--blue); }
.chip__dot { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }

/* Session card */
.day { margin-top: 20px; }
.day__head { font-family: var(--font-display); font-weight: 900; font-size: 15px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--orange); padding-bottom: 8px; border-bottom: 1px solid var(--line); }
.day__head { display: flex; align-items: center; gap: 10px; }   /* the date, then «Hoy» (Estela, 13-oct) */
.day__date { color: var(--heading); }   /* like a title, so «Hoy» in the accent stands out (Estela, 13-oct) */
.day__tag { margin-left: 0; font-family: var(--font-body); font-size: 12px; letter-spacing: 0.08em; }
.card {
  display: block; margin-top: 10px; padding: 14px 16px; min-height: var(--tap);
  background-color: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  color: var(--text); text-decoration: none;
}
/* "Finalizada": a past day's session, shown like the rest with this tag (Estela, 30-sep) */
.hero__meta { margin-top: 8px; }   /* the level under the activity (Estela, 30-sep) */
/* "Tienes plaza" top right (Estela, 30-sep): over the seats and over the buttons; not in the detail,
   where being in the list says it. */
.hero__side { flex: none; }
.card__side, .hero__side, .booking__side { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; text-align: right; }
.card__side > .state, .booking__tags > .state { margin-top: 0; }
.booking__tags { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; }   /* "Tienes plaza", then "Finalizada" under it (Estela, 30-sep) */
/* A one-off session (Estela, 1-oct): "Puntual · Regata", a square blue label (not the prototype's amber). */
.tag-one-off, .tag-partner { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 4px; font-size: 13px; color: var(--blue); background-color: rgba(41, 121, 255, 0.14); border: 1px solid; border-color: var(--blue); }   /* "Puntual" and "Socio" (2-oct: blue; the orange is for buttons and titles) */
/* «Pago pendiente» (dirección's, payments P1, 12-oct): amber like the demo's note; "De baja" in Pagos: grey. */
.tag-payment, .tag-inactive { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 4px; font-size: 14px; white-space: nowrap; }
.tag-payment { color: var(--amber); background-color: rgba(224, 163, 62, 0.14); border: 1px solid; border-color: var(--amber); }
.tag-inactive { color: var(--text-dim); background-color: var(--panel-2); border: 1px solid; border-color: var(--line); }
.tag-own { display: inline-flex; align-items: center; margin-top: 4px; padding: 2px 8px; border-radius: 4px; font-size: 13px; color: var(--green); background-color: rgba(40, 169, 107, 0.14); border: 1px solid; border-color: var(--green); }   /* the logbook's own sessions (1-oct) */
.card__when, .card__title { display: flex; flex-wrap: wrap; align-items: center; column-gap: 10px; row-gap: 4px; }   /* "Sábado 3 oct  10:00", then "REMO  [Puntual · Regata]" (Estela, 1-oct) */
.tag-finished { display: inline-flex; align-items: center; padding: 3px 10px; border-radius: var(--radius);
  border: 1px solid var(--text-dim); background-color: var(--text-dim); color: var(--bg);   /* solid, it must be seen (30-sep) */
  font-family: var(--font-display); font-weight: 900; font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; }
.tag-cancelled { border-color: var(--red); background-color: var(--red); color: #fff; }   /* solid red, it must be seen (1-oct) */
.card { position: relative; }
.card::after { content: "›"; position: absolute; top: 10px; right: 14px; color: var(--text-dim); font-size: 18px; }   /* like the prototype (30-sep) */
.card__top { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; padding-right: 18px; }
.card__meta { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 8px; font-size: 13px; color: var(--text-dim); }
.card__meta b { color: var(--text); font-weight: 600; }
.card__time { font-family: var(--font-display); font-weight: 900; font-size: 22px; }
.card__activity { font-size: 14px; text-transform: uppercase; letter-spacing: 0.05em; }
.bar { height: 7px; margin-top: 10px; border-radius: 4px; overflow: hidden; display: flex; background-color: var(--line); }   /* translucent: seen on any card */
.bar__full { background-color: var(--blue); }
.bar__pending { background-color: var(--amber); }

/* Tones: one map (lib/copy.js bookingStates), four tones */
.tone-ok { color: var(--green); }
.tone-warn { color: var(--amber); }
.tone-risk { color: var(--red); }
.tone-info { color: var(--blue); }
.state { font-weight: 700; font-size: 15px; margin-top: 8px; }
/* The day's forecast: its activities as pills in THEIR colour (--activity, from the
   API through safeColor). The risk is one tag for the whole day (Estela, 28-sep). */
.pill { display: inline-flex; align-items: center; padding: 6px 14px; border-radius: 20px;
  color: var(--activity); background-color: color-mix(in srgb, var(--activity) 16%, transparent); font-size: 15px; }
/* A state as a tinted pill, after the plain one so it wins (Estela, 1-oct, the prototype's licence states): green, amber, red. */
.pill--ok { color: var(--green); background-color: rgba(40, 169, 107, 0.14); border: 1px solid; border-color: var(--green); }
.pill--warn { color: var(--amber); background-color: rgba(224, 163, 62, 0.14); border: 1px solid; border-color: var(--amber); }
.pill--risk { color: var(--red); background-color: rgba(229, 72, 77, 0.14); border: 1px solid; border-color: var(--red); }
.licences .pill { white-space: nowrap; margin-left: auto; }   /* on the name's line, pulled right (Estela, 1-oct) */
.licences .row > div:first-child { flex-grow: 1; min-width: 0; }

/* Blocks, lists, notices */
.block { margin-top: 14px; padding: 14px 16px; background-color: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); }
.row { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 10px 0; border-top: 1px solid var(--line); }
.row:first-child { border-top: none; }
.notice { display: flex; gap: 10px; padding: 12px 0; border-top: 1px solid var(--line); }
.notice:first-child { border-top: none; }
.notice--unread strong { color: var(--text); }
/* Unread (Estela, 29-sep): a small orange dot before it and the text bright; read ones stay grey.
   (An orange edge first: "sale un poco feo".) */
.notice { align-items: baseline; }
.notice--unread::before { content: ""; flex: none; width: 8px; height: 8px; border-radius: 50%; background-color: var(--orange); transform: translateY(-1px); }
.notice--unread .meta { color: var(--text); }
.page-head__action { margin-left: auto; }   /* a page's own button on its title's line (Avisos) */
.page-head__action .btn { width: auto; }
/* A count on a nav link and beside its title (the unread notices) */
.badge { display: inline-flex; align-items: center; justify-content: center; min-width: 22px; height: 22px; padding: 0 7px;
  margin-left: 8px; border-radius: 11px; background-color: var(--accent); color: var(--ink); font-size: 13px; font-weight: 700; line-height: 1; }
.field { width: 100%; min-height: var(--tap); padding: 12px; border: 1px solid var(--line); border-radius: var(--radius); background-color: var(--panel-2); color: var(--text); font-family: var(--font-body); font-size: 16px; }

/* The route map: SVG at once, OpenFreeMap's dark style when MapLibre loads (phase 5; 2-oct). The credit, ours,
   always visible over the map's corner. */
.map { position: relative; margin-top: 10px; height: 220px; border-radius: var(--radius); overflow: hidden; background-color: var(--panel-2); }
.map .route { width: 100%; height: 100%; display: block; }
.route { color: var(--text); }   /* the SVG route's marks (currentColor): the text's colour, any theme */
.map__attribution { position: absolute; right: 0; bottom: 0; z-index: 2; padding: 2px 6px; border-top-left-radius: 4px;
  background-color: rgba(11, 15, 25, 0.75); color: var(--text-dim); font-size: 11px; line-height: 1.4; }
.map__attribution a { color: var(--text-dim); }

/* Logbook: the numbers and the bars (phase 5) */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr)); gap: 10px; margin-top: 14px; }
.stat { display: flex; flex-direction: column; padding: 12px; background-color: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); }
.stat strong { font-family: var(--font-display); font-size: 22px; }
.stat--link { color: inherit; text-decoration: none; border-color: var(--amber); }   /* "Cosas que mirar": to Por resolver (Estela, 1-oct) */
.stat--link .meta { color: var(--amber); }
.stat--risk { border-color: var(--red); }   /* to "En riesgo de no salir", red like its table (Estela, 1-oct) */
.stat--risk .meta { color: var(--red); }
/* The logbook like the prototype (Estela, 1-oct): km per session as rows (date, bar, km); a small route drawing */
.kmbars__row { display: flex; align-items: center; column-gap: 10px; padding: 4px 0; }
.kmbars__day { width: 52px; flex: none; font-size: 13px; color: var(--text-dim); }
.kmbars__track { flex-grow: 1; height: 10px; border-radius: 4px; overflow: hidden; background-color: var(--panel-2); }
.kmbars__track i { display: block; height: 100%; background-color: var(--blue); }
.kmbars__km { width: 42px; flex: none; text-align: right; font-size: 13px; }
.route--thumb { display: block; flex: none; width: 140px; height: auto; border-radius: 8px; background-color: var(--panel-2); }   /* on the right of its row, small (1-oct) */
/* Your sessions: one column on a phone, two on a desktop (Estela, 2-oct); a line between cells */
.logbook__rows { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: 32px; }
.logbook__cell { border-top: 1px solid var(--line); }
.logbook__cell:first-child { border-top: none; }
.logbook__cell .row { border-top: none; }
@media (min-width: 900px) {
  .logbook__rows { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .logbook__cell:nth-child(2) { border-top: none; }
}
.logbook__more { display: flex; justify-content: center; margin-top: 14px; }   /* out of the block, centred (1-oct) */

/* A line-up row: name, seat selector (takes the room left), save */
.seat { flex-wrap: wrap; }
.seat select { flex: 1 1 9rem; min-width: 0; width: auto; }

/* Toast: role="status", written to AFTER it is shown */
.toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  top: calc(16px + env(safe-area-inset-top, 0px)); width: min(92vw, 460px);   /* at the top (Estela, 29-sep) */
  padding: 14px 16px; background-color: var(--panel-2); border: 1px solid var(--blue); border-radius: var(--radius);
  font-size: 15px; z-index: 50;
}

/* Day cards (plan responsive, step 2): one per day, scroll sideways on mobile */
.daycards { position: relative; display: flex; gap: 8px; overflow-x: auto; padding: 2px 0 6px; flex: 0 1 auto; min-width: 0; }   /* › right after Sunday */
/* The seven days, "MIÉ 30 SEP" and nothing else, square like the filters (Estela, 30-sep); a 44 px tap target. */
.daycard { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; min-height: var(--tap);
  padding: 0 14px; border: 1px solid var(--line); border-radius: var(--radius); background-color: var(--panel);
  color: var(--text); font-family: var(--font-body); cursor: pointer; }
.daycard[aria-pressed="true"] { border-color: var(--blue); background-color: var(--panel-2); }
.daycard__day { font-family: var(--font-display); font-weight: 900; font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-dim); }
.daycard__date { display: flex; align-items: baseline; gap: 6px; }   /* "MIÉ 30 SEP" on one line */
.daycard__day--today { color: var(--orange); }
.daycard__num { font-family: var(--font-display); font-weight: 900; font-size: 15px; line-height: 1; }
.daycard[aria-pressed="true"] .daycard__day { color: inherit; }
/* The week's pills (Estela, 13-oct, the CNF's guide): "MIÉ" over "30" at every width, no month (the day's title
   under them says it), the seven as wide as each other, the chosen one filled. A phone: each a seventh, narrow. */
.weeknav .daycard[aria-pressed="true"] { border-color: var(--orange); background-color: var(--orange); color: var(--ink); }
.weeknav .daycards { flex: 1 1 auto; justify-content: center; gap: 4px; overflow-x: visible; }
.weeknav .daycard { flex: 1 1 0px; min-width: 0; max-width: 44px; padding: 4px 0; }   /* narrow (Estela, 30-sep) */
.weeknav .daycard__date { flex-direction: column; align-items: center; gap: 2px; }
.weeknav .daycard__day { font-size: 11px; letter-spacing: 0.02em; }
.weeknav .weeknav__arrow { min-width: 32px; padding-left: 0; padding-right: 0; }   /* no wider than a day on a phone */
@media (min-width: 600px) {
  .weeknav .daycards { gap: 8px; }
  .weeknav .daycard { max-width: none; min-height: 60px; padding: 6px 0; }
  .weeknav .daycard__date { gap: 4px; }
  .weeknav .daycard__day { font-size: 13px; letter-spacing: 0.06em; }
  .weeknav .daycard__num { font-size: 20px; }
  .weeknav .weeknav__arrow { min-height: 60px; min-width: var(--tap-secondary); padding-left: 14px; padding-right: 14px; }
}
.weather--line .state { font-size: 13px; white-space: nowrap; }   /* "No recomendado" on one line (Estela, 29-sep) */

/* ==== The responsive shell (Claude Design handoff, 28-sep; plan responsive, step 1) ====
   Mobile first: a header with the brand and "Salir", and the nav in a tab bar
   fixed at the bottom. From 900 px: a 280 px side bar with the nav and the user
   card. Both navs are painted by app/main.js from the table's ONE nav(). */
.shell { min-height: 100vh; }
.shell > main { padding: 16px 16px calc(96px + env(safe-area-inset-bottom, 0px)); min-width: 0; }
.side { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 16px 12px; border-bottom: 1px solid var(--line); background-color: var(--side); }
.side .brand { padding: 0; }
.side__nav, .side__user { display: none; }
.side__logout-mobile { width: auto; min-height: var(--tap-secondary); padding: 8px 14px; }

.tabbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; display: flex;
  background-color: var(--side); border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom, 0px); }
.tabbar a { flex: 1 1 0; min-width: 0; min-height: 60px; display: flex; align-items: center; justify-content: center;
  padding: 6px 4px; border-top: 3px solid transparent; color: var(--text-dim); font-size: 14px; text-decoration: none; }
.tabbar a[aria-current="page"] { color: var(--text); font-weight: 700; border-top-color: var(--orange); }
/* "Más" (Estela, 1-oct: dirección's 7 tabs did not fit): a tab like the others, its sheet above the bar */
.tabbar__more { flex-grow: 1; flex-shrink: 1; flex-basis: 0; min-width: 0; min-height: 60px; display: flex; align-items: center; justify-content: center; gap: 4px;
  padding: 6px 4px; border: none; border-top: 3px solid transparent; background-color: transparent; color: var(--text-dim);
  font: inherit; font-size: 14px; cursor: pointer; }
.tabbar__more[aria-current="page"], .tabbar__more[aria-expanded="true"] { color: var(--text); font-weight: 700; border-top-color: var(--orange); }
.tabbar__sheet { position: fixed; left: 0; right: 0; bottom: calc(63px + env(safe-area-inset-bottom, 0px)); z-index: 41;
  display: flex; flex-direction: column; background-color: var(--side); border-top: 1px solid var(--line); box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.4); }
.tabbar__sheet a { min-height: 52px; display: flex; align-items: center; justify-content: space-between; padding: 0 20px;
  border-bottom: 1px solid var(--line); color: var(--text); text-decoration: none; }
.tabbar__sheet a[aria-current="page"] { color: var(--orange); font-weight: 700; }
/* The phone's tab bar like the CNF's guide (Estela, 13-oct, for every club): the icon above a short label, the count
   on the icon's corner, and the current tab marked by a short bar under its label. */
.tabbar a, .tabbar__more { position: relative; flex-direction: column; gap: 4px; border-top: none; font-size: 13px; }
.tabbar .nav-icon { display: block; }
.tabbar a[aria-current="page"], .tabbar__more[aria-current="page"], .tabbar__more[aria-expanded="true"] { color: var(--text); }
.tabbar a[aria-current="page"]::after, .tabbar__more[aria-current="page"]::after {
  content: ""; width: 22px; height: 3px; border-radius: 2px; background-color: var(--orange); }
.tabbar .badge { position: absolute; top: 4px; left: calc(50% + 4px); margin: 0; min-width: 18px; height: 18px; padding: 0 5px;
  font-size: 11px; }

/* The page head: role tag + section title, and its line */
.page-head { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.page-head__row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.role-tag { padding: 5px 10px; border: 1px solid var(--line); border-radius: var(--radius);
  background-color: var(--panel-2); font-family: var(--font-display); font-weight: 900;
  font-size: 15px; letter-spacing: 0.08em; text-transform: uppercase; }
.page-head .meta { font-size: 15px; margin: 0; }
/* A section page (Estela, 13-oct, from the CNF's guide): who it is for, small and in the accent, above the section as
   the big title. Our fonts; only the sizes of the two lines swap. */
.page-head--section { gap: 4px; }
/* A menu link's icon: hidden but in the desktop side bar (the media query below). */
.nav-icon { display: none; width: 22px; height: 22px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round; }
.pagetop { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; }   /* the title | today and the bell */
.pagetop > .page-head { flex: 1 1 auto; min-width: 0; }
.todo__hint { margin: -4px 0 8px; }   /* where a group of Avisos comes from (Estela, 13-oct: «que se distinga») */
.topbar { display: none; }   /* a phone: the tab bar has Avisos and its count */
.topbar__date { color: var(--text-dim); font-size: 15px; }
.topbar__bell { position: relative; display: inline-flex; align-items: center; justify-content: center; min-width: 48px;
  min-height: 48px; border: 1px solid var(--line); border-radius: var(--radius); color: var(--heading); }
.topbar__bell .badge { position: absolute; top: -8px; right: -10px; margin: 0; }
.page-head__eyebrow { margin: 0; font-size: 12px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--accent); }
.page-head--section h1 { color: var(--heading); }

@media (min-width: 900px) {
  .shell { display: grid; grid-template-columns: 300px minmax(0, 1fr); }   /* a little wider (Estela, 13-oct) */
  .side { position: sticky; top: 0; height: 100vh; overflow-y: auto; flex-direction: column; align-items: stretch;
    justify-content: flex-start; gap: 22px; padding: 24px 16px; border-bottom: none; border-right: 1px solid var(--line); }
  .side__logout-mobile, .tabbar, .tabbar__sheet { display: none; }
  .side__nav { display: flex; flex-direction: column; gap: 2px; }
  .side__nav .nav-icon { display: block; }   /* the icons: the desktop side bar only (Estela, 13-oct) */
  /* Today and the bell (Estela, 13-oct, the CNF's guide): on the title's line, at its right; no bar of their own. */
  .topbar { display: flex; align-items: center; gap: 16px; margin-left: auto; }
  .topbar .nav-icon { display: block; }
  .side__nav a { display: flex; align-items: center; gap: 10px; min-height: var(--tap-secondary);
    padding: 10px 14px; border-radius: var(--radius); color: var(--text-dim); font-size: 15px; text-decoration: none; }
  .side__nav a[aria-current="page"] { background-color: var(--panel-2); color: var(--text); }
  /* Bigger, with its icon (Estela, 13-oct, from the CNF's guide, for every club). */
  .side__nav a { gap: 12px; min-height: 52px; padding: 12px 16px; font-size: 17px; }
  .side__user { display: flex; flex-direction: column; gap: 10px; margin-top: auto; padding: 14px;
    background-color: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); }
  .side__who { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; }   /* name and role, one line (Estela, 30-sep) */
  .shell > main { padding: 28px 36px 60px; }
  .page-head h1 { font-size: 34px; }
}

/* List + detail at once (plan responsive, step 3): the detail route paints both;
   under 1180 px the detail replaces the list, with its back link. */
.split__list { display: none; }
.split--pick .split__list { display: block; }
.split--pick .split__detail { display: none; }
.wide-only { display: none; }   /* the calendar above a session detail: only beside it, from 1180 px */
.card[aria-current="true"] { border-color: var(--blue); background-color: var(--panel-2); }
@media (min-width: 1180px) {
  .split { display: flex; gap: 28px; align-items: flex-start; }
  .split__list { display: block; flex: 0 1 460px; min-width: 0; }
  .split__detail { flex: 1 1 0; min-width: 0;   /* its own height, no scroll of its own: the page scrolls (Estela, 28-sep) */
    padding: 20px 22px; background-color: var(--side); border: 1px solid var(--line); border-radius: 12px; }
  .split__detail .back { display: none; }
  .split__list > .day:first-child, .split__list > .day:first-child > .card:first-child { margin-top: 0; }   /* list and detail start level */
  .split--pick .split__detail { display: block; }
  .wide-only { display: block; }
}

/* Attendance: Está / Falta, three states (plan responsive, step 4). The pressed
   one is what the API has; neither pressed is "not marked yet". */
.block__head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
/* A block's button in its head (Licencias, Estela 1-oct): a phone, under the title, centred; a wide
   screen, beside it, right. Only heads with a button: Apuntados keeps its "x de y" beside the title. */
.licences .block__head h2 { flex-basis: 100%; }
.block__head .btn { margin-left: auto; margin-right: auto; }
@media (min-width: 600px) {
  .licences .block__head h2 { flex-basis: auto; }
  .block__head .btn { margin-right: 0; }
}
.block__head + .row { border-top: none; }
/* Mis datos (Estela, 30-sep: "no es responsive"): on a phone the label over its value, the pills
   wrap; from 600 px, side by side as before. */
.profile .row { flex-direction: column; align-items: flex-start; gap: 4px; }
.profile .chips { flex-wrap: wrap; overflow-x: visible; padding: 4px 0; }
.profile .plans { display: flex; flex-direction: column; gap: 8px; }   /* one line per activity paid (Estela, 1-oct) */
.profile .plan { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }
@media (min-width: 600px) {
  .profile .row { flex-direction: row; align-items: center; gap: 10px; }
  .profile .row > :last-child { text-align: right; }
  .profile .chips { justify-content: flex-end; }
  .profile .plans { align-items: flex-end; }
}
/* Mensajes (Estela, 29-sep): who and about what, the text, and the reply on one line */
.message { padding: 12px 0; border-top: 1px solid var(--line); }
.message:first-child { border-top: none; padding-top: 0; }
.message__text { margin: 8px 0 10px; }
.reply { display: flex; gap: 10px; align-items: stretch; }
.reply .field { flex: 1 1 auto; min-width: 0; margin: 0; }
.reply .btn { width: auto; flex: none; }
.person { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; min-width: 0; }   /* name and level on one line */
.person .meta { margin: 0; }
.profile__fix { margin-top: 32px; }   /* Mi perfil's last line, apart from the WhatsApp blocks (Estela, 7-oct) */
.person__extra { flex-basis: 100%; }   /* the guardian, below */   /* no line under the title (Estela, 29-sep) */
/* Inicio (Estela, 29-sep): one booking per row, what it is on the left, its action on the right. */
.bookings { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }
.bookings .card { margin-top: 0; }
/* Mis sesiones on a big screen: two per row (Estela, 30-sep); a phone keeps one column. */
@media (min-width: 1180px) { .bookings { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.bookings__item { display: flex; flex-direction: column; gap: 10px; }
.bookings__item > .card { flex: 1; }
/* An Inicio row (Estela, 29-sep): the date and its state on one line; the activity with the
   button on its right (no hole under it); then the sea. The link's rows sit in the card's grid. */
.booking { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px; row-gap: 6px; align-items: center; }
.booking__main { display: contents; color: inherit; text-decoration: none; }
.booking__main > * { grid-column: 1; }   /* the right column is the state and the buttons (30-sep) */
.booking .card__meta { flex-direction: column; gap: 2px; }   /* a phone: one fact per line, every card alike */
@media (min-width: 600px) { .booking .card__meta { flex-direction: row; gap: 4px 14px; } }
.booking__main > .booking__title { grid-column: 1; grid-row: 2; }
.booking__when { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; min-width: 0; }   /* "Finalizada" drops a line on a phone, never under the state (Estela, 30-sep) */
.booking__when .eyebrow { white-space: nowrap; }
.booking__title { display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px; }
.booking__info { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 14px; }
.booking__main .state, .booking__main .weather { margin-top: 0; }
.booking__side { grid-column-start: 2; grid-row-start: 1; grid-row-end: span 3; align-self: stretch; justify-content: space-between; }   /* state on top, buttons on the last line (Estela, 30-sep) */   /* longhands: jsdom reads no grid shorthand */
.booking__actions { display: flex; gap: 8px; }
.card.booking::after { content: none; }   /* "Ver" is its own button (Estela, 30-sep) */
.booking .weather--line .meta { font-size: 13px; }   /* a phone: "Se sale" beside the gusts (Estela, 29-sep) */
/* A phone (Estela, 29-sep): the row's buttons are their icons (Action's .btn--icon, plan buttons). */
@media (min-width: 600px) {
  .booking .weather--line .meta { font-size: 14px; }
}
.attend { display: flex; gap: 8px; }
/* A past day: not dimmed, the same as any other; its "Finalizada" tag says it (Estela, 3-oct; it was muted, 29-sep). */
.attend .btn { width: auto; min-width: 64px; }
/* Está / Falta are grey; marked, they take their state's soft colour, like its pill (Estela, 6-oct: never like an action). */
.attend .btn[aria-pressed="true"][data-value="true"] { border-color: var(--green); color: var(--green); background-color: rgba(40, 169, 107, 0.14); }
.attend .btn[aria-pressed="true"][data-value="false"] { border-color: var(--red); color: var(--red); background-color: rgba(229, 72, 77, 0.14); }

/* Cards that fit the width by themselves: one column on a phone, three on a wide screen */

/* The week navigator: ‹ 28 sep – 4 oct › (Estela, 28-sep) */
.daycard--empty { opacity: 0.45; cursor: default; }   /* a day with nothing: there, but off (Estela, 30-sep) */
.weeknav { display: flex; align-items: center; gap: 4px; margin: 20px 0 18px; }   /* room above and below (Estela, 13-oct: «dale espacios») */   /* ‹ the seven days › (Estela, 30-sep) */
@media (min-width: 600px) { .weeknav { gap: 8px; } }
.weeknav .daycards { margin: 0; padding: 0; }
.weeknav__arrow { flex: none; }
/* A week not open yet: when it opens, under the navigator (Estela, 30-sep) */
.week-closed { margin: 6px 0 0; color: var(--amber); }
/* The week's chosen classes used: a notice that shows, next to the disabled button (Estela, 30-sep) */
/* A notice in its sentence: «Ya tienes…» and «Tus plazas … se abren» (Estela, 13-oct: the bare line looked like a bug). */
.weekly-full, .next-week-opens { margin: 0; padding: 10px 14px; border-left: 4px solid var(--amber); border-radius: 8px; background-color: rgba(224, 163, 62, 0.12); color: var(--amber); font-weight: 600; }
.chip:disabled { opacity: 0.4; cursor: default; }

/* Parte del día (Estela, 1-oct, the prototype): the number big on top, the label in capitals, no block around. */
.stats--big { grid-template-columns: repeat(2, 1fr); gap: 10px; margin: 0 0 16px; }
.stats--big .stat { padding: 16px 18px; gap: 6px; }
.stats--big .stat strong { font-size: 30px; line-height: 1; }
.stats--big .stat .meta { text-transform: uppercase; letter-spacing: 0.06em; font-size: 13px; }
@media (min-width: 600px) { .stats--big { grid-template-columns: repeat(4, 1fr); } }
.stats--three { grid-template-columns: repeat(3, 1fr); }   /* Licencias: its three in one line, a phone too (Estela, 1-oct) */
.stats--three .stat { padding: 14px 12px; }
.stats--three .stat .meta { font-size: 12px; letter-spacing: 0.03em; }
/* Parte del día: the day's cards two per row on a big screen, like Mis sesiones (Estela, 1-oct). */
.dayreport .day { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; margin-top: 0; }
.dayreport .day .card { margin-top: 0; }
@media (min-width: 1180px) { .dayreport .day { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Previsión (Estela, 1-oct, the prototype): the sea in a blue-edged block, one day per row; dirección's
   weather report in a red-edged one. */
.forecast__sea { border-left: 4px solid var(--blue); }
.forecast__report { border-left: 4px solid var(--red); }
.forecast > .block + .block { margin-top: 16px; }   /* the report on top, then the sea (Estela, 1-oct) */
.forecast__report h2 { color: var(--red); }
.forecast__day { padding: 14px 0; border-top: 1px solid var(--line); }
.forecast__day h3 { margin: 0 0 4px; font-size: 16px; }
.forecast__day h3::first-letter { text-transform: uppercase; }   /* "Jueves 1 oct" (the prototype) */
.forecast__day .meta { margin: 0; }
.forecast__day .chips { flex-wrap: wrap; overflow-x: visible; padding: 10px 0 6px; }
.pill--none { color: var(--text-dim); background-color: var(--panel-2); }
/* Sesiones, the fixed schedules (Estela, 1-oct): the form on one line, the cards two per row on a big screen. */
.schedules__form { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 10px; }
.schedules__form .field { flex: 1 1 9rem; min-width: 0; }
.schedules__form .btn { flex: none; margin-left: auto; }   /* always right, also alone on its line (Estela, 1-oct) */
/* Sesiones' two «Crear» forms the same shape (Estela, 15-oct: «salen feos o descolocados»): the fields in a grid that
   fills its rows, then the button on a line of its own, on the right; on a phone, the whole width. */
.schedules__create .schedules__form { display: grid; grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr)); gap: 10px; }
.schedules__create .schedules__form .btn { grid-column-start: 1; grid-column-end: -1; justify-self: stretch; margin-left: 0; }
/* From 600 px, the last column of the first row with room (Estela, 15-oct): up beside the fields, or its own line. */
@media (min-width: 600px) { .schedules__create .schedules__form .btn { grid-column-start: auto; grid-column-end: -1; justify-self: end; align-self: center; } }
.schedules__create .btn { min-width: 10.5rem; justify-content: center; }   /* both "Crear" the same width (Estela, 1-oct) */
.forecast__report .schedules__form .field { flex-grow: 1; flex-basis: 9rem; max-width: 20rem; }   /* a day picker beside its button, never the whole block (Estela, 1-oct) */
.card-section { margin-top: 32px; }   /* a titled group of cards: Sesiones' days (Estela, 1-oct), the gym's plans (6-oct) */
.card-section > .day__head { margin-top: 0; margin-bottom: 14px; }
.block + .card-section { margin-top: 48px; }   /* more room after a box: the generator, the create forms (Estela, 6-oct) */
.card-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; align-items: start; }   /* editing one never stretches its neighbour (1-oct) */
.card-grid .card { margin-top: 0; }
.card__head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.schedule .confirm-inline { margin-top: 10px; }
.card__buttons { display: flex; gap: 8px; flex: none; }
/* Editing a schedule (Estela, 1-oct): under its card, its instructor and its fixed seats */
.schedule-edit { display: flex; flex-direction: column; row-gap: 10px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line); }
.schedule-edit h3 { margin: 6px 0 0; font-size: 15px; }
.schedule-edit__label { display: flex; flex-direction: column; row-gap: 6px; font-size: 14px; color: var(--text-dim); }
.card--still::after { content: none; }   /* a card that is not a link: no "›" (Sesiones, the gym's plans) */
@media (min-width: 1180px) { .card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.btn--small { width: auto; min-height: var(--tap-secondary); padding: 8px 14px; font-size: 14px; }

/* The day's title above the list and the detail (Estela, 28-sep): room around it */
.chips + .day__head { margin-top: 18px; }
.day__head + .split, .wide-only + .split { margin-top: 14px; }
/* Sesiones' two parts (14-oct): «Horarios fijos» and «Sesiones puntuales», bigger than a weekday and in the text's colour. */
.schedules__title { margin: 28px 0 14px; }
.schedules__title h2 { margin: 0; font-family: var(--font-display); font-weight: 900; font-size: 22px; color: var(--heading); }
.schedules__title .meta { margin: 4px 0 0; }

/* The group's level (Estela, 28-sep, option C): a neutral tag with one, two or
   three dots lit; no colour, so it competes with nothing (activities, sea, notices). */

/* "Con avisos": another kind of filter, amber, a little apart from the activities (Estela, 28-sep) */

/* The session hero (Estela, 28-sep): date · time, the activity and its status,
   level and seats; confirmed/capacity big on the right; a row of small buttons. */
.hero { padding: 4px 0 0; }
.hero__top { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; }
.hero__main { min-width: 0; }
.hero__when { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }   /* the date, then "Anulada: …" */
.hero__eyebrow, .eyebrow { font-family: var(--font-display); font-weight: 900; font-size: 14px; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--text); }
.hero__title { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; margin-top: 6px; }
.hero__title h1 { font-family: var(--font-body); font-weight: 500; }   /* small, like the activity on a card */
.hero__count { flex: none; display: flex; flex-direction: column; align-items: flex-end; padding-left: 18px;
  border-left: 1px solid var(--line); }
.hero__count strong { font-family: var(--font-display); font-weight: 900; font-size: 44px; line-height: 1; }
.hero__count strong span { font-size: 22px; color: var(--text-dim); }
.hero__count .meta { margin: 6px 0 0; font-family: var(--font-display); font-weight: 900; letter-spacing: 0.1em; text-transform: uppercase; }
.hero__actions { display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 10px;
  margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--line); }
.hero__actions-main, .hero__actions-danger { display: flex; flex-wrap: wrap; gap: 10px; }
.hero { margin-bottom: 16px; }   /* room before what follows (the sea, the notices) */

/* The card's second line: the activity on the left, the level on the right (Estela, 28-sep) */
.card__row { display: flex; justify-content: space-between; align-items: center; gap: 10px; }

/* Monitor responsable, like the prototype (Estela, 28-sep): a coloured left edge
   and title, amber with no monitor, green with one; the select saves on change. */
.assign { border-left: 4px solid var(--amber); }
.assign h2 { color: var(--amber); margin-bottom: 10px; }
.assign--set { border-left-color: var(--green); }
.assign--set h2 { color: var(--green); }

/* Apuntados (Estela, 28-sep): "Meter a alguien" and its button on one line at the end of the block. */
.row .actions { flex-direction: row; align-items: center; margin-top: 0; }
/* From a tablet up, a row's buttons keep their size and their line, whatever the text beside them (Estela, 14-oct:
   «los botones los alineas»): the text wraps, never the buttons. A phone keeps its wrap (it would not fit). */
@media (min-width: 600px) { .row > .actions { flex-shrink: 0; flex-wrap: nowrap; } }
.add-find { position: relative; margin-top: 12px; }
.add-find .field { margin: 0; }
/* The matches as a dropdown under the field, only while typing (Estela, 29-sep) */
.add-results:empty { display: none; }
.add-results { position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 20; max-height: 360px; overflow-y: auto;
  padding: 4px 12px; background-color: var(--panel-2); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.45); }
.add-results .row { padding: 8px 0; }
.add-match { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }

/* The sea and the notices sit left of the hero's buttons, in their row (Estela, 28-sep) */
.hero__info { flex-grow: 1; flex-shrink: 1; flex-basis: 0; min-width: 0; }   /* takes what is left: the buttons never drop below (Estela, 29-sep) */
.hero__info .weather .meta:first-child { margin-top: 0; }
.hero__buttons { display: flex; flex-wrap: wrap; gap: 10px; margin-left: auto; }

/* The boat (Estela, 28-sep, like the prototype): babor on top, estribor below,
   row 1 at the bow (left); each taken seat in its side's colour. */
.boat { margin: 16px 0 8px; text-align: center; }
.boat__label { display: block; font-family: var(--font-mono); font-size: 14px; }
.boat__label--port { color: var(--orange); margin-bottom: 6px; }
.boat__label--starboard { color: var(--blue); margin-top: 6px; }
.boat__hull { position: relative; border: 2px solid var(--line); border-radius: 50%; padding: 22px 9% 22px 12%; }
.boat__stern { position: absolute; left: 14px; top: 50%; transform: translateY(-50%); font-family: var(--font-mono); font-size: 14px; color: var(--text-dim); }
.boat__seats { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 44px 12px; }
.boat__seat { min-height: var(--tap-secondary); display: flex; align-items: center; justify-content: center; padding: 0 4px;
  border-radius: 6px; background-color: var(--panel-2); color: var(--text-dim); font-family: var(--font-mono); font-size: 14px;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.boat__seat--port { background-color: var(--orange); color: var(--ink); }
.boat__seat--starboard { background-color: var(--blue); color: var(--ink); }
.field--small { width: auto; min-height: var(--tap-secondary); }
/* The line-up's rows (Estela, 2-oct: three selects did not fit on a phone): when Fila, Lado and Rema a do not fit
   beside the name, they wrap under it and share the width; where they fit, beside it as before. Longhands: jsdom. */
/* The line-up in columns (6-oct): the header and each row share one grid, so Fila and Lado line up. */
.lineup__head, .lineup__seat { display: grid; grid-template-columns: minmax(0, 1fr) 5.5rem 8rem; gap: 10px; align-items: center; }
.lineup__head { padding: 12px 0 4px; font-family: var(--font-mono); font-size: 12px; color: var(--text-dim); text-transform: uppercase; letter-spacing: .08em; }
.lineup__seat { padding: 10px 0; border-top: 1px solid var(--line); }
.lineup__seat select { width: 100%; min-width: 0; }
.lineup__who { min-width: 0; }
.lineup__who strong { display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }

/* A label-button (the GPX upload) that cannot be used yet: same place, dimmed (Estela, 28-sep) */
.is-disabled { opacity: 0.45; pointer-events: none; }

/* Por resolver (Estela, 28-sep, from the prototype): a coloured edge and title per kind */
.todo--warn { border-left: 4px solid var(--amber); }
.todo--warn h2 { color: var(--amber); }
.todo--risk { border-left: 4px solid var(--red); }
.todo--risk h2 { color: var(--red); }
.todo--ok { border-left: 4px solid var(--green); }   /* nothing to do there (Estela, 1-oct) */
.todo--ok h2 { color: var(--green); }
.todo .row { flex-direction: column; align-items: stretch; }   /* a phone: the text full width, the buttons in one line under it (Estela, 1-oct) */
@media (min-width: 600px) { .todo .row { flex-direction: row; align-items: center; } }
.todo .row .actions { flex-wrap: wrap; justify-content: flex-end; }
.todo .row .actions .field { flex-grow: 1; flex-basis: 8rem; min-width: 0; width: auto; }   /* Licencias: the number beside "Tramitada" */
.todo__why { flex-basis: 100%; text-align: right; font-size: 13px; }   /* why "Invitar" is off, under the buttons (Estela, 1-oct) */

/* Compact confirmation (Estela, 28-sep): the question and small Sí / No on one line */
.confirm-inline { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px 16px;
  margin-top: 12px; padding: 10px 14px; border: 1px solid var(--red); border-radius: var(--radius); background-color: var(--panel-2); }
.confirm-inline .meta { margin: 0; color: var(--text); }
.confirm-inline__buttons { display: flex; gap: 8px; margin-left: auto; }
.confirm-inline--note .meta { flex: 1 1 100%; }   /* with a note: the sentence, then the note and Sí / No below */
.confirm-inline__note { flex: 1 1 220px; width: auto; min-width: 0; margin: 0; padding: 8px 12px; }
.row .confirm-inline { margin-top: 0; }
.hero__confirm { margin-top: 12px; }
/* The verdict right after the sea line (Estela, 28-sep) */
.weather--line { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 8px; }
.weather--line .meta { margin: 0; }
.weather--line .state, .hero__when .state, .booking__when .state { margin-top: 0; }
.hero__when .state, .booking__when .state { font-size: 13px; }   /* beside the date, small like the sea's verdict (29-sep) */
/* The footer (Estela, 29-sep): the forecast's source, refresh and reach, small and apart */
.app-footer { margin-top: 40px; padding-top: 14px; border-top: 1px solid var(--line); font-size: 14px; color: var(--text-dim); }

/* Usuarios (Estela, 2-oct; "Personas" until the same day): the name opens the commitment (a button that reads as text); search and filters */
/* The search and its filters on one line that wraps (Estela, 6-oct): on a phone the search takes its line, the chips under it. */
.people__tools { display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; column-gap: 12px; row-gap: 10px; margin: 14px 0; }
.people__tools > .field { flex-grow: 1; flex-shrink: 1; flex-basis: 16rem; width: auto; }
.people__tools > .chips { flex-grow: 0; flex-shrink: 1; flex-basis: auto; min-width: 0; padding: 0; }
.people__name { display: inline-flex; align-items: center; column-gap: 6px; min-height: var(--tap-secondary); padding: 0; border: none; background-color: transparent; color: var(--text); font-family: inherit; font-size: inherit; text-align: left; cursor: pointer; }
/* It says it opens (Estela, 6-oct): a chevron that turns when open; the name underlines under the pointer. */
.people__chevron { flex: none; color: var(--text-dim); transition: transform 0.15s; }
.people__name[aria-expanded="true"] .people__chevron { transform: rotate(90deg); }
.people__name:hover strong { text-decoration: underline; }
.people__row + .people__row { border-top: 1px solid var(--line); }
/* A phone (Estela, 14-oct: «Pago pendiente» ran under «Sin licencia» and the name was squeezed): the name and its tags
   own the first line and wrap inside it (span 2, not -1: jsdom drops -1); then the plan and the licence; then the buttons, on the right. On a wide
   screen the licence and the buttons sit on the right of both lines (2-oct). */
.people__row { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 10px; row-gap: 6px; align-items: center; padding: 10px 0; }
.people__row > * { grid-column-start: 1; grid-column-end: -1; }   /* the question and the commitment: full width (longhands: jsdom does not expand the shorthand) */
.people__row > .people__name { grid-column-start: 1; grid-column-end: span 2; grid-row-start: 1; justify-self: start; flex-wrap: wrap; row-gap: 4px; min-width: 0; max-width: 100%; }
.people__row > .meta { grid-column-start: 1; grid-column-end: auto; grid-row-start: 2; min-width: 0; }
.people__row > .people__licence { grid-column-start: 2; grid-column-end: auto; grid-row-start: 2; justify-self: end; white-space: nowrap; }
.people__row > .people__buttons { grid-column-start: 1; grid-column-end: span 2; grid-row-start: 3; justify-self: end; white-space: nowrap; }
.people__buttons { display: flex; align-items: center; column-gap: 8px; }   /* the pencil, then Hacer socio */
@media (min-width: 600px) {
  .people__row { grid-template-columns: minmax(0, 1fr) auto auto; }
  .people__row > .people__name { grid-column-end: auto; }
  .people__row > .people__licence { grid-row-start: 1; grid-row-end: span 2; }
  .people__row > .people__buttons { grid-column-start: 3; grid-column-end: auto; grid-row-start: 1; grid-row-end: span 2; }
}
.people__commitment { padding: 0 0 12px; }
.people__commitment p { margin: 4px 0; }
/* Usuarios, the whole screen (6-oct): the open sheet's buttons; "Nuevo usuario" on top and its form, one column on a phone, two on a wide screen. */
.people__actions { display: flex; flex-wrap: wrap; column-gap: 10px; row-gap: 10px; padding: 0 0 12px; }
/* The toolbar on top (Estela, 6-oct): "Nuevo usuario" and "Descargar en Excel", compact; on a phone they share the
   line; on a wide screen, on the right. */
.people__toolbar { display: flex; flex-wrap: wrap; justify-content: flex-end; column-gap: 10px; row-gap: 10px; }
/* The list's line (Estela, 14-oct, a rule for every list screen): search, filters, then the buttons. On a phone the
   buttons take their own line, the whole width, side by side; on a wide screen they close the line, on the right. */
.people__tools > .people__toolbar { flex-grow: 1; flex-shrink: 1; flex-basis: 100%; }
.people__toolbar .btn { width: auto; flex-grow: 1; flex-shrink: 1; flex-basis: auto; }
.people__toolbar [data-action="person-new"] .btn__label::before { content: "+ "; }   /* an action, not a title */
@media (min-width: 600px) {
  .people__tools > .people__toolbar { flex-grow: 0; flex-basis: auto; margin-left: auto; }
  .people__toolbar .btn { flex-grow: 0; }
}
.person-form h2 { margin-bottom: 12px; }
.person-form__fields { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: 12px; row-gap: 12px; }
@media (min-width: 600px) { .person-form__fields { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* A box and the activities take the whole line (span 2: jsdom drops "-1"). */
@media (min-width: 600px) { .person-form__fields > .check, .person-form__plans { grid-column-start: 1; grid-column-end: span 2; } }
/* A field with its label above it: ONE look for every form (Usuarios, Avisos por WhatsApp; renamed 7-oct). */
.field-label { display: flex; flex-direction: column; row-gap: 6px; font-size: 14px; color: var(--text-dim); }
.person-form__note { margin: 0; }
.check { display: flex; align-items: center; column-gap: 10px; min-height: var(--tap); font-size: 15px; color: var(--text); cursor: pointer; }
.check input { flex: none; width: 22px; height: 22px; margin: 0; accent-color: var(--orange); }
.person-form__plans { margin: 0; padding: 0; border-width: 0; min-width: 0; }
.person-form__plans legend { padding: 0; font-size: 14px; color: var(--text-dim); }
.person-form__plans > .meta { margin: 2px 0 6px; }
.person-form__plan { display: flex; align-items: center; justify-content: space-between; column-gap: 12px; padding: 6px 0; }
.person-form__plan .field--small { width: 5.5rem; }
/* The Ficha's four parts (14-oct): a title each, the same grid as the fields above. */
.person-form__group { margin: 16px 0 0; padding: 0; border-width: 0; min-width: 0; }
.person-form__group legend { padding: 0 0 8px; font-weight: 600; color: var(--text); }
.person-form textarea.field { resize: vertical; min-height: 4.5rem; font-family: inherit; }
/* A person's Ficha in their sheet: label over answer on a phone, side by side on a wide screen. */
.people__record { padding: 0 0 12px; }
/* Mis alumnos: what a student told the club about the water, under their row (14-oct): like a person's Ficha. */
.students__water { padding: 0 0 12px; }
/* Their titles in the accent: the club's red in the CNF, Nautelia's orange by default (Estela, 14-oct). */
.students__water h3, .people__record h3 { color: var(--accent); }
.students__water h3 { margin: 4px 0 8px; }
.students__water dl { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: 16px; row-gap: 2px; margin: 0; }
.students__water dd { margin: 0 0 8px; overflow-wrap: anywhere; }
@media (min-width: 600px) { .students__water dl { grid-template-columns: minmax(10rem, max-content) minmax(0, 1fr); } .students__water dd { margin-bottom: 4px; } }
.people__record h3 { margin: 4px 0 8px; }
.people__record dl { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: 16px; row-gap: 2px; margin: 0; }
.people__record dd { margin: 0 0 8px; overflow-wrap: anywhere; }
@media (min-width: 600px) { .people__record dl { grid-template-columns: minmax(10rem, max-content) minmax(0, 1fr); } .people__record dd { margin-bottom: 4px; } }
/* Guardar and Cancelar: stacked on a phone (the main one on top); on a wide screen, side by side on the right. */
@media (min-width: 600px) {
  .person-form__actions { justify-content: flex-end; }   /* the row and the width are every block's (6-oct) */
}

/* The gym (Estela, 6-oct; plan gym): the plan's blocks like the prototype's verGym, the three selects in a row,
   the assigned plan in a green frame and the sport's key in blue. */
/* The generator's ONE row (Estela, 6-oct): the three selects and "Asignar" right after them, so the coach decides
   without scrolling the session. A phone stacks them ("Competición" was cut at 390 px), the button full width last. */
.gym__toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 10px; }
.gym__toolbar .field { flex: 1 1 100%; min-width: 0; }
.gym__toolbar .btn { flex: 1 1 100%; }
@media (min-width: 600px) {
  .gym__toolbar .field { flex: 1 1 9rem; width: auto; }
  .gym__toolbar .btn { flex: 0 0 auto; }
}
/* The dose beside the exercise when there is room; on a phone it goes under it (390 px squeezed the name, 6-oct). */
.gym__row { flex-wrap: wrap; }
.gym__row > div { flex: 1 1 14rem; min-width: 0; }
.gym__dose { flex: none; font-family: var(--font-mono); font-size: 14px; white-space: nowrap; }
.gym .stat strong { font-size: 18px; white-space: nowrap; }   /* "RPE 7–8" on one line in a third of a phone */
.gym__text { margin: 0; }
.gym__block--info { border-left: 4px solid var(--blue); }
.gym__block h2 { color: var(--blue); }   /* every block title in the secondary blue (Estela, 6-oct) */
.gym__medical { margin-top: 14px; }
.gym-assigned { margin-top: 16px; }
.gym-assigned { padding: 14px 12px; border: 1px solid var(--line); border-left: 4px solid var(--green); border-radius: var(--radius); }
.gym-assigned > h2 { margin: 0; color: var(--green); }
/* The staff's Gimnasio like the prototype (Estela, 6-oct): the two orange buttons full width; the generator's head. */
/* Open / close the generator: a chevron drawn by the border (no emoji), down closed and up open. */
.gym__toggle::after { content: ""; width: 7px; height: 7px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: translateY(-2px) rotate(45deg); }
.gym__toggle[aria-expanded="true"]::after { transform: translateY(2px) rotate(-135deg); }
.gym-generator { margin-top: 14px; }
.notice .btn { margin-top: 6px; }

/* Mis alumnos (Estela, 6-oct): the licence and the commitment on the right of each row, one under the other. */
.students__note { margin: 0 0 4px; }
.students .row > div:first-child { flex-grow: 1; min-width: 0; }
.students__pills { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; flex: none; }
.students__pills .pill { white-space: nowrap; }
@media (min-width: 600px) { .students__pills { flex-direction: row; align-items: center; } }   /* side by side: one line per person */

/* Avisos por WhatsApp (Estela, 7-oct; 7W.4): the member's phone and consent, one column; dirección's events in two
   columns on a wide screen (twenty checkboxes in one would be a long list). */
.whatsapp-notices__form { display: flex; flex-direction: column; row-gap: 10px; margin-top: 12px; }
.whatsapp-notices__consent { margin: 0; }
.whatsapp-notices__fields { display: flex; flex-direction: column; row-gap: 10px; }
/* Desktop: the phone (narrow) and the switch side by side, the switch level with the field (Estela, 7-oct: "feo"). */
@media (min-width: 600px) {
  .whatsapp-notices__fields { flex-direction: row; align-items: flex-end; column-gap: 24px; }
  .whatsapp-notices__fields .phone { width: 16rem; flex: none; }
}
.whatsapp-events__list { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: 16px; margin-top: 8px; }
@media (min-width: 600px) { .whatsapp-events__list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Información del club (7-oct): each entry's title over its text, the text with its own line breaks (as the member
   reads it in WhatsApp); its buttons beside it from 600 px, under it on a phone (like Avisos' rows). */
.club-info__entry { flex-direction: column; align-items: stretch; }
@media (min-width: 600px) { .club-info__entry { flex-direction: row; align-items: flex-start; } }
.club-info__body { min-width: 0; }
.club-info__text { margin: 4px 0 0; white-space: pre-line; overflow-wrap: anywhere; color: var(--text-dim); }
.club-info__entry .actions { flex-wrap: wrap; justify-content: flex-end; flex: none; }
.club-info__form { display: flex; flex-direction: column; row-gap: 10px; padding: 12px 0; border-top: 1px solid var(--line); }
.club-info__list > .club-info__form:first-child { border-top: none; }
.club-info__auto { margin: 12px 0 0; }
/* WhatsApp del club (7W.3 C): its state in bold, the lists readable (14 px, the dim grey), the late sync as a warning
   with an amber edge, like "Por resolver". */
.club-whatsapp__state { margin: 8px 0 0; font-weight: 700; overflow-wrap: anywhere; }
.club-whatsapp__implies ul { margin: 6px 0 0; padding-left: 20px; font-size: 14px; color: var(--text-dim); }
.club-whatsapp__implies li + li { margin-top: 4px; }
.club-whatsapp__late { margin: 10px 0 0; padding: 10px 14px; border-left: 4px solid var(--amber); border-radius: 8px; background-color: rgba(224, 163, 62, 0.12); color: var(--amber); font-weight: 600; }
/* The page apart (connect-whatsapp/): one column, the safe areas of a phone. */
.connect { max-width: 560px; margin: 0 auto; padding: calc(24px + env(safe-area-inset-top)) 16px calc(24px + env(safe-area-inset-bottom)); }
.connect__title { color: var(--orange); }
.connect__state, .connect__error { margin: 10px 0 0; font-weight: 700; overflow-wrap: anywhere; }
/* The assistant's switch (8-oct): its state and line, the toggle beside them from 600 px, under them on a phone. */
.club-whatsapp__bot-row { display: flex; flex-direction: column; row-gap: 8px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
@media (min-width: 600px) { .club-whatsapp__bot-row { flex-direction: row; align-items: center; justify-content: space-between; column-gap: 16px; } }
.club-whatsapp__bot-row .actions { margin-top: 0; flex: none; }
.club-whatsapp__bot { margin: 0; font-weight: 700; }

/* Payments P1 (12-oct; the demo's verPagosAlumno): the year as 12 cells, 4 a row (a phone too, like the demo); what is
   still to come, dimmed. The month's word at 15 px and the pill under it. */
.paymonths { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin: 12px 0; }
.paymonth { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 10px 4px; border-radius: 8px;
  background-color: var(--panel-2); border: 1px solid; border-color: var(--line); text-align: center; }
.paymonth strong { font-size: 15px; text-transform: capitalize; }
.paymonth .pill { padding: 4px 8px; font-size: 14px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.paymonth--off { opacity: 0.45; }
.payments-summary .row .pill, .payments__sent .row .pill { white-space: nowrap; margin-left: auto; }

/* Pagos pendientes as a list with a box per person (Estela, 13-oct: «hazlo como una tabla con checkbox»). The bar
   («Seleccionar todos», «Marcar como pagado (N)», «Recordatorio a los N») sticks to the top over a long list (the tab bar
   is at the bottom on a phone). A row on a phone: the box left, the name, then the months and the amount under it, the
   receipt's line under them; from 600 px, one line like a table. The open row's months under it all. */
.payments__bar { position: sticky; top: env(safe-area-inset-top, 0px); z-index: 2; margin: 0 -16px; padding: 4px 16px 8px;
  background-color: var(--panel); border-bottom: 1px solid var(--line); }
.payments__bar-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; }
.payments__bar-row .actions { margin-top: 0; flex-wrap: wrap; gap: 8px; }
.payments__bar-row > .meta { margin: 0; }
.payments__bar .confirm-inline { margin-top: 8px; }
/* «Seleccionar todos» in the rows' column: its box centred in the same 44 px as each row's (Estela, 13-oct: «alinea eso»). */
.yearnav .chip--off { opacity: 0.35; }   /* no year before the API's first (review 13-oct) */
.payments__bar .check { column-gap: 8px; }
.payments__bar .check input { margin-inline: calc((var(--tap-secondary) - 22px) / 2); }
.payrow { display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; column-gap: 8px; row-gap: 2px; align-items: center;
  padding: 6px 0; border-top: 1px solid var(--line); }
.payrows > .payrow:first-child { border-top: none; }
.payrow__pick { grid-column-start: 1; grid-row-start: 1; display: flex; align-items: center; justify-content: center;
  min-width: var(--tap-secondary); min-height: var(--tap-secondary); cursor: pointer; }
.payrow__pick input { flex: none; width: 22px; height: 22px; margin: 0; accent-color: var(--orange); }
.payrow__who { grid-column-start: 2; grid-column-end: 4; grid-row-start: 1; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; min-width: 0; }
.payrow__due { grid-column-start: 2; grid-row-start: 2; }
.payrow__total { grid-column-start: 3; grid-row-start: 2; white-space: nowrap; }
.payrow__status { grid-column-start: 2; grid-column-end: 4; grid-row-start: 3; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.payrow__status .pill { margin-top: 0; }
.payrow__months { grid-column-start: 2; grid-column-end: 4; grid-row-start: 4; margin-top: 4px; padding: 4px 12px; border-radius: var(--radius); background-color: var(--panel-2); }
.payrow__months .row { flex-direction: row; align-items: center; padding: 6px 0; }
.payrow__months > .meta { margin: 6px 0; }
@media (min-width: 600px) {
  .payrow { grid-template-columns: 44px minmax(0, 1.4fr) minmax(0, 1fr) auto minmax(0, 1.4fr); column-gap: 12px; }
  .payrow__who { grid-column-end: auto; }
  .payrow__due { grid-column-start: 3; grid-row-start: 1; }
  .payrow__total { grid-column-start: 4; grid-row-start: 1; }
  .payrow__status { grid-column-start: 5; grid-column-end: auto; grid-row-start: 1; justify-content: flex-end; }
  .payrow__months { grid-column-start: 2; grid-column-end: 6; grid-row-start: 2; }
}

/* Pagos' search under the figures (Estela, 13-oct: «tipo input + botón inline»): the field and «Ver pagos» in ONE row,
   as high; the field takes the room (999 to the button's 1), the button its own width; too narrow for both, the button
   drops under and fills its line. Its matches, the usual dropdown, each a 44 px button that chooses. */
.payfind { display: flex; flex-wrap: wrap; align-items: stretch; gap: 8px; margin: 16px 0; }
.payfind .add-find { flex-grow: 999; flex-shrink: 1; flex-basis: 14rem; min-width: 0; margin-top: 0; }
.payfind .btn { flex-grow: 1; flex-shrink: 0; flex-basis: auto; width: auto; min-height: var(--tap); }   /* as high as the field */
.add-pick { width: 100%; min-height: var(--tap-secondary); padding: 8px 0; border: none; background-color: transparent; color: var(--text);
  font-family: inherit; font-size: 15px; text-align: left; cursor: pointer; }
.add-pick + .add-pick { border-top: 1px solid var(--line); }
/* One person's history in Pagos (Estela, 13-oct). ‹ the year › with 44 px arrows. A month a row: on a phone, the month,
   the amount and the state on one line, how it was settled under them and the buttons under that; from 600 px, one line
   like a table. A month not owed before billing or after leaving (13-oct): dimmed, «—» where the pill goes. */
.paydash { font-size: 15px; color: var(--text-dim); }
.payhist__row--off { opacity: 0.45; }
.payhist__row > .paydash { grid-column-start: 3; grid-row-start: 1; justify-self: center; }
.yearnav { display: flex; align-items: center; gap: 12px; }
.yearnav .chip { font-size: 18px; }   /* a .chip: 44 px already */
.yearnav__year { font-size: 18px; }
.payhist__months { margin-top: 8px; }
.payhist__row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; column-gap: 10px; row-gap: 6px; align-items: center;
  padding: 10px 0; border-top: 1px solid var(--line); }
.payhist__row:first-child { border-top: none; }
.payhist__month { grid-column-start: 1; grid-row-start: 1; text-transform: capitalize; }
.payhist__amount { grid-column-start: 2; grid-row-start: 1; white-space: nowrap; }
.payhist__row > .pill { grid-column-start: 3; grid-row-start: 1; margin-top: 0; white-space: nowrap; }
.payhist__detail { grid-column-start: 1; grid-column-end: 4; grid-row-start: 2; margin: 0; overflow-wrap: anywhere; }
.payhist__actions, .payhist__row > .confirm-inline { grid-column-start: 1; grid-column-end: 4; grid-row-start: 3; margin-top: 0; }
.payhist__actions { flex-direction: row; flex-wrap: wrap; gap: 8px; }
@media (min-width: 600px) {
  .payhist__row { grid-template-columns: 110px 70px auto minmax(0, 1fr) auto; column-gap: 12px; }
  .payhist__detail { grid-column-start: 4; grid-column-end: auto; grid-row-start: 1; }
  .payhist__actions { grid-column-start: 5; grid-column-end: auto; grid-row-start: 1; justify-content: flex-end; }
  .payhist__row > .confirm-inline { grid-column-start: 1; grid-column-end: 6; grid-row-start: 2; }
}

/* ==== A club's own look (13-oct, the hub's ADR-0012) ====
   lib/theme.js gives the variables the club's values and marks <html data-theme="club">. Only colours, never a size
   or a position: these lines fix the few fixed colours that assumed Nautelia's dark ground. The tinted pills and tags
   (rgba(..., 0.14)) stay: a pale tint of their own tone, with the club's darker tone as text, reads on white too. */
/* the map's credit sits on OpenFreeMap's dark tiles (dark in every theme): a light chip keeps the club's dim text legible */
[data-theme="club"] .map__attribution { background-color: rgba(255, 255, 255, 0.85); }
/* a black 40-45 % shadow is a smudge on a light ground: the same lift, lighter */
[data-theme="club"] .tabbar__sheet { box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.12); }
[data-theme="club"] .add-results { box-shadow: 0 12px 28px rgba(0, 0, 0, 0.12); }

