/* ═══════════════════════════════════════════════════════════════════
   WORKOUTS v2 — ATLETA (base_public.html): card WOD, home timeline,
   scoreboard, auth, date strip, personal records, classifica, privacy,
   competitor, profilo e foto, timer, abbonamento, statistiche (la sheet
   di registrazione e i commenti stanno in base.css: li usa anche il
   coach). Caricato dopo base.css e codifiche.css.
   ═══════════════════════════════════════════════════════════════════ */

/* ── Atleta: card WOD ─────────────────────────────────────────────── */
/* La card contiene il WOD per intero: head (24px) · titolo+sottotitolo ·
   descrizione · azioni. Ritmo verticale dal solo gap s3 — niente margini
   sparsi. NB: non è un <a> (chip score e CTA sono link a loro volta). */
.wod-card {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  color: var(--text);
  transition: border-color var(--speed), transform var(--speed);
}
a.wod-card:hover {
  text-decoration: none;
  border-color: var(--purple-line);
}
a.wod-card:active { transform: scale(.99); }
.wod-card-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s2);
  min-height: 24px;
  min-width: 0;
}
.wod-card-head .badge { flex: 0 1 auto; min-width: 0; }
.wod-card-head .score-pill { flex: 0 0 auto; }
/* stagger d'ingresso: gated da body.cards-stagger (aggiunta da
   stagger.js al primo load, MAI dal bfcache) — senza JS niente nodi
   nascosti. --stg = indice, settato dal JS.
   ⭐ Dal 2026-08-17 non è più solo la home: i selettori coprono gli
   elementi-riga di OGNI pagina atleta (nodi timeline, feed e tessere
   RM, gruppi del dettaglio massimale, righe di classifica, card del
   profilo) — «gli effetti devono essere ovunque lato atleta». */
@keyframes card-in {
  from { opacity: 0; transform: translateY(10px); }
}
body.cards-stagger .tl-node,
body.cards-stagger .cat-card,
body.cards-stagger .tile,
body.cards-stagger .rm-group,
body.cards-stagger .lb-row,
body.cards-stagger .stx-card,
body.cards-stagger main .card {
  animation: card-in .3s ease both;
  animation-delay: calc(var(--stg, 0) * 40ms);
}

.score-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: var(--r-pill);
  font-size: var(--fs-sm);
  font-weight: 700;
  background: var(--ok-dim);
  color: var(--ok);
  white-space: nowrap;
}
/* il chip è l'unico ingresso al form di log: l'area cliccabile arriva a
   44px senza gonfiare la pill (che resta alta 30px nel ritmo della head) */
a.score-pill { position: relative; text-decoration: none; }
a.score-pill::after { content: ''; position: absolute; inset: -7px -6px; }
a.score-pill:hover { text-decoration: none; filter: brightness(1.15); }
/* nessuno score ancora: pill «Score» del ui-kit (tinta viola, icona piena
   add_circle 19px), stesso posto della pill verde col risultato */
.score-pill--add {
  gap: 6px;
  padding: 7px 14px;
  background: var(--btn-tint);
  color: var(--brand-light);
  font-size: 13px;
  font-weight: 500;
}
.score-pill--add .icon { width: 18px; height: 18px; }
a.score-pill--add:hover { filter: none; background: var(--btn-tint-hover); }

/* ══ HOME TIMELINE (grafica-wod del coach, 2026-08-11) ═══════════════
   Scritta sul riferimento grafico "grafica-wod" del coach.
   Mappa classi spec → produzione (collisioni col CSS esistente):
   .head→.home-head · .week/.day→.date-strip/.date-pill (restyle in
   place) · .node→.tl-node · .rail→.tl-rail · .dot→.tl-dot ·
   .card→.tl-card · .mini→.tl-mini · .result→.tl-result ·
   .actions→.tl-actions · .btn→.tl-btn · .pill-score→.tl-pill ·
   .empty→.tl-empty (il nodo .end della spec è stato rimosso su
   decisione del coach: la timeline finisce sull'ultimo lavoro).
   Colore categoria = tracks.color dal DB via --tc sul nodo.
   Valori copiati 1:1 dalla spec (vincolo del coach: non arrotondare). */

/* app-like anche desktop: colonna centrata, niente topbar (la testata
   la sostituisce), bottom nav sempre visibile */
body.home-timeline .topbar { display: none; }
body.home-timeline main { padding-top: 0; padding-bottom: calc(var(--nav-h) + env(safe-area-inset-bottom)); }
body.home-timeline main > .container { max-width: 480px; }
body.home-timeline .bottom-nav { display: block; }
body.home-timeline .bottom-nav-inner { max-width: 480px; margin: 0 auto; }
body.home-timeline .footer-pub { display: none; }

/* ⭐ 2026-08-28 (Roberta, chiesto da Francesco che li guarda dal PC): da
   computer il lato atleta smette di fingersi un'app. Sopra i 900 punti
   torna la barra in alto col menu, sparisce quella in fondo — sono le
   stesse cinque voci, due volte, su uno schermo dove il pollice non
   c'entra niente — e la colonna sale a 720.
   Il 720 l'abbiamo scelto guardando una giornata vera, con i testi dentro
   le card (che ci sono sempre): a 480 le righe del coach vanno a capo tre
   volte, a 720 stanno quasi tutte su una riga sola e la giornata ci sta
   in una schermata.
   ⚠️ Sotto i 900 non cambia NIENTE: il telefono resta com'era. */
@media (min-width: 900px) {
  /* ⚠️ flex, NON block: la barra centra logotipo e menu in verticale con
     align-items, e con display:block quel centraggio salta — il contenuto
     si incolla in alto e sotto resta un dito di vuoto. Roberta l'ha visto
     subito confrontandola col Profilo, che la barra ce l'ha da sempre. */
  body.home-timeline .topbar { display: flex; }
  body.home-timeline header.topbar > .container { justify-content: space-between; }
  body.home-timeline .bottom-nav { display: none; }
  /* stessa aria del Profilo sopra il contenuto (il padding-top vero lo
     scrive la regola della data, qui sotto: sopra restano 10px) */
  body.home-timeline main { padding-bottom: var(--s6); }
  body.home-timeline main > .container { max-width: 720px; }
  /* il logotipo ce l'ha gia la barra, quindi sparisce dalla testata della
     pagina — che smette anche di stare appiccicata in alto.
     ⚠️ Ma quel riquadro non contiene sempre il logotipo: su Oggi e sui PR
     sì, sullo STORICO è il titolo della pagina e va lasciato. E sui PR il
     nome della schermata sta nella riga sotto («Personal records»), che
     qui diventa lei il titolo: sennò la pagina resta senza nome. */
  body.home-timeline .home-head-box { display: none; }
  body.home-timeline.st-page .home-head-box { display: block; }
  /* ⚠️ senza il logotipo la data restava orfana: una riga grigia sola
     sotto un buco di 46 punti. Sale ad appoggiarsi alla barra, cresce di
     un punto e si ingrassa, e si mette in asse con l'anello. */
  body.home-timeline .home-head { position: static; padding-top: 0; }
  body.home-timeline main { padding-top: 10px; }
  body.home-timeline .home-head-date {
    font-size: 15px;
    font-weight: 700;
    margin-top: 0;
  }
  body.home-timeline.rm-page .home-head-sub {
    font-family: var(--font-display);
    font-size: 24px;
    line-height: 1.05;
    text-transform: uppercase;
    color: var(--text);
    font-weight: 400;
    margin-top: 0;
  }
  /* senza la barra in fondo i toast tornano al loro posto */
  body.home-timeline #toast-region { bottom: var(--s5); }

}

/* testata: nome box + data + anello di avanzamento; sticky comprimibile
   (classe .shrunk sul body oltre i 28px di scroll, home_timeline.js) */
.home-head {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  /* l'imbottitura SOTTO non è un vezzo: la testata è appiccicata in alto
     con fondo opaco, e senza quello spazio il testo che scorre le arriva
     a filo della data e dell'anello (segnalato da Roberta scorrendo) */
  padding: 18px 4px 12px;
  /* ⚠️ fondo OPACO e niente backdrop-filter (2026-08-18): stesso difetto
     e stessa cura della bottom nav — su iPhone lo sticky col blur veniva
     ricomposto in ritardo dalla barra indirizzi dinamica e il titolo
     "non restava dove deve", col contenuto visibile attraverso.
     rgba(10,10,11) era anche il vecchio nero caldo, non --ink. */
  background: var(--ink);
  transition: padding var(--speed);
}
/* paraurti sopra, gemello di .bottom-nav::after: quando il viewport
   shifta, sopra la testata si apriva la stessa fessura */
.home-head::before {
  content: '';
  position: absolute;
  bottom: 100%;
  left: 0; right: 0;
  height: 120px;
  background: var(--ink);
}
/* ⚠️ Impersonando, questo paraurti copriva a metà la barra gialla
   dell'impersonazione (segnalato da Francesco, 2026-08-23): sta sopra la
   testata sticky e la barra scorre lì sotto. Serve solo a tappare lo
   shift del viewport dinamico di Safari a pagina SCROLLATA, quindi in
   cima si può togliere — e lo si toglie solo mentre si impersona, per
   non cambiare niente a tutti gli altri. `shrunk` = testata compressa,
   cioè pagina già scrollata: lì il paraurti torna. */
body.impersonating .home-head::before { display: none; }
body.impersonating.shrunk .home-head::before { display: block; }
.home-head-box {
  font-family: var(--font-display);
  font-size: 24px;
  color: var(--text);
  line-height: 1.05;
  transition: font-size .18s ease;
}
.home-head-date {
  font-size: 14px;
  font-weight: 500;
  color: var(--grigio-66);
  margin-top: 5px;
  transition: font-size .18s ease, margin-top .18s ease;
}
.home-ring {
  flex: none;
  /* alzato di 2px: centrando le scatole del testo l'anello cade più in
     basso di dove l'occhio se lo aspetta, perché sopra il nome c'è l'aria
     dell'interlinea e sotto la data lo spazio per la coda della «g» */
  margin-top: -2px;
  transition: width .18s ease, height .18s ease, margin-top .18s ease;
}
/* compressa (scroll): titolo, data e anello restano, RIMPICCIOLITI
   (round 2: prima data e anello sparivano); a sparire è il calendario
   (.strip-slot qui sotto) */
body.shrunk .home-head { padding-top: 8px; padding-bottom: 6px; }
body.shrunk .home-head-box { font-size: 17px; }
body.shrunk .home-head-date { font-size: var(--fs-meta); margin-top: 1px; }
/* da compressa l'anello sale un altro paio di pixel: la testata si
   stringe e con corpi più piccoli il cerchio sembra sedersi sulla data */
body.shrunk .home-ring { width: 30px; height: 30px; margin-top: -4px; }

/* slot collapse del calendario: allo scroll la strip SPARISCE del tutto.
   overflow-anchor spento: il collasso accorcia il contenuto sopra il
   viewport e lo scroll anchoring del browser entrerebbe in oscillazione
   con l'isteresi di home_timeline.js (soglie 96/24) */
.strip-slot { overflow-anchor: none; }
body.shrunk .strip-slot {
  grid-template-rows: 0fr;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: grid-template-rows .28s ease, opacity .2s ease,
              visibility 0s linear .28s;
}

/* timeline */
.tl-feed { padding: 0 2px 20px; }
.tl-node { display: grid; grid-template-columns: 26px 1fr; }
.tl-content { min-width: 0; }
.tl-rail { position: relative; }
.tl-rail-top, .tl-rail-bot {
  position: absolute;
  left: 12px;
  width: 2px;
  background: var(--rail-off);
}
/* allineamento verticale: dipende da cosa sta in cima al nodo — card
   aperta (is-open, centro linea a ~25px) o riga compatta (~20px) — non
   più dallo stato done/todo: un done riaperto ha la card come prima riga */
.tl-rail-top { top: 0; height: 17px; }
.tl-rail-bot { top: 17px; bottom: 0; }
.tl-node.is-open .tl-rail-top { height: 22px; }
.tl-node.is-open .tl-rail-bot { top: 22px; }
.tl-rail-top, .tl-rail-bot, .tl-dot { transition: top .28s ease, height .28s ease; }
.tl-node--first .tl-rail-top { display: none; }
.tl-node--last  .tl-rail-bot { display: none; }

.tl-dot {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  border-radius: 50%;
  box-sizing: content-box;
  border: 3px solid var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--tc, var(--rail-off));
}
/* dimensione del pallino = stato; top = stato × apertura (centrato sul
   titolo della riga in cima: card ~25px, riga compatta ~20px) */
.tl-node--done    .tl-dot { width: 12px; height: 12px; top: 11px; }
.tl-node--done.is-open    .tl-dot { top: 16px; }
.tl-node--current .tl-dot { width: 16px; height: 16px; top: 9px; }
.tl-node--current.is-open .tl-dot { top: 14px; }
.tl-node--todo    .tl-dot { width: 10px; height: 10px; top: 12px; }
.tl-node--todo.is-open    .tl-dot { top: 17px; }
/* entrambe le icone vivono nel dot: le accende lo stato (il repaint JS
   cambia solo classi, mai markup) */
.tl-dot .tl-ico-check, .tl-dot .tl-ico-bolt { display: none; }
.tl-node--done .tl-dot .tl-ico-check {
  display: block; width: 10px; height: 10px; color: var(--surface);
}
.tl-node--current .tl-dot .tl-ico-bolt {
  display: block; width: 12px; height: 12px; color: #0D2C22;
}

/* blocco aperto */
.tl-card {
  background: var(--surface);
  border-radius: 14px;
  padding: 12px 14px 14px;
  margin-bottom: 9px;
  min-width: 0;
}
.tl-card--current {
  outline: 1px solid color-mix(in srgb, var(--tc, #5DC2A6) 30%, transparent);
  outline-offset: -1px;
}
.tl-card-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 10px;
  /* il respiro tra testata (titolo+pill) e corpo sta QUI, non sul
     sottotitolo: così i lavori SENZA sottotitolo non attaccano la pill
     al testo (fix coach 2026-08-11) */
  margin-bottom: 8px;
}
.tl-card-headings { min-width: 0; }
.tl-card-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.2;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}
/* il titolo della card è un bottone (chiude la card, toggle universale) */
button.tl-card-title {
  display: block;
  width: 100%;
  background: none;
  border: 0;
  padding: 0;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  position: relative;
}
button.tl-card-title::after { content: ''; position: absolute; inset: -12px -4px; }
button.tl-card-title:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
.tl-card-scheme {
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  text-transform: uppercase;
  margin: 3px 0 0;   /* il gap verso il corpo lo dà .tl-card-row */
  color: var(--tc, var(--muted));
}
.tl-card-body {
  font-size: 12px;
  font-weight: 400;
  color: var(--body-text);
  line-height: 1.6;
  overflow-wrap: anywhere;
}
/* il rich-text dentro il corpo eredita la scala della timeline */
.tl-card-body.rich-text { font-size: 12px; }
.tl-card-body.rich-text h2 { font-size: 14px; }
.tl-card-body.rich-text h3 { font-size: 13px; }
/* card info (0046): descrizione E istruzioni coach sono due corpi in
   fila — il :last-child del rich-text azzera i margini interni e senza
   questo respiro i due blocchi si incollerebbero */
.tl-card-body + .tl-card-body { margin-top: var(--s3); }
.tl-card-sub { font-size: var(--fs-meta); font-weight: 400; color: var(--muted); margin-top: 5px; }
.tl-card-divider { height: 1px; background: rgba(255, 255, 255, .07); margin: 11px 0; }
/* ⭐ La nota del calendario competitor, che vede SOLO lo staff: non è
   contenuto del WOD ma un'informazione sull'app, quindi si stacca dal
   testo del coach — icona davanti e un filo di rientro, come le
   `.hintline` della sheet. */
.tl-nota-cmp {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 7px;
  font-style: italic;
}
.tl-nota-cmp .icon { width: 13px; height: 13px; flex: none; }

/* riga compatta del blocco — DUE azioni separate: il TITOLO commuta
   riga↔card (toggle universale, coach 2026-08-11 round 2), a destra lo
   SCORE apre la sheet di modifica (fatto) o la pill «Score» (da fare) */
.tl-mini {
  background: rgba(255, 255, 255, .035);
  border-radius: 12px;
  padding: 9px 12px;
  margin-bottom: 9px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.tl-mini-title {
  font-size: 13px;
  font-weight: 500;
  color: var(--grigio-62);
  text-transform: uppercase;
  overflow-wrap: anywhere;
  min-width: 0;
}
button.tl-mini-title {
  background: none;
  border: 0;
  padding: 0;
  font-family: inherit;
  text-align: left;
  flex: 1;
  cursor: pointer;
  position: relative;
}
button.tl-mini-title::after { content: ''; position: absolute; inset: -12px -4px; }
button.tl-mini-title:hover { color: var(--text); }
button.tl-mini-title:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
.tl-mini--locked .tl-mini-title { text-transform: none; display: flex; align-items: center; gap: var(--s2); }
.tl-result {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  flex: none;
  text-decoration: none;
  position: relative;
  /* tabulari: è un valore che si aggiorna da solo dopo il salvataggio */
  font-variant-numeric: tabular-nums;
}
a.tl-result::after { content: ''; position: absolute; inset: -12px -8px; }
a.tl-result:hover { text-decoration: none; filter: brightness(1.2); }
.tl-result-value { font-size: 13px; font-weight: 600; color: var(--grigio-91); }
.tl-result-unit { font-size: var(--fs-eyebrow); color: var(--muted); }
/* la matita accanto al risultato registrato (2026-09-10, Roberta): il
   numero da solo non diceva che si può correggere. Staccata dal testo —
   il gap della riga è 3, qui ne servono 8 in tutto — e grigia come
   l'unità: è un'indicazione, non un bottone da premere. */
.tl-result-ic {
  width: 12px;
  height: 12px;
  margin-left: 5px;
  align-self: center;
  flex: none;
  color: var(--muted);
}

/* bottoni del blocco: «Coach notes» prende tutto lo spazio che resta,
   classifica e commenti sono due bottoncini a sola icona col numerino
   (pesano meno, e a tre etichette per riga il testo non ci starebbe) */
/* ⭐ Le colonne dei mini le fa il CONTENUTO (2026-09-23): la prima è
   dichiarata, le altre nascono una per bottone presente. Prima erano
   contate a mano (1fr auto auto, e auto auto auto col timer), e sul
   Personal Trainer, dove la classifica non c'è, restava una colonna
   vuota che pagava il suo gap: 9px in più a destra che a sinistra
   (Francesco, su Android). */
.tl-actions {
  display: grid;
  grid-template-columns: 1fr;
  grid-auto-flow: column;
  grid-auto-columns: auto;
  gap: 9px;
}
/* nota del giorno (0046): l'unica azione sono i commenti, a tutta
   larghezza come il Coach notes delle altre card */
.tl-actions--info { grid-template-columns: 1fr; }
.tl-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  /* ⚠️ senza gap l'etichetta e il numero dei commenti si incollavano:
     sulla card del Daily Brief usciva «Commenti2» (2026-08-28, Roberta).
     Sui bottoncini con la sola icona non cambia niente: lì l'icona è
     fuori dal flusso e in riga c'è solo il numero. */
  gap: 6px;
  border: 0;
  /* --r-btn: il raggio dei bottoni in linea. Era 11px, unico nel file */
  border-radius: var(--r-btn);
  padding: 10px 0 10px 10px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  min-width: 0;
  cursor: pointer;
  transition: background-color var(--speed);
}
.tl-btn:hover { text-decoration: none; }
.tl-btn .tl-btn-icon { position: absolute; left: 10px; width: 17px; height: 17px; }
.tl-btn--primary { background: var(--btn-tint); color: var(--brand-light); }
.tl-btn--primary:hover { background: var(--btn-tint-hover); }
.tl-btn--primary:active { background: var(--btn-tint-active); }
.tl-btn--secondary { background: var(--btn-sec-bg); color: var(--btn-sec-fg); }
.tl-btn--secondary:hover { background: var(--btn-sec-bg-hover); }
.tl-btn:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
/* Classifica e commenti: solo icona (+ numerino), quadrati come i
   bottoni-icona del kit. Qui l'icona NON è ancorata a sinistra — non c'è
   un'etichetta da cui stare larga — e il padding torna simmetrico */
.tl-btn--mini {
  gap: 5px;
  min-width: 40px;
  padding: 10px;
}
.tl-btn--mini .icon { width: 17px; height: 17px; flex: none; }
/* l'etichetta dei due bottoncini: sul telefono non c'e posto, da computer
   si accende (vedi il blocco a 900 punti in fondo al file) */
.tl-btn-et { display: none; }
.tl-btn-count { font-size: var(--fs-meta); font-variant-numeric: tabular-nums; }
/* ⚠️ Sul bottone largo con l'etichetta scritta (la card del Daily Brief) il
   numero sta ACCANTO ALL'ICONA, come su tutti gli altri bottoni della
   card — non attaccato alla parola. Si aggancia col position come l'icona,
   così l'etichetta resta centrata comunque (2026-08-28, Roberta).
   ⚠️ Solo qui: sui bottoncini con la sola icona il numero è l'unica cosa
   in riga, e deve restare al centro. */
.tl-actions--info .tl-btn-count { position: absolute; left: 33px; }

/* pill Score: identica in ogni blocco, incluso quello in corso */
.tl-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: none;
  border: 0;
  border-radius: 999px;
  padding: 6px 10px;
  font-family: inherit;
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  color: var(--brand-light);
  background: var(--btn-tint);
  text-decoration: none;
  cursor: pointer;
  position: relative;
}
.tl-pill:hover { text-decoration: none; background: var(--btn-tint-hover); }
.tl-pill::after { content: ''; position: absolute; inset: -8px -6px; }  /* tap 44px */
.tl-pill .tl-pill-icon { width: 14px; height: 14px; }

/* stato vuoto (giorno senza programmazione) */
.tl-empty {
  border: 1px dashed rgba(255, 255, 255, .11);
  border-radius: 14px;
  padding: 26px 14px;
  text-align: center;
  margin-top: 6px;
}
.tl-empty-icon { width: 28px; height: 28px; color: var(--dim); }
/* nella scheda di un movimento il riquadro prende il posto del record, e
   sotto un titolo a poster i 6 punti del .tl-empty erano un'incollatura
   (2026-09-04, Roberta) */
.detail-head .tl-empty { margin-top: var(--s5); }
.tl-empty-title { font-size: 14px; font-weight: 600; color: var(--grigio-62); margin-top: 8px; }
.tl-empty-sub { font-size: var(--fs-meta); color: var(--grigio-44); margin-top: 3px; }

/* storico a timeline (round 2): heading del giorno sopra ogni feed */
.tl-day-heading {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  color: var(--muted);
  margin: var(--s5) 2px var(--s2);
}
.tl-day-heading:first-of-type { margin-top: var(--s3); }
/* la seconda linea della home, il Personal Trainer (0065): stessa
   intestazione dello storico. */
.tl-heading--pt {
  color: var(--purple-hi);
  border-top: 1px solid var(--line);
  padding-top: var(--s4);
  margin-top: var(--s6);
}

/* sheet-calendario dello storico: solo i giorni con una sessione */
.hd-month { margin-bottom: var(--s4); }
.hd-month-label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text);
  margin-bottom: var(--s2);
}
.hd-days { display: flex; flex-wrap: wrap; gap: var(--s2); }
.hd-day {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
}
.hd-day:hover { text-decoration: none; border-color: var(--purple-line); }
.hd-day.active { border-color: var(--purple); }

/* video: riga compatta che al play si ESPANDE fluida fino al 16:9 */
.video-list {
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  margin-bottom: var(--s4);
}
/* ⚠️ Il respiro sopra i video vale OVUNQUE (2026-09-04, Roberta): stava
   su due regole legate al vicino di sopra (.cn-text, .cn-movements), e
   dove il vicino era un altro — il testo della nota del giorno, o la riga
   «il coach non ha lasciato note» — la fascia del video restava
   appiccicata al paragrafo. */
.video-list:not(:first-child) { margin-top: var(--s4); }
.video-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  width: 100%;
  /* 50 e non 56 (2026-09-04, Roberta): dentro la card, dove intorno c'è
     solo testo, la fascia da 56 pesava troppo. Cerchio del play e scritta
     restano quelli — cambia solo l'altezza. ⛔ Non scendere sotto 44: è il
     bersaglio da prendere col dito. */
  min-height: 50px;
  padding: var(--s2) var(--s3);
  /* velatura di bianco, non --surface-2: dentro la sheet il fondo è già
     --surface-2 e la fascia spariva, per questo aveva un filo attorno.
     Il bordo resta trasparente così l'hover viola non sposta il layout. */
  background: rgba(255, 255, 255, .05);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--fs-base);
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  transition: border-color var(--speed), height .3s ease;
}
.video-row:hover { border-color: var(--purple-line); }
.video-row-play {
  position: relative;
  width: 38px; height: 38px;
  border-radius: 50%;
  background: var(--purple);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  overflow: hidden;
}
.video-row-play .icon { position: relative; }
/* un titolo lungo non deve mandare la riga su più righe: l'animazione di
   espansione parte dall'altezza reale e finirebbe per collassare */
.video-row-label {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.video-row > .icon:last-child { color: var(--muted); }
/* durante l'espansione il contenuto della riga sfuma via */
.video-row.expanding { pointer-events: none; }
.video-row.expanding > * { opacity: 0; transition: opacity .15s ease; }
.video-iframe {
  width: 100%;
  aspect-ratio: 16/9;
  border: none;
  border-radius: var(--r-md);
}
.video-iframe--fade { opacity: 0; transition: opacity .25s ease; }
.video-iframe--fade.is-on { opacity: 1; }

/* ── Atleta: scoreboard ───────────────────────────────────────────── */
.board { padding: var(--s2) var(--s5); }
.board-title {
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--purple-hi);
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--line);
}
.board-row {
  display: grid;
  grid-template-columns: 30px 36px minmax(0,1fr) auto;
  align-items: center;
  gap: var(--s2);
  padding: var(--s2) 0;
  border-bottom: 1px solid var(--line);
}
.board-row:last-child { border-bottom: none; }
.board-pos {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  /* .02em e 6px d'aria sotto l'occhiello: entrambi nel riferimento
     (`.ttl{margin-top:6px}`) e nessuno dei due
     c'era */
  margin-top: 6px;
  color: var(--muted);
  text-align: center;
  line-height: 1;
}
.board-row--p1 .board-pos { color: var(--purple-hi); font-size: 26px; }
.board-row--p2 .board-pos, .board-row--p3 .board-pos { color: var(--text); }
.board-name {
  font-weight: 600;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--s2);
}
.board-name .btn-icon { width: 30px; height: 30px; }
.board-score {
  font-size: 19px;
  font-weight: 800;
  text-align: right;
  white-space: nowrap;
  letter-spacing: -.01em;
}
.board-row--me {
  background: var(--purple-dim);
  border-left: 3px solid var(--purple);
  margin: 0 calc(-1 * var(--s5));
  padding-left: calc(var(--s5) - 3px);
  padding-right: var(--s5);
}

/* filtro track (storico) */
.filter-bar {
  display: flex;
  gap: var(--s2);
  margin-bottom: var(--s4);
  flex-wrap: wrap;
  align-items: center;
}

.day-heading {
  position: sticky;
  top: 60px;
  z-index: 5;
  /* opaca e senza blur, come la topbar qui sopra */
  background: var(--ink);
  padding: var(--s2) 0;
  margin-bottom: var(--s3);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
}

/* ── Auth ─────────────────────────────────────────────────────────── */
/* ── Accesso e registrazione (rifatte il 2026-08-18) ──────────────────
   Erano una scatola dentro una pagina già vuota, con il logo ripetuto
   tre volte e il bottone viola pieno con testo bianco — l'unico in tutta
   l'app, e proprio quello che le specifiche vietano. Ora: schermo pieno,
   un logo solo, e il bottone col filo viola.
   Niente titolo: l'accesso non ne ha bisogno (il logo dice dove sei, il
   bottone dice cosa fai) e la registrazione si presenta con la frase che
   serviva comunque a spiegare l'email. Due scritte grosse non si
   incontrano mai. */
body.auth .topbar { display: none; }
/* ⭐ 2026-08-31 (Roberta): le pagine SENZA VIE DI FUGA — abbonati,
   completa il profilo, senza abbonamento — non mostrano la barra in
   fondo. Le linguette invitavano a toccare Oggi, Storico, PR… che da lì
   rimbalzano indietro: un invito a sbattere la testa. */
/* ⚠️ body.public.senza-uscite e non solo la seconda classe: la regola
   che ACCENDE la barra sul telefono (body.public .bottom-nav) sta dentro
   una media query piu in basso nel file, e a parita di forza vince
   l'ultima scritta. Con due classi vinciamo noi ovunque. */
body.public.senza-uscite .bottom-nav { display: none; }
body.public.senza-uscite main { padding-bottom: var(--s6); }

/* riquadro stretto al centro: lo usano la pagina d'errore e quella di
   account bloccato, che non sono schermate d'ingresso ma hanno la stessa
   forma. Prima si chiamava .auth-card ed è rimasta orfana quando
   l'accesso è passato allo schermo pieno. */
.page-card { max-width: 420px; margin: var(--s6) auto; }
/* la conferma dell'abbonamento al centro (2026-09-10, Francesco) */
.page-card--centro { text-align: center; }

.auth {
  width: 100%;
  max-width: 430px;
  margin: 0 auto;
  padding: var(--s5) var(--s4) var(--s6);
}
.auth-logo { display: block; width: 168px; height: auto; margin: 0 auto 44px; }
.auth-frase {
  margin: 0 0 30px;
  font-size: 13px;
  line-height: 1.6;
  text-align: center;
  color: var(--muted);
}
.auth-frase strong { color: var(--text); font-weight: 600; }

.auth-field { margin-bottom: 20px; }
.auth-field label {
  display: block;
  margin-bottom: 8px;
  font-size: var(--fs-meta);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--muted);
}
/* ⚠️ Il campo segnala GIÀ il fuoco diventando viola sul bordo: l'anello
   di sistema, staccato di 2px, era un secondo segnale per la stessa cosa
   e si accendeva a ogni tocco sul telefono (segnalato da Roberta). Qui
   diventa un alone attaccato al campo — resta ben visibile a chi si
   muove col tabulatore, senza la riga staccata. Niente `outline: none`
   e basta: lasciare un campo senza NESSUN segno di fuoco lo rende
   inservibile da tastiera. */
.auth-field input:focus,
.auth-field input:focus-visible {
  outline: none;
  border-color: var(--purple);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), .16);
}
/* Col dito l'alone non serve: sai benissimo quale campo hai toccato,
   l'hai toccato tu. Serve invece a chi si muove col tabulatore da
   computer, che senza non saprebbe dove sta scrivendo — e sulle pagine
   coach si lavora così tutto il giorno. Quindi resta di là e sparisce
   di qua, dove basta il bordo viola. `hover: none` + `pointer: coarse`
   = schermo che si usa col dito. */
@media (hover: none) and (pointer: coarse) {
  .auth-field input:focus,
  .auth-field input:focus-visible { box-shadow: none; }
}

.auth-aiuto {
  margin: 8px 0 0;
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--muted);
}
/* l'aiuto della casella sta attaccato alla sua riga, non a mezz'aria */
.auth-aiuto--ck { margin-top: 4px; padding-left: 34px; }

/* Casella a filo: il quadrato non si riempie, si accende. La spunta è
   DISEGNATA (icona del set) e non costruita ruotando l'angolo di un
   bordo, che è il trucco da cui veniva quella «v» storta. */
.auth-ck {
  display: flex;
  /* comanda la PRIMA riga dell'etichetta: con `center` e un'etichetta su
     due righe il quadrato finiva a metà, e con min-height finiva
     addirittura in cima a una riga alta 44px, staccato dalla scritta */
  align-items: flex-start;
  gap: 12px;
  /* l'area toccabile viene dall'imbottitura, non da un'altezza minima */
  padding: 11px 0;
  margin-top: 4px;
  font-size: 13.5px;
  line-height: 1.45;
  cursor: pointer;
}
.auth-ck input { position: absolute; opacity: 0; }
.auth-ck-box {
  display: grid;
  place-items: center;
  width: 22px; height: 22px;
  flex: none;
  /* il quadrato è 22px e la riga di testo 19,6: il mezzo pixel in su lo
     centra otticamente sulla scritta invece di appoggiarlo alla riga */
  margin-top: -1px;
  border: 1px solid var(--purple);
  border-radius: 7px;
  transition: background-color var(--speed);
}
.auth-ck-v {
  width: 15px; height: 15px;
  fill: none;
  stroke: var(--sel-fg);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
  transition: opacity var(--speed);
}
.auth-ck input:checked ~ .auth-ck-box { background: var(--sel-tint); }
.auth-ck input:checked ~ .auth-ck-box .auth-ck-v { opacity: 1; }
.auth-ck input:focus-visible ~ .auth-ck-box {
  outline: var(--fuoco-w) solid var(--fuoco-c);
  outline-offset: calc(-1 * var(--fuoco-w));
}

/* Il bottone è l'UNICA azione della pagina e deve pesare: filo viola
   acceso, non viola pieno con testo bianco. */
.auth-cta {
  display: block;
  width: 100%;
  margin-top: 26px;
  padding: 15px 0;
  border: 1px solid var(--purple);
  border-radius: var(--r-btn-lg);
  background: rgba(var(--accent-rgb), .14);
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  /* serve perché lo stesso stile veste anche dei collegamenti (link
     scaduto, email confermata): un <a> non centra il testo da solo */
  text-align: center;
  color: var(--sel-fg);
  cursor: pointer;
  transition: background-color var(--speed);
}
.auth-cta:hover { background: var(--sel-tint); text-decoration: none; }
.auth-cta:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }

/* «Accedi con Google» (2026-08-25, prima stesura — grafica da rivedere
   con Roberta): stessa ossatura del CTA ma a filo NEUTRO, non viola —
   è l'ingresso alternativo, non l'azione della pagina, e il marchio
   Google porta già i suoi colori. */
.auth-cta--google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 0;              /* il distacco lo dà il separatore */
  border-color: transparent;  /* stessa lingua di .btn-ghost */
  background: rgba(255, 255, 255, .06);
  color: var(--text);
}
.auth-cta--google:hover { background: rgba(255, 255, 255, .11); }
.auth-google-g { width: 18px; height: 18px; flex: none; }

/* la riga «oppure»: due filetti e la parola in mezzo */
.auth-sep {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 24px 0 18px;
  font-size: var(--fs-sm);
  color: var(--muted);
}
.auth-sep::before,
.auth-sep::after {
  content: '';
  flex: 1;
  border-top: 1px solid var(--line);
}

/* l'aiuto sotto il bottone Google della registrazione, centrato come lui */
.auth-aiuto--google { margin-top: 12px; text-align: center; }

.auth-nota { margin: 20px 0 0; font-size: var(--fs-sm); line-height: 1.55; color: var(--muted); }
.auth-nota a, .auth-links a { color: var(--brand-light); }
.auth-links {
  margin-top: 26px;
  font-size: 13px;
  text-align: center;
  color: var(--muted);
}
.auth-links p { margin-top: 10px; }
/* il messaggio d'errore sta sopra i campi, dove guarda chi ha sbagliato */
.auth .flash { margin-bottom: 22px; }

/* ══ v2.1 — DATE STRIP ═════════════════════════════════════════════── */
/* settimana fissa lun-dom: swipe (touch) o frecce per cambiare settimana */
.date-strip {
  /* non più sticky (round 2): allo scroll il calendario collassa dentro
     .strip-slot — per riaverlo si torna in cima */
  display: flex;
  align-items: center;
  gap: var(--s1);
  touch-action: pan-y;
  /* Niente più rettangolo a sé (2026-08-18). Aveva un fondo diverso dalla
     testata — rgba(10,10,11,.92), il vecchio nero caldo — più sfocatura e
     filo sotto: da lì lo stacco visibile fra testata e calendario. La
     sfocatura serviva quando la fascia era appiccicata in alto; da quando
     collassa scorrendo non serve più, ed è la stessa cosa che è già stata
     tolta dalla testata perché su iPhone veniva ricomposta in ritardo.
     L'imbottitura resta com'era: le caselle stanno più strette della
     testata di proposito, non devono allinearsi al nome. */
  padding: 10px var(--s2) 12px;
  margin: 0 0 var(--s2);
  background: var(--ink);
}
.date-strip-week { justify-items: center; }
/* viewport + track a 3 settimane: lo swipe fa scorrere le caselle in
   continuità (il track parte inquadrato sulla settimana centrale) */
.date-strip-view {
  flex: 1;
  min-width: 0;
  overflow: hidden;
}
.date-strip-track {
  display: flex;
  gap: var(--s1);
  transform: translateX(calc(-100% - var(--s1)));
}
.date-strip-week {
  flex: 0 0 100%;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--s1);
  min-width: 0;
}
.date-strip-arrow {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 44px;
  border-radius: var(--r-sm);
  color: var(--muted);
  text-decoration: none;
  transition: color var(--speed), background-color var(--speed);
}
a.date-strip-arrow:hover { color: var(--text); background: var(--surface-2); }
.date-strip-arrow--off { opacity: .25; }
/* su mobile basta lo swipe: via le frecce, le caselle guadagnano ~64px
   e il bordo arrotondato non si schiaccia più a "ovale" sui 360px */
@media (max-width: 639px) {
  .date-strip-arrow { display: none; }
}
/* Stati (grafica-wod 2026-08-11): selezionato = bordo viola 1px; oggi
   non selezionato = riempimento bianco .09; passato con score loggato =
   bordo bianco .16; futuri = numero spento. Il bordo transparent su
   TUTTE le celle evita che l'aggiunta del bordo sposti il layout. */
.date-pill {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 34px;
  padding: 7px 0;
  border-radius: 10px;
  border: 1px solid transparent;
  text-align: center;
  text-decoration: none;
  transition: color var(--speed), background-color var(--speed), border-color var(--speed);
}
a.date-pill:hover { text-decoration: none; background: var(--surface-2); }
/* giorno senza programmazione (o futuro non sbloccato): non cliccabile */
.date-pill--off { opacity: .55; }
.date-pill--off .date-pill-num { color: var(--dim); }
.date-pill-dow {
  font-family: var(--font);
  font-size: 8px;
  font-weight: 500;
  color: var(--grigio-44);
}
.date-pill-num {
  font-family: var(--font);
  font-size: 13px;
  font-weight: 600;
  color: var(--grigio-66);
  margin-top: 2px;
  /* niente cifre tabulari: il coach le ha bandite (2026-08-11, parevano
     un font monospaziato) — ovunque le proporzionali standard di Inter */
}
.date-pill.has-log { border-color: rgba(255,255,255,.16); }

/* ⭐ 2026-08-29 (chiesto da Francesco, che le card le guarda dal PC).
   ⚠️ Questo blocco sta QUI e non insieme alle altre regole da computer,
   che vivono più in alto: là dentro «.tl-btn-et { display: inline }»
   perdeva contro il «display: none» scritto dopo, a parità di forza.
   In CSS, a parità, vince l'ultima scritta. */
@media (min-width: 900px) {
  /* i tre bottoni della card si dividono la riga in parti uguali, e i due
     che avevano la sola icona scrivono cosa sono. Si vestono come «Coach
     notes»: icona agganciata a sinistra, etichetta al centro, numerino
     accanto all'icona.
     ⚠️ La card della nota del giorno (--info) resta a una colonna sola:
     lì l'azione è una e sta larga quanto la card. */
  /* ⭐ 2026-09-19 (Francesco: «da PC i pulsanti non occupano più tutto
     lo schermo, si fermano nel mezzo»): le colonne si contano da sole.
     Prima erano un numero FISSO — tre, quattro col cronometro — ma i
     bottoni presenti sono meno quando la card non ha «Leaderboard» (il
     WOD senza nessun risultato) o non ha il cronometro: la colonna in
     più restava vuota e la fila si fermava a due terzi della card.
     Con `grid-auto-flow: column` + `grid-auto-columns: 1fr` le colonne
     sono quante sono i bottoni, tutte uguali, e la riga arriva in fondo
     comunque. ⚠️ Serve `grid-template-columns: none` per spegnere le
     colonne dichiarate sotto i 900, sennò quelle vincono e le auto si
     aggiungono in coda. */
  .tl-actions:not(.tl-actions--info) {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
  }
  .tl-btn-et { display: inline; }
  .tl-btn--mini { min-width: 0; padding: 10px 12px; }
  /* ⭐ 2026-08-31 (Roberta, dopo averle guardate tutte e sei): icona e
     scritta stanno INSIEME, e la coppia si centra nel bottone. Sul
     telefono l'icona resta agganciata al bordo con la scritta al centro —
     lì il bottone è largo e ci sta — ma da computer, coi bottoni stretti,
     l'icona restava sola contro il bordo e la scritta lontana.
     ⚠️ Il prezzo, misurato e accettato: le icone dei quattro bottoni NON
     stanno in colonna fra loro (35, 55, 35, 31 dal bordo), perché ogni
     gruppo si centra per conto suo e le parole hanno lunghezze diverse.
     Con bottoni tutti uguali o si centrano i gruppi o si allineano le
     icone: provate tutte e due, scelto centrare. */
  .tl-actions:not(.tl-actions--info) .tl-btn--mini .icon,
  .tl-actions:not(.tl-actions--info) .tl-btn-icon { position: static; }
  /* 9 e non 6 fra icona e scritta: la coppia respira e non sembra un
     blocco unico incollato */
  .tl-actions:not(.tl-actions--info) .tl-btn { gap: 9px; }
  /* Il numerino sta NEL gruppo centrato, dopo la scritta, con un filo
     di aria in più (2026-09-04, Francesco: «Leaderboard 11» col numero
     appeso al bordo destro in assoluto era «totalmente disallineato»:
     lontano a tre bottoni, incollato alla parola a quattro, e la scritta
     non era mai al centro col resto). Prima stava a destra in assoluto
     (2026-08-31): a specchio dell'icona, ma il gruppo icona+scritta si
     centrava da solo e il numero galleggiava. */
  .tl-actions:not(.tl-actions--info) .tl-btn-count {
    position: static;
    margin-left: 2px;
    opacity: .75;
  }
  /* imbottitura pari: con l'icona in riga non c'è più un lato che deve
     tenerle il posto */
  .tl-actions:not(.tl-actions--info) .tl-btn { padding-left: 12px; padding-right: 12px; }

  /* il calendario: le pastiglie erano larghe 34 dentro caselle da 83, e la
     settimana sembrava rannicchiata in mezzo a tutta quell'aria. A 64
     respirano senza prendersi tutta la casella (provata anche a tutta
     larghezza: troppo). */
  .date-strip .date-pill { width: 64px; margin: 0 auto; }
}
.date-pill.is-today:not(.active) { background: rgba(255,255,255,.09); }
.date-pill.is-today:not(.active) .date-pill-num { color: var(--grigio-91); }
.date-pill.active { border-color: var(--purple); }
.date-pill.active .date-pill-dow { color: var(--accent-etichetta); }
.date-pill.active .date-pill-num { color: var(--text); }
.home-day-title { margin-bottom: var(--s3); }

/* ══ v2.1 — TIME DUO / TOGGLE SM ══════════════════════════════════── */
/* Tempo = due celle MIN/SEC affiancate (pacchetto grafico v2: il wheel a
   scorrimento è stato rimosso). Lo stile pieno è .two/.cell nella
   sezione v1.3 in fondo: qui resta il minimo per il markup legacy. */
.time-duo { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.time-duo input { width: 100%; text-align: center; }
/* ⛔ i due punti FRA le due caselle sono durati mezz'ora il 2026-08-28:
   provati su richiesta di Francesco e tolti subito dopo averli visti
   («non mi piacciono»). Restano invece nei tempi per intervallo, dove
   le caselle sono strette e senza separatore non si leggerebbero come
   un tempo (`.mc-duo`). La classe resta spenta com'era. */
.time-duo-sep { display: none; }

/* sparkline dei personal records: la classe la scrive l'SVG generato da
   services/spark.py (il wrapper è .rm-spark, sezione PERSONAL RECORDS) */
.spark { display: block; max-width: 100%; }

/* ══ v1.2 — PERSONAL RECORDS (grafica-crossfit-iris, 2026-08-11) ═════
   Scritta sul riferimento "record" del kit grafico.
   Valori copiati 1:1 (vincolo del coach: non arrotondare). Mappa classi
   spec → produzione (prefisso rm- SOLO sulle collisioni con la
   timeline): .feed→.rm-feed · .node→.rm-node · .rail→.rm-rail ·
   .dot→.rm-dot · .group→.rm-group · .cta→.rm-cta; tutte le altre
   (.filters .filter .cat-card .rm-row .tiles .tile .section-label
   .detail-* .rep-tag .type-tag .pct*) sono 1:1 dalla spec.
   Colore categoria via --cat (inline dal server); il viola brand non
   identifica MAI una categoria. */

.home-head-sub { font-size: 14px; font-weight: 500; color: var(--grigio-66); margin-top: 5px; }

/* filtri categoria: il chip attivo mostra il nome per esteso, gli altri
   l'iniziale. L'espansione è animata dalle View Transitions cross-doc
   (view-transition-name inline per chip): 200ms come da spec */
.filters { display: flex; gap: 7px; padding: 16px 2px 0; }
.filter {
  display: flex;
  align-items: center;
  gap: 6px;
  border: 0;
  border-radius: 999px;
  padding: 7px 12px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  color: var(--grigio-62);
  background: rgba(255, 255, 255, .05);
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  transition: background .15s ease;
}
.filter:hover { text-decoration: none; background: rgba(255, 255, 255, .09); }
.filter--compact { padding: 7px 11px; font-weight: 600; }
.filter--icon { padding: 7px 11px; }
.filter--icon .filter-ms { width: 16px; height: 16px; }
.filter.is-active { background: var(--sel-tint); color: var(--sel-fg); }
.filter-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
::view-transition-group(rm-f-all),
::view-transition-group(rm-f-weightlifting),
::view-transition-group(rm-f-strength),
::view-transition-group(rm-f-gymnastics),
::view-transition-group(rm-f-cardio) { animation-duration: .2s; }

/* lista a nodi (stato Tutti): stessa geometria della timeline ma
   statica — niente stati, niente toggle, dot fisso 12px */
.rm-feed { padding: 16px 2px 10px; }
.rm-node { display: grid; grid-template-columns: 26px 1fr; }
.rm-rail { position: relative; }
.rm-rail-top, .rm-rail-bot {
  position: absolute;
  left: 12px;
  width: 2px;
  background: var(--rail-off);
}
.rm-rail-top { top: 0; height: 19px; }
.rm-rail-bot { top: 19px; bottom: 0; }
.rm-node--first .rm-rail-top { display: none; }
.rm-node--last  .rm-rail-bot { display: none; }
.rm-dot {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  border-radius: 50%;
  box-sizing: content-box;
  border: 3px solid var(--ink);
  width: 12px;
  height: 12px;
  top: 13px;
}

.cat-card { background: var(--surface); border-radius: 14px; padding: 12px 14px 6px; margin-bottom: 10px; }
.cat-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.cat-title { font-size: 15px; font-weight: 600; color: var(--text); }
.cat-count { font-size: var(--fs-meta); font-weight: 500; font-variant-numeric: tabular-nums; }
.cat-divider { height: 1px; background: rgba(255, 255, 255, .07); margin: 10px 0 2px; }

.rm-row {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 0;
  border-bottom: 1px solid rgba(255, 255, 255, .05);
  text-decoration: none;
}
.rm-row:last-of-type { border-bottom: 0; }
.rm-row:hover { text-decoration: none; }
a.rm-row:hover .rm-name { color: var(--text); }
.rm-name { flex: 1; font-size: 13px; font-weight: 400; color: var(--body-text); min-width: 0; overflow-wrap: anywhere; }
.rm-value { font-size: 14px; font-weight: 600; color: var(--text); white-space: nowrap; font-variant-numeric: tabular-nums; }
.rm-value span { font-size: var(--fs-eyebrow); font-weight: 500; color: var(--muted); margin-left: 2px; }
.cat-more {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 0 12px;
  font-size: 12px;
  font-weight: 500;
  color: var(--grigio-44);
  text-decoration: none;
}
.cat-more:hover { text-decoration: none; color: var(--grigio-62); }
.cat-more .icon { width: 16px; height: 16px; color: var(--dim); }

/* griglia tessere (categoria aperta) */
.section-label { font-size: var(--fs-eyebrow); font-weight: 600; padding: 18px 2px 9px; }
.tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 0 2px; }
.tile {
  background: var(--surface);
  border-radius: 12px;
  padding: 10px 12px 11px;
  text-decoration: none;
  display: block;
}
.tile:hover { text-decoration: none; }
a.tile:hover .tile-name { color: var(--grigio-80); }
.tile-name { font-size: var(--fs-eyebrow); font-weight: 500; color: var(--grigio-62); overflow-wrap: anywhere; }
.tile-value { font-size: 21px; font-weight: 700; color: var(--text); margin-top: 4px; font-variant-numeric: tabular-nums; }
.tile-value span { font-size: var(--fs-meta); font-weight: 500; color: var(--muted); margin-left: 2px; }
.tile-meta { font-size: 9px; color: var(--grigio-35); margin-top: 3px; }
.tile--empty { background: none; border: 1px dashed rgba(255, 255, 255, .10); }
.tile-add { display: flex; align-items: center; gap: 4px; font-size: var(--fs-meta); font-weight: 500; color: var(--grigio-44); margin-top: 6px; }
.tile-add .icon { width: 15px; height: 15px; }

/* dettaglio movimento. position+z-index: nei PR spiati la barra sta
   SOPRA una .home-head sticky (z-index 20), e senza stacking context il
   paraurti .home-head::before la copriva — freccia invisibile e non
   cliccabile (QA 2026-08-18) */
.detail-nav { display: flex; align-items: center; gap: 12px; padding: 15px 0 13px; position: relative; z-index: 21; }
.detail-head { padding: 6px 2px 0; }
.detail-eyebrow { font-size: var(--fs-eyebrow); font-weight: 500; }
/* Inter 22/700, MAI Anton: è la stessa entità dell'elenco (regola coach) */
.detail-title { font-size: 22px; font-weight: 700; color: var(--text); line-height: 1.15; margin-top: 6px; overflow-wrap: anywhere; }
.detail-big { display: flex; align-items: baseline; gap: 6px; margin-top: 12px; }
.detail-big-value { font-size: 42px; font-weight: 700; color: var(--text); line-height: 1; }
.detail-big-unit { font-size: 15px; font-weight: 500; color: var(--muted); }
.detail-meta { font-size: var(--fs-meta); color: var(--grigio-44); margin-top: 6px; }
.rm-spark { color: var(--cat, var(--purple)); margin-top: 12px; }
.rm-spark .spark { width: 100%; }

/* gruppo record (MASSIMALI / I TUOI RECORD) */
.rm-group { background: var(--surface); border-radius: 14px; margin: 0 2px; overflow: hidden; }
.rm-group-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 13px;
  border-bottom: 1px solid rgba(255, 255, 255, .05);
}
.rm-group-row:last-child { border-bottom: 0; }
/* larghezza fissa SOLO per 1RM…5RM (tutti lunghi uguali, si incolonnano);
   i tipi (MAX SET, MAX KG…) hanno lunghezze diverse: larghezza auto,
   sennò il testo esce dal badge */
.rep-tag {
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  color: var(--grigio-80);
  background: rgba(255, 255, 255, .07);
  padding: 3px 7px;
  border-radius: 6px;
  width: 42px;
  text-align: center;
  flex: none;
}
.type-tag {
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  color: var(--grigio-80);
  background: rgba(255, 255, 255, .07);
  padding: 3px 8px;
  border-radius: 6px;
  text-align: center;
  flex: none;
  white-space: nowrap;
}
.rep-date { flex: 1; font-size: var(--fs-meta); color: var(--grigio-44); min-width: 0; overflow-wrap: anywhere; }
.rep-add {
  font-size: 12px;
  font-weight: 500;
  color: var(--brand-light);
  background: none;
  border: 0;
  padding: 0;
  font-family: inherit;
  cursor: pointer;
  position: relative;
}
.rep-add::after { content: ''; position: absolute; inset: -12px -8px; }
.rep-add:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
/* il valore registrato è cliccabile (riapre la sheet di aggiornamento) */
.rm-row-btn { background: none; border: 0; padding: 0; font-family: inherit; cursor: pointer; position: relative; }
.rm-row-btn::after { content: ''; position: absolute; inset: -12px -8px; }
.rm-row-btn:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }

/* percentuali: fascia di lavoro 70-85 tinta nel colore della categoria */
.pct { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 0 2px; }
.pct-cell { background: var(--surface); border-radius: 10px; padding: 9px 11px; display: flex; align-items: baseline; justify-content: space-between; }
.pct-key { font-size: var(--fs-meta); font-weight: 600; color: var(--muted); font-variant-numeric: tabular-nums; }
.pct-value { font-size: 15px; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.pct-value span { font-size: var(--fs-eyebrow); font-weight: 500; color: var(--muted); margin-left: 2px; }
.pct-cell--work { background: color-mix(in srgb, var(--cat, var(--purple)) 10%, transparent); }
.pct-cell--work .pct-key { color: var(--cat, var(--purple)); }

.rm-cta {
  margin: 18px 2px;
  width: calc(100% - 4px);
  border-radius: var(--r-btn);
  background: var(--btn-tint);
  color: var(--brand-light);
  font-size: 13px;
  font-weight: 500;
  padding: 13px 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  border: 0;
  font-family: inherit;
  cursor: pointer;
  transition: background-color var(--speed);
}
.rm-cta:hover { background: var(--btn-tint-hover); }
.rm-cta:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
.rm-cta .icon { width: 18px; height: 18px; }

/* storico prove nella sheet */
.rm-group--sheet .rm-group-row { flex-wrap: wrap; }
.rm-src { color: var(--brand-light); text-decoration: none; }
.rm-src:hover { text-decoration: underline; }
.rm-del { flex: 0 0 auto; }

/* ══ v1.3 — CLASSIFICA (kit grafico v2, riferimento-leaderboard.html) ═
   Pagina piena: nav · occhiello+titolo · chip filtro · conteggio ·
   righe con pastiglia commenti · dock in fondo.
   Mappa classi spec → produzione (i nomi della spec sono troppo
   generici per un CSS globale): .lbcard→.lb-card · .lr→.lb-row ·
   .pos→.lb-pos · .av→.lb-av · .nm→.lb-name · .sc→.lb-score ·
   .cpill→.lb-cpill · .me→.lb-row--me · .exp→.lb-exp · .quote→.lb-quote ·
   .dock→.lb-dock · .lbempty→.lb-empty; 1:1 .cmt* e .chip.
   Regole non negoziabili: la pastiglia commenti è larga 38px in OGNI
   stato (se si stringe il punteggio balla a ogni tocco) e sopra la
   fascia viola i controlli si SCHIARISCONO, non si scuriscono. */

body.lb-page main > .container { padding-bottom: 96px; }
.lb-hero { padding-bottom: 0; }
.lb-chips { padding: 0 2px; margin-top: 14px; }
.lb-sep { width: 1px; background: rgba(255, 255, 255, .08); margin: 4px 3px; }
.lb-count { font-size: var(--fs-meta); color: var(--muted); padding: 13px 2px 8px; }

.lb-card { background: var(--surface); border-radius: 14px; padding: 4px 14px; }
.lb-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 0;
  border-bottom: 1px solid rgba(255, 255, 255, .05);
}
/* ⚠️ :last-of-type non bastava: dopo ogni riga c'è il blocco dei commenti,
   quindi l'ultima riga non è mai l'ultimo div fra i fratelli e la regola
   non mordeva mai — era il filetto che restava sotto l'ultimo in classifica.
   «Una riga che non ha altre righe dopo di sé» invece è sempre l'ultima. */
.lb-row:not(:has(~ .lb-row)) { border-bottom: 0; }
/* ⚠️ Nemmeno la riga SOPRA la mia: il riquadro viola ha già un bordo suo
   e il filo ci finiva appoggiato sopra (segnalato da Roberta il
   2026-08-19). Le quattro varianti non sono un vezzo: fra una riga e
   l'altra stanno le tendine (serie, fist bump, commenti), da zero a tre,
   quindi la mia riga non è quasi mai la vicina immediata di quella
   sopra e `+ .lb-row--me` da solo non aggancia niente. */
.lb-row:has(+ .lb-row--me),
.lb-row:has(+ .lb-exp + .lb-row--me),
.lb-row:has(+ .lb-exp + .lb-exp + .lb-row--me),
.lb-row:has(+ .lb-exp + .lb-exp + .lb-exp + .lb-row--me) { border-bottom: 0; }
.lb-pos {
  width: 18px;
  font-size: 12px;
  font-weight: 700;
  color: var(--grigio-51);
  /* a SINISTRA e non a destra (2026-08-19): allineata a destra, la cifra
     di una posizione a una sola cifra cominciava 6px dentro la sua
     casella — i bordi erano simmetrici (14px di qua, 14 di là) ma
     l'inchiostro no, e il numero sembrava rientrato. Le posizioni a due
     cifre restano incolonnate lo stesso: la casella è larga uguale. */
  text-align: left;
  /* 4px in più: a filo esatto della pastiglia (14px per entrambi) la
     cifra sembrava comunque più fuori, perché la pastiglia è una forma
     PIENA e il numero è solo inchiostro — a parità di distanza il pieno
     tiene il bordo, il segno no. Misure: cifra a 18px, pastiglia a 14. */
  padding-left: 4px;
  font-variant-numeric: tabular-nums;
  flex: none;
}
.lb-av {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .10);
  color: var(--grigio-80);
  font-size: 9px;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  overflow: hidden;
  text-decoration: none;
}
.lb-av img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lb-av .avatar-initials { font-size: 9px; font-weight: 600; }
/* Persona = foto + nome: stanno vicini fra loro e più vicini al numero.
   Lo spazio uniforme della riga li teneva distanti come se fossero tre
   cose separate, e con la cifra allineata a sinistra restava un buco fra
   il numero e la foto (2026-08-19). La cifra a due numeri ha comunque
   8px di franco prima della foto. */
.lb-pos + .lb-av { margin-left: -6px; }
.lb-av + .lb-name { margin-left: -4px; }
/* Tocco sul nome: foto e nome si accendono e restano accesi finché la
   pagina si apre — aprire il profilo di un altro atleta è lento e senza
   segnale sembra che il tocco non sia stato preso (2026-08-19). Solo
   foto e nome, NON tutta la riga: il punteggio e le due pastiglie si
   toccano per conto loro e accenderli direbbe una cosa falsa.
   ⚠️ Stato PREMUTO e non «passaggio del mouse»: sul telefono l'hover
   resta appiccicato dopo il tocco, e qui lascerebbe acceso un nome anche
   dopo essere tornati indietro. */
.lb-name:active { color: var(--brand-light); }
.lb-row.is-attesa .lb-name { color: var(--brand-light); }
.lb-row.is-attesa .lb-av,
.lb-row.is-attesa .lb-name { opacity: .55; }
.lb-av, .lb-name { transition: opacity .12s ease, color .12s ease; }

.lb-name {
  flex: 1;
  min-width: 0;
  /* 11 e non 12 (2026-08-19): insieme al punteggio a 12 dà al nome sei
     pixel in più di respiro */
  font-size: 11px;
  font-weight: 500;
  color: var(--grigio-91);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-decoration: none;
}
a.lb-name:hover { text-decoration: none; color: var(--text); }
.lb-score {
  /* 13 e non 15: a 15px il punteggio pesava più del nome e con i
     `sets_load` («60 → 105 kg») mangiava lo spazio che serve all'altro,
     che finiva in ellissi già su «Francesco B.».
     ⚠️ 13px è fuori scala di mezzo pixel rispetto a --fs-sm (13.5).
     Scelto da Roberta guardandolo sul telefono: si tiene com'è, ma se un
     giorno si riordina la scala questo è il punto da rivedere. */
  /* 12 e non 13 (2026-08-19): sei pixel in più al nome, che nella riga
     è la colonna più stretta — su sei nomi di prova ne entra uno in più.
     Non è la soluzione del nome tagliato, è una rifinitura: le leve vere
     sono le due pastiglie o il punteggio a capo. */
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  flex: none;
  text-align: right;
  min-width: 58px;
}
.lb-score span { font-size: var(--fs-eyebrow); font-weight: 400; color: var(--muted); margin-left: 2px; }

/* pastiglia commenti: LARGHEZZA 38px IN OGNI STATO */
.lb-cpill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  width: 38px;
  padding: 4px 0;
  border: 0;
  border-radius: 999px;
  font-family: inherit;
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  color: var(--grigio-66);
  background: rgba(255, 255, 255, .07);
  flex: none;
  cursor: pointer;
  font-variant-numeric: tabular-nums;
  transition: background-color .15s ease, color .15s ease;
}
/* 15 e non 12: il disegno del pugno non era il problema principale, la
   misura sì — nel riferimento (Strive) l'icona è quasi il doppio, dentro
   una pastiglia con l'etichetta scritta. A 12px i solchi fra le dita
   valgono mezzo pixel e spariscono; a 15 si vedono. */
.lb-cpill .icon { width: 15px; height: 15px; }
.lb-cpill--empty { color: var(--dim); background: rgba(255, 255, 255, .035); }
/* ⚠️ Da APERTA la pastiglia esce dallo stato «vuoto»: aperta è aperta, e
   due pastiglie aperte devono vedersi uguali. Con lo spento addosso, lo
   stesso chevron dentro un fondo al 3,5% e dentro uno al 13% sembrava
   due chevron diversi (segnalato da Roberta il 2026-08-19). */
.lb-cpill--empty.open { color: var(--grigio-80); background: rgba(255, 255, 255, .13); }
.lb-row--me .lb-cpill--empty.open { color: var(--grigio-80); background: rgba(255, 255, 255, .13); }
.lb-cpill:hover { color: var(--grigio-91); }
/* aperta: al posto della nuvoletta compare un chevron, che dice come si
   chiude. Prima si girava di 180° l'icona stessa e la nuvoletta finiva a
   testa in giù. Colore e larghezza non cambiano: che la riga sia aperta si
   vede già dal blocco che si è aperto sotto. */
.lb-cpill-shut { display: flex; align-items: center; gap: 3px; }
.lb-cpill-open { display: none; }
.lb-cpill.open .lb-cpill-shut { display: none; }
.lb-cpill.open .lb-cpill-open { display: block; }
.lb-cpill:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }

/* fist bump: stessa pastiglia dei commenti, ma non apre nulla — il tap
   lo dà e lo toglie. Acceso = il viola della selezione, lo stesso dei
   chip: in questa app "scelto da me" è sempre viola.
   ⚠️ .open non la riguarda (niente freccia da girare) */
.lb-cpill--bump.on {
  color: var(--brand-light);
  background: rgba(var(--accent-rgb), .22);
}
/* in sola lettura (la propria riga, o chi non può darlo): resta una
   pastiglia, ma non finge di essere un bottone */
span.lb-cpill--bump { cursor: default; }

/* la tua riga: fascia viola, controlli SCHIARITI (con un colore più
   scuro la pastiglia diventa quasi nera e sparisce) */
.lb-row--me {
  background: rgba(var(--accent-rgb), .12);
  border-radius: 10px;
  margin: 0 -8px;
  padding-left: 8px;
  padding-right: 8px;
  border-bottom: 0;
}
.lb-row--me .lb-pos { color: var(--accent-etichetta); }
.lb-row--me .lb-name { color: var(--accent-testo); }
.lb-row--me .lb-av { background: rgba(var(--accent-rgb), .30); color: var(--accent-testo); }
.lb-row--me .lb-cpill { background: rgba(255, 255, 255, .13); color: var(--grigio-80); }
.lb-row--me .lb-cpill--empty { background: rgba(255, 255, 255, .07); color: var(--grigio-44); }

/* commenti: la fascia viola NON si estende qui — evidenzia la riga, non
   il blocco. .lb-exp è un wrapper .clp (apertura animata, 2026-08-18):
   il padding sta sull'INNER, sul wrapper resterebbe visibile da chiuso.
   ⛔ .lb-quote rimossa lo stesso giorno: la nota pubblica è renderizzata
   come primo commento (.cmt--note), deciso da Francesco. */
/* Il punteggio compattato è un bottone: si apre e mostra le serie.
   Deve restare identico al punteggio normale — se cambia peso o colore,
   la colonna dei numeri smette di leggersi come una colonna. */
.lb-score--apri {
  border: 0;
  background: none;
  padding: 0;
  color: inherit;
  cursor: pointer;
  /* ⚠️ NON `font: inherit`: la scorciatoia azzera anche il peso e il
     numero perdeva il grassetto di .lb-score, diventando più leggero
     degli altri della stessa colonna (visto da Roberta). Qui serve solo
     la famiglia, che sui bottoni il browser cambia di suo. */
  font-family: inherit;
}
/* ⚠️ Il colore del passaggio vale SOLO dove esiste un mouse: sul dito
   il :hover resta appiccicato dopo il tocco — il numero restava viola
   anche dopo aver richiuso la tendina, e tornava bianco solo toccando
   altrove (segnalato da Roberta il 2026-08-19) */
@media (hover: hover) {
  .lb-score--apri:hover { color: var(--brand-light); }
}
.lb-score--apri:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
/* il chevron dei punteggi che si aprono (2026-09-10, Roberta): il numero
   nudo non diceva che sotto c'è il dettaglio dello scaling o delle serie.
   Guarda in GIÙ da chiuso e si raddrizza da aperto, così dice anche come
   si richiude — la stessa cosa che fa la pastiglia dei commenti accanto.
   ⚠️ L'icona sta dentro il bottone, che diventa una riga a due: senza
   inline-flex il numero perdeva l'allineamento a destra della colonna. */
.lb-score--apri {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 5px;
}
.lb-score-ic {
  width: 12px;
  height: 12px;
  flex: none;
  color: var(--muted);
  transform: rotate(180deg);
  transition: transform .2s ease;
}
.lb-score--apri[aria-expanded="true"] .lb-score-ic { transform: rotate(0); }
/* ⚠️ Il posto della freccia lo tengono ANCHE i punteggi che non si
   aprono (2026-09-10, visto da Roberta): in una classifica mista —
   chi ha scalato e chi no — i numeri con la freccia rientravano di 17
   e la colonna dei tempi non era più incolonnata. 12 dell'icona + 5 di
   stacco: la stessa misura, tenuta vuota. */
.lb-row .lb-score:not(.lb-score--apri) { padding-right: 17px; }
/* ⚠️ `.lb-row` davanti: il punteggio della barra in basso (.lb-dock)
   usa la stessa classe e non ha righe da incolonnare — lì i 17
   punti erano solo un buco a destra. */
/* chi tiene spente le animazioni non vede girare niente: il chevron
   cambia verso e basta (stessa regola del resto dell'app) */
@media (prefers-reduced-motion: reduce) {
  .lb-score-ic { transition: none; }
}

/* le serie, una per riga: il numero della serie e il carico */
.lb-serie { list-style: none; display: grid; gap: 7px; }
.lb-serie li { display: flex; align-items: baseline; gap: 10px; }
.lb-serie-n {
  width: 18px;
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}
.lb-serie-kg {
  /* 12 come il punteggio nella riga: è lo stesso dato, scomposto */
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* dettaglio per-intervallo degli Intervals (0045): etichette parlanti
   («#3 · Ski Erg», «G2 · Sandbag Clean»), non i soli numeri di serie */
.lb-serie--iv .lb-serie-n { width: auto; min-width: 18px; }
.lb-serie--iv + .lb-scaling { margin-top: 12px; }

/* cosa ha scalato (WOD codificati, 0041): righe di diff vs l'Rx */
.lb-scaling { list-style: none; display: grid; gap: 7px; }
.lb-scaling li {
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* chi ti ha dato il pugno */
.lb-bumpers { list-style: none; display: grid; gap: 10px; }
.lb-bumpers li { display: flex; align-items: center; gap: 9px; }
/* ⚠️ nome e ora COME NEI COMMENTI: sono la stessa cosa — una persona e
   quando l'ha fatto — e le due tendine si aprono a due centimetri di
   distanza. Avevo scritto misure mie: nome 13/400 contro 11/600 e ora
   12,5 chiara contro 10 spenta (trovate il 2026-08-19 confrontandole). */
.lb-bumper-nome { flex: 1; min-width: 0; font-size: 11px; font-weight: 600; color: var(--grigio-80); }
.lb-bumper-ic { width: 15px; height: 15px; color: var(--brand-light); flex: none; }
.lb-bumper-quando { font-size: var(--fs-eyebrow); color: var(--grigio-35); }

/* Titolo di gruppo della lista unica (2026-08-19): stessa etichetta
   delle sezioni del profilo. Quello del genere di chi guarda è viola:
   con quattro gruppi in colonna serve un aggancio per l'occhio. */
.lb-gtitle {
  margin: 22px 0 7px;
  padding-left: 2px;
  font-size: var(--fs-meta);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--muted);
}
.lb-gtitle--mio { color: var(--brand-light); }
.lb-group:first-child .lb-gtitle { margin-top: 6px; }
/* categoria senza risultati: resta solo il titolo, spento. Il gruppo
   c'è ancora — si vede che quella categoria esiste — ma non ruba spazio
   ai risultati veri. ⚠️ Il grigio è quello dei giorni futuri: più chiaro
   e non si distingueva dalle categorie piene. */
.lb-gtitle--vuoto { color: var(--dim); }

/* ── Rispondi + tag @ nei commenti (0052, 2026-08-27) — grafica prima
   stesura ────────────────────────────────── */
/* il bottone «Rispondi»: fantasma come il cestino accanto, ma all'hover
   prende il viola dell'azione, non il rosso del pericolo */
.cmt-reply-btn {
  background: none;
  border: 0;
  padding: 0 0 0 4px;
  color: var(--grigio-35);
  cursor: pointer;
  display: flex;
  transition: color var(--speed);
}
.cmt-reply-btn:hover { color: var(--brand-light); }
/* il tag dentro il commento: viola e col peso di un nome. È un <a> se il
   profilo del taggato è consultabile, uno <span> identico se è fuori
   classifica (mai un link morto) */
.cmt-tag { color: var(--brand-light); font-weight: 600; text-decoration: none; }
a.cmt-tag:hover { text-decoration: underline; }
.lb-goto:hover { text-decoration: underline; }

/* dock: compare quando la tua riga esce dallo schermo */
.lb-dock {
  position: fixed;
  /* centrato coi margini, non con una trasformazione: un elemento fisso
     E trasformato è il pattern che su iOS si scolla dal bordo quando la
     barra degli indirizzi si muove. La trasformazione resta solo per i
     200ms dell'entrata, e da fermo torna `none` (2026-08-21). */
  left: 0; right: 0;
  margin-inline: auto;
  translate: 0 12px;
  bottom: calc(var(--nav-h) + env(safe-area-inset-bottom));
  width: min(calc(100% - 32px), 448px);
  background: var(--surface);
  border-radius: 14px;
  padding: 5px 14px;
  box-shadow: 0 6px 22px rgba(0, 0, 0, .6),
              inset 0 0 0 1px rgba(var(--accent-rgb), .45);
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease, translate .2s ease;
  z-index: 30;
}
.lb-dock.show { opacity: 1; translate: none; pointer-events: auto; }
.lb-dock-inner { display: flex; align-items: center; gap: 10px; padding: 6px 0; }
.lb-dock .lb-name { color: var(--accent-testo); }
.lb-dock .lb-pos { color: var(--accent-etichetta); }
.lb-dock .lb-av { background: rgba(var(--accent-rgb), .30); color: var(--accent-testo); }
.lb-edit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  /* stessa altezza delle due pastiglie della riga: era 20px contro i loro
     26 e nel dock si vedeva schiacciata. Il padding è quello di
     .lb-cpill, così restano uguali per costruzione e non per coincidenza */
  padding: 4px 0;
  border-radius: 999px;
  background: rgba(var(--accent-rgb), .18);
  color: var(--brand-light);
  flex: none;
  text-decoration: none;
}
.lb-edit .icon { width: 15px; height: 15px; }
/* col solo bottone Score il bottone È il dock: niente padding attorno,
   stesso raggio (sennò l'hover lascia una cornice scura).
   ⚠️ `translate: none` come .show, e NIENTE transform: dal 2026-08-21 la
   base si centra coi margini, e il vecchio translate(-50%) — rimasto qui
   dopo la #26 — la spostava di mezzo dock a sinistra (bug segnalato da
   Francesco sulla classifica senza score). */
.lb-dock--always { padding: 0; opacity: 1; pointer-events: auto; translate: none; }
/* dock sempre visibile ma col RISULTATO dentro (chi è fuori dalla
   classifica ha già registrato): --always azzera il padding perché
   pensato per il bottone a tutta larghezza, qui va rimesso.
   ⛔ .lb-dock--score rimossa il 2026-08-18: il suo unico consumatore era
   il ramo anti-sbircio di wod_board.html, caduto con la regola */
.lb-dockbtn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 15px 0;
  border-radius: var(--r-btn-lg);
  font-size: 14px;
  font-weight: 600;
  color: var(--brand-light);
  text-decoration: none;
  transition: background-color .15s ease, color .15s ease;
}
.lb-dockbtn:hover { background: rgba(var(--accent-rgb), .14); color: var(--accent-testo); text-decoration: none; }
.lb-dockbtn .icon { width: 19px; height: 19px; }
/* pastiglia commenti spenta (l'atleta non li accetta): occupa lo spazio
   ma non è un controllo — la riga resta allineata come le altre */
/* pastiglia spenta: niente sfondo neppure nella PROPRIA riga, dove
   `.lb-row--me .lb-cpill` (0,2,0) vincerebbe per specificità e la
   farebbe sembrare un bottone pieno ma finto */
.lb-cpill--off,
.lb-row--me .lb-cpill--off { background: none; pointer-events: none; }

/* ── Privacy: pannello nel profilo e informativa ──────────────────── */
.privacy-consent {
  margin-top: var(--s4);
  padding-top: var(--s3);
  border-top: 1px solid var(--line);
}
.privacy-page h2 { margin-top: var(--s5); }
.privacy-page p { line-height: 1.7; }
.auth-privacy { margin-top: var(--s3); text-align: left; }

/* ── Variante COMPETITOR ──────────────────────────────────────────── */
/* il selettore delle due versioni riusa la barra segmentata del kit v2
   (.mini/.mbtn): qui però sono <button> (dal 2026-08-14: prima erano link
   alla pagina /wod/<id>, che non esiste più), non radio */
/* ⭐ Dal 2026-08-17 non è più una barra segmentata piazzata in mezzo al
   testo, ma due nomi in coda al workout: ACCESO quello che stai leggendo,
   spento e toccabile l'altro. Ordine fisso, Competitor a sinistra.
   ⚠️ Solo il COLORE del carattere, nessuno sfondo: è una riga di testo,
   non un controllo pieno. La pastiglia l'aveva provata e scartata. */
.tl-variant {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 10px;
  font-size: var(--fs-meta);
  font-weight: 600;
}
.tl-variant-arrow { width: 12px; height: 12px; color: var(--dim); flex: none; }
.tl-variant-on,
.tl-variant-go {
  padding: 0;
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  background: none;
  /* il colore passa da un nome all'altro mentre la card si ribalta,
     invece di saltare a metà animazione */
  transition: color .3s ease;
}
.tl-variant-on { color: var(--brand-light); }
.tl-variant-go {
  position: relative;
  border: 0;
  color: var(--muted);
  cursor: pointer;
}
.tl-variant-go:hover { color: var(--text); }
/* il testo è alto 17px: senza questo il bersaglio sarebbe metà del minimo */
.tl-variant-go::after { content: ''; position: absolute; inset: -13px -8px; }
.tl-variant-go:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }

/* Lo scambio fra le due versioni è tutto in JS (home_timeline.js): non
   bastavano le view transition perché il difetto non era di paint ma di
   LAYOUT — le due versioni hanno testi di lunghezza diversa, la card
   cambia altezza e il segmento di barra della timeline si spezzava.
   Là l'altezza viene animata da quella vecchia a quella nuova, così la
   barra si allunga in continuità. Qui non serve nulla. */

/* nella riga compatta e nello storico: quale versione hai fatto */
.tl-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: var(--r-pill);
  background: var(--purple-dim);
  color: var(--brand-light);
  font-size: 9px;
  font-weight: 700;
  vertical-align: 2px;
}
/* ── Profilo (rifatto il 2026-08-18) ──────────────────────────────────
   La pagina era sei moduli aperti uno sotto l'altro, tre schermate di
   scorrimento. Ora è un elenco di righe: una riga per cosa, il dettaglio
   in una sheet (le stesse .score-sheet del resto dell'app), gli
   interruttori che si salvano da soli. Riferimento: le impostazioni di
   sistema del telefono, che è il posto dove la gente ha già imparato
   dove si guarda. */

/* Testata: foto ferma a 96px, il nome lo dimensiona profilo.js perché
   va misurato, non stimato. Niente riquadro dietro: sotto ci sono sei
   gruppi già dentro riquadri e la testata sembrava il settimo. */
.pf-hero {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 20px 0;
}
.pf-av { width: 96px; height: 96px; }
.pf-av .avatar-initials { font-size: 33px; }
.pf-nome {
  align-self: center;
  flex: 1;
  min-width: 0;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  text-transform: uppercase;
  line-height: 1.02;
  white-space: nowrap;   /* le righe le decide profilo.js */
  font-size: 30px;       /* misura di partenza, sostituita al caricamento */
}

/* Testata del profilo di un ALTRO atleta. Più contenuta di quella del
   proprio profilo, e con il nome in Inter invece che in Anton: là sei tu
   e la pagina è tua, qui il protagonista sono i suoi risultati. */
.pf-hero--altro { align-items: center; gap: 14px; padding: 16px 0; }
.pf-hero--altro .pf-av { width: 64px; height: 64px; }
.pf-hero--altro .pf-av .avatar-initials { font-size: 22px; }
.pf-hero-txt { flex: 1; min-width: 0; }
/* ── La foto del profilo si guarda grande (2026-09-10, Roberta) ───────
   Nella testata la foto è un ritaglio tondo da 64: di una persona si
   vede la faccia e basta. Toccandola si apre INTERA, su fondo scuro.
   Il bottone non si veste: è il guscio della foto, non un comando in
   più — niente fondo, niente filo, e il tocco lo racconta la foto che
   si apre. */
.pf-av-apri {
  appearance: none;
  border: 0;
  background: none;
  padding: 0;
  line-height: 0;
  cursor: pointer;
  border-radius: 50%;
  flex: 0 0 auto;
}
.foto-big {
  border: 0;
  padding: 0;
  background: none;
  max-width: none;
  max-height: none;
  width: 100%;
  height: 100%;
}
/* ⚠️ Il display si scrive su [open] e non sul dialog nudo: un <dialog>
   chiuso è display:none per il browser, e un `display: flex` scritto
   sopra lo tiene VISIBILE a pagina ferma (la × restava lì in alto a
   destra, 2026-09-10). */
.foto-big[open] {
  display: flex;
  align-items: center;
  justify-content: center;
}
.foto-big::backdrop { background: rgba(6, 5, 9, .92); }
/* ⚠️ TONDA e non intera (2026-09-10, scelta di Roberta): «un po' come
   su Instagram, che ti si zooma la parte tonda». Il ritaglio resta
   quello della testata — quello che si guadagna è la misura, e la foto
   resta la stessa cosa che eri abituato a vedere, solo grande. */
.foto-big img {
  width: min(86vw, 86vh);
  height: min(86vw, 86vh);
  object-fit: cover;
  border-radius: 50%;
  display: block;
}
/* la × sta in alto a destra: dice che si chiude, ma il tocco vale
   ovunque (foto compresa) */
.foto-big-x {
  position: fixed;
  top: 14px;
  right: 14px;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, .10);
  color: var(--text);
}

.pf-nome-altro {
  margin: 0;
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -.01em;
  line-height: 1.2;
  overflow-wrap: anywhere;
}
.pf-hero-sotto { margin: 5px 0 0; font-size: 12.5px; color: var(--muted); }
/* ⚠️ larghezza AUTO: con la scritta accanto all'icona il testo finiva a
   filo del bordo, perché il bottone-icona impone 44px fissi */
.pf-hero-pr {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: none;
  width: auto;
  height: 38px;
  padding: 0 14px;
  border-radius: var(--r-btn);
  background: var(--surface-2);
  font-size: 12px;
  font-weight: 600;
  color: var(--brand-light);
}
.pf-hero-pr:hover { text-decoration: none; background: rgba(var(--accent-rgb), .18); }
.pf-hero-pr .icon { width: 17px; height: 17px; flex: none; }

.pf-sez {
  margin: 24px 0 7px;
  padding-left: 2px;
  font-size: var(--fs-meta);
  font-weight: 600;
  text-transform: uppercase;
  color: var(--muted);
}
.pf-group { background: var(--surface); border-radius: 14px; overflow: hidden; }

.pf-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 13px 14px;
  border: 0;
  border-bottom: 1px solid rgba(255, 255, 255, .05);
  background: none;
  font-family: inherit;
  color: var(--text);
  text-align: left;
  cursor: pointer;
}
.pf-row:last-child { border-bottom: 0; }
.pf-row:hover { background: rgba(255, 255, 255, .03); text-decoration: none; }
.pf-row:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
/* righe che non si toccano: stessa griglia, senza freccia e senza mano */
.pf-row--fermo { cursor: default; }
.pf-row--fermo:hover { background: none; }
.pf-row--azione .pf-lab { color: var(--brand-light); }

.pf-lab { flex: 1; min-width: 0; font-size: 14px; font-weight: 500; }
.pf-sub {
  display: block;
  margin-top: 3px;
  font-size: var(--fs-sm);
  font-weight: 400;
  line-height: 1.45;
  color: var(--muted);
}
.pf-val { flex: none; font-size: 13px; color: var(--muted); }
.pf-chev {
  width: 16px; height: 16px;
  flex: none;
  color: var(--dim);
}
.pf-nota {
  margin: 8px 2px 0;
  font-size: var(--fs-sm);
  line-height: 1.55;
  color: var(--muted);
}
.pf-nota a { color: var(--brand-light); }
/* dentro una sheet la spiegazione ha bisogno di più aria: appoggiata al
   gruppo si legge come se ne facesse parte (segnalato da Roberta) */
.score-sheet-inner .pf-nota { margin-top: 15px; }

/* ── La foto del profilo (0054) ──────────────────────────────────────
   ⚠️ Grafica di servizio, in attesa di Roberta: il campo file nativo è
   una scritta grigia con un bottone di sistema, cioè l'unico pezzo
   dell'app che parla la lingua del browser invece della nostra. Qui il
   comando è una label vestita da .btn-add (il tratteggiato degli
   «aggiungi») e il tondo fa da anteprima — la foto si vede ritagliata
   PRIMA di salvarla, che è l'informazione che serve davvero. */
.foto-picker {
  display: grid;
  justify-items: center;
  gap: var(--s3);
  text-align: center;
  padding: var(--s2) 0 var(--s1);
}
.foto-vista {
  width: 112px;
  height: 112px;
  border-radius: 50%;
  overflow: clip;
  display: grid;
  place-items: center;
  background: var(--surface);
  border: 1px solid var(--line);
  transition: border-color .2s ease;
}
.foto-vista img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* appena si sceglie una foto nuova il filo diventa viola: è il segno che
   quella nel tondo non è ancora quella salvata */
.foto-vista.is-nuova { border-color: var(--purple); }
.foto-iniziali {
  font-weight: 700;
  font-size: 32px;
  color: var(--muted);
}
/* visually-hidden e non display:none: da tastiera l'input resta
   raggiungibile e il focus si vede sulla label (regola qui sotto) */
.foto-input {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  clip-path: inset(50%);
}
.foto-scegli { cursor: pointer; }
.foto-input:focus-visible + .foto-scegli {
  outline: 2px solid var(--purple);
  outline-offset: 2px;
}
.foto-hint { margin: 0; max-width: 34ch; }
.foto-rimuovi { margin-top: var(--s3); }


.pf-group--esci { margin-top: 9px; }

/* la zona rossa sta staccata dal resto e non si sfiora per sbaglio */
.pf-group--rosso { margin-top: 26px; }
.pf-group--rosso .pf-lab { color: var(--err); }
.pf-group--rosso .pf-chev { color: var(--err-line); }

/* le ore della notifica del WOD, dentro la sua sheet */
.pf-ore { display: flex; flex-wrap: wrap; gap: 7px; }
.pf-ora {
  position: relative;
  border: 0;
  border-radius: var(--r-pill);
  padding: 9px 14px;
  background: rgba(255, 255, 255, .05);
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
}
.pf-ora input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
/* l'acceso lo dice la casella spuntata, non una classe messa dal JS:
   così non può restare indietro rispetto a quello che è stato salvato */
.pf-ora:has(input:checked) { background: var(--sel-tint); color: var(--sel-fg); }
.pf-ora:has(input:focus-visible) { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }

/* Scelta del nome in classifica: una riga per forma, con la foto
   accanto — si sceglie guardando come si comparirà, non leggendo. */
.pf-scelta { position: relative; }
.pf-scelta input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.pf-mini-av { width: 32px; height: 32px; }
.pf-mini-av .avatar-initials { font-size: 12px; }
.pf-nomeform { font-size: 15px; font-weight: 500; }
.pf-ck {
  width: 19px; height: 19px;
  flex: none;
  color: var(--purple);
  opacity: 0;
  transition: opacity var(--speed);
}
.pf-scelta:has(input:checked) .pf-ck { opacity: 1; }
.pf-scelta:has(input:checked) .pf-nomeform { color: var(--sel-fg); }
.pf-scelta:has(input:focus-visible) { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
/* Moduli dell'abbonamento: il pallino porta il colore che il track ha
   già in tracks.color, lo stesso della sua categoria sui WOD. Il viola è
   riservato al Competitor, che non è un modulo ma un tipo di abbonamento
   — e viola non è mai una categoria. Le pastiglie di prima coloravano
   tutto uguale e buttavano via quei colori. */
/* il pallino si allinea alla PRIMA riga dell'etichetta, non al centro
   del blocco: sulla riga del Competitor, che ha la spiegazione sotto,
   centrato sul blocco finiva in mezzo al nulla */
.pf-dot {
  width: 9px; height: 9px;
  flex: none;
  align-self: flex-start;
  /* 7px e non il centro geometrico della riga: la scatola del carattere
     ha vuoto sopra, e a occhio il pallino sembrava alto */
  margin-top: 7px;
  border-radius: 50%;
}
.pf-dot--comp { background: var(--brand-light); }

/* dentro una sheet le etichette di sezione prendono aria sopra, sennò il
   secondo gruppo si appoggia al primo (segnalato da Roberta) */
.score-sheet-inner .pf-sez { margin-top: 24px; }
.score-sheet-inner .pf-sez:first-of-type { margin-top: 0; }

/* ══════════════════════════════════════════════════════════════════════
   TIMER — pagina /timer. Rifatta con Roberta il 2026-08-20.
   Impostazione: niente testata, il tipo è un filo di nodi come le card
   della home, i numeri sono campi veri (si scrivono a tastiera, i due
   punti li mette il campo). In corsa: numero gigante, barra attaccata
   sotto (un segmento per round sugli intervalli), comandi con l'icona
   piena a sinistra come i «Coach notes».
   ⚠️ Il viola qui non è mai una categoria: è azione e stato attivo.
   ══════════════════════════════════════════════════════════════════════ */

/* ── il tipo di timer: tre nodi su un filo ── */
/* niente testata né occhiello: la barra in basso dice già dove sei.
   Solo aria, perché il filo non resti incollato al bordo. */
.tm-tipi { position: relative; display: flex; justify-content: space-between; margin-top: 40px; }
.tm-filo {
  position: absolute; left: 16.66%; right: 16.66%; top: 21px;
  height: 2px; background: var(--rail-off);
}
.tm-nodo {
  position: relative; z-index: 1; flex: 1;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  background: none; border: 0; padding: 0; cursor: pointer; font-family: var(--font);
}
.tm-nodo-box { height: 44px; display: grid; place-items: center; }
.tm-dot {
  width: 16px; height: 16px; border-radius: 50%;
  border: 6px solid var(--ink); box-sizing: content-box;
  background: var(--rail-off); display: grid; place-items: center;
  transition: width var(--speed), height var(--speed), background var(--speed);
}
.tm-nodo.on .tm-dot { width: 26px; height: 26px; background: var(--purple); }
.tm-dot-ico { width: 14px; height: 14px; color: var(--ink); stroke-width: 2.6; }
.tm-nodo:not(.on) .tm-dot-ico { display: none; }
.tm-nodo b { font-size: 14px; font-weight: 700; color: var(--muted); }
.tm-nodo.on b { color: var(--text); }
.tm-nodo:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); border-radius: var(--r-sm); }

.tm-panel { margin-top: 26px; }
/* AMRAP e Intervals: il numero scende un filo. Sopra c'è una scritta
   piccola, sotto un bottone alto 52px che pesa parecchio all'occhio:
   messo a metà esatta il numero sembra alto. For Time no — lì sotto al
   filo c'è la barra a due scelte, che pesa già di suo. */
.tm-panel[data-type="amrap"] .tm-num,
.tm-panel[data-type="interval"] .tm-tre,
.tm-panel[data-type="sections"] .tm-tre { margin-top: 34px; }

/* ── la scelta a due: alternative pari, non un interruttore ── */
.tm-seg {
  display: flex; gap: 4px; padding: 4px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
}
.tm-seg-b {
  flex: 1; padding: 11px 8px; border: 0; border-radius: 10px; cursor: pointer;
  background: none; color: var(--muted);
  font-family: var(--font); font-size: 14px; font-weight: 600;
}
.tm-seg-b.on { background: var(--sel-tint); color: var(--sel-fg); }
.tm-seg-b:focus { outline: none; }
.tm-seg-b:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }

/* ── i numeri: campi veri, minimali ── */
.tm-num { margin-top: 26px; text-align: center; }
.tm-num-et {
  display: block; margin-bottom: 6px;
  font-size: 10px; font-weight: 700;
  text-transform: uppercase; color: var(--muted);
}
.tm-num-riga { display: flex; align-items: center; justify-content: center; gap: 18px; }
.tm-num-in {
  width: 100%; max-width: 100%; min-width: 0; box-sizing: border-box;
  padding: 4px 0 6px; background: none; border: 0;
  color: var(--text); font-family: var(--font); caret-color: var(--purple);
  font-size: 30px; font-weight: 700; font-variant-numeric: tabular-nums;
  text-align: center; letter-spacing: -.01em;
}
/* niente riga sotto: quando scrivi lo dice il numero, che passa al lilla */
.tm-num-in:focus { outline: none; color: var(--brand-light); }
/* il 22% del selezionato qui non basta: è testo grande su fondo nero,
   e la velatura spariva */
.tm-num-in::selection { background: rgba(var(--accent-rgb), .55); color: #fff; }
.tm-num-zero { color: var(--dim); }
.tm-num--grande .tm-num-in { font-size: 40px; width: auto; min-width: 150px; padding-bottom: 8px; }
.tm-num-b {
  position: relative; width: 44px; height: 44px; flex: none; padding: 0;
  border: 1px solid var(--line); border-radius: 50%;
  background: var(--surface-2); color: var(--text); cursor: pointer;
  /* il segno NON è testo: centrando un carattere il browser allinea la
     riga del font, non il disegno, e «−» e «+» hanno ink diversi */
  font-size: 0;
}
.tm-num-b::before, .tm-num-b[data-su]::after {
  content: ''; position: absolute; left: 50%; top: 50%;
  background: currentColor; border-radius: 1px;
}
.tm-num-b::before { width: 17px; height: 2.5px; transform: translate(-50%, -50%); }
.tm-num-b[data-su]::after { width: 2.5px; height: 17px; transform: translate(-50%, -50%); }
.tm-num-b:hover { border-color: var(--purple-line); color: var(--sel-fg); }
.tm-num-b:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }

/* Intervals: i tre numeri in fila, senza tasti — con tre colonne non ci
   starebbero, e lì si scrive a tastiera */
/* 26 come il margine del campo singolo: erano 30, e quei 4px di
   differenza bastavano a far scendere lo Start solo su Intervals */
.tm-tre { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 4px; margin-top: 26px; }
/* le Sezioni (2026-09-15): due campi e basta, poi il cap come For Time */
.tm-tre.tm-due { grid-template-columns: 1fr 1fr; }
.tm-panel[data-type="sections"] .tm-seg { margin-top: 26px; }
.tm-tre .tm-num { margin-top: 0; }
.tm-tre .tm-num-in { font-size: 30px; }

/* ── Start ── */
.tm-start {
  position: relative; display: flex; align-items: center; justify-content: center;
  width: 100%; min-height: 52px; margin-top: 26px; padding: 0 12px;
  border: 1px solid var(--purple); border-radius: var(--r-btn-lg);
  background: rgba(var(--accent-rgb), .14); color: var(--sel-fg);
  font-family: var(--font); font-size: 17px; font-weight: 600;
 text-transform: uppercase; cursor: pointer;
  transition: background-color var(--speed);
}
.tm-start:hover { background: var(--sel-tint); }
.tm-start-ico { width: 22.5px; height: 22.5px; margin-right: 10px; }
/* la riga del countdown va al centro come tutto il resto della pagina */
.tm-page .hintline { justify-content: center; margin-top: 12px; }
/* lo spazio di coda della maiuscoletta spaziata sposta il gruppo a
   sinistra: se ne toglie METÀ, e icona e scritta stanno al centro vero */
.tm-start span { margin-right: -.05em; }

/* ── overlay: sopra bottom-nav (100) e toast (110). Il fondo è pieno:
   copre tutto anche dove la Fullscreen API non c'è (iPhone). ── */
.tm-screen {
  position: fixed; inset: 0; height: 100%; height: 100dvh; z-index: 200;
  display: flex; flex-direction: column; align-items: center;
  background: var(--ink);
  padding: calc(16px + env(safe-area-inset-top)) 20px
           calc(20px + env(safe-area-inset-bottom));
  user-select: none; -webkit-user-select: none; touch-action: manipulation;
  /* il display gigante è l'unico posto dove la scala token non basta:
     misura locale, non entra nei token globali. Il cap in dvh serve al
     LANDSCAPE (il fullscreen blocca in orizzontale): senza, 26vw su un
     telefono girato sfonda l'altezza dello schermo */
  --tm-hero: min(clamp(80px, 24vw, 300px), 40dvh);
}
.tm-screen[hidden] { display: none; }
/* l'ingresso dello schermo (2026-09-10, chiesto da Francesco): il WOD
   passa dalla scheda in setup al pannello in basso. Con la View
   Transition same-document (timer.js) il pannello scivola da una
   posizione all'altra; altrove lo schermo entra in dissolvenza e il
   pannello sale dal basso. */
body:not(.tm-open) .tm-wod--setup { view-transition-name: tm-wod; }
body.tm-open .tm-wod--screen { view-transition-name: tm-wod; }
::view-transition-old(tm-wod), ::view-transition-new(tm-wod) {
  animation-duration: .38s;
  animation-timing-function: cubic-bezier(.32, .72, 0, 1);
}
.tm-screen.tm-entra { animation: tm-entra .32s ease-out both; }
.tm-screen.tm-entra .tm-wod--screen { animation: tm-entra-wod .38s cubic-bezier(.32, .72, 0, 1) both; }
@keyframes tm-entra { from { opacity: 0; } to { opacity: 1; } }
@keyframes tm-entra-wod { from { opacity: 0; translate: 0 24px; } to { opacity: 1; translate: 0 0; } }
@media (prefers-reduced-motion: reduce) {
  .tm-screen.tm-entra, .tm-screen.tm-entra .tm-wod--screen { animation: none; }
}

.tm-fs {
  position: absolute; top: calc(14px + env(safe-area-inset-top)); right: 14px;
  width: var(--tap); height: var(--tap);
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: var(--r-sm); background: none; color: var(--muted); cursor: pointer;
}
.tm-fs:hover { color: var(--text); }
.tm-fs .icon { width: 22px; height: 22px; }
.tm-fs-collapse { display: none; }
.tm-screen.is-fs .tm-fs-expand { display: none; }
.tm-screen.is-fs .tm-fs-collapse { display: block; }

.tm-top {
  margin-top: 6px; min-height: 20px;
  display: flex; align-items: center; justify-content: center; gap: 14px; flex-wrap: wrap;
}
.tm-eyebrow {
  font-size: var(--fs-meta); font-weight: 600;
  text-transform: uppercase; color: var(--muted);
}
.tm-round {
  font-size: var(--fs-lg); font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--body-text);
}

.tm-mid {
  flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 10px; width: 100%;
}
.tm-display {
  /* ⛔ NON Anton: quello è riservato al nome del box. I numeri sono
     Inter grassetto, come nell'anteprima approvata — Anton è
     condensato e su un 0:06 gigante sembra un'altra app. */
  font-family: var(--font); font-weight: 700; letter-spacing: -.02em;
  font-size: var(--tm-hero); font-variant-numeric: tabular-nums;
  line-height: .95; color: var(--text);
}
/* ultimi secondi: cambio di colore, niente lampeggio. Il viola pieno
   sta nella palette; il giallo di sistema accanto al lilla litigava. */
.tm-screen.tm-warn .tm-display { color: var(--accent-vivo); }
.tm-screen.tm-warn .tm-barra i.on,
.tm-screen.tm-warn .tm-barra > span { background: var(--accent-vivo); }
.tm-screen.tm-warn .tm-barra i.ora {
  background: linear-gradient(to right, var(--accent-vivo) var(--q), rgba(255,255,255,.09) var(--q));
}
/* flash al beep: inversione di tinta breve e statica, il segnale
   ridondante quando l'audio non si sente (mute switch iOS, sala) */
.tm-screen.tm-flash { background: var(--accent-lampo); }
/* in pausa: numero e barra si spengono ma restano leggibili, sennò
   sembra che il timer stia ancora correndo */
.tm-screen[data-state="paused"] .tm-display { opacity: .5; }
.tm-screen[data-state="paused"] .tm-barra { opacity: .45; }
/* a timer finito il numero è bianco: due viola diversi insieme (numero
   spento e barra accesa) si pestavano i piedi */
.tm-screen[data-state="finished"] .tm-display { color: var(--text); }

.tm-phase {
  font-size: 15px; font-weight: 800;
  padding: 6px 20px; border-radius: var(--r-pill);
  background: var(--purple); color: var(--ink);
}
/* OFF acceso: sul nero un grigio scuro non si legge da lontano */
.tm-phase.off { background: var(--dim); color: var(--grigio-93); }

/* ── la barra attaccata sotto al numero ── */
.tm-barra {
  display: flex; gap: 5px; width: min(76%, 420px); height: 7px; border-radius: 4px;
}
.tm-barra > span { display: block; height: 100%; background: var(--purple); border-radius: 4px; }
.tm-barra i { flex: 1; height: 100%; border-radius: 4px; background: rgba(255, 255, 255, .09); }
.tm-barra i.on { background: var(--purple); }
.tm-barra i.ora {
  background: linear-gradient(to right, var(--purple) var(--q), rgba(255,255,255,.09) var(--q));
}
.tm-barra:not(.tm-barra--round) { background: rgba(255, 255, 255, .09); overflow: hidden; }

.tm-sub {
  min-height: 22px; display: flex; align-items: center; justify-content: center; gap: 8px;
  font-size: var(--fs-base); font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--muted);
}
.tm-fine-segno { display: flex; }
.tm-fine-segno .icon { width: 20px; height: 20px; color: var(--purple); }

/* ── i comandi: icona piena a sinistra, scritta centrata — come i
   bottoni «Coach notes». Il rientro destro è 10px più corto del
   sinistro, così la scritta si stacca di 5px dall'icona; il bottone
   largo (--largo) resta centrato, perché lì l'occhio vuole il centro. ── */
.tm-controls {
  display: flex; gap: 10px; justify-content: center; flex-wrap: wrap;
  width: 100%; max-width: 480px;
}
.tm-cmd {
  position: relative; flex: 1 1 0; min-height: 52px;
  --scarto: 5px;
  padding: 0 calc(46px - var(--scarto) * 2) 0 46px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--line); border-radius: var(--r-btn-lg);
  background: var(--surface-2); color: var(--text);
  font-family: var(--font); font-size: 14px; font-weight: 500;
  white-space: nowrap; cursor: pointer;
  transition: border-color var(--speed), background-color var(--speed);
}
/* il bottone principale della fine sta su una riga sua: è la scelta
   più probabile, e da solo l'occhio vuole la scritta al centro vero */
.tm-cmd--largo { --scarto: 0px; flex-basis: 100%; }
.tm-cmd:hover { border-color: var(--purple-line); }
/* il filo del fuoco sta DENTRO al bottone: fuori spuntava sopra il
   bordo e si vedeva una riga viola staccata */
.tm-cmd:focus { outline: none; }
.tm-cmd:focus-visible { outline: var(--fuoco-w) solid var(--fuoco-c); outline-offset: calc(-1 * var(--fuoco-w)); }
.tm-cmd--forte {
  border-color: var(--purple); background: rgba(var(--accent-rgb), .14); color: var(--sel-fg);
}
.tm-cmd--forte:hover { background: var(--sel-tint); }
/* Stop armato: cambia solo la parola, «Confermi?». Nessun colore
   diverso — deciso il 2026-08-20. */
.tm-cmd-ico {
  position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  width: 22.5px; height: 22.5px; display: block;
}
/* Pausa ⇄ Riprendi: due icone nello stesso bottone, ne appare una sola */
.tm-cmd-play { display: none; }
.tm-cmd.e-play .tm-cmd-play { display: block; }
.tm-cmd.e-play .tm-cmd-pausa { display: none; }

/* visibilità dei comandi per stato */
.tm-screen .tm-cmd { display: none; }
.tm-screen[data-state="countdown"] #tm-cancel,
.tm-screen[data-state="running"] #tm-pause,
.tm-screen[data-state="running"] #tm-stop,
.tm-screen[data-state="paused"] #tm-pause,
.tm-screen[data-state="paused"] #tm-stop,
.tm-screen[data-state="finished"] #tm-again,
.tm-screen[data-state="finished"] #tm-new,
.tm-screen[data-state="finished"] #tm-exit { display: flex; }
/* ⭐ Sezioni (2026-09-15): «Fatto» chiude la sezione in corso — largo
   sulla sua riga sopra Pausa e Stop, perché è il gesto che si fa a ogni
   blocco. Nel rest non c'è niente da chiudere (e non si salta): resta ma
   spento. */
.tm-screen--sez[data-state="running"] #tm-next,
.tm-screen--sez[data-state="paused"] #tm-next { display: flex; order: -1; }
.tm-screen--sez.tm-rest #tm-next,
.tm-screen--sez[data-state="paused"] #tm-next { opacity: .4; pointer-events: none; }

/* il 3-2-1: ogni numero entra grande e si assesta. Spento per chi ha
   chiesto di ridurre il movimento, come ovunque nel progetto. */
@media (prefers-reduced-motion: no-preference) {
  .tm-display.tm-batte { animation: tm-batte .42s ease-out; }
  @keyframes tm-batte {
    0%   { transform: scale(1.35); opacity: .25; }
    60%  { transform: scale(.97); opacity: 1; }
    100% { transform: scale(1); }
  }
}

/* ── Il WOD dentro il timer (2026-09-02, chiesto da Francesco) ─────────
   Lo stesso partial due volte: la scheda in setup (sopra il filo dei
   tipi) e il pannello nell'overlay. In portrait il pannello sta SOTTO
   il numero con scroll interno; in landscape/desktop l'overlay diventa
   una griglia a due colonne (timer 2/3, WOD 1/3). 30dvh e 26dvh sono
   misure locali come --tm-hero: numero e comandi devono restare in
   vista su un telefono in verticale. Grafica prima stesura: da rivedere
   con Roberta. ── */
.tm-wod { width: 100%; max-width: 480px; min-width: 0; text-align: left; }
.tm-wod-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); }
.tm-wod-eyebrow {
  display: flex; align-items: center; gap: 6px; min-width: 0;
  font-size: var(--fs-eyebrow); font-weight: 600;
  text-transform: uppercase; color: var(--tc, var(--muted));
}
.tm-wod-eyebrow .tl-tag { margin-left: 0; }
.tm-wod-title {
  margin-top: 2px; font-size: var(--fs-lg); font-weight: 700; line-height: 1.2;
  text-transform: uppercase; color: var(--text); overflow-wrap: anywhere;
}
.tm-wod-scheme {
  margin-top: 3px; font-size: var(--fs-eyebrow); font-weight: 600;
 text-transform: uppercase; color: var(--tc, var(--muted));
}
.tm-wod-desc.rich-text { margin-top: var(--s2); font-size: var(--fs-sm); line-height: 1.5; color: var(--body-text); }
.tm-wod-sub { margin-top: 5px; font-size: var(--fs-meta); color: var(--muted); }
/* ⭐ Squadrato e velato (2026-09-04, Roberta): era una pastiglia tonda col
   filo e la scritta in maiuscoletto spaziato, l'unica di quella foggia in
   una schermata dove tutti gli altri comandi — Pausa, Stop, Annulla —
   sono squadrati, velati e scritti normali. Stessa lingua di .btn-ghost,
   misura piccola perché sta nella testata del pannello accanto
   all'occhiello del track. */
.tm-wod-toggle {
  flex: none; min-height: 32px; padding: 0 12px;
  border: 1px solid transparent; border-radius: var(--r-btn);
  background: rgba(255, 255, 255, .06);
  color: var(--grigio-66); font: inherit; font-size: var(--fs-sm); font-weight: 600;
  cursor: pointer;
}
.tm-wod-toggle:hover { background: rgba(255, 255, 255, .11); color: var(--text); }
.tm-wod-toggle-show { display: none; }
.tm-screen.tm-wod-off .tm-wod-toggle-show { display: inline; }
.tm-screen.tm-wod-off .tm-wod-toggle-hide { display: none; }
.tm-screen.tm-wod-off .tm-wod-body { display: none; }
/* setup: la scheda sopra il filo dei tipi */
.tm-wod--setup { margin: var(--s5) auto 0; padding: 12px 14px 14px; background: var(--surface); border-radius: var(--r-md); }
.tm-wod--setup + .tm-tipi { margin-top: 28px; }
/* in corsa, portrait: sotto il numero, con scroll interno */
.tm-wod--screen {
  flex: 0 1 auto; min-height: 0; max-height: 30dvh; overflow-y: auto;
  overscroll-behavior: contain; margin-bottom: var(--s3);
  padding-top: var(--s3); border-top: 1px solid var(--line);
}
.tm-screen--wod { --tm-hero: min(clamp(72px, 20vw, 300px), 26dvh); }
.tm-screen--wod.tm-wod-off { --tm-hero: min(clamp(80px, 24vw, 300px), 40dvh); }
.tm-screen--wod.tm-wod-off .tm-wod--screen { flex: none; max-height: none; overflow: visible; }
/* landscape e desktop: due colonne, timer 2/3 e WOD 1/3. In fullscreen il
   telefono è bloccato in orizzontale, quindi in sala questo è il caso
   normale; il portrait serve a iPhone (niente fullscreen) e all'overlay
   senza. Le righe minmax(0, 1fr): la colonna del WOD scorre dentro di sé
   e non gonfia la griglia oltre i 100dvh. */
@media (min-width: 900px), (orientation: landscape) and (min-width: 640px) {
  .tm-screen--wod:not([hidden]):not(.tm-wod-off) {
    display: grid;
    grid-template-columns: 2fr 1fr;
    grid-template-rows: auto minmax(0, 1fr) auto;
    grid-template-areas: "top wod" "mid wod" "ctl wod";
    column-gap: var(--s5);
    --tm-hero: min(clamp(80px, 16vw, 300px), 40dvh);
  }
  .tm-screen--wod:not(.tm-wod-off) .tm-top { grid-area: top; justify-self: center; }
  .tm-screen--wod:not(.tm-wod-off) .tm-mid { grid-area: mid; }
  .tm-screen--wod:not(.tm-wod-off) .tm-controls { grid-area: ctl; justify-self: center; }
  .tm-screen--wod:not(.tm-wod-off) .tm-wod--screen {
    grid-area: wod; align-self: stretch; min-height: 0; max-width: none; max-height: none;
    margin: 0; padding: calc(var(--tap) + 4px) 0 0 var(--s5);
    border-top: 0; border-left: 1px solid var(--line); overflow-y: auto;
  }
  /* il bottone dello schermo intero finirebbe sopra la testata del WOD */
  .tm-screen--wod:not(.tm-wod-off) .tm-fs { right: auto; left: 14px; }
}

/* schermo intero dal setup (2026-09-02): stesso comando dell'overlay, su
   una riga sua sotto lo Start; a schermo intero cambia icona e parola */
.tm-fs-setup { width: 100%; margin: var(--s3) auto 0; }
.tm-fs-setup-collapse, .tm-fs-setup-off { display: none; }
body.tm-fs .tm-fs-setup-expand, body.tm-fs .tm-fs-setup-on { display: none; }
body.tm-fs .tm-fs-setup-collapse { display: block; }
body.tm-fs .tm-fs-setup-off { display: inline; }

/* con l'overlay timer aperto la pagina sotto non scorre */
body.tm-open { overflow: hidden; }

/* ── Abbonamento App e accesso bloccato (2026-08-31, con Roberta) ─────
   Le due pagine che vede chi arriva da fuori o chi resta fuori. Non hanno
   la barra in fondo (body.senza-uscite): da qui non si va da nessuna
   parte, e le linguette invitavano solo a rimbalzare.
   ⛔ Erano due «card + prose», prima stesura di Francesco: guardate
   insieme e rifatte. Provate anche col prezzo grande al centro e col
   riquadro-ricevuta: ha scelto l'elenco di cosa c'e dentro. */
.ab-lista { display: grid; gap: 10px; margin: var(--s4) 0 var(--s5); }
.ab-voce {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: var(--fs-sm);
  line-height: 1.4;
  color: var(--text);
}
.ab-voce .icon {
  flex: none;
  width: 17px;
  height: 17px;
  color: var(--brand-light);
  margin-top: 1px;
}
.ab-testo { color: var(--body-text); font-size: var(--fs-base); line-height: 1.6; margin: 8px 0 0; }
/* l'uscita in fondo alla pagina bloccata (2026-09-17): staccata dal
   resto, testo piccolo sopra il bottone */
.ab-esci { margin-top: var(--s5); }
.ab-esci-txt {
  color: var(--muted);
  font-size: var(--fs-sm);
  text-align: center;
  margin: 0 0 8px;
}
.ab-nota {
  color: var(--muted);
  font-size: var(--fs-xs);
  line-height: 1.5;
  margin: 10px 0 0;
  text-align: center;
}
/* il riquadro dell'offerta, sotto l'«oppure» della pagina bloccata */
.ab-box {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--s4);
  margin: var(--s5) 0 0;
}
.ab-box-tit { font-size: var(--fs-base); font-weight: 700; color: var(--text); }
/* il bottone non si appiccica mai al testo che lo precede: la riga che
   spiega e il comando che la esegue sono due cose diverse. 24 come il
   respiro sotto l'elenco, così tutte le schermate hanno lo stesso passo. */
.ab-box .btn,
.ab-testo + form .btn { margin-top: var(--s5); }
.ab-oppure {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: var(--s5) 0;
  color: var(--muted);
  font-size: var(--fs-eyebrow);
  text-transform: uppercase;
}
.ab-oppure::before, .ab-oppure::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--line);
}
/* il lucchetto nel riquadro tratteggiato: e lo stesso .err-box della
   pagina di errore, che parla gia la lingua degli stati vuoti */
.err-box .err-ic { width: 26px; height: 26px; color: var(--muted); }

/* ═══════════════════════════════════════════════════════════════════
   Statistiche atleta — /statistiche (stx-, 2026-08-31)
   Il profilo-numeri: heatmap di costanza, KPI, tonnellaggio, benchmark
   e badge. Costruita sui componenti esistenti (.tiles, .rm-row,
   .section-label, .pf-hero--altro, .cat-more); qui vive solo ciò che
   non esisteva.
   ═══════════════════════════════════════════════════════════════════ */

/* guscio di sezione: stessa pelle di .cat-card, in più entra nello
   stagger d'ingresso (stagger.js elenca .stx-card fra le righe) */
.stx-card { background: var(--surface); border-radius: 14px; padding: 12px 14px; }

/* KPI su tre colonne: sei tessere in due righe. Sotto i 400px i numeri
   coi decimali («12.4 t») non ci stanno più in tre colonne: due. */
.stx-tiles { grid-template-columns: repeat(3, 1fr); padding-top: 4px; }
@media (max-width: 480px) { .stx-tiles { grid-template-columns: 1fr 1fr; } }
/* ⭐ L'ultima tessera, se resta spaiata, prende tutta la riga
   (2026-09-04, Roberta): le due file ne hanno 3 e 5, e a due colonne
   lasciavano due mezze righe vuote in mezzo alla pagina. ⚠️ :nth-child
   e non :nth-of-type — le tessere sono <div> come tutto il resto. */
.stx-tiles > *:last-child:nth-child(odd) { grid-column: 1 / -1; }
@media (min-width: 481px) {
  .stx-tiles > *:last-child:nth-child(odd) { grid-column: auto; }
  /* a tre colonne: si allarga solo l'ultima che aprirebbe una riga tutta sua */
  .stx-tiles > *:last-child:nth-child(3n + 1) { grid-column: 1 / -1; }
}

/* ── heatmap ──────────────────────────────────────────────────────
   Griglia GitHub-style: colonne = settimane (grid-auto-flow: column
   impila i 7 giorni lun→dom da sé), scala viola a 5 livelli su soglie
   fisse. Le due misure nude sono il modulo della griglia. */
.stx-heat-wrap { --stx-cell: 11px; --stx-gap: 3px; display: flex; gap: 6px; }
.stx-heat-days {
  display: grid;
  /* stesse 7 righe della griglia, ma etichettate a giorni alterni */
  grid-template-rows: repeat(7, var(--stx-cell));
  gap: var(--stx-gap);
  /* l'etichetta mesi sopra la griglia è alta 14px: si compensa qui */
  margin-top: 18px;
  flex: none;
}
.stx-heat-days span {
  grid-row: span 2;
  font-size: 9px;
  line-height: var(--stx-cell);
  color: var(--muted);
}
/* ⚠️ il trucco rtl/ltr non è un vezzo: apre lo scroller già ancorato a
   DESTRA (oggi) senza una riga di JS; il contenuto torna ltr subito */
.stx-heat-scroll { overflow-x: auto; direction: rtl; flex: 1; min-width: 0; }
.stx-heat { direction: ltr; width: max-content; }
.stx-heat-months { display: flex; height: 14px; }
.stx-heat-months span {
  width: calc(var(--w) * (var(--stx-cell) + var(--stx-gap)));
  flex: none;
  font-size: 9px;
  color: var(--muted);
  overflow: hidden;
  white-space: nowrap;
}
.stx-heat-grid {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(7, var(--stx-cell));
  grid-auto-columns: var(--stx-cell);
  gap: var(--stx-gap);
}
.stx-cell { width: var(--stx-cell); height: var(--stx-cell); border-radius: 3px; }
.stx-l0 { background: rgba(255, 255, 255, .04); }
.stx-l1 { background: color-mix(in srgb, var(--purple) 28%, var(--surface)); }
.stx-l2 { background: color-mix(in srgb, var(--purple) 48%, var(--surface)); }
.stx-l3 { background: color-mix(in srgb, var(--purple) 72%, var(--surface)); }
.stx-l4 { background: var(--purple); }
.stx-l--x { visibility: hidden; }   /* futuro: la colonna resta piena */
.stx-heat-legend {
  --stx-cell: 10px;
  display: flex;
  align-items: center;
  gap: 4px;
  justify-content: flex-end;
  margin-top: 10px;
  font-size: 9px;
  color: var(--muted);
}
.stx-heat-legend span { margin: 0 3px; }

/* ── distribuzione per track + Rx/Scaled ────────────────────────── */
.stx-bar-row { display: flex; align-items: center; gap: 10px; padding: 6px 0; }
.stx-bar-name {
  flex: none;
  width: 108px;
  font-size: var(--fs-xs);
  color: var(--body-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.stx-bar { flex: 1; height: 8px; border-radius: 4px; background: rgba(255, 255, 255, .05); }
.stx-bar-fill { height: 100%; border-radius: 4px; }
.stx-bar-n {
  flex: none;
  min-width: 26px;
  text-align: right;
  font-size: var(--fs-xs);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
.stx-rx { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); }
.stx-rx-head {
  display: flex;
  justify-content: space-between;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--body-text);
  margin-bottom: 6px;
}
.stx-rx-bar { height: 8px; border-radius: 4px; background: rgba(255, 255, 255, .10); overflow: hidden; }
.stx-rx-fill { height: 100%; background: var(--purple); border-radius: 4px 0 0 4px; }
.stx-rx-sub { font-size: var(--fs-eyebrow); color: var(--muted); margin-top: 6px; }

/* ── i totali, i track a zero, il breakdown dello scaling (2026-09-04) ──────────────── */
/* le due file di tessere (2026-09-04, Francesco): «Le tue sessioni»
   (tre) e «I tuoi totali» (fino a sei, quelle a zero non si mostrano),
   sulla stessa griglia a tre colonne di .stx-tiles. Gli «ultimi 30
   giorni» di ogni totale arriveranno dopo, agganciati alle tessere. */
/* un track dell'abbonamento senza nessuno score: riga spenta, barra
   vuota, trattino al posto del numero */
.stx-bar-row--zero .stx-bar-name,
.stx-bar-row--zero .stx-bar-n { color: var(--muted); }
.stx-tag {
  display: inline-block;
  margin-left: 4px;
  padding: 0 5px;
  border-radius: 4px;
  font-size: 9px;
  font-weight: 600;
  line-height: 14px;
  text-transform: uppercase;
  color: var(--muted);
  background: rgba(255, 255, 255, .06);
  vertical-align: 1px;
}
/* la barra Rx/Scaled in testa alla sua sezione: niente riga sopra */
.stx-rx--top { margin-top: 0; padding-top: 0; border-top: 0; }
.stx-cat-row { padding: 8px 0 2px; }
.stx-cat-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 6px;
  font-size: var(--fs-xs);
  color: var(--body-text);
}
.stx-cat-name { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; color: var(--text); }
.stx-cat-rx { font-variant-numeric: tabular-nums; color: var(--muted); }
.stx-cat-sub { font-size: var(--fs-eyebrow); color: var(--muted); margin-top: 5px; }
.stx-cat-giri { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--line); }

/* ── personal records ────────────────────────────────────────────── */
.stx-pr-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  font-size: var(--fs-xs);
  color: var(--body-text);
}
.stx-pr-head strong { font-size: var(--fs-lg); color: var(--text); }
.stx-pr-tot { font-size: var(--fs-eyebrow); color: var(--muted); }
.stx-pr-when { display: block; font-size: var(--fs-eyebrow); color: var(--muted); margin-top: 1px; }
/* il delta è BIANCO come su tutta l'app: sui tempi migliorare è scendere,
   e un verde automatico direbbe il contrario */
.stx-pr-delta { font-size: var(--fs-eyebrow); font-weight: 600; color: var(--text); white-space: nowrap; }

/* ── benchmark ───────────────────────────────────────────────────── */
.stx-bm-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid rgba(255, 255, 255, .05);
}
.stx-bm-row:last-child { border-bottom: 0; }
.stx-bm-txt { flex: 1; min-width: 0; }
.stx-bm-title { display: block; font-size: var(--fs-sm); font-weight: 600; color: var(--text); overflow-wrap: anywhere; }
.stx-bm-n { font-size: var(--fs-eyebrow); font-weight: 500; color: var(--muted); margin-left: 4px; }
.stx-bm-last { display: block; font-size: var(--fs-eyebrow); color: var(--muted); margin-top: 2px; }
.stx-bm-spark { flex: none; color: var(--purple); }

/* ── badge ───────────────────────────────────────────────────────── */
.stx-badges { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; padding: 0 2px; }
/* ⭐ Tre per riga anche sul telefono (2026-09-04, Roberta): a due erano
   dodici righe, 1213px — una schermata e mezza di soli badge in fondo
   alla pagina. A tre la fila scende a otto righe e il blocco a ~820. */
@media (max-width: 480px) {
  .stx-badge { padding: 10px 5px 9px; }
  .stx-badge-name { font-size: 11px; }
  .stx-badge-ic { width: 30px; height: 30px; }
  .stx-badge-ic .icon { width: 15px; height: 15px; }
}
/* è un <button> (il tap apre il fumetto del dettaglio): font e cursor
   vanno ridichiarati, l'agente utente ci metterebbe i suoi */
.stx-badge {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  background: var(--surface);
  border-radius: 12px;
  border: 1px solid transparent;
  padding: 12px 8px 10px;
  text-align: center;
  font-family: inherit;
  cursor: pointer;
}
.stx-badge-ic {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--purple-dim);
  color: var(--purple-hi);
}
.stx-badge-ic .icon { width: 17px; height: 17px; }
.stx-badge-name { font-size: var(--fs-meta); font-weight: 600; color: var(--text); line-height: 1.25; }
.stx-badge-meta { font-size: var(--fs-eyebrow); color: var(--muted); font-variant-numeric: tabular-nums; }
/* il livello sta nel filo: bronzo = l'oro delle categorie WL, argento =
   grigio chiaro, oro = il warn. Il bloccato si spegne, non sparisce:
   vedere cosa manca è metà del gioco */
/* ⭐ I tre livelli nella NOSTRA lingua (2026-09-04, Roberta). Prima erano
   bronzo/argento/oro presi da fuori, e non era solo questione di gusto:
   il bronzo #D8A864 era il giallo del Weightlifting PRIMA della 0061, a
   distanza percepita 4,5 dal nuovo — un badge sembrava sempre roba di
   Weightlifting; e l'oro era `--warn`, cioè il colore con cui l'app dice
   «attenzione».
   Qui il livello si legge da QUANTO colore ha la tessera, non da che
   tinta: 1 = solo la pastiglia accesa, 2 = filo viola e pastiglia più
   accesa, 3 = la tessera si accende tutta. Stessa progressione dei nostri
   stati (spento → selezionato → pieno), e nessun colore nuovo nel foglio. */
/* La pastiglia dell'icona è viola PIENA su tutti e tre i livelli e non
   partecipa alla scala: fa da àncora, dice «questo l'hai preso». Il
   livello lo dice quanto è velata la TESSERA, nella lingua dei bottoni
   primari — fondo scuro velato e filo viola, mai una campitura accesa.
   ⛔ Provati e scartati da Roberta (2026-09-07): i tre metalli, la scala
   sulla sola pastiglia («non colorare solo il cerchio piccolo»), i tre
   viola pieni sulla tessera («orribile»), i trattini contabili, l'anello,
   il numero del livello in un angolo.
   ⚠️ I gradini sono volutamente STRETTI (7 e 9 di distanza percepita, 15
   dal primo all'ultimo): la griglia resta sobria e il livello si legge
   sulla tessera guardata da sola, non scorrendo. Se un domani lo si vuole
   a colpo d'occhio, l'ultimo gradino va oltre il 30%. */
.stx-badge--bronze { border-color: var(--purple-line); }
.stx-badge--silver { border-color: rgba(var(--accent-rgb), .55); background: rgba(var(--accent-rgb), .10); }
.stx-badge--gold { border-color: var(--purple); background: rgba(var(--accent-rgb), .28); }
.stx-badge--bronze .stx-badge-ic,
.stx-badge--silver .stx-badge-ic,
.stx-badge--gold .stx-badge-ic { background: var(--purple); color: #fff; }
/* ⚠️ lo spento sta sui FIGLI, mai sul badge intero: l'opacity di un
   genitore si porta dietro tutto il sottoalbero e il figlio non può
   annullarla — col .45 sul badge il fumetto del dettaglio usciva mezzo
   trasparente, col badge sovrastante che si leggeva attraverso
   (segnalato da Francesco, 2026-08-31 sera) */
.stx-badge--locked .stx-badge-ic,
.stx-badge--locked .stx-badge-name,
.stx-badge--locked .stx-badge-meta { opacity: .45; }
.stx-badge--locked .stx-badge-ic { background: rgba(255, 255, 255, .06); color: var(--muted); }

/* Il fumetto del dettaglio: sostituisce il title del browser (che non si
   veste e sul telefono non esiste). Si apre in hover/focus da desktop e
   col tap ovunque (.is-tip via stats.js); l'ingresso è la solita salita
   morbida delle sheet, in piccolo. --tx tiene il translateX per non
   raddoppiare le regole sulle colonne laterali. */
.stx-badge-tip {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  --tx: -50%;
  transform: translate(var(--tx), 4px);
  width: max-content;
  max-width: 210px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 8px 11px;
  font-size: var(--fs-xs);
  font-weight: 400;
  line-height: 1.45;
  color: var(--body-text);
  text-align: left;
  /* l'ombra dei popover dell'app (stessa della tendina dei tag @):
     senza, --surface-2 sul grigio delle tessere affoga e il fumetto
     sembra parte del badge che copre invece di starci sopra */
  box-shadow: 0 12px 32px rgba(0, 0, 0, .45);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--speed), transform var(--speed),
              visibility var(--speed);
  z-index: 5;
}
.stx-badge-tip-lv {
  display: block;
  text-align: center;
  margin-top: 6px;
  font-size: var(--fs-eyebrow);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
/* le tre soglie in fila: quelle già prese si accendono, come la tessera.
   ⚠️ Niente numero del livello davanti alla soglia («1 · 2»): due numeri
   di fila si leggevano come un intervallo. Il livello è la POSIZIONE. */
.stx-lv { color: var(--dim); }
.stx-lv.is-preso { color: var(--brand-light); font-weight: 600; }
/* aperto: dal tap (is-tip, tutti i dispositivi) o dall'hover/focus —
   ⚠️ l'hover SOLO dove esiste davvero (hover: hover): sul touch il tap
   lo lascia appiccicato e il secondo tap non chiuderebbe il fumetto */
.stx-badge.is-tip { z-index: 6; }
.stx-badge.is-tip .stx-badge-tip,
.stx-badge:focus-visible .stx-badge-tip {
  opacity: 1;
  visibility: visible;
  transform: translate(var(--tx), 0);
}
@media (hover: hover) {
  .stx-badge:hover { z-index: 6; }
  .stx-badge:hover .stx-badge-tip {
    opacity: 1;
    visibility: visible;
    transform: translate(var(--tx), 0);
  }
}
/* colonne laterali: il fumetto si allinea al bordo della tessera invece
   di uscire dallo schermo. ⚠️ La griglia è a TRE anche sul telefono
   (04/09): le regole pari/dispari sotto i 400px, residuo delle due
   colonne, ancoravano «Hype Man» (22°, colonna 1) al bordo destro e il
   fumetto usciva a sinistra dello schermo (iPhone, 2026-09-10). */
.stx-badges .stx-badge:nth-child(3n+1) .stx-badge-tip { left: 0; --tx: 0; }
.stx-badges .stx-badge:nth-child(3n) .stx-badge-tip { left: auto; right: 0; --tx: 0; }

/* ── Il SETUP del timer in orizzontale e su desktop (2026-09-16, chiesto
   da Francesco: «se giro il telefono prima di far partire il timer non
   c'è il formato landscape con comandi a sinistra e WOD a destra»).
   Stessa media query e stesse proporzioni delle due colonne dell'overlay
   in corsa (2fr / 1fr): i comandi (tipi, campi, Start) a sinistra, la
   scheda del WOD a destra, appiccicata in alto e che scorre dentro di
   sé. Solo quando c'è un WOD (body.tm-con-wod) e solo con l'overlay
   chiuso: in corsa comanda la griglia di .tm-screen--wod. ⚠️ Niente
   :has(): la WebView del guscio può essere un Chrome 90. */
@media (min-width: 900px), (orientation: landscape) and (min-width: 640px) {
  body.tm-page.tm-con-wod:not(.tm-open) main > .container {
    max-width: 960px;
    display: grid;
    grid-template-columns: 2fr 1fr;
    column-gap: var(--s5);
    align-items: start;
  }
  body.tm-page.tm-con-wod:not(.tm-open) main > .container > * { grid-column: 1; }
  body.tm-page.tm-con-wod:not(.tm-open) main > .container > .tm-wod--setup {
    grid-column: 2;
    grid-row: 1 / span 12;
    position: sticky;
    top: var(--s4);
    margin: var(--s4) 0 0;
    max-width: none;
    max-height: calc(100dvh - var(--nav-h) - env(safe-area-inset-bottom) - var(--s5));
    overflow-y: auto;
  }
  body.tm-page.tm-con-wod:not(.tm-open) main > .container > .tm-tipi { margin-top: var(--s4); }
}

/* ── L'INVITO alle notifiche al primo avvio dentro l'app (2026-09-19) ──
   Pannello ancorato in fondo, sopra la barra di navigazione, che sale
   quando push_invito.js lo accende. Esiste solo nel guscio degli store.
   ⚠️ Niente backdrop-filter e niente translateZ su un elemento fisso:
   su iPhone fanno ballare la pagina (design-system.md). */
.push-invito {
  position: fixed;
  left: var(--s3);
  right: var(--s3);
  bottom: calc(var(--nav-h) + env(safe-area-inset-bottom) + var(--s3));
  z-index: 60;
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  flex-wrap: wrap;
  padding: var(--s4);
  border-radius: var(--r-md);
  background: var(--surface-2);
  border: 1px solid var(--line);
  box-shadow: 0 8px 30px rgba(0, 0, 0, .45);
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .24s ease, transform .24s ease;
}
.push-invito--on { opacity: 1; transform: translateY(0); }
/* ⚠️ Niente :has(): la WebView del guscio può essere un Chrome 90. La
   barra in fondo sparisce con la stessa classe che la nasconde. */
body.public.senza-uscite .push-invito {
  bottom: calc(env(safe-area-inset-bottom) + var(--s4));
}
.push-invito-ico {
  flex: none;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--btn-tint);
  color: var(--purple-hi);
}
.push-invito-ico .icon { width: 18px; height: 18px; }
.push-invito-txt { flex: 1; min-width: 190px; }
.push-invito-txt strong { display: block; font-size: var(--fs-base); }
.push-invito-txt p {
  margin: var(--s1) 0 0;
  font-size: var(--fs-sm);
  color: var(--muted);
  line-height: 1.45;
}
/* ⭐ I due bottoni a TUTTA larghezza, un terzo «Non ora» e due terzi
   «Attiva» (deciso da Francesco il 19/09 sulla vetrina 6.11): la riga va
   a capo sotto il testo e si prende tutto lo spazio. */
.push-invito-azioni {
  flex: 1 0 100%;
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: var(--s2);
  padding-top: var(--s1);
}
.push-invito-azioni .btn { width: 100%; }
