/*
 * Hybrx — visual system.
 *
 * Ported from the reference mockup (index.html): the same shapes, spacing, glow
 * and typography, with the palette narrowed to black and neon pink. Cyan
 * survives only where a second colour genuinely carries meaning, so nothing
 * competes with the accent.
 *
 * Everything is self-hosted, fonts included, which is what lets the
 * Content-Security-Policy stay at default-src 'self' with no exceptions - and
 * keeps visitors' IP addresses away from a font CDN (spec §5.2, §7.5).
 */

/*
 * The `hidden` attribute has to actually hide.
 *
 * The browser hides it with `[hidden] { display: none }` from its own stylesheet, and
 * ANY author rule that sets `display` beats that - so `.btn { display: inline-flex }`
 * quietly made every hidden button visible again. That is not theoretical: the tracker
 * shipped with "Salva nota" still on screen after script had hidden it, and a "Salvata"
 * confirmation that was never hidden in the first place, so it sat there permanently
 * and told the athlete nothing. One rule, and every `hidden` in the application means
 * what it says.
 *
 * !important is the point rather than a shortcut: the attribute must outrank whatever
 * class the element happens to carry, which is exactly what the browser intended and
 * failed to achieve on its own.
 */
[hidden] { display: none !important; }

/* ---------- self-hosted fonts ---------- */
@font-face {
  font-family: 'Manrope';
  src: url('/fonts/manrope-latin-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Manrope';
  src: url('/fonts/manrope-latin-600-normal.woff2') format('woff2');
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: 'Manrope';
  src: url('/fonts/manrope-latin-700-normal.woff2') format('woff2');
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: 'Manrope';
  src: url('/fonts/manrope-latin-800-normal.woff2') format('woff2');
  font-weight: 800;
  font-display: swap;
}
@font-face {
  font-family: 'Barlow Condensed';
  src: url('/fonts/barlow-condensed-latin-500-normal.woff2') format('woff2');
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: 'Barlow Condensed';
  src: url('/fonts/barlow-condensed-latin-600-normal.woff2') format('woff2');
  font-weight: 600;
  font-display: swap;
}

/*
  Poppins: sta soltanto sulla cartolina da condividere.

  Non e' un carattere in piu' per l'interfaccia - l'interfaccia ha Manrope, Jost e Barlow. E' il
  carattere del disegno che e' stato approvato, e una cartolina che finisce in una storia di
  qualcun altro e' l'unico posto dove le proporzioni di quel disegno contano al pixel. Quattro
  pesi, sottoinsieme del latino: 28 KB in tutto, e il browser li scarica solo quando una regola
  che li nomina viene davvero disegnata, cioe' quando il foglio della condivisione si apre.
*/
@font-face {
  font-family: 'Poppins';
  src: url('/fonts/poppins-latin-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Poppins';
  src: url('/fonts/poppins-latin-500-normal.woff2') format('woff2');
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: 'Poppins';
  src: url('/fonts/poppins-latin-600-normal.woff2') format('woff2');
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: 'Poppins';
  src: url('/fonts/poppins-latin-700-normal.woff2') format('woff2');
  font-weight: 700;
  font-display: swap;
}

/*
  Knewave e Kanit corsivo: il secondo carattere della cartolina, e sta soltanto li'.

  "Usa lo stesso font della foto che ti ho mandato." Il riferimento scrive i numeri con un pennello
  corsivo e le etichette con un bastoncino corsivo pesante: nessuno dei due e' un carattere di
  sistema, e nessun geometrico li somiglia - messi accanto al riferimento, Kanit, Exo 2, Saira,
  Titillium e Barlow in corsivo davano tutti lo stesso "1:23:02" ordinato che il riferimento non e'.
  Knewave ha lo stesso 7 e lo stesso 2, e Kanit 700 corsivo e' la stessa etichetta.

  Un peso ciascuno, sottoinsieme del latino, 38 KB in tutto, licenza SIL OFL come gli altri. Come
  Poppins, il browser li scarica solo quando la cartolina li disegna.
*/
@font-face {
  font-family: 'Knewave';
  src: url('/fonts/knewave-latin-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Kanit';
  src: url('/fonts/kanit-latin-700-italic.woff2') format('woff2');
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}

/*
  Jost: un geometrico simile a Futura, auto-hostato.

  Chiesto un font come Futura ma presente sia su Android che su Apple. Futura di sistema c'e' su
  Apple e non su Android, e Impact aveva lo stesso problema. Jost e' un omaggio libero a Futura (SIL
  Open Font License): incorporato qui come Manrope e Barlow, rende identico su ogni dispositivo e non
  dipende da cosa c'e' installato. Sta dentro la CSP font-src 'self' perche' e' servito dal jar, e
  non manda l'indirizzo di nessuno a un CDN di font.
*/
@font-face {
  font-family: 'Jost';
  src: url('/fonts/jost-latin-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Jost';
  src: url('/fonts/jost-latin-500-normal.woff2') format('woff2');
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: 'Jost';
  src: url('/fonts/jost-latin-600-normal.woff2') format('woff2');
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: 'Jost';
  src: url('/fonts/jost-latin-700-normal.woff2') format('woff2');
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: 'Jost';
  src: url('/fonts/jost-latin-800-normal.woff2') format('woff2');
  font-weight: 800;
  font-display: swap;
}

/*
  Colour tokens.

  Every colour in this stylesheet comes from here, which is the whole reason a
  light theme is a dozen overrides rather than a rewrite. :root is the dark
  theme; [data-theme="light"] on <html> swaps the surfaces and the text.

  Two independent axes, and keeping them independent is what makes four accents
  cost eight small blocks instead of eight stylesheets:

    data-theme  = dark | light          -> surfaces, text, shadows
    data-accent = pink | green | orange | tiffany -> the accent tokens only

  The accent tokens used to be called --pink, which stopped being true the day
  the athlete could choose Tiffany. They are --accent* now: same values, honest
  name, and every rule in this file already went through them.

  The light theme exists for a real situation, not for taste: outdoors in
  sunlight a black screen is close to unreadable, and an athlete checking their
  session mid-ride is exactly the person who will be outdoors.
*/
:root {
  color-scheme: dark;

  /*
    NOTHING UNDER 12px. There were thirty-odd declarations between 9px and 11.5px in here - the
    eyebrows, the units, the tile captions, the meta under a meal - and on a phone in daylight they
    were the small print of an application whose whole job is to be read at a glance, one-handed,
    often outdoors. Davide asked for a floor and 12px is it. Where something needed to look smaller
    than what it labels, it is the weight and the colour that carry that now, not the size.
  */

  /*
    Tiffany, fixed. Every other colour here follows the accent the athlete chose; this one marks
    things that are not about them and not controls - where a workout came from, and the training
    icons. A constant colour is what makes those findable without reading them.
  */
  --tiffany: #2ee6df;
  --tiffany-line: rgba(46, 230, 223, .45);

  /* ---------- il fondo scuro e' blu navy, per tutte le tavolozze ----------

     "Tutti gli sfondi scuri rendili blu navy scuro."

     Era antracite - un grigio quasi neutro - e prima ancora, per due tavolozze, un asfalto verdastro
     e un'ardesia bluastra che sono stati unificati proprio in quell'antracite. Adesso il navy e' il
     fondo di tutti, e quindi torna a essere una decisione del TEMA e non dell'accento: nessuna
     tavolozza porta piu' un fondo suo, e non c'e' piu' niente da tenere in pari fra otto blocchi.

     I GRADINI SONO GLI STESSI DI PRIMA, spostati in blocco. Il fondo, la faccia della carta e il suo
     lato scuro stavano a +8/+9/+10 e +3/+4/+5 dal fondo: quelle distanze sono state misurate contro
     il testo e portate qui identiche, perche' e' la distanza a decidere se una carta si stacca dalla
     pagina - non il colore. Cambiare tinta e ricalcolare i passi a occhio vorrebbe dire rifare una
     misura che era gia' stata fatta.

     I veli chiari (--line, --field, --track) restano bianchi e non diventano azzurri: un velo bianco
     su un fondo blu prende da solo la sua tinta, mentre un velo gia' azzurro su un fondo blu diventa
     una macchia di colore invece di una schiaritura. */
  --bg: #0b1220;
  /*
    Four steps of grey, and the two quiet ones were too quiet. Measured against #08080b: --mut was
    6.2 : 1 and --mut2 only 3.2 : 1, which is under the 4.5 : 1 that body text needs - and those two
    carry the hints, the units and the tile captions, the small print that explains what every number
    on the dashboard means. On a phone in daylight it read as dark grey on black.

    Lifted to 8.8 : 1 and 6.2 : 1, and deliberately still grey: --ink is the white one, and if every
    step were white there would be no hierarchy left to read. Each remains distinctly quieter than
    the one above it.
  */
  --ink: #f2f3f7;
  --ink-2: #dcdfe7;
  --mut: #a8acba;
  --mut2: #8b8f9c;

  --line: rgba(255, 255, 255, .09);
  --line-soft: rgba(255, 255, 255, .06);
  /* Il contorno delle caselle della settimana: grigio scuro nel tema scuro, grigio chiaro nel chiaro
     (Luca, 27/09: «Metti dei contorni alle pastiglie e box della settimana»). */
  --week-outline: #3a3f4b;

  /*
    Card face, top and bottom of its gradient. OPAQUE, and that is the whole point of these two
    values being written as hex rather than as the rgba(255,255,255,.045) they replace.

    A translucent white only looks dark because --bg is painted behind it. Every time the browser
    composites a card against something else, the card turns white - and the ink on it is white
    too, so the card empties. That is not hypothetical: it is what a full-page screenshot on iOS
    does to the two tallest cards on the dashboard, which get their own compositing layer and are
    rasterised against the blank page rather than against the body. Everything inside them goes with
    it, because --accent-soft, --field and --track are translucent as well and were compositing
    against that same white. Printing does the same thing, for the same reason.

    These are the exact colours the old values produced over the page ground, so nothing on screen
    changes: quando il fondo e' passato al navy sono stati spostati con lui, mantenendo gli stessi
    scarti (+8/+9/+10 e +3/+4/+5) che erano stati misurati contro il testo.
    An opaque card also means the fills inside it composite against the card itself, which is what
    makes one translucent value work on a card, a panel and a bar alike - so those stay as they are.
  */
  --surface: #131b2a;
  --surface-2: #0e1625;
  /* Quieter fills: tiles, inputs, chips. */
  --field: rgba(255, 255, 255, .03);
  --field-soft: rgba(255, 255, 255, .015);
  --track: rgba(255, 255, 255, .07);

  /* Bars and floating panels are opaque: content scrolls behind them. */
  --bar: rgba(9, 16, 30, .98);
  --panel: rgba(19, 27, 42, .99);
  --scrim: rgba(0, 0, 0, .6);
  /*
    ---------- l'elevazione: ogni riquadro e' una superficie solida sollevata di 4px ----------

    "Dai un offset con ombra a tutti i box in app per farli sembrare superfici solide rialzate di
    4px."

    TRE STRATI E NON UNO, ed e' quello che distingue un oggetto sollevato da un rettangolo con una
    macchia sotto. Un'ombra sola grande e sfocata - che e' quello che c'era - dice "c'e' del buio
    qui sotto" e non dice a che altezza sta la cosa: la sfocatura larga e' la stessa a quattro
    millimetri e a quattro centimetri.

    - IL CONTATTO, corto e quasi netto: e' l'ombra che un oggetto proietta dove quasi tocca. E'
      questa a dichiarare lo spessore, perche' e' l'unica la cui distanza si legge.
    - LA PROPRIA, media: il corpo dell'ombra, gia' sfumata.
    - L'AMBIENTE, larga e leggera: la luce diffusa che arriva da tutto il resto della stanza.

    Tutte verso il basso e verso destra di un soffio, perche' la luce viene dall'alto a sinistra -
    ed e' la stessa luce del filo chiaro sul bordo superiore, che e' la faccia illuminata del
    bordo. Un'ombra che cade da una parte e un riflesso che arriva dall'altra e' la cosa che fa
    sembrare finta una superficie, ed e' il difetto che la barra in fondo aveva.

    Il filo chiaro e' dentro il riquadro e non fuori: e' lo spessore del bordo che prende luce, non
    un alone.
  */

  /*
    ---------- lo spessore: ogni riquadro e' una tessera, non un rettangolo ----------

    "Tutti i riquadri devono avere ombre e uno spessore del LORO STESSO COLORE, come fossero tessere
    di un domino."

    L'esempio del domino e' anche la regola fisica, ed e' quella che mancava: il fianco di una
    tessera non e' di un altro colore, e' la stessa materia vista dove prende meno luce. Un fianco
    colorato diversamente si legge come un bordo disegnato - che e' esattamente cio' che era la barra
    in fondo prima di questa passata, e il motivo per cui sembrava appiccicata li' invece che
    appoggiata sopra.

    QUINDI IL COLORE NON E' SCRITTO QUI: e' --solid, che ogni riquadro imposta con la propria faccia.
    Questa e' la ricetta, e il colore lo mette chi la usa. Una variabile dentro una variabile si
    risolve sull'elemento che la ADOPERA, non su :root, quindi la stessa riga produce un fianco
    grigio su una carta e un fianco rosato sul promemoria dell'evento senza una seconda regola.

    LA RAMPA SCURISCE PROGRESSIVAMENTE, un gradino per pixel: un fianco piatto resta una
    striscia, ed e' la sfumatura a farne uno spigolo. Chi imposta --solid deve dare il colore che il
    riquadro ha DOVE il fianco lo incontra - il fondo della sfumatura, non la cima - se no la
    tessera si stacca dal suo stesso spessore di un tono.

    SPAZZATO E NON COPIATO: un passo per pixel, invece di una sagoma sola sfalsata di tutto lo
    spessore. Il passo corto tiene le sagome sempre in contatto anche lungo le curve, quindi la loro unione e' un
    volume continuo e gli angoli si chiudono da soli. Con una copia sola, dove il bordo curva le due
    sagome si staccano e restano due monconi: e' successo sulla barra, cerchiato in rosso su uno
    screenshot.

    IN BASSO A DESTRA come ogni ombra di questa pagina, perche' la luce viene dall'alto a sinistra.
    Una sola direzione per tutta l'applicazione: due oggetti sullo stesso piano con due soli diversi
    si leggono come un collage, ed e' la cosa che l'occhio nota per prima senza saper dire cosa.

    Le misure (27/09, "Bottoni principali 4px spessore, schede ecc 2px"): due pixel su ogni riquadro
    che non si preme, la carta e le caselle dentro la carta (erano quattro, e le caselle tre); quattro
    sui bottoni (--button-edge, erano sei), e dallo stesso giorno anche sull'allenamento in corso e
    sulla carta dell'esercizio nel costruttore, che si premono e avevano un fianco da tre tutto loro
    ("Anche allenamento e carta esercizio 4px"); due su una colonna della settimana larga quaranta
    pixel (--lift-edge-xs).
  */
  --solid: var(--surface-2);

  /*
    ---------- dal 27/09: i riquadri sono mosaico, i bottoni sono metallo bombato ----------

    "Tutti i bottoni cliccabili devono avere effetto metallico, superficie lievemente bombata,
    tridimensionalita' e bordo tagliato con spessore di 6px con ombreggiatura e illuminazione
    coerente. I box non interagibili devono avere effetto metallico, superficie piatta stile tessera
    mosaico, bordo spessore 4px e ombreggiatura e illuminazione coerente." (Luca)
    E lo stesso giorno gli spessori: "Bottoni principali 4px spessore, schede ecc 2px". Il bottone
    scende da sei a quattro e il riquadro da quattro a due: la distanza fra i due resta, e dice
    ancora quale si preme.

    UNA LUCE SOLA, IN ALTO A SINISTRA, per tutti e due. Quindi il filo di luce prende il bordo alto E
    quello sinistro (era solo l'alto), ogni ombra portata cade in basso a destra (era solo in basso,
    mentre questo commento lo diceva gia' "verso destra di un soffio"), e il taglio dei bottoni ha la
    faccetta chiara in alto a sinistra e quella scura in basso a destra.

    --shadow-card e' l'ombra di un riquadro alto due pixel; --shadow-tile quella corta di una
    casella appoggiata su una carta (era scritta a mano due volte per tema, sotto .metric e .tile);
    --shadow-button quella di un bottone alto quattro, piu' lontana e piu' netta al contatto. Tutte e
    tre scalate con lo spessore (27/09: meta' quelle dei riquadri, due terzi quella dei bottoni),
    perche' un'ombra lunga sotto una cosa bassa la fa galleggiare.
    --button-bevel e' il bordo tagliato: due faccette da due pixel dentro al bottone, fra la faccia e
    il fianco. Non leggono --solid (sono bianco e nero con alfa), quindi stanno qui e non su `*`.
  */
  --shadow-card:
    1px 1px 1px rgba(0, 0, 0, .34),
    1px 2px 4px -1px rgba(0, 0, 0, .38),
    2px 6px 13px -4px rgba(0, 0, 0, .34);
  --shadow-tile:
    1px 1px 1px rgba(0, 0, 0, .24),
    1px 2px 4px -2px rgba(0, 0, 0, .26);
  --shadow-button:
    1px 1px 1px rgba(0, 0, 0, .32),
    2px 3px 6px -3px rgba(0, 0, 0, .36),
    2px 5px 10px -6px rgba(0, 0, 0, .30);
  --edge-lit: inset 1px 1px 0 rgba(255, 255, 255, .10);
  --button-bevel:
    inset 1px 1px 0 rgba(255, 255, 255, .13),
    inset -1px -1px 0 rgba(0, 0, 0, .18);
  --shadow-panel: 0 18px 44px rgba(0, 0, 0, .6);

  /*
    THE ACCENT: ONE VALUE PER COLOUR, and it is --accent-base. Everything else on this page is
    derived from it, in both modes, which is why adding a fifth colour is a single line.

    Derived rather than hand-picked twice because two hand-written variants drift: the first time
    somebody tunes the dark pink and forgets the light one, the app has two different pinks and
    nobody notices for a month. color-mix() does the tuning, and the percentages below were chosen
    by measuring contrast, not by eye - see the light block.

    E IL VALORE E' CAMPIONATO DAL MARCHIO, non scelto. Era #ff1e8e, e a fianco del logo si vedeva:
    "i colori non matchano, nel logo sono piu' accesi". Misurato invece che guardato, il rosa del
    token aveva saturazione 88 dove quello del file ce l'ha 100, e tinta 330 dove il file sta a 323 -
    cioe' lo stesso rosa lavato, di mezzo passo. Il marchio e' un PNG e i suoi colori non si possono
    piegare; questi si, quindi si piegano loro. Presi dal pixel piu' saturo all'inizio della parola.
    PaletteMatchesTheMarkTest li rimisura a ogni build, sul file, perche' questa e' la quinta volta
    che il marchio e l'applicazione si allontanano e nessuna delle quattro precedenti si e' vista da
    sola.
  */
  --accent-base: #ff009f;
  --accent: var(--accent-base);

  /*
    THE SECOND BRAND COLOUR, and the reason it exists: the official logo is a gradient, not a colour.
    The ring runs from the accent at its foot to a cooler cousin at its head, and the word carries
    the same run. One value per palette, exactly like --accent-base, so a new accent is two lines rather
    than a hunt through the stylesheet.

    Every pairing is the accent's own neighbour on the wheel rather than a fixed blue: a cold blue
    beside orange is two brands arguing. Pink gets the light blue of the logo as drawn, which is
    where this started.

    E come il rosa qui sopra, e' il celeste campionato dalla "x" del marchio - il punto esatto che
    era stato indicato. Era #4cc9f0: stessa tinta, ma saturazione 68 contro 78 e luminosita' 94
    contro 100. Gli altri sei accenti non cambiano: il marchio ha un colore solo, e l'anello prende
    quello dell'atleta - erano d'accordo soltanto sul rosa, ed e' li' che dovevano tornare a esserlo.
  */
  --accent-2: #39cdfe;

  /*
    IL TERZO COLORE, e perche' non e' dichiarato.

    "Aumentiamo la palette a tre colori: i due scelti dall'utente e una variante, in affinita', in
    qualche elemento della dashboard." Dichiararlo vorrebbe dire scriverlo per ognuna delle sette
    tavolozze, in tre posti ciascuna - i selettori per attributo, quelli della scelta in corso e il
    blocco chiaro - cioe' ventun valori da tenere in riga a mano. La prima tavolozza nuova ne
    dimenticherebbe uno.

    Quindi si ricava, ruotando la TINTA del secondo colore di sessanta gradi. E' la stessa
    regola di --accent-2 rispetto all'accento - il vicino sulla ruota - fatta un passo piu' in la':
    con il rosa si arriva al viola - quello suggerito - col verde al blu, con l'arancio al verde. La
    rotazione e' stata scelta provandole: a quarantacinque il rosa dava ancora un blu, a ottanta due
    tavolozze finivano nel magenta. Sempre in famiglia,
    mai un colore che litiga.

    E la proprieta' che la rende giusta e non solo comoda: ruotare la tinta di un colore SENZA tinta
    non fa niente. "volt" ha un bianco per secondo colore e "mono" un grigio, e tutte e due restano
    esattamente quello che sono - che e' il comportamento corretto, perche' una tavolozza neutra con
    dentro un viola non sarebbe piu' neutra.

    La sintassi relativa non c'e' ovunque, quindi prima la mescola a meta' strada come ripiego: un
    colore fra i due, che non e' il terzo ma non e' mai sbagliato. Il valore vero arriva dentro al
    @supports, dove si puo' chiedere.
  */
  --accent-3: color-mix(in srgb, var(--accent) 50%, var(--accent-2));
  --accent-soft: color-mix(in srgb, var(--accent) 9%, transparent);
  --accent-line: color-mix(in srgb, var(--accent) 50%, transparent);
  /* Near-black ink on a filled accent button. Measured against all four bases: dark ink scores
     5.7 to 15.5, white ink 1.3 to 3.6 - so one value serves every colour on dark surfaces. */
  --on-accent: #0a0006;
  /* Accent-coloured text on the page background, lifted towards white so it stays legible at 13px. */
  --accent-ink: color-mix(in srgb, var(--accent) 55%, white);
  /* Accent-coloured text, as its own token so it can be darkened without touching the colour
     itself. Identical to the accent today, in both modes: the athlete asked for one colour that does
     not change, and this is the seam to pull if a neon on white turns out to be too pale to read. */
  --accent-text: var(--accent);
  /* Il gemello di --accent-text per il secondo colore del marchio: i segni delle date segnate (il
     pallino della striscia, la sagoma della gara, la stella del mese) sono nel secondo colore
     perche' una data e' un'altra famiglia di cose rispetto a un allenamento. Nello scuro e' il
     colore stesso; nel chiaro si scurisce come --accent-text, perche' con volt --accent-2 e'
     #f2f4f7, bianco su bianco (verifiche del 26/09). */
  --accent-2-text: var(--accent-2);
  /* Quanto nero entra nelle cifre dei macronutrienti scritte su un foglio (i sette giorni): niente nel
     buio, meta' nel chiaro, dove il ciano e il giallo delle barre sul bianco erano 1,5 a 1. */
  --macro-shade: 0%;

  /* Fluorescent means the colour bleeds past its own edge: a tight core and a wide wash.
     GRAPHICS ONLY. These went on headings, values and the brand word as a text-shadow, and a glow
     on a glyph eats the very edge that makes it a letter - at 13px a number stops being crisp and
     starts being a smudge in the accent colour. Rings, bars, the gauge and the microphone keep it;
     nothing with text in it does. */
  --glow-accent: 0 0 10px color-mix(in srgb, var(--accent) 55%, transparent),
                 0 0 26px color-mix(in srgb, var(--accent) 35%, transparent);
  /* Tre strati e 110 px di alone erano un'insegna al neon dietro a ogni comando principale: la cosa
     che fa leggere una schermata come una dashboard generata piu' di qualunque altra. Due strati e
     32 px lasciano il rilievo - il bottone pieno resta staccato dalla carta - e tolgono la luce che
     si allargava mezzo schermo. "Piu' raffinata e meno da Dashboard ai generated." */
  --glow-accent-strong: 0 0 10px color-mix(in srgb, var(--accent) 45%, transparent),
                        0 0 32px color-mix(in srgb, var(--accent) 18%, transparent);
  /* The quiet one. It used to light every button; it now lights one floating control, the chat's
     jump-to-latest, where the shadow is separating a round button from the conversation scrolling
     under it rather than advertising anything. A single tight layer, no wide wash - a page of these
     beside the strong glow's 110px halo is a smear in the accent colour, which is what it became. */
  --glow-accent-soft: 0 0 12px color-mix(in srgb, var(--accent) 22%, transparent);

  --danger: #ff5c5c;
  --danger-ink: #ffb3b3;
  --ok: #7ee787;
  /* Il gradino di mezzo fra --ok e --danger: "ne resta, ma non tanto". Dichiarato qui accanto agli
     altri due perche' un colore semantico che vive in un solo punto del foglio e' un colore che il
     prossimo reinventa leggermente diverso. */
  --warn: #f0b429;
  /* Oltre l'obiettivo: il numero di una barra del monitor nutrizionale che l'ha passato, per tutte e
     quattro - "il numero cambia colore, arancione" (Davide, 25/09). Non --warn: quell'ambra e' quasi
     il giallo dei grassi (a 4 di distanza percepita), e sulla loro riga il numero passato si
     leggerebbe come il colore della riga. Questo sta a 15. */
  --over: #ff7f2a;

  /* Da 22 e 16 a 18 e 13: carte meno bombate. Con il bagliore ridotto e le etichette strette e'
     la terza cosa che stacca l'aria "generata" - un raggio molto largo su ogni riquadro fa sembrare
     tutto un widget. */
  --r: 18px;
  --r-sm: 13px;
  --bar-h: 70px;
  /*
    I due caratteri, con un nome ciascuno.

    --sans veniva gia' usato da una regola ed era una variabile che non esisteva: una var() senza
    valore rende la dichiarazione invalida e la proprieta' torna a ereditare, quindi il carattere
    giusto arrivava per caso, perche' body e' Manrope. Definito qui, e la pila completa e' scritta
    una volta sola invece che in quattro punti del foglio.
  */
  --sans: 'Jost', Futura, 'Century Gothic', 'Avenir Next', sans-serif;
  --cond: 'Jost', Futura, 'Century Gothic', 'Avenir Next', sans-serif;
}

/* ---------- perche' queste quattro non stanno in :root con tutto il resto ----------

   UN var() DENTRO UNA CUSTOM PROPERTY SI RISOLVE DOVE LA CUSTOM PROPERTY E' DICHIARATA, non dove
   viene usata. --metal-face e le rampe del fianco leggono --solid: dichiarate su :root, quel
   --solid e' quello di :root, e ci resta anche quando l'elemento che le usa ne ha dichiarato un
   altro tre righe sopra. Il risultato non e' un errore visibile: la faccia si disegna, il fianco si
   disegna, semplicemente sono sempre del colore della pagina. Ogni `--solid:` scritto su un
   elemento in questo foglio - la carta, la casella, la colonna della settimana, il giorno con una
   gara - non ha mai fatto niente, e nessuno se ne e' accorto perche' il valore di ripiego e' un
   colore che ci sta bene dappertutto.

   E' venuto fuori dando la faccia dell'accento alle caselle dell'ultima seduta: --solid calcolava
   #ff009f, e la tessera restava blu notte. La stessa regola cercata con un misurino invece che con
   uno screenshot - a occhio quella tessera era semplicemente "un po' spenta".

   Dichiarandole su `*` ogni elemento le ricalcola con il PROPRIO --solid, che e' quello che il
   foglio ha sempre creduto di fare. --solid resta su :root, perche' quello si eredita davvero ed e'
   il valore di ripiego per i novantanove elementi che non lo toccano.

   Le ombre che NON leggono --solid (--shadow-card, --edge-lit, --shadow-panel) restano dov'erano:
   non hanno questo problema e ricalcolarle su ogni elemento sarebbe lavoro per niente. */
*, *::before, *::after {
  /*
    ---------- la faccia dei riquadri: metallo piatto, non bombato ----------

    "Fai un test e dagli un aspetto metallico." Dal 27/09 (Luca): "superficie piatta stile tessera
    mosaico". E lo stesso giorno, guardandola in produzione senza la luce: "le schede contenenti
    informazioni prima avevano effetto metallico ora sono piatte, adeguare sennò i bottoni ora
    risultano fuori luogo rispetto al resto delle grafiche". PIATTA VUOL DIRE NON CONVESSA, NON SENZA
    METALLO: per qualche ora questa faccia e' stata solo la spazzolatura sul colore, e accanto ai
    bottoni bombati le carte si leggevano come carta stampata.

    UN METALLO NON HA UN COLORE, HA UNA CURVA DI LUCE. Una lastra piana di metallo sotto una luce in
    alto a sinistra ha una fascia chiara dove la luce batte di striscio, il tono proprio, e uno
    spegnimento in fretta verso l'angolo lontano dalla luce. E' una lineare e non una radiale: una
    radiale che si spegne ai bordi e' una superficie che si volta, cioe' il bottone (--button-face,
    sotto). La lastra non si volta, riflette.

    IN PIXEL E NON IN PERCENTUALE: settantotto pixel di lucentezza dal bordo alto a sinistra e
    sessantaquattro di spegnimento da quello basso a destra, su ogni riquadro. In percentuale la stessa
    sfumatura si stirava su una carta alta seicento pixel e diventava "scolorito e slavato" (13/09): un
    riflesso ha una lunghezza sua, non una frazione dell'oggetto.

    UNA LUCE SOLA, IN ALTO A SINISTRA: 168 gradi e' la verticale inclinata di un soffio verso destra,
    quindi la fascia chiara parte dall'angolo in alto a sinistra, e 348 e' lo stesso asse letto dal
    basso a destra, dove sta lo spegnimento. E' la stessa luce del taglio dei bottoni e del filo
    (--edge-lit, in alto e a sinistra); il fianco (--lift-edge) e' in basso a destra.

    SOTTO C'E' --plain-face: la spazzolatura, righe da un pixel ogni tre a un'opacita' cosi' bassa da
    non vedersi come righe - si vede come materia - e il colore del riquadro, --solid, che e'
    l'anodizzazione e non la vernice: ogni tessera resta del proprio colore, e fianco e faccia
    continuano a essere la stessa materia. In bianco e nero con alfa e non in color-mix, cosi' gli
    stessi strati funzionano su qualunque --solid.
  */
  --metal-face:
    linear-gradient(
      168deg,
      rgba(255, 255, 255, .085) 0,
      rgba(255, 255, 255, .036) 26px,
      rgba(255, 255, 255, 0) 78px),
    linear-gradient(
      348deg,
      rgba(0, 0, 0, .17) 0,
      rgba(0, 0, 0, 0) 64px),
    var(--plain-face);

  /*
    ---------- la faccia senza luce: il metallo spazzolato e il colore ----------

    Quello che resta del metallo togliendo la luce: e' stata la faccia di tutti i riquadri per qualche
    ora del 27/09, e resta quella delle cose in cui la luce in pixel copre tutta la faccia e cade sulla
    scritta. Una pastiglia da 34 o da 44 punti e una colonna della settimana larga 40 sono piu' corte
    della fascia di luce (78) e dello spegnimento (64): la cifra della settimana accesa scendeva da 4,9
    a 4,1 a 1 (rosa), «Successiva ›» da 4,2 a 4,0, il «DOM» di oggi nella colonna da 4,2 a 3,6. La
    usano le pastiglie di scelta (.programme-pill, .programme-goal, .programme-chip: "la faccia resta
    com'e' oggi", con il fianco da due), i passi di /programma ("presente e successiva piatti") e le
    colonne della settimana (home e /planned).
  */
  --plain-face:
    repeating-linear-gradient(
      168deg,
      rgba(255, 255, 255, .02) 0 1px,
      rgba(0, 0, 0, 0) 1px 3px),
    linear-gradient(var(--solid), var(--solid));

  /*
    ---------- la faccia dei bottoni: metallo lievemente bombato ----------

    "Superficie lievemente bombata." Una superficie convessa sotto una luce in alto a sinistra ha il
    colmo di luce poco sopra e a sinistra del centro, e si spegne verso i bordi, dove si volta: e' una
    radiale e non una lineare, perche' una lineare e' una lastra inclinata. Il colmo sta al 40% della
    larghezza e al 22% dell'altezza. LIEVEMENTE: al colmo un bianco al 16%, al bordo un nero al 16%.

    IN PERCENTUALE, E QUI VA BENE. Il riflesso dei riquadri era in pixel perche' su una carta alta
    seicento pixel una sfumatura in percentuale diventava "scolorito e slavato"; un bottone e' alto
    44, e una bombatura e' una frazione dell'oggetto: un cuscino largo e' bombato quanto uno stretto.

    La spazzolatura e --solid sono quelli dei riquadri: per un bottone pieno --solid e' l'accento,
    per uno distruttivo una tinta del rosso. Il bordo tagliato e' --button-bevel (in :root, perche'
    non legge --solid) e lo spessore --button-edge.
  */
  --button-face:
    radial-gradient(
      ellipse farthest-corner at 40% 22%,
      rgba(255, 255, 255, .16) 0,
      rgba(255, 255, 255, .05) 34%,
      rgba(255, 255, 255, 0) 56%,
      rgba(0, 0, 0, .16) 100%),
    repeating-linear-gradient(
      168deg,
      rgba(255, 255, 255, .02) 0 1px,
      rgba(0, 0, 0, 0) 1px 3px),
    linear-gradient(var(--solid), var(--solid));

  /* I due pixel dei riquadri (27/09: erano quattro, "schede ecc 2px"). Il primo gradino e' all'80%
     e non al 90: nell'angolo in basso a destra la faccia e' gia' scesa del 17% verso il nero, e un
     fianco che parte piu' chiaro di li' e' un filo di luce fra la tessera e il suo spessore - il
     contrario di uno spessore. Il secondo e' al 60,
     dove la rampa da quattro stava a meta' strada fra il secondo e il terzo gradino: con due pixel
     l'ultimo porta il buio di tutto il fianco, e al 44 di prima sarebbe un contorno nero. */
  --lift-edge:
    1px 1px 0 0 color-mix(in srgb, var(--solid) 80%, #000),
    2px 2px 0 0 color-mix(in srgb, var(--solid) 60%, #000);
  /* Bottoni: fianco ridotto a 2px, così la faccia resta più vicina al piano. */
  --button-edge:
    1px 1px 0 0 color-mix(in srgb, var(--solid) 64%, #000),
    2px 2px 0 0 color-mix(in srgb, var(--solid) 45%, #000);
  /* I due pixel dei segni, le icone che si premono (27/09: "tutte le icone cliccabili devono avere
     spessore 2px e bombatura, ombre luci e bordi"). Bombati come i bottoni, quindi il fianco parte
     dove parte il loro, al 64, e il secondo gradino e' il loro terzo: la stessa curva, meta' dei
     passi. Non --lift-edge, che e' il fianco di una lastra piatta e parte all'80. */
  --sign-edge:
    1px 1px 0 0 color-mix(in srgb, var(--solid) 64%, #000),
    2px 2px 0 0 color-mix(in srgb, var(--solid) 45%, #000);
  --lift-edge-xs:
    1px 1px 0 0 color-mix(in srgb, var(--solid) 88%, #000),
    2px 2px 0 0 color-mix(in srgb, var(--solid) 74%, #000);
  /* Un pixel solo: le colonne della settimana e le righe delle date (prova del 27/09 sera). */
  --lift-edge-1: 1px 1px 0 0 color-mix(in srgb, var(--solid) 74%, #000);
}

/* Le stesse in chiaro. La lista di selettori e' quella del blocco del tema con ` *` in coda:
   piu' specifica del `*` nudo, quindi vince, ed e' l'unico modo di tenerle per elemento in tutti e
   due i temi. Il :root da solo c'e' perche' `*` prende anche <html>, e senza di lui la radice
   resterebbe con i valori del tema scuro. */
:root:has(.lp-theme-light:checked),
:root:has(.lp-theme-light:checked) *,
:root:has(.lp-theme-light:checked) *::before,
:root:has(.lp-theme-light:checked) *::after,
:root[data-theme="light"],
:root[data-theme="light"] *,
:root[data-theme="light"] *::before,
:root[data-theme="light"] *::after {
  /* Su fondo chiaro la spazzolatura passa a righe scure, perche' su un metallo chiaro il solco e'
     l'ombra e non la luce. La lucentezza dei riquadri e' quasi tutta bianca (su una faccia bianca non
     si vede, e su una tinta si') e lo spegnimento un quarto di quello scuro: su una faccia chiara una
     scura di troppo fa una macchia, e un bianco piu' bianco non e' un riflesso, e' uno strappo. Le
     lunghezze sono quelle del tema scuro. La bombatura dei bottoni ha il colmo a meta' e il bordo a
     poco piu' di meta': su un bottone bianco il colmo non si vede, e si vede il bordo che si volta; su
     un pieno nell'accento si vedono tutti e due. */
  --metal-face:
    linear-gradient(
      168deg,
      rgba(255, 255, 255, .75) 0,
      rgba(255, 255, 255, .30) 26px,
      rgba(255, 255, 255, 0) 78px),
    linear-gradient(
      348deg,
      rgba(16, 16, 28, .045) 0,
      rgba(16, 16, 28, 0) 64px),
    var(--plain-face);
  --plain-face:
    repeating-linear-gradient(
      168deg,
      rgba(16, 16, 28, .012) 0 1px,
      rgba(0, 0, 0, 0) 1px 3px),
    linear-gradient(var(--solid), var(--solid));
  --button-face:
    radial-gradient(
      ellipse farthest-corner at 40% 22%,
      rgba(255, 255, 255, .30) 0,
      rgba(255, 255, 255, .10) 34%,
      rgba(255, 255, 255, 0) 56%,
      rgba(16, 16, 28, .09) 100%),
    repeating-linear-gradient(
      168deg,
      rgba(16, 16, 28, .012) 0 1px,
      rgba(0, 0, 0, 0) 1px 3px),
    linear-gradient(var(--solid), var(--solid));
  /* I due pixel anche qui, ma la rampa resta corta: su una faccia bianca il 60% verso il nero
     sarebbe un grigio medio, e una tessera il cui spessore e' piu' scuro del piano su cui poggia
     non si legge come sollevata, si legge come un buco. Abbastanza da vedersi, non tanto da
     pesare: 93 e 82, la cima e la meta' scura della rampa da quattro di prima. Il 93 sta sotto
     l'angolo spento della faccia, che qui arriva a poco meno del 96. */
  --lift-edge:
    1px 1px 0 0 color-mix(in srgb, var(--solid) 93%, #000),
    2px 2px 0 0 color-mix(in srgb, var(--solid) 82%, #000);
  /* E i quattro dei bottoni, per la stessa ragione piu' corti del tema scuro: partono sotto alla
     faccetta in ombra (intorno all'85%) e si fermano al 72, sotto all'ultimo gradino dei riquadri. */
  --button-edge:
    1px 1px 0 0 color-mix(in srgb, var(--solid) 83%, #000),
    2px 2px 0 0 color-mix(in srgb, var(--solid) 79%, #000),
    3px 3px 0 0 color-mix(in srgb, var(--solid) 75%, #000),
    4px 4px 0 0 color-mix(in srgb, var(--solid) 72%, #000);
  /* E i due dei segni, con la stessa regola: il primo e il terzo gradino dei bottoni. */
  --sign-edge:
    1px 1px 0 0 color-mix(in srgb, var(--solid) 83%, #000),
    2px 2px 0 0 color-mix(in srgb, var(--solid) 75%, #000);
  --lift-edge-xs:
    1px 1px 0 0 color-mix(in srgb, var(--solid) 93%, #000),
    2px 2px 0 0 color-mix(in srgb, var(--solid) 87%, #000);
  --lift-edge-1: 1px 1px 0 0 color-mix(in srgb, var(--solid) 87%, #000);
}
/* La rotazione vera, dove la sintassi relativa esiste. Fuori di qui resta la mescola, che e' un
   ripiego e non un errore: si vede un colore in meno, non un colore sbagliato. */
@supports (color: oklch(from red l c h)) {
  :root { --accent-3: oklch(from var(--accent-2) l c calc(h + 60)); }
}


/*
  Light theme.

  Not an inversion. Neon pink on white at full strength is unpleasant and fails
  contrast on small text, so the accent is darkened for text while the fills stay
  the brand pink, and the glows are cut right back - a glow on a white background
  reads as a printing error.
*/
/*
  Il secondo selettore e' la vetrina, che un attributo data-theme non ce l'ha e non puo' averlo: li'
  non c'e' un profilo su cui scrivere la preferenza, quindi il comando e' una casella di spunta e
  :has() la legge da :root - lo stesso meccanismo con cui la stessa pagina sceglie l'accento.

  Scritto prima e non dopo di proposito: AccentTest cerca la stringa `:root[data-theme="light"] {`
  per leggere questo blocco e controllare che il chiaro non ridipinga l'accento. Messo in coda al
  gruppo, quel testo resta dov'era.
*/
:root:has(.lp-theme-light:checked),
:root[data-theme="light"] {
  color-scheme: light;

  --bg: #f6f6f8;
  --ink: #16161c;
  --ink-2: #35353f;
  /*
    THE TWO QUIET GREYS, MEASURED AGAINST THE DARKEST THING THEY LAND ON.

    --mut2 was #83879a: 3.30 : 1 on this background, under the 4.5 : 1 body text needs, and it carries
    the small print - the units, the hints, the tile captions. The same defect was found and fixed in
    the dark palette by reading the dashboard outdoors; here nobody had measured, and the light theme
    shipped with it.

    Then measured again on the painted page rather than against the page colour, which is what found
    the rest of it. Neither grey sits only on white: they land on the tile fill (#eeeef0 composited),
    the metric fill (#e2e2e4) and the setup banner (#d9d8da), and on that last one --mut itself was
    4.40 : 1 and --mut2 3.56.

    So both are set against the worst ground and not the best. --mut is 4.91 : 1 on the banner and
    6.46 on the page; --mut2 is 4.61 and 6.07. Still two distinct steps, still both quieter than
    --ink-2 above them: the hierarchy is what these four levels are for.
  */
  --mut: #555967;
  --mut2: #595d6c;

  --line: rgba(16, 16, 28, .14);
  --line-soft: rgba(16, 16, 28, .09);
  --week-outline: #cfd3db;

  --surface: #ffffff;
  --surface-2: #ffffff;
  --field: rgba(16, 16, 28, .035);
  --field-soft: rgba(16, 16, 28, .02);
  --track: rgba(16, 16, 28, .10);

  --bar: rgba(255, 255, 255, .98);
  --panel: #ffffff;
  --scrim: rgba(16, 16, 28, .38);
  --shadow-card:
    1px 1px 1px rgba(16, 16, 28, .07),
    1px 2px 4px -1px rgba(16, 16, 28, .08),
    2px 6px 13px -4px rgba(16, 16, 28, .10);
  --shadow-tile:
    1px 1px 1px rgba(16, 16, 28, .06),
    1px 2px 4px -2px rgba(16, 16, 28, .07);
  --shadow-button:
    1px 1px 2px rgba(16, 16, 28, .09),
    3px 5px 8px -3px rgba(16, 16, 28, .10),
    4px 9px 16px -7px rgba(16, 16, 28, .12);
  --edge-lit: inset 1px 1px 0 rgba(255, 255, 255, .9);
  /* Su una faccia bianca la faccetta alla luce e' il bianco pieno, e quella in ombra un grigio appena:
     una scura di troppo su un bottone chiaro disegna un contorno, non un taglio. */
  --button-bevel:
    inset 2px 2px 0 rgba(255, 255, 255, .85),
    inset -2px -2px 0 rgba(16, 16, 28, .09);
  --shadow-panel: 0 18px 44px rgba(16, 16, 28, .18);

  /*
    THE ACCENT DOES NOT CHANGE BETWEEN MODES. One coded value per colour, and light mode uses the
    same one at the same strength, glow included - the surfaces change, the accent does not. That is
    the point of having two independent axes.

    It used to darken the accent by half here and drop the glows. The reasoning was contrast, and the
    numbers are worth keeping written down: neon green at full strength on #f6f6f8 measures 1.4 : 1,
    where body text wants 4.5 : 1. It is fine for a filled button (dark ink on a bright fill), fine
    for a border, fine for a ring, and hard to read as small text.

    So if accent-coloured *text* on the light background ever needs help, the knob is --accent-text
    below: it is the accent everywhere it is a colour, and the one place to darken if it has to be
    read at 13px. Nothing else needs touching, and no colour has to be picked twice.
  */
  --accent-soft: color-mix(in srgb, var(--accent) 12%, transparent);
  --accent-line: color-mix(in srgb, var(--accent) 55%, transparent);
  /* Dark ink on a bright fill: measured 5.7 to 15.5 against all four bases, where white scores
     1.3 to 3.6. The same value serves both modes for the same reason. */
  --on-accent: #0a0006;
  /*
    Mixed half and half, down from 70%. At 70% the green resolved to #1eb25f and measured 2.77 : 1 on
    white, and Tiffany 3.16 - so accent-coloured text was illegible on a light page for two of the
    four palettes, in the one token whose entire job is being legible. At 50% the worst of the four is
    the green at 4.99 : 1 and the best the pink at 10.11.
  */
  --accent-ink: color-mix(in srgb, var(--accent) 50%, black);
  /*
    And the knob, turned. This is the value links and other accent-coloured text take; on the dark
    theme it is the accent itself, here it is the darkened one. The fills, borders, rings and glows
    keep the brand colour at full strength - only text moves, which is the whole reason this is a
    separate token from --accent.
  */
  --accent-text: var(--accent-ink);
  /* Lo stesso per il secondo colore: a meta' con il nero. Con volt #797a7c, 4,3 a 1 sul bianco; per
     un segno ne basta 3. */
  --accent-2-text: color-mix(in srgb, var(--accent-2) 50%, black);
  /* Le cifre dei macronutrienti a meta' con il nero: il ciano delle proteine 5,5 a 1 sul bianco. */
  --macro-shade: 50%;

  --danger: #c62828;
  --danger-ink: #8c1d1d;
  --ok: #1a7f37;
  /* Piu' scuro del gemello notturno: su fondo chiaro un ambra brillante non si legge. */
  --warn: #a35c00;
  /* Lo stesso: un arancione acceso su bianco, a 12px, non si legge. 5,2 a 1 sul bianco. */
  --over: #c2410c;

}

/*
  ---------- accents ----------

  One line per colour. Nothing else: the tokens above derive the soft fills, the lines, the ink and
  the glows from whichever base is in force, and the light block darkens that same base by half. A
  fifth colour is a value here, a constant in the Accent enum and a label in the two bundles.

  Tiffany is the one named after a colour that already exists in the world: #0ABAB5, brightened here
  because the original goes muddy on black.
*/
:root[data-accent="green"] { --accent-base: #2bff88; --accent-2: #2ee6df; }
:root[data-accent="orange"] { --accent-base: #ff7a1a; --accent-2: #ffd23f; }
:root[data-accent="tiffany"] { --accent-base: #2ee6df; --accent-2: #6ea8ff; }
/*
  Le due palette che spostano anche le superfici.

  Le quattro qui sopra sono un accento su un fondo solo: nero quasi puro, uguale per tutte. Queste
  due sono nate come palette intere - "Tactical Performance" e "Clinical Bio-Tech" - e la meta' del
  loro carattere sta nel fondo: il volt su nero vero e' una torcia in una stanza buia, sull'asfalto
  e' una striscia su una strada; e la menta chiede l'ardesia, o resta il Tiffany su nero che c'e'
  gia'.

  I due valori dell'accento restano in una regola loro, come per tutte le altre - vedi AccentTest,
  che pretende esattamente due codici colore per accento e non tollera che ne compaia un terzo li'
  dentro. Le superfici sono una seconda regola, sotto: chi aggiunge un accento continua a scriverne
  due, e chi vuole anche un fondo scrive un blocco in piu' invece di allargare il primo.

  :not([data-theme="light"]) e non una seconda regola per il chiaro. Le superfici del tema chiaro
  sono dichiarate piu' in alto in questo file, quindi un blocco per accento scritto qui sotto le
  batterebbe per ordine di sorgente e l'atleta che passa al chiaro si ritroverebbe l'asfalto. Con la
  negazione questi due blocchi semplicemente non si applicano al chiaro, che si tiene i suoi bianchi
  - e' una decisione sulla luce in cui si sta, e un fondo antracite al sole non e' piu' leggibile del
  bianco. Ed e' anche cio' che tiene in piedi la regola di AccentTest: nessun accento scrive una
  seconda tavolozza per il chiaro.

  I due selettori raggruppati sono le due vie per arrivare allo stesso posto: l'attributo che scrive
  il server per chi ha un account, e il radio spuntato sulle pagine pubbliche, che un account non ce
  l'hanno. Raggruppati e non ripetuti: le superfici sono cinque valori, e due copie sono due copie
  che prima o poi divergono - la vetrina mostrerebbe una palette che l'applicazione non ha.
*/
:root[data-accent="volt"] { --accent-base: #d7ff2e; --accent-2: #f2f4f7; }
:root[data-accent="ice"] { --accent-base: #4fe3b0; --accent-2: #7dd3fc; }
:root[data-accent="mono"] { --accent-base: #ffffff; --accent-2: #b9c0cc; }

/*
  ---------- bianco e nero, l'unico accento che si inverte ----------

  Gli altri sei sono lo stesso colore in tutti e due i modi, ed e' una regola voluta: l'accento e'
  una decisione sul gusto, il tema una decisione sulla luce in cui si sta, e cambiare l'una non deve
  cambiare l'altra. Questo e' l'unico che deve fare il contrario, e il motivo non e' un'eccezione di
  comodo: qui l'accento non e' un colore, e' l'estremo neutro - che esiste solo rispetto al fondo.
  Bianco su nero, letto in tema chiaro, e' un riempimento bianco su una carta bianca: il bottone
  sparisce, l'anello sparisce, e resta solo l'inchiostro scuro che ci sta sopra.

  Quindi in chiaro diventa il nero quasi pieno del testo, e con lui l'unica altra cosa che va
  ribaltata: --on-accent, l'inchiostro scritto sopra un riempimento pieno. Vale scuro per tutti e sei
  gli accenti fluorescenti perche' sono tutti chiari; sopra un riempimento nero deve essere chiaro,
  o il bottone e' nero su nero.

  --accent-text torna a essere l'accento stesso invece dell'accento mescolato al nero: mescolare il
  nero con il nero e' una operazione senza risultato, e la ragione per cui quel token esiste - un
  fluorescente troppo pallido da leggere a 13px - qui non si presenta.

  I tre selettori sono i tre modi di arrivare allo stesso posto: l'attributo che scrive il server, il
  radio delle pagine pubbliche con il tema chiaro dichiarato, e la vetrina, dove il chiaro e' una
  casella spuntata e non un attributo.
*/
:root[data-theme="light"][data-accent="mono"],
:root[data-theme="light"]:has(.accent-pick[value="mono"]:checked),
:root:has(.lp-theme-light:checked):has(.accent-pick[value="mono"]:checked) {
  --accent-base: #16161c;
  --accent-2: #4a4f5c;
  --on-accent: #f6f6f8;
  --accent-text: var(--accent);
}

/* ---------- nessun accento porta piu' un fondo suo ----------

   Qui c'erano due blocchi per volt e ice - l'asfalto verdastro e l'ardesia bluastra - poi ridotti a
   riscrivere l'antracite con l'antracite, poi sostituiti da un blocco navy quando e' stato chiesto
   "voglio testare uno sfondo blu navy scuro con l'arancione". E' durato un'ora: subito dopo il navy
   e' diventato il fondo di TUTTI ("tutti gli sfondi scuri rendili blu navy scuro"), e a quel punto
   quella tavolozza era l'arancione con scritto sopra un fondo che ormai avevano tutti.

   LA LEZIONE, ed e' il motivo per cui questo commento resta al posto del codice: il fondo e'
   una decisione del TEMA, non dell'accento. Ogni volta che una tavolozza si e' portata dietro il
   proprio fondo, il fondo ha finito per essere generalizzato a tutte - tre volte su tre - lasciando
   dietro un blocco che riscriveva i valori di base con gli stessi valori di base. Un accento sceglie
   due colori; la stanza in cui si sta e' un'altra scelta. */


/*
  ---------- lo stesso colore, scelto prima di avere un account ----------

  Le due pagine pubbliche - la vetrina e la registrazione - non hanno un atleta da cui leggere una
  preferenza, quindi non possono avere data-accent addosso: quell'attributo lo scrive il server, e
  qui non c'e' ancora niente da scrivere. Ma il colore si deve poter provare lo stesso, ed e' anche
  il modo piu' onesto di mostrare che l'applicazione lo lascia scegliere: si preme un pallino e la
  pagina cambia sotto le dita.

  Un gruppo di radio con classe .accent-pick, e :has() che guarda quale e' spuntato. Le due
  proprieta' finiscono su :root - lo stesso elemento su cui stanno le derivazioni li' sopra - quindi
  cambia tutto quello che ne discende: i riempimenti, le linee, l'inchiostro, i bagliori e il
  gradiente del marchio. Non una riga in piu' per ogni colore.

  Niente per il rosa: e' quello di :root, quindi il suo radio non ha bisogno di nessuna regola.

  Il valore, non l'id: sulla vetrina i radio si chiamano in un modo e nella registrazione sono il
  campo del form, ma il valore e' l'id dell'accento in tutti e due i casi - lo stesso che il server
  poi convalida contro l'enum.

  Dove :has() non c'e', il selettore e' invalido e la regola sparisce: la pagina resta rosa e i
  pallini non fanno niente. E' la degradazione giusta per una decorazione, e non serve una riga di
  JavaScript - che su queste pagine non c'e' proprio.
*/
:root:has(.accent-pick[value="green"]:checked) { --accent-base: #2bff88; --accent-2: #2ee6df; }
:root:has(.accent-pick[value="orange"]:checked) { --accent-base: #ff7a1a; --accent-2: #ffd23f; }
:root:has(.accent-pick[value="tiffany"]:checked) { --accent-base: #2ee6df; --accent-2: #6ea8ff; }
:root:has(.accent-pick[value="volt"]:checked) { --accent-base: #d7ff2e; --accent-2: #f2f4f7; }
:root:has(.accent-pick[value="ice"]:checked) { --accent-base: #4fe3b0; --accent-2: #7dd3fc; }
:root:has(.accent-pick[value="mono"]:checked) { --accent-base: #ffffff; --accent-2: #b9c0cc; }

* {
  box-sizing: border-box;
  margin: 0;
  -webkit-tap-highlight-color: transparent;
}

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.5;
  min-height: 100vh;
  /*
    Niente doppio tocco per ingrandire, e niente attesa di 300ms per scoprire se il tocco era doppio.
    La terza gamba del "visualizzazione fissa al 100%", dopo il meta viewport e i campi a 16px: quel
    gesto e' l'unico modo di zoomare che il meta non copre nemmeno dove viene rispettato.
  */
  touch-action: manipulation;
}

/* ---------- non c'e' piu' nessun disegno dietro alla pagina ----------

   C'era un'illustrazione vettoriale fissa dietro a tutto - "una sala buia con una lampada sopra" -
   con tre passi regolabili dall'atleta: pieno, attenuato, spento. Poi il disegno e' uscito in attesa
   di uno nuovo, e i tre bottoni sono usciti con lui dal selettore dei colori; per un po' e' rimasto
   in piedi tutto l'impianto - la colonna, il CHECK, l'enum - "che e' esattamente quello che serve
   quando l'immagine arriva".

   Adesso e' uscito anche quello: "togli la texture di fondo, abbiamo tolto il comando pieno
   attenuato e spento". Il fondo e' una tinta unita e basta.

   PERCHE' NON VALEVA LA PENA TENERLO IN CALDO. Un impianto conservato per una cosa che forse
   arrivera' e' un impianto che nessuno mantiene ma che tutti devono attraversare: un parametro in
   piu' in updateAppearance, un attributo in piu' sul tag html, una colonna NOT NULL che nessuno
   legge, e un enum importato da sei file. Il costo non e' scriverlo di nuovo - e' mezza giornata -
   il costo e' che finche' sta li' assomiglia a codice vivo. E se l'immagine arriva davvero, arriva
   in un'applicazione che nel frattempo ha scelto materia e luce al posto dell'atmosfera: quel che
   servira' allora non e' questo. */


/* ---------- niente alone dietro alla pagina: il fondo e' a tinta unita ----------

   C'erano tre macchie radiali fisse dietro a tutto - due nel colore dell'accento agli angoli alti e
   una viola in basso - prese dal mockup di partenza. Tolte guardandole: "questo alone non mi piace,
   toglilo, sfondo tinta unita".

   E' anche l'ultimo pezzo di una direzione che la pagina ha abbandonato per gradi. Le carte hanno
   preso una faccia metallica e un fianco, cioe' materia e luce; un alone colorato dietro di loro e'
   l'altra cosa - atmosfera - e le due insieme si annullano: il fondo colorato toglie contrasto al
   metallo e il metallo fa leggere l'alone come una macchia. Su una superficie sola, la luce viene da
   alto-sinistra e il fondo non emette niente.

   Il disegno di fondo vero e proprio (body::after) resta e resta regolabile dall'atleta con i suoi
   tre passi - pieno, attenuato, spento. Quello e' una texture, non una luce, e non e' mai stato il
   problema. */


/* z-index 2 e non 1: un gradino sopra al piè di pagina (.site-footer, 1), sotto alle due barre (30).
   Quello che e' fisso dentro a <main> - la barra del salva dopo un trascinamento - vive nel contesto
   di .app-shell, e allo stesso livello il piè di pagina, che viene dopo, gli si dipingeva sopra: su
   una pagina corta scorsa in fondo «Annulla» non prendeva il dito (la libreria delle schede, 26/09). */
.app-shell {
  position: relative;
  z-index: 2;
  max-width: 520px;
  margin: 0 auto;
  padding: 16px 16px 96px;
}

button, input, select, textarea {
  font-family: inherit;
  color: inherit;
  font-size: inherit;
  outline: none;
}
button { cursor: pointer; }
input::placeholder { color: var(--mut2); }

/*
  Links take --accent-text, not the accent itself, and that one word is a real fix.

  On the dark theme the two are the same value and always have been: the neon on near-black measures
  5.2 to 15.0 : 1 depending on the palette. On the light theme the raw accent as 13px text measured
  1.23 : 1 for the green, 1.44 for Tiffany, 2.42 for the orange and 3.34 for the pink - against the
  4.5 : 1 body text needs. Every link in the application, and the stylesheet had already written down
  both the diagnosis and the cure beside the light palette: "if accent-coloured *text* ever needs help,
  the knob is --accent-text". Nobody had turned it. With it turned, the same four are 4.63 to 9.37.

  Found by measuring the painted page rather than the tokens - the token test passes either way,
  because --accent-text was correct and simply unused here.
*/
a { color: var(--accent-text); text-decoration: none; }
a:hover { text-decoration: underline; }

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

/* ---------- navbar ---------- */
nav.top {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 14px;
  max-width: 520px;
  margin: 0 auto;
  /* Sotto ci vuole quanto sopra. Era zero, e il pulsante del tema - alto 44 pixel, che e' l'area
     minima da toccare - appoggiava sul bordo inferiore della barra. Con un controllo tondo si
     vede subito: sembra scivolato fuori invece che dentro. */
  padding: 12px 16px;
  font-family: var(--cond);
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: 1.8px;
  text-transform: uppercase;
}
nav.top .logo {
  font-family: var(--sans);
  font-weight: 800;
  font-size: 20px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--accent-text);
}
nav.top a { color: var(--mut); }
nav.top a:hover { color: var(--ink); text-decoration: none; }
nav.top button {
  background: none;
  border: 1px solid var(--line);
  color: var(--mut);
  border-radius: 999px;
  padding: 7px 14px;
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
}
nav.top button:hover { border-color: var(--accent-line); color: var(--accent-text); }

/* ---------- hero: the logo, full size ---------- */
/*
  The five pages with no top bar - sign in, register, and the three error pages - carry the logo here
  instead, and it is the same logo: the fragment the bar renders, scaled up.

  It used to be the word alone with a gradient across all of it. That was a second logo: the ring was
  missing, and the first half of the word took the accent instead of the page's ink. On the one page
  every visitor sees before anything else. Reported from production with a photograph of it.

  A flex row rather than a line of text, because the mark is a lockup: ring, gap, word. Everything
  scales with the viewport so it fills a phone without overflowing a narrow one, and the ring's stroke
  is thinned in viewBox units - at 50px across, the bar's 2.4 would draw a 5px band.
*/
.brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(9px, 2.8vw, 15px);
  margin: 18px 0 2px;
  line-height: 1.05;
}
/* Il marchio e' un collegamento alla vetrina: e' l'anello piu' la parola, quindi il collegamento
   deve contenerli entrambi e non solo il testo. Nessuna sottolineatura e nessun colore suo - il
   marchio ha gia' i suoi, e un logo che si tinge di blu al passaggio non e' piu' il logo. */
.brand > a {
  display: flex;
  align-items: center;
  gap: inherit;
  color: inherit;
  text-decoration: none;
}
.brand .logo-mark { height: clamp(34px, 9.5vw, 48px); }
/* La data di oggi, l'occhiello della testata della home: sopra il saluto, a sinistra (mock 01,
   26/09; stava sotto il saluto, centrata, dentro l'anello).

   Attenuata di proposito. E' la riga che dice all'atleta in che giorno e' - e la settimana di
   allenamento finisce domenica notte, quindi non e' un dettaglio - ma non e' la ragione per cui
   apre l'applicazione: quella e' l'anello, subito sotto. Maiuscoletto e spaziatura come le altre
   etichette della pagina, cosi' si legge come un'intestazione e non come una frase. Grigia e non
   nell'accento come nel mock: l'occhiello di una carta qui e' grigio, e un colore che dice
   "cliccami" su una data che non si clicca le darebbe un significato suo. --mut2, il grigio di
   .gauge-caption: era `var(--muted)`, un gettone che non esiste, e una `var()` senza ripiego su una
   proprieta' ereditata vale `inherit` - la data usciva bianca come il saluto (verifiche del 26/09). */
.greet-today {
  margin: 0 0 6px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mut2);
  font-variant-numeric: tabular-nums;
}

/* ---------- tornare indietro ----------
   Un collegamento, non un bottone, e uguale su ogni schermata che non sia una destinazione della
   barra in basso: la chevron e' disegnata qui con un ::before, cosi' il markup e' un <a> e basta.
   Stava dentro alla sezione della scheda nuova, che era l'unica pagina ad averlo; e' salito qui
   il giorno che lo hanno preso tutte. */
/* Alto 44, il bersaglio di casa (era 36, misurato col dito il 26/09): i margini riprendono gli 8 punti in
   piu', e il titolo sotto resta dov'era - 44 - 8 + 6 fanno i 42 di prima (36 - 4 + 10). */
.back-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  margin: -8px 0 6px;
  color: var(--mut);
  font-size: 13px;
  text-decoration: none;
}
.back-link::before {
  content: "‹";
  margin-right: 7px;
  font-size: 22px;
  line-height: .8;
}
.back-link:hover {
  color: var(--accent-text);
  text-decoration: none;
}

/* Oggi: una silhouette di montagna molto discreta sul fondo della carta, senza coprire il contenuto. */
.home-today {
  overflow: hidden;
}
.home-today::after {
  content: "";
  position: absolute;
  z-index: 0;
  left: -8%;
  right: -8%;
  bottom: -8%;
  height: 64%;
  pointer-events: none;
  opacity: .62;
  background:
    linear-gradient(135deg,
      color-mix(in srgb, var(--accent) 24%, transparent),
      color-mix(in srgb, var(--surface) 42%, transparent));
  clip-path: polygon(
    0 100%, 0 78%, 12% 66%, 22% 78%, 34% 42%, 43% 58%,
    55% 20%, 67% 58%, 77% 38%, 88% 68%, 100% 50%, 100% 100%
  );
}
.home-today > * {
  position: relative;
  z-index: 1;
}

/* ---------- cards ---------- */
.card {
  position: relative;
  margin-top: 16px;
  padding: 20px 18px;
  border-radius: var(--r);
  /* Metallo piatto: contorno neutro sulle card esterne. Manteniamo il bagliore accentato
     nell'angolo alto a sinistra, mentre il rilievo/ombra della card resta verso il basso a destra. */
  background:
    radial-gradient(130% 90% at 0 0, color-mix(in srgb, var(--accent) 16%, transparent), transparent 55%),
    var(--metal-face);
  border: 1px solid var(--line);
  border-width: 1px;
  /* La faccia e' PIU' CHIARA DELLA PAGINA, ed e' la condizione perche' ci sia una tessera: con
     --surface-2 (#0e1625 contro un fondo #0b1220) la faccia e il piano erano lo stesso colore a
     occhio, e il fianco scuro cadeva fra due cose scure - il rilievo c'era nel foglio di stile e
     non nel disegno. La cima della rampa parte sotto al punto piu' scuro della faccia, quindi il
     fianco non si stacca dalla sua tessera. */
  --solid: var(--surface);
  box-shadow: var(--edge-lit), var(--lift-edge), var(--shadow-card);
}

/* Una tessera sopra a un'altra tessera. Senza, le due facce sono lo stesso colore e la carta
   interna sparisce dentro a quella che la contiene: e' il caso di ogni esercizio dentro alla
   scheda, che e' la schermata in cui si passa piu' tempo. Un gradino di chiaro per ogni livello,
   che e' come si impilano gli oggetti veri. */
.card .card {
  --solid: color-mix(in srgb, var(--surface) 88%, #ffffff);
  background: var(--metal-face);
  border: 1px solid var(--line-soft);
}
/*
  A page's own title, and it is an h1 because it is the page's heading.

  Every page used to open with the wordmark at 44-58px, six centimetres under the same wordmark in
  the top bar - the product's name said twice before the page said what it was once, on a screen
  844px tall. The dashboard and the chat had already dropped it for that reason; this is the rest of
  the application catching up. The card's own heading was promoted in its place, so the page still
  has exactly one h1 and a screen reader is told where it is rather than which product it is.

  Same size as the h2 it replaces: nothing moves, the tag and the meaning changed.
*/
/*
  Peso 700 e non 800, e un filo piu' di crenatura negativa.

  Ogni titolo di questa applicazione era all'estremo grasso del carattere, e con i sottotitoli a 700
  la differenza fra un livello e l'altro era solo la misura. Tutto grasso e' come tutto maiuscolo:
  non c'e' piu' gerarchia, c'e' solo volume - ed e' l'altra meta' dell'aria da schermata generata,
  insieme al neon e alle etichette larghe. Il titolo di carta scende a 600, cosi' i due livelli si
  distinguono per peso oltre che per corpo.
*/
.card h1.page-title,
.card h2 { font-size: 23px; font-weight: 700; letter-spacing: -.4px; }
.card h3 { font-size: 17px; font-weight: 600; letter-spacing: -.2px; }
/* La testata di una pagina fuori da ogni carta: il titolo grande e una riga sotto. Nasce con «Gare,
   eventi e obiettivi» (25/09, la pagina C del mock), dove la testata era una carta con un paragrafo
   di istruzioni. `.page-top` e non `.page-head`: quella e' gia' la testata del check-up, con regole
   sue. */
.page-top { margin: 6px 0 18px; }
.page-top .page-title { margin: 0; font-size: 31px; line-height: 1.08; font-weight: 700; letter-spacing: -.2px; }
.page-top .muted { margin: 6px 0 0; }
/* L'occhiello sopra al titolo, dove la pagina ne ha uno: «Scheda palestra», «Nuova scheda» (taglio
   4a). Una regola sola per la testata: `.eyebrow` da sola non disegnava niente - ha regole solo
   dentro ai contenitori del check-up - e un paragrafo nudo prendeva il carattere del corpo. In
   grigio, come la data sopra il saluto della home. */
.page-top .eyebrow {
  margin: 0 0 6px;
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut2);
}
/* La testata con i segni nell'angolo (taglio 7, mock 02, 22, 23, 24): il «?» che apre la spiegazione, il
   `+` di una cosa nuova. Stanno in alto a destra, fuori dal flusso, e il titolo e la riga lasciano loro
   il posto; quello che il «?» apre scorre sotto la riga, a tutta larghezza. Ogni segno prende 44 punti.
   Due segni insieme solo sulle note (il «?» e il `+`): il «?» si sposta a sinistra del `+`, e il titolo
   lascia il posto a tutti e due; lo dice la classe `has-two-signs`. */
.page-top.has-sign { position: relative; }
.page-top.has-sign > .eyebrow,
.page-top.has-sign > .page-title,
.page-top.has-sign > .muted { padding-right: 50px; }
.page-top .page-top-explain > summary {
  position: absolute;
  top: -6px;
  right: -8px;
  width: 44px;
  height: 44px;
  min-height: 44px;
  margin: 0;
  justify-content: center;
}
.page-top .page-top-explain > p { margin: 12px 0 0; color: var(--mut); font-size: 14px; line-height: 1.5; }
.page-top .page-top-explain[open] { margin-top: 10px; }
.page-top.has-two-signs > .eyebrow,
.page-top.has-two-signs > .page-title,
.page-top.has-two-signs > .muted { padding-right: 94px; }
.page-top.has-two-signs .page-top-explain > summary { right: 36px; }
.page-top-signs {
  position: absolute;
  top: -6px;
  right: -8px;
  display: flex;
}
.page-top-sign {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  color: var(--accent-text);
}
.page-top-sign:hover { color: var(--accent-text); opacity: .8; }
.page-top-sign:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 0; border-radius: 12px; }

/*
  ---------- figures line up ----------

  Every place the application prints a number. In a proportional face a 1 is narrower than an 8, so
  "12,4 km" and "8,1 km" start at different places and a column of distances down a list wobbles;
  worse, a counter that ticks 9 -> 10 shifts the text beside it sideways. tabular-nums makes every
  digit the same width, which is what the numerals in a table were designed for.

  One rule listing them rather than a declaration in each: this is a single typographic decision, and
  spread across fourteen rules it is fourteen places for the next figure to be forgotten.

  Only figures. Body text keeps proportional numerals, where they read better inside a sentence.
*/
.gauge-score,
.record-sub,
.record-time,
.macro-amount,
.metric-value,
.nutrition-history-kcal,
.nutrition-kcal-value,
.nutrition-kcal-target,
.plan-entry-count,
.planned-figure,
.session-when-value,
.tile-value,
.volume-value,
.zone-pct { font-variant-numeric: tabular-nums; }

/* Uppercase condensed micro-labels: the mockup's signature detail. */
.microlbl, .metric-label, .tile-label, .bubble-who, label {
  display: block;
  font-family: var(--cond);
  font-weight: 600;
  /* 1,2 px di spaziatura e non 2,4. Maiuscolo largo su ogni etichetta della pagina - CONDIZIONE
     FISICA, CARICO DI ALLENAMENTO, HYBRX DICE - e' il secondo tell piu' forte di una schermata che
     sembra generata, dopo il neon: le parole si leggono come un'insegna invece che come un'etichetta.
     Il maiuscolo resta, perche' su una micro-etichetta e' un mestiere vero; e' la larghezza che era
     da rivista di fantascienza. */
  font-size: 11.5px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut);
}
/* A label belongs above the field it names, never beside it. `display: block` is what
   makes that true even inside a flex row, where an inline label would otherwise sit on
   the same line as its input and squeeze it. The one exception is a checkbox, whose
   label reads as a sentence next to the box - handled in .checkbox-row below. */
label { display: block; margin: 16px 0 8px; }

/* ---------- forms ---------- */
/* Ogni campo in cui si scrive qualcosa, per tipo. La lista e' esplicita e va tenuta completa: un
   tipo che non compare qui non eredita niente e il browser lo disegna a modo suo - che e' come il
   campo "ora" della pianificazione e' finito a essere un rettangolo grigio squadrato in mezzo a
   pillole arrotondate. FormFieldStyleTest confronta questa lista con i tipi usati nei template. */
/* datetime-local era l'unico campo fuori da questo elenco, quindi l'unico disegnato dal sistema:
   "input data non e' coerente con lo stile". Su Android usciva grigio con la freccina nativa in
   mezzo a campi con il bordo, il fondo e il raggio di questa interfaccia. */
input[type="text"], input[type="email"], input[type="password"],
input[type="date"], input[type="time"], input[type="datetime-local"],
input[type="number"], textarea, select {
  width: 100%;
  border: 1px solid var(--line);
  background: var(--field);
  color: var(--ink);
  border-radius: 999px;
  padding: 13px 18px;
  /*
    SEDICI E NON QUINDICI, ed e' la meta' vera del "non si deve poter zoomare".

    Safari su iPhone ingrandisce la pagina da solo quando si mette a fuoco un campo con il testo
    sotto i 16px, e non c'e' meta viewport che glielo impedisca: user-scalable=no lo ignora da iOS 10.
    Un pixel di differenza, e bastava toccare la barra della chat perche' la home restasse ingrandita
    con l'anello e mezza barra rapida fuori dallo schermo.

    Un pixel piu' grandi si leggono anche meglio, quindi non e' un prezzo: e' il minimo che il campo
    doveva gia' avere, come il pavimento dei 12px che vale per tutto il resto.
  */
  font-size: 16px;
  appearance: none;
}
textarea { border-radius: var(--r-sm); }
input:focus, textarea:focus, select:focus { border-color: var(--accent-line); }

input[type="file"] {
  width: 100%;
  border: 1px dashed var(--line);
  background: var(--surface-2);
  color: var(--ink);
  border-radius: var(--r-sm);
  padding: 14px 16px;
  font-size: 14px;
}

.checkbox-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  /* 44px, the tap target the rest of the application uses. The row is usually taller than that
     already - the health-data consent runs to two lines - but a one-line row must not be smaller. */
  min-height: 44px;
  margin: 14px 0;
  padding: 4px 0;
  font-size: 14px;
  color: var(--ink-2);
}
/*
  20px, not the browser's 13.

  Reported from the registration screen: the biometric-consent box "is too small, make it match the
  other one". Measured, both boxes were the same 13x13 - the browser's default, which the rest of the
  interface had grown past. What differed was the text beside them: one line against two, so the same
  small square looked smaller next to the taller block, and it was the more important of the two
  consents. Both are 20px now, which is also a target a thumb can hit.

  flex: 0 0 auto, or the box is squeezed by the label as it wraps - which is what made it look
  narrower than square on a phone in the first place.
*/
.checkbox-row input[type="checkbox"] {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin: 0;
  accent-color: var(--accent-text);
}
.checkbox-row label {
  margin: 0;
  font-family: var(--sans);
  font-size: 14px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-2);
}


/* ---------- buttons ---------- */
/*
  ---------- i bottoni, di una misura piu' sobria ----------

  "Riduci dimensioni di tutti i bottoni, rendiamo l'app un po' piu' raffinata." Erano alti 52 px
  reali - 16 di imbottitura sopra e sotto su una riga da 20 - con 2,2 px di spaziatura fra le
  lettere: una pagina con tre bottoni pieni si leggeva come tre insegne. Adesso 12 e 18, testo a 15 e
  spaziatura a 1,8.

  I 44 px di min-height restano intoccabili e non sono estetica: e' la misura minima di un bersaglio
  che un pollice prende al primo colpo, e sotto quella si comincia a sbagliare pressione. Quindi il
  bottone si e' stretto fino a quel pavimento e li' si ferma - da 52 a 44, otto pixel in meno su
  ogni bottone dell'applicazione, senza toccare la cosa che li rende usabili.

  Il margine sopra scende da 18 a 14 per la stessa ragione: un comando piu' piccolo circondato dalla
  stessa aria di prima sembra piu' perso, non piu' raffinato.
*/
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  width: 100%;
  min-height: 44px;
  border: none;
  border-radius: 999px;
  padding: 11px 18px;
  margin-top: 14px;
  font-family: var(--sans);
  font-weight: 650;
  font-size: 15px;
  letter-spacing: 0;
  text-transform: none;
  text-decoration: none;
  /*
    NO GLOW HERE. Every button used to be lit, on the reasoning that an outlined button should read
    as lit and one tight layer is not a light show. Measured on a real dashboard it is: eight or
    nine controls down the page, each with a halo, and the one button that actually starts something
    is indistinguishable from the seven that expand a fold.

    The glow is what says "this is the thing to press", so it belongs to .btn-primary and nowhere
    else. A box-shadow still lights the shape rather than the letters when it is used - glow belongs
    to graphics, never to type - and that rule has not changed.
  */
}
.btn:hover { text-decoration: none; }
/* Nessun "cedimento" alla pressione: il bottone resta fermo. */
.btn:active { transform: none; }

/* The filled button is the loudest thing on its card, so it keeps the wide wash. */
.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--glow-accent-strong);
}
.btn-secondary {
  background: var(--field);
  color: var(--ink);
  border: 1px solid var(--line);
}
.btn-secondary:hover { border-color: var(--accent-line); color: var(--accent-text); }
/* Its own colour, not the accent's: a delete button that glows in the brand colour is inviting. */
.btn-danger {
  background: rgba(255, 92, 92, .1);
  border: 1px solid rgba(255, 92, 92, .5);
  color: var(--danger-ink);
  box-shadow: 0 0 12px rgba(255, 92, 92, .18);
}

/* Compact, inline variant: sits next to a set's inputs or under one exercise's
   note, not stretched full width like a page-level action. */
/* Small in width, never in height: 44px is what a thumb needs whatever the label says. */
.btn-small {
  width: auto;
  min-height: 44px;
  padding: 8px 16px;
  margin-top: 0;
  font-size: 13px;
  letter-spacing: 1.4px;
}

/* ---------- messages ---------- */
/*
  Margin on both sides, not just the bottom. An alert usually follows a paragraph
  of explanation, and with a bottom margin only it sat right up against that text
  - two blocks of prose with a border drawn between them, reading as one.
*/
.alert {
  border-radius: var(--r-sm);
  padding: 12px 16px;
  margin: 18px 0 16px;
  font-size: 14.5px;
  line-height: 1.55;
}
/* At the very top of a card the heading already provides the separation. */
.card > .alert:first-child, .app-shell > .alert:first-child { margin-top: 0; }

.alert-error {
  background: rgba(255, 92, 92, .12);
  border: 1px solid rgba(255, 92, 92, .4);
  color: var(--danger-ink);
}
.alert-success {
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  color: var(--accent-ink);
}
/*
  ---------- una buona notizia che resta ----------

  .alert-success e' un avviso a comparsa: fisso in cima e sfuma dopo quattro secondi. E' la forma
  giusta per "salvato", che e' la conferma di un gesto appena fatto e non ha altro da dire.

  Non e' la forma giusta per una notizia da leggere. "Account creato, lo attiviamo a mano e ti
  contattiamo" e' un'informazione che si legge una volta e serve tutta: sfumata via mentre gli occhi
  sono ancora sul modulo, e' un messaggio che non e' mai stato dato. Segnalato cosi': "il messaggio
  dopo la registrazione non deve essere un toast ma deve rimanere in pagina in alto del form".

  Stessi colori, nessuna posizione e nessuna animazione: resta dove sta nel documento, cioe' in cima
  alla carta sopra al modulo, e resta finche' la pagina resta.
*/
.alert-notice {
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  color: var(--accent-ink);
}
/* Always under the field, never beside it. The margin does that in a normal block form.
   A message written by the script leaves any row of side-by-side controls before it is
   inserted (app.js, show()); flex-basis is the fallback for a message already inside a
   WRAPPING row - .plan-inline, .plan-add, or one the server rendered there. In a row that
   does not wrap it would squeeze the inputs to nothing, which is how the h/m/s boxes of a
   record were reported. width: 100% keeps long messages from stretching the row. */
.field-error {
  color: var(--danger);
  font-size: 13px;
  margin-top: 6px;
  flex: 0 0 100%;
  width: 100%;
}
.muted { color: var(--mut); font-size: 14px; }

/*
  ---------- "disponibile nell'app" ----------

  Il riquadro che una sezione nativa mostra a un browser. Un pannello e non un avviso rosso: non e'
  un errore, e' un posto diverso in cui sta la stessa cosa. Sta dentro la carta che lo ospita,
  quindi niente ombra ne' bordo proprio - solo un fondo appena piu' chiaro e il filo di separazione
  che usano le altre sezioni interne.

  L'icona e' block: una <svg> in linea si appoggia alla base e la riga tiene lo spazio dei
  discendenti che non ci sono, quindi dentro un flex centrato verrebbe alta due pixel e mezzo.
*/
.native-only {
  margin: 16px 0;
  padding: 14px 16px;
  border-radius: var(--r);
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--mut) 8%, transparent);
}
.native-only-badge {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 8px;
  font-weight: 700;
  color: var(--accent-2);
}
.native-only-badge .ico { display: block; flex: 0 0 auto; }
.native-only .muted:last-child { margin-bottom: 0; }
/* Provider credit and the link back to it, side by side and quiet: required by the
   Strava API Agreement, but it is their credit, not our headline. */
.attribution {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  margin-top: 14px;
  font-size: 13px;
}
.attribution .muted { font-size: 13px; }
/* Il tempo effettivo, nella sua carta sotto ai numeri dell'attivita': il titolo, a cosa serve, le
   tre caselle, cosa cambia, il salva. Le caselle si staccano dalla frase sopra, e il salva - che
   da checkin.css arriva senza margine, perche' nel foglio sta nella barra in fondo - dalla riga
   sotto. */
.effective-time .record-hms { margin-top: 14px; }
.effective-time .checkin-submit { margin-top: 14px; }

/* ---------- Strava card ----------
   Grouped rather than a single column of paragraphs: facts, then actions, then
   the credit on its own rule at the foot. The old stack gave "Sync now" and
   "Disconnect" the same visual weight, one above the other, which is a poor way
   to present one everyday action and one that deletes an athlete's history. */
.strava-card .strava-body { margin-top: 14px; }
.strava-card .strava-line { margin-top: 6px; }
.strava-card .strava-line:first-child { margin-top: 0; }

/*
  Due comandi che devono stare in pari.

  Erano un flex con `margin-left: auto` sul secondo: su un telefono i due bottoni non ci stavano
  in riga, andavano a capo, e l'auto-margine spingeva "Disconnetti" all'estremo destro della riga
  sotto - uno a sinistra in alto, l'altro a destra in basso, disallineati in entrambe le direzioni.
  Segnalato con lo screenshot.

  Adesso i due moduli si dividono la riga in parti uguali: `flex: 1 1 160px` li tiene affiancati e
  della stessa larghezza dove c'e' spazio, e quando non ce n'e' vanno a capo occupando l'intera
  riga ciascuno - quindi allineati sia in orizzontale sia in verticale, in tutti e due i casi.
  La gerarchia resta dove deve stare, nel riempimento del bottone: pieno per la sincronia di ogni
  giorno, silenzioso per la disconnessione che cancella lo storico.
*/
.strava-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 10px;
  margin-top: 16px;
}
.strava-actions form { flex: 1 1 160px; display: flex; }
/* Il margine superiore del bottone e' pensato per una colonna di comandi; qui la riga ha gia' il
   suo, e lasciarlo disallineerebbe i due moduli fra loro. */
.strava-actions .btn { margin-top: 0; }

/* The quiet variant: legible, reachable, and not competing for the press. It
   turns red only on hover, when the intention is already there. */
.btn-quiet {
  background: none;
  border: 1px solid var(--line);
  color: var(--mut);
}
.btn-quiet:hover { border-color: var(--danger); color: var(--danger); }

/*
  ---------- the guided setup ----------

  Up to eight questions after the first login, one to a screen. Everything here is in service of one
  idea: the athlete should be able to see, without reading, how much is left and that they may stop.

  The bars are the progress - one per question this athlete is asked, filled when the account holds an
  answer and solid when it is the screen in front of you. The name of each is in the markup as hidden
  text, because a row of coloured bars tells somebody using a screen reader nothing at all, and the
  name of the current one is printed on the line below.

  Two ways out, styled apart on purpose: "I'll add this later" sits inside the card, under the question
  it skips, and "leave the setup" sits below the card. Neither uses the destructive quiet button of the
  rest of the application - that one turns red on hover, and skipping a question is not a dangerous act.
*/
.onboarding { max-width: 560px; margin: 0 auto; }
.onboarding-mark { display: flex; justify-content: center; margin: 6px 0 18px; }
.onboarding-mark .logo-mark { height: 24px; }

.onboarding-progress {
  display: flex;
  gap: 6px;
  list-style: none;
  padding: 0;
  margin: 0 0 14px;
}
/* A bar and nothing else. The names sit on the line below now: there are up to eight questions, and
   eight words across a phone came out at five characters each. The name is still in the markup for a
   screen reader, hidden with .sr-only. */
.onboarding-progress li {
  flex: 1;
  height: 3px;
  border-radius: 2px;
  background: var(--line);
}
/* Answered: filled, but softly. Current: the full accent, so the screen you are on reads loudest even
   when it is not the one furthest along. */
.onboarding-progress li.is-done { background: color-mix(in srgb, var(--accent) 45%, transparent); }
.onboarding-progress li.is-current { background: var(--accent); }

/* "Step 3 of 7 — Measurements". The count is of the questions this athlete is actually asked. */
.onboarding-where {
  display: flex;
  gap: 8px;
  align-items: baseline;
  margin: 0 0 14px;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut2);
}
.onboarding-where-what { color: var(--ink); font-weight: 700; }

.onboarding-card { padding-bottom: 22px; }
.onboarding-card .step-body > p:first-child { margin-bottom: 16px; }

/* What each question is for, on the welcome screen; what a skipped one costs, on the closing one. */
.onboarding-list { list-style: none; padding: 0; margin: 18px 0; display: grid; gap: 14px; }
.onboarding-list li { display: grid; gap: 2px; }
.onboarding-list-what {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--accent-text);
}

/* The doors on the sync question. Cards rather than a list of links: they are the only thing
   on that screen, and each one is a decision with a consequence written under it. */
.onboarding-routes { list-style: none; padding: 0; margin: 18px 0 0; display: grid; gap: 10px; }
.onboarding-route {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  min-height: 44px;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--field);
  text-decoration: none;
  color: var(--ink);
}
.onboarding-route:hover { border-color: var(--accent-line); text-decoration: none; }
.onboarding-route .ico { flex: 0 0 auto; margin-top: 2px; color: var(--accent-2); }
.onboarding-route-text { display: grid; gap: 2px; min-width: 0; }
.onboarding-route-name { font-weight: 700; }

/*
  ---------- i comandi sotto la domanda ----------

  Tre cose si possono fare con una domanda della configurazione: rispondere, tornare a quella prima,
  lasciarla per dopo. Tutte e tre riguardano la domanda: dalla procedura non si esce piu' a meta',
  la si attraversa - e le facoltative si saltano con "lo inserisco dopo", che porta avanti.

  IN COLONNA, e non due per riga come erano prima. Meta' e meta' sembrava la divisione ovvia e non
  reggeva le parole: "lo inserisco dopo" e' lungo il doppio di "indietro", e su meta' di uno schermo
  da 390px - 154 pixel - andava a capo a qualunque dimensione leggibile. Da li' in poi ogni tentativo
  era un compromesso fra il testo tagliato e i due bottoni di misura diversa, che e' un altro
  problema: fra due comandi affiancati sembra piu' importante quello piu' largo, e sarebbe stato
  quello con piu' lettere per il solo fatto di averne di piu'.

  In colonna il problema non esiste. Sono larghi uguale, alti uguale, e a distanza uguale l'uno
  dall'altro: la gerarchia la fa il colore - Avanti e' pieno, gli altri due bordati - non la
  dimensione, che e' il modo giusto perche' non dipende da quanto sono lunghe le etichette in una
  lingua.
*/
.onboarding-nav {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 12px;
}

/* La stessa misura per i due comandi sotto la domanda. Una sola regola, perche' due valori scritti
   in due punti diversi diventano due misure diverse alla prima modifica. */
.onboarding-nav .btn {
  width: 100%;
  margin-top: 0;
  min-height: 56px;
  padding: 13px 16px;
  font-size: 14px;
  letter-spacing: 1.4px;
  line-height: 1.25;
  gap: 10px;
  text-align: center;
}
.onboarding-nav form { display: flex; margin-top: 0; }
.onboarding-back-arrow { font-size: 19px; line-height: 1; }

/* Non l'hover distruttivo di .btn-quiet: tornare indietro o rimandare una domanda sono scelte
   ordinarie, non cancellazioni. */
.onboarding-nav .btn-quiet:hover { border-color: var(--accent-line); color: var(--accent-text); }

/* Il comando che chiude la configurazione, sull'ultima schermata. Stessa altezza dei secondari, e
   staccato sopra e sotto: e' l'ultima cosa della card e senza margine sotto ci si appoggiava. */
.onboarding-done-go { margin: 24px 0 8px; }
.onboarding-done-go .btn { margin-top: 0; min-height: 56px; }

/* A line of consequence under an action: what the button is about to do to the rest of the walk. */
.onboarding-aside { margin-top: 14px; font-size: 13px; }

/* The free-text goal box, set apart from the checkbox list it is an alternative to. */
.onboarding-card .goal-text {
  margin: 18px 0 4px;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--field);
}
.onboarding-card .goal-text textarea { margin-bottom: 6px; }

/*
  ---------- the four goal areas, closed ----------

  Eighteen checkboxes in four headed lists was a screen and a half of small print on a phone, and the
  athlete had to read all of it to find the two that were theirs. Closed, the question is four rows.

  Opening is CSS and nothing else: the toggle is a checkbox, and `:checked ~ .goal-group-body` shows what
  follows it. Which is why the input is a sibling of the body rather than inside the label - a selector
  cannot climb back out of one. It works with scripting off, and app.js only adds the tidying-up when an
  area is closed again.

  The toggle is hidden but not display:none - it has to stay focusable and reachable by keyboard, and its
  label is the 44px row, so the whole row is the target.
*/
.goal-group { border-bottom: 1px solid var(--line); }
.goal-group:last-of-type { border-bottom: 0; }
.goal-group-toggle { position: absolute; opacity: 0; width: 1px; height: 1px; }
.goal-group-head {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  margin: 0;
  padding: 4px 2px;
  cursor: pointer;
  font-family: var(--cond);
  font-size: 13px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--mut);
}
/*
  The chevron, and why it is not a tick box.

  It was a tick box, and it read as one: reported from the live setup, an athlete who cycles as well as
  lifts saw the gym area open with a filled box and the other three closed with empty ones, and
  understood that he was only allowed to choose from the gym. He was not - the closed rows have always
  opened - but a control that looks like a checkbox says "selected", not "there is more inside".

  So it is the same rotating chevron as the schedules and the ask boxes: one meaning, one drawing,
  everywhere in the application. Written in text so it needs no asset.
*/
.goal-group-mark {
  flex: 0 0 auto;
  font-size: 18px;
  line-height: 1;
  color: var(--accent-text);
  transition: transform .15s ease;
}
.goal-group-mark::before { content: "\203A"; }
.goal-group-toggle:checked + .goal-group-head { color: var(--ink); }
.goal-group-toggle:checked + .goal-group-head .goal-group-mark { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) {
  .goal-group-mark { transition: none; }
}
/* What is chosen inside, so a closed area never hides an answer. app.js keeps it current. */
.goal-group-count {
  margin-left: auto;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.2px;
  color: var(--accent-text);
  white-space: nowrap;
}
.goal-group-name { flex: 0 1 auto; }
/* The focus ring belongs on the row, since the input itself is not what the eye follows. */
.goal-group-toggle:focus-visible + .goal-group-head {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}
.goal-group-body { display: none; }
.goal-group-toggle:checked ~ .goal-group-body { display: block; padding-bottom: 8px; }
.goal-weight { margin-top: 10px; }
/* What the reading found, named one per line: a wrong tick has to be visible before it is saved. */
.goal-suggested ul { margin: 6px 0 0; padding-left: 18px; }

/* "or, if you already have one" - a rule with a word on it, between the written schedule and the two
   ways of supplying your own. */
.onboarding-or {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 18px 0;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--mut2);
}
.onboarding-or::before, .onboarding-or::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}
.onboarding-gym-ai .muted { margin-top: 8px; font-size: 13px; }

/* The written-schedule card on the builder. Same shape as the camera card below it: one explanation,
   one control, one button. */
/* The two warnings on the scanner, set apart from the explanation above them: they are the two
   mistakes athletes actually made, and a reader who skims the paragraph still has to meet them. */
/*
  The figures of one session, folded.

  Three workouts on the card meant twelve tiles between the athlete and the rest of the page. The
  heading identifies the workout - sport, when, and which device sent it - and everything else is one
  tap away. Same chevron as the schedules, the ask boxes and the goal areas: one drawing for "there is
  more inside", everywhere in the application.
*/
/* .card-fold folds a whole card - the gym schedules use it, and so does the goals page's "what do
   you train". It used to be grouped here with .session-detail, the fold over one session's figures;
   that one is gone, because the last-session card now opens the newest workout outright and puts
   the day before behind a single fold. */
/*
  ---------- un solo "espandi", sempre nello stesso posto ----------

  Segnalato: "in alcune sezioni espandi e' a destra, alcune al centro, metti il bottone sempre a
  destra e meno invasivo, e lo stile deve essere uguale per tutti i bottoni di quel tipo".

  Erano due controlli diversi nati in momenti diversi. Quello delle schede era una riga larga tutta
  la carta con un disco accentato da 26 pixel; quello sotto il commento del coach era un testo in
  accento con una freccina, in linea - e siccome l'eroe della home e' una colonna centrata, li' si
  centrava da solo. Da cui "alcune al centro": non era una scelta, era l'allineamento del genitore
  che passava attraverso.

  Adesso i due selettori condividono una regola sola. A destra per costruzione - margin-left: auto
  sul contenuto, che non dipende da come e' allineato il contenitore - e piu' leggero: via il disco,
  resta la freccina, che e' la meta' discreta delle due. In accento e non in grigio, perche' su
  questa interfaccia l'accento vuol dire "si puo' premere", e la piega che nessuno vedeva era
  esattamente il difetto che il disco era stato messo a curare.

  L'area da toccare resta di 44 pixel: e' data dall'altezza minima, non dalla dimensione del segno.
*/
/* Il segno della piega, uno solo per tutte: una freccina disegnata con due bordi, che gira quando
   la piega si apre. Era un disco bordato da 26 pixel con il fondo in accento, messo quando le
   pieghe non si leggevano come premibili; adesso a dire "si puo' premere" ci pensa l'etichetta in
   accento accanto, e il disco restava solo a pesare. */
/* Grande quanto la sua etichetta: a sei pixel con un bordo da uno e mezzo era una virgola accanto
   a un testo da dodici e mezzo, e non si leggeva come parte dello stesso controllo. */
.session-detail-mark {
  display: inline-block;
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  /* L'accento e non currentColor: su "Importa una scheda" e sulle discipline il testo della piega
     e' bianco perche' e' un titolo, e la freccia ereditandolo usciva grigia - "il simbolo espandi
     deve essere sempre colorato come il colore del tema". Su questa interfaccia l'accento vuol
     dire "si puo' premere", e questa e' la sola cosa premibile della riga. */
  color: var(--accent-text);
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-3px);
  transition: transform .15s ease;
}
.card-fold[open] > summary .session-detail-mark { transform: rotate(-135deg) translateY(3px); }
@media (prefers-reduced-motion: reduce) {
  .session-detail-mark { transition: none; }
}
/* Quante schede ci sono dentro, cosi' la carta chiusa risponde comunque a "qui c'e' qualcosa?".
   Prima dell'etichetta, non spinto a destra: adesso e' la riga intera ad andare a destra, e un
   margin-left: auto qui dentro la riaprirebbe da un lato all'altro della carta. */
.card-fold-count { order: -1; color: var(--mut); }

/* ---------- il segno della piega sta sulla riga del titolo ----------

   La piega avvolge il CORPO della carta e non il titolo - il titolo resta fuori, cosi' una carta
   chiusa dice comunque che cos'e' e il suo "?" continua a spiegarlo. Il comando quindi nasceva
   sulla riga sotto, e con l'etichetta tolta restava una freccia sola in mezzo a una fascia vuota:
   "togli la scritta espandi e allinea il simbolo al titolo".

   Portarla sulla riga del titolo vorrebbe dire metterla dentro all'intestazione, che pero' e' gia'
   una piega sua (il "?"): due <details> annidati con due comandi diversi nello stesso punto. Quindi
   resta dov'e' nel documento - dove un lettore di schermo la trova insieme a cio' che apre - e il
   foglio la porta in alto a destra della carta, che e' dove la riga del titolo finisce.

   L'altezza minima di 44 pixel resta: e' il bersaglio del dito, e da qui in poi e' anche l'unica
   cosa che tiene la freccia lontana dal bordo. */
/* Solo le pieghe NUDE, cioe' quelle il cui summary contiene il solo segno: "Importa una scheda" e
   le discipline sono pieghe anche loro, ma il titolo ce l'hanno dentro, e spostarle in alto a
   destra della carta le staccherebbe dal corpo che aprono - e infatti, provato, finivano a
   cavallo della carta sopra. */
.card:has(> .card-fold-bare) { position: relative; }
.card-fold-bare > summary {
  position: absolute;
  top: 14px;
  right: 16px;
  z-index: 2;
}

/*
  ---------- the last seven days ----------

  Columns, and deliberately the same family as the weekly chart directly below it: the week by day,
  then the month by week, one above the other. Davide asked for exactly that, and it is also the
  cheaper reading - the eye learns one shape and applies it twice.

  Sixty pixels a column is what a phone gives, which is enough for the bar, the weekday, the date and
  one figure a line. Not enough for the sport's name, so the figure takes that discipline's colour -
  the same colour it has in the chart underneath, where the legend names it. A title attribute carries
  the name for a pointer, and the legend carries it for everybody else.

  Heights come from line-N and not bar-N: the bar-N classes set a width as well, so a 50% day would
  come out half as wide as its neighbours. That is what the line-N classes exist for.
*/
.day-bars {
  display: flex;
  align-items: flex-start;
  gap: 4px;
  list-style: none;
  margin: 10px 0 0;
  padding: 0;
}
.day-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 0;
}
/*
  A fixed height, not flex: 1.

  Measured, and it was wrong the first time: with the bar box stretching to fill what the labels left
  over, a day with two workouts under it got a shorter box than a day with one - so the busier day drew
  the shorter bar. Two figures where its neighbour had one, and the chart said the opposite of the
  truth. Every bar box is the same height now and the figures hang below it, however many there are.
*/
.day-bar {
  width: 100%;
  height: 96px;
  display: flex;
  align-items: flex-end;
  border-radius: 8px 8px 0 0;
  background: var(--field);
}
.day-fill {
  width: 100%;
  min-height: 3px;
  border-radius: 8px 8px 0 0;
  background: linear-gradient(180deg, var(--accent),
                              color-mix(in srgb, var(--accent) 35%, transparent));
}
/* A day with nothing on it keeps its column and loses its ground: the gap is the rest day. */
.day-rest .day-bar { background: transparent; border-bottom: 1px dashed var(--line); }

.day-label { display: grid; justify-items: center; margin-top: 8px; line-height: 1.1; }
.day-weekday {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut2);
}
.day-date { font-size: 12px; color: var(--mut2); font-variant-numeric: tabular-nums; }
/* Today is the column the athlete is standing in, and it is not finished yet. */
.day-today .day-weekday { color: var(--accent-text); }

.day-figures { display: grid; justify-items: center; gap: 2px; margin-top: 6px; }
.day-figure {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--ink-2);
}
/* The discipline's own colour, the same one the weekly chart gives it. vol-accent for the athlete
   with a single discipline, whose chart is drawn in their chosen palette colour. */
.day-figure.vol-accent { color: var(--accent-text); }
.day-figure[class*="vol-c"],
.day-figure.vol-walking,
.day-figure.vol-hiking { color: var(--bar); }
.day-rest-word {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut2);
}

.scan-warning {
  margin: 8px 0 0;
  padding-left: 10px;
  border-left: 2px solid var(--accent-line);
  font-size: 13px;
}

/*
  ---------- the three questions ----------

  They sit inside the two forms that ask for a plan, above the controls that were already there, so
  the athlete reads what is being asked before the button that spends the interaction.

  Boxed and set apart from the rest of the form: these are questions rather than settings, and one of
  them is about injuries. Two rows each because an answer is a sentence - "spalla destra operata nel
  2023, niente spinte sopra la testa" does not fit on one line at this width, and a field that hides
  the second half of the answer while it is typed is a field people give up on.
*/
.intake {
  display: grid;
  gap: 6px;
  margin-bottom: 14px;
  padding: 12px;
  border: 1px solid var(--line-soft);
  border-radius: 12px;
  background: var(--field);
}
.intake-lead { margin: 0 0 4px; font-size: 12.5px; line-height: 1.45; }
.intake label {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut2);
}
.intake textarea {
  width: 100%;
  resize: vertical;
  min-height: 56px;
  font: inherit;
  line-height: 1.4;
}
.intake .checkbox-row label { text-transform: none; letter-spacing: 0; font-size: 13px; }


.onboarding-plan-form { margin-top: 18px; }
.onboarding-plan-form .muted { margin-top: 8px; font-size: 13px; text-align: center; }

/* A button that owns its line, for a screen with exactly one thing to do next. */
.btn-block { display: block; width: 100%; text-align: center; }

.strava-hint {
  margin-top: 8px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--mut2);
}

.strava-status.is-ok { color: var(--ok); }
.strava-status.is-ok .dot { background: var(--ok); box-shadow: 0 0 8px var(--ok); }
.strava-status.is-error { color: var(--danger); }
.strava-status.is-error .dot { background: var(--danger); box-shadow: 0 0 8px var(--danger); }

/* The spinner replaces the status dot while a sync runs. A static "SYNC IN
   PROGRESS" on a page that never changes is indistinguishable from a page that
   has frozen; this is the part that says the waiting is expected. One element,
   one keyframe: no image, no script, nothing for the CSP to block. */
.spinner {
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 2px solid var(--accent-line);
  border-top-color: var(--accent-text);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
/* Motion is the whole point here, so it is not simply switched off: the ring
   stays and pulses instead of turning, which still reads as "working". */
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: spinner-pulse 1.6s ease-in-out infinite; }
}
@keyframes spinner-pulse { 50% { opacity: .35; } }

/* The credit, bottom left, on its own rule. Required by Strava's Brand
   Guidelines, and it belongs here rather than among the controls, where it read
   as one more thing to act on. */
.strava-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}
.strava-credit {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--mut2);
}
.strava-account { font-size: 13px; }

/* ---------- la libreria delle schede: una carta di righe (mock 06, taglio 4a del 26/09) ----------

   Una riga per scheda, come le righe della home e dell'agenda (.record-tile, piu' giu'): la presa a
   sinistra, il collegamento con il nome e la riga piccola, «Esegui» in coda. Era una carta per
   scheda - la faccia metallica, una griglia alta 92 con overflow: hidden, il collegamento esteso
   da un velo (::after, inset: 0) e il bottone e la presa sopra con uno z-index - e sotto i 520
   punti si impilava. Tutte quelle regole se ne sono andate con lei: .plan-card-row resta nel markup
   solo come gancio dello script del trascinamento, e nessuna regola le da' piu' una forma.

   IL MARGINE STA SUL COLLEGAMENTO, non sulla tessera (lezione del 26/09: collegamento alto 41 su
   una riga di 67), e a sinistra e' di due punti soli: la presa gli sta accanto, e ogni punto
   tolto al margine e' un punto dato al nome. Misurato a 360 punti: «Forza A — spinta» e «5 ESERCIZI
   · 15 SERIE» ci stanno interi; un nome di ventidue lettere si taglia con i puntini, e si puo'
   perche' toccando si apre la scheda con il nome intero nel titolo (decisioni del 26/09). */
.record-tile.plan-row > .record-open {
  align-self: stretch;
  padding: 12px 8px 12px 2px;
}
/* La presa alta quanto la riga: il dito la trova su tutta l'altezza, non su una fascia da 44 in
   mezzo. Nessun order: e' la prima nel markup, quindi sta a sinistra da se'. */
.plan-row > .plan-grip { align-self: stretch; }
/* «Esegui» in coda, largo quanto la sua parola e alto 44: la parola corta, perche' «Esegui scheda»
   a 360 punti si prendeva il nome. `.btn` lo vuole largo quanto la riga e staccato di 14 sopra:
   qui no. Un antenato nel selettore, perche' .btn e la regola dei bottoni pesano quanto una classe. */
.plan-row > .plan-row-run {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  margin: 0 10px 0 0;
}
.plan-row > .plan-row-run > .plan-row-go {
  flex: 0 0 auto;
  width: auto;
  min-height: 44px;
  margin: 0;
  padding: 0 14px;
  font-size: 14px;
}
/* Su una scheda vuota «Esegui» e' spento, e si deve vedere: nessuna regola disegnava un bottone
   spento, e il pieno nell'accento diceva «premi» proprio dove non succede niente. */
.plan-row > .plan-row-run > .plan-row-go:disabled { opacity: .42; box-shadow: none; cursor: default; }
/* Le due frecce di chi non ha JavaScript: al posto della presa, a sinistra, in colonna - affiancate
   raddoppierebbero la larghezza che tolgono al nome - e 44 per 44 (erano 38). app.js le nasconde
   quando il trascinamento c'e', e allora la presa torna. Sei punti sopra e sotto, o i cerchi
   toccavano i bordi della riga; e allora la riga di mezzo, con due frecce, e' alta 106 invece di 67:
   senza script, e solo su quelle righe (misurato a 360 e 390, verifiche del taglio 4a, 26/09). Il
   collegamento accanto alle frecce ha quattro punti a sinistra e non dieci: a 360 «30 ESERCIZI ·
   49 SERIE» ne chiede 144, e con dieci ne aveva 141. */
.plan-move { display: flex; flex-direction: column; justify-content: center; gap: 4px; }
.plan-row > .plan-move { order: -1; flex: 0 0 auto; margin-left: 4px; padding-block: 6px; }
.plan-row .exercise-move-btn { width: 44px; min-height: 44px; margin: 0; }
.plan-row:has(> .plan-move:not([hidden])) > .plan-grip { display: none; }
.plan-row:has(> .plan-move:not([hidden])) > .record-open { padding-left: 4px; }
/* La riga che segue il dito: sollevata, e trasparente ai puntatori, o elementFromPoint
   restituirebbe lei e ogni rilascio finirebbe dove era gia'. E PIENA: una tessera d'elenco non ha
   fondo, e in aria sopra a un'altra riga si vedevano «due nomi sovrapposti nello stesso rettangolo».
   Che sia in aria lo dicono l'ombra e il bordo in accento; il colore segue la tavolozza. */
.plan-row.is-dragging {
  position: relative;
  z-index: 2;
  pointer-events: none;
  border-color: var(--accent);
  background: var(--surface-2);
  box-shadow: var(--edge-lit), var(--lift-edge), var(--shadow-card);
}
/* Il vicino su cui si sta per lasciarla. */
.plan-row.is-target { border-color: var(--accent); }
/* Il comando per crearne una sta fra la testata e la carta; la frase del vuoto sotto di lui. */
.plan-empty { margin: 14px 0 0; }
/* La riga di «Me la scrive Hybrx», nella sua carta sotto alle schede. */
.plan-ways { padding-block: 14px; }

/* ---------- La domanda mandata dalla home, mentre il coach scrive ----------
   Arriva qui gia' inviata: la bolla con le proprie parole e, sotto, "sta scrivendo". Vive dentro a
   #thread, quindi la risposta che sostituisce il thread se la porta via da sola. */
.chat-pending { opacity: .72; }
.chat-pending-send {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 10px 0 0;
}
.chat-pending-wait { margin: 0; }

/* ---------- workout history ---------- */
/* Un allenamento non finito e' una cosa normale da vedere in un elenco, non un errore: sta nella
   colonna dello stato - dove sulle altre righe c'e' la cifra - e nell'accento invece che in rosso.
   Un allenamento aperto non ha una durata: e' il numero che sta salendo mentre lo si guarda. */
.history-open { color: var(--accent-text); }
.history-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 16px;
  font-size: 13px;
}
.plan-more { margin-top: 14px; font-size: 13px; }

/* Le vie d'ingresso sotto alla dashboard vuota: una per riga, perche' sono alternative e non una
   frase sola - tre collegamenti in fila si leggono come un elenco di navigazione, e qui sono tre
   risposte diverse alla stessa domanda. Le regole del riquadro le disegna .card; qui c'e' solo
   l'impaginazione. */
.dashboard-empty-ways {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  margin-top: 16px;
  font-size: 14px;
}

/* ---------- intestazione della lista esercizi ---------- */
.plan-exercise-list-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 2px;
}
.plan-exercise-list-head h2 {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: .2px;
  text-transform: uppercase;
}
/* Il manubrio prende il suo colore - quello dell'allenamento, non l'accento - e la parola resta
   nell'inchiostro della pagina: un'intestazione tutta colorata e' un'intestazione che grida. */
.plan-exercise-list-head h2 > .ico {
  /* Il secondo colore del marchio, nel suo gemello da leggere: .ico-training da' --accent-2, che
     con volt nel chiaro e' quasi bianco su bianco (visto il 26/09, taglio 4a). */
  --ico-tint: var(--accent-2-text);
  width: 19px;
  height: 19px;
  color: var(--ico-tint, var(--accent));
}
.plan-exercise-count {
  flex: 0 0 auto;
  padding: 7px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--cond);
  font-size: 12.5px;
  color: var(--ink-2);
  white-space: nowrap;
}
.plan-exercise-empty {
  display: grid;
  place-items: center;
  gap: 6px;
  margin-top: 4px;
  padding: 22px 18px;
  border: 1px dashed var(--line);
  border-radius: var(--r-sm);
  color: var(--mut);
  text-align: center;
}
.plan-exercise-empty-icon {
  display: inline-grid;
  place-items: center;
  width: 38px;
  height: 38px;
  margin-bottom: 2px;
  color: var(--mut2);
}
.plan-exercise-empty-icon svg {
  width: 28px;
  height: 28px;
}
.plan-exercise-empty strong {
  color: var(--ink-2);
  font-size: 14px;
  font-weight: 650;
}
.plan-exercise-empty > span:last-child {
  max-width: 30ch;
  font-size: 13px;
  line-height: 1.45;
}

/* ---------- gli esercizi della scheda, chiusi di default ----------
   La lista resta compatta da chiusa; aperta, una riga diventa un piccolo editor leggibile con
   controlli, campi e serie chiaramente separati. Gli input NON cambiano forma: continuano a prendere
   border-radius: 999px dalla regola globale dei form. */
.plan-exercise-list {
  display: grid;
  gap: 10px;
  padding: 18px;
}
.plan-builder-exercise {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  background: var(--field);
  transition: border-color .16s ease, box-shadow .16s ease;
}
.plan-builder-exercise[open] {
  border-color: var(--accent-line);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .04),
    0 8px 24px -18px color-mix(in srgb, var(--accent) 55%, transparent);
}
.plan-exercise-summary {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 76px;
  padding: 11px 14px;
  list-style: none;
  cursor: pointer;
}
.plan-exercise-summary::-webkit-details-marker { display: none; }
.plan-exercise-summary::marker { content: ""; }
.plan-exercise-summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}
.plan-exercise-summary-copy {
  display: grid;
  gap: 3px;
  min-width: 0;
}
/* Una riga e i puntini, e resta cosi': "solo il titolo che sta nella input deve essere esteso, non
   della card". Il nome per intero si legge aprendo l'esercizio, dove il titolo va a capo; qui una
   riga per riga tiene la lista leggibile a colpo d'occhio, che e' il lavoro di questa schermata. */
.plan-exercise-summary-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 15.5px;
  font-weight: 700;
  color: var(--ink);
}
.plan-exercise-summary-meta {
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: .8px;
  color: var(--mut2);
}
/* SOLO LA FRECCIA, senza la parola. Era il comando del box "Volume settimanale" - ESPANDI in
   accento che diventava RIDUCI - e su questa riga era di troppo: il nome dell'esercizio, il numero
   di serie e la maniglia dicono tutti qualcosa dell'esercizio, "ESPANDI" no, e si prendeva ottanta
   pixel al nome, che infatti arrivava troncato. "Togli espandi e lascia solo l'icona".

   La riga dell'esercizio resta il contenitore cliccabile e porta lei l'etichetta; questo span e'
   la sola parte visiva del comando, allineata a destra. */
.plan-exercise-fold-control {
  margin-left: auto;
  /* Un filo dentro il bordo: appoggiata ai quattordici pixel di padding sembrava tagliata via dal
     lato della carta - "e' troppo attaccata al bordo di destra". */
  margin-right: 6px;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--accent-text);
}
.plan-exercise-summary:hover .plan-exercise-fold-control { color: var(--accent); }
.plan-exercise-fold-control .session-detail-mark { color: currentColor; }
.plan-builder-exercise[open] > .plan-exercise-summary {
  border-bottom: 1px solid var(--line-soft);
}
.plan-builder-exercise[open] > .plan-exercise-summary .session-detail-mark {
  transform: rotate(-135deg) translateY(3px);
}

.plan-exercise-body {
  padding: 16px 14px 18px;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--surface-2) 20%, transparent), transparent 35%);
}

/* Quando l'esercizio e' aperto, riordino e X vivono nel corpo, non sopra il comando Riduci.
   In questo modo il disclosure resta identico a Volume settimanale anche su un telefono stretto. */
/* ---------- il titolo dell'esercizio aperto, e la crocetta accanto ----------

   La crocetta stava su una riga tutta sua allineata a destra, e a sinistra le restava mezza carta
   di niente - "a sinistra della x c'e' dello spazio vuoto che non mi piace". Adesso divide la riga
   con il nome, che da etichetta + pastiglia e' diventato un titolo. */
/* L'etichetta e la crocetta sulla stessa riga, il campo sotto a tutta larghezza: "la x deve stare
   parallela all'etichetta non di lato alla input". Cosi' la riga della crocetta dice qualcosa - il
   vuoto che le stava a sinistra era il difetto di partenza - e un nome lungo ha tutta la carta per
   andare a capo invece di lasciarne quarantaquattro pixel al bottone. */
.plan-exercise-title-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 44px;
  margin-bottom: 2px;
}
/* L'etichetta si appoggia al fondo della riga, non al suo centro: la riga e' alta quarantaquattro
   pixel perche' li' dentro c'e' il bersaglio della crocetta, e un'etichetta centrata lascerebbe
   sedici pixel d'aria fra lei e il campo che nomina - il doppio di quanta ne lascia "NOTE". */
.plan-exercise-title-head > .plan-field-label {
  margin: 0;
  align-self: end;
  padding-bottom: 2px;
}
.plan-exercise-title-head form { margin: 0; flex: 0 0 auto; }
/* LA STESSA SCATOLA DELLE SERIE (.set-field): bordo, fondo e raggio identici, e l'accento quando
   ci si scrive dentro. Per un giro sono stati un testo con il bordo che compariva solo al
   passaggio - l'effetto del nome della scheda - ed e' andata male dove conta: su un telefono non
   si passa sopra a niente, quindi il bordo non compariva mai e i due campi sembravano due
   paragrafi da leggere. "Sia il titolo che le note si deve capire che e' un input, devono avere
   lo stesso stile delle input dove metti kg rip recupero".

   Le misure del testo restano diverse - il nome e' un titolo, la nota un paragrafo - perche' la
   richiesta e' che si capisca che sono campi, non che siano lo stesso campo. */
textarea.plan-exercise-title {
  width: 100%;
  min-width: 0;
  /* Una riga intera come pavimento, e non zero. L'altezza la scrive app.js sul testo che c'e', ma
     quando non puo' - il campo non e' ancora stato disegnato, lo script non e' arrivato - deve
     restare un campo alto una riga. Con zero era una fessura con dentro la meta' di una lettera:
     "input nome esercizio e' troppo piccola". */
  min-height: calc(1.4em + 20px);
  margin: 0;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--ink);
  font-family: inherit;
  /* La stessa misura della nota qui sotto: sono due campi dello stesso modulo, e il nome scritto
     piu' grande li faceva leggere come un titolo e una didascalia. "Il font del nome esercizio
     deve essere uguale". */
  font-size: 16px;
  font-weight: 500;
  line-height: 1.4;
  /* Va a capo e non scorre: l'altezza la mette app.js sul testo che c'e'. La maniglia di
     ridimensionamento non serve - il nome e' lungo quello che e'. */
  resize: none;
  overflow: hidden;
}
textarea.plan-exercise-title:focus {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  outline: none;
}

/* La crocetta dell'esercizio. Una regola sola e non due: da quando la maniglia e' quella della
   libreria questa classe e' rimasta da sola nel selettore, e le sue misure e il suo glifo stavano
   in due blocchi separati - due regole a classe secca con lo stesso nome sono esattamente cio' che
   StylesheetClashTest vieta, perche' la seconda vince in silenzio e chi legge la prima non lo sa. */
.plan-exercise-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  min-width: 44px;
  padding: 0;
  border-radius: 50%;
  background: var(--field);
  box-shadow: var(--edge-lit), 0 6px 14px -8px rgba(0, 0, 0, .55);
  font-size: 27px;
  font-weight: 400;
  line-height: 1;
}
/* La maniglia dell'esercizio e' quella della libreria, .plan-grip: "usa il simbolo presente di
   fianco a esegui scheda per spostare gli elementi". Il disegno, il cursore e i punti stanno tutti
   li'; qui cambia solo dove cade.

   A sinistra, prima del nome: "metti a sinistra l'icona per spostare le schede". Nel markup viene
   dopo il nome, per essere l'ultima cosa che un lettore di schermo incontra, quindi serve un order
   negativo. Il margine negativo la riallinea al bordo della carta: .plan-grip ha i suoi pixel di
   bersaglio, che senza questo spingerebbero il nome dentro di sei. */
.plan-exercise-summary > .plan-grip { order: -1; margin-left: -6px; }
/* In aria: sollevata, semitrasparente e invisibile al puntatore, cosi' elementFromPoint vede la
   riga SOTTO di lei e non lei stessa. Le stesse tre proprieta' della scheda trascinata nella
   libreria - e' lo stesso gesto, e prima era l'unica delle due che non si muoveva affatto. */
.plan-builder-exercise.is-dragging {
  position: relative;
  z-index: 2;
  pointer-events: none;
  border-color: var(--accent);
  box-shadow: var(--edge-lit), var(--lift-edge), var(--shadow-card);
  /* UNO SFONDO PIENO, e non e' un dettaglio estetico: a riposo la riga e' var(--field), cioe' tre
     centesimi di bianco - si vede attraverso, e va benissimo finche' sotto c'e' la carta. In aria
     sotto c'e' un'altra riga, e le due scritte si sovrapponevano al punto da non leggersi piu'. */
  background: var(--surface-2);
}
/* Il vicino su cui si sta per lasciarla. */
.plan-builder-exercise.is-target { border-color: var(--accent); }

/* Nome sopra, nota sotto, come nel modulo che ha scritto l'esercizio: una colonna sola. Erano due
   affiancate, e mezza carta per una nota di trecento caratteri e' una riga da centottanta pixel -
   cioe' tre parole e i puntini. La nota qui e' come si esegue l'esercizio, non un'etichetta. */
.plan-edit-form {
  display: grid;
  gap: 12px;
  margin: 0;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line-soft);
}
/* La nota: la stessa scatola del titolo qui sopra e delle serie. Ha fatto il giro completo - era
   una pastiglia, e' diventata un testo con il bordo al passaggio ("le note sembrano troppo input"),
   e con il bordo al passaggio su un telefono non si vedeva mai che era un campo. L'etichetta
   piccola sopra resta comunque: "metti note in piccolo sopra le note". */
.plan-edit-field-notes > textarea {
  min-height: 76px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--ink);
  /* Sedici e non quattordici: sotto i 16px iOS Safari ingrandisce la pagina appena il campo viene
     toccato, e il meta viewport non lo ferma. FixedZoomTest lo ha fermato qui. */
  font-size: 16px;
  line-height: 1.5;
  resize: vertical;
}
.plan-edit-field-notes > textarea:focus {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  outline: none;
}
.plan-edit-field-notes > .plan-field-label { padding-left: 4px; }
.plan-edit-field {
  display: grid;
  min-width: 0;
  gap: 6px;
  margin: 0;
}
/* Il maiuscolo sta scritto qui e non solo nella regola globale delle <label>: queste etichette
   sono <span>, e finora erano maiuscole soltanto perche' stavano DENTRO a una <label>, che lo
   eredita. La prima messa fuori da una - quella dell'esercizio, che divide la riga con la crocetta
   e quindi non puo' avvolgere il campo - e' uscita in minuscolo accanto a "NOTE". */
.plan-field-label {
  padding-left: 4px;
  font-family: var(--cond);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .55px;
  text-transform: uppercase;
  color: var(--mut2);
}
.plan-edit-field input {
  width: 100%;
  min-width: 0;
  margin: 0;
}

/* Una serie e' un blocco: titolo/rimozione sopra, i tre valori sotto. */
.plan-sets {
  list-style: none;
  margin: 0;
  padding: 0;
}
.plan-set {
  display: block;
  padding: 16px 0;
  border-bottom: 1px solid var(--line-soft);
}
.plan-set:last-child { border-bottom: none; }
.plan-set-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}
.plan-set-title {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-size: 14px;
  font-weight: 650;
  color: var(--ink-2);
}
.plan-set-index {
  min-width: auto;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
}
.plan-set-word {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: .5px;
  text-transform: lowercase;
  color: var(--mut2);
}
/* La stessa fila della seduta: tre scatole uguali (.set-field porta flex: 1 1 0 e min-width: 0),
   non tre colonne di larghezza diversa. Era una griglia di pastiglie con l'etichetta sopra. */
.plan-set-edit {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 8px;
  min-width: 0;
  margin: 0;
}
.plan-set-remove { flex: 0 0 auto; margin: 0; }
/* La carta appena creata si accende per un secondo, dove lo scorrimento l'ha portata: "per
   enfatizzare dove sta". Bordo e fondo, niente alone: l'alone largo appartiene a cio' che e'
   riempito nel colore dell'accento - un bottone - e non a un contorno che si accende, che e' la
   regola tenuta ferma da DashboardShapeTest. E niente che sposti il disegno: una riga che cresce
   farebbe saltare la lista proprio mentre la si sta guardando. */
.plan-builder-exercise.is-arrived,
.session-exercise.is-arrived {
  border-color: var(--accent);
  animation: plan-arrived 1.4s ease-out;
}
@keyframes plan-arrived {
  0% {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 16%, transparent);
  }
  100% { border-color: var(--line-soft); background: transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .plan-builder-exercise.is-arrived,
  .session-exercise.is-arrived { animation: none; }
}

/* Empty state della seconda proposta: "SERIE", segno grafico centrale e una sola CTA leggibile.
   Il simbolo e' CSS, quindi niente nuova icona o asset da mantenere. */
.plan-series-empty {
  display: grid;
  justify-items: center;
  gap: 10px;
  margin-top: 16px;
  padding: 14px 14px 8px;
  border: 1px solid var(--line-soft);
  border-bottom: 0;
  border-radius: var(--r-sm) var(--r-sm) 0 0;
  background: color-mix(in srgb, var(--surface-2) 32%, transparent);
  text-align: center;
}
.plan-series-empty[hidden] { display: none; }
.plan-series-empty-title {
  justify-self: start;
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  color: var(--mut2);
}
.plan-series-empty-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-top: 2px;
  color: var(--mut2);
}
.plan-series-empty-icon .ico {
  width: 38px;
  height: 38px;
}
.plan-series-empty p {
  max-width: 290px;
  margin: 0 0 4px;
  color: var(--mut2);
  font-size: 13.5px;
  line-height: 1.45;
}

.plan-set-more {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 58px;
  margin: 12px 0 0;
  padding: 6px 10px 6px 6px;
  border: 1px dashed var(--line);
  border-radius: var(--r-sm);
}
.plan-set-more-empty {
  margin-top: 0;
  padding: 10px 16px;
  justify-content: center;
  border-style: solid;
  border-top-color: color-mix(in srgb, var(--line) 70%, transparent);
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--glow-accent-strong);
}
.plan-set-more-empty .plan-set-plus {
  width: 32px;
  height: 32px;
  flex-basis: 32px;
  background: transparent;
  color: inherit;
  box-shadow: none;
  font-size: 25px;
}
.plan-set-more-label {
  font-size: 13.5px;
  color: var(--mut2);
}
.plan-set-more-empty .plan-set-more-label {
  color: inherit;
  font-weight: 650;
}
/* Il bersaglio resta quarantaquattro, il bollo pieno no: "icone + X e penna sempre senza sfondo di
   nessun tipo". E' la stessa regola delle X, che qui dentro sono solo un glifo da un pezzo. */
.plan-set-plus {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex: 0 0 44px;
  padding: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
  color: var(--accent-text);
  font: inherit;
  line-height: 1;
  cursor: pointer;
}
.plan-set-plus:active { background: transparent; box-shadow: none; }
.plan-set-plus:hover { filter: brightness(1.06); }
.plan-set-plus:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

@media (max-width: 380px) {
  .plan-exercise-remove { width: 42px; height: 42px; min-width: 42px; }
  .plan-set-edit { gap: 6px; }
  .plan-field-label { font-size: 11px; }
}

/* ---------- "Crea una nuova scheda" ----------
   Era un "+" in pastello di fianco al titolo, alto quanto una riga di testo: la cosa piu' piccola
   sulla pagina era l'unica che ci si viene a fare la prima volta. "Rendi piu' evidente il comando
   per creare una nuova scheda e ingrandiscilo" - quindi pieno, largo quanto la pagina e sotto il
   titolo invece che accanto, cioe' l'ultima cosa che si legge prima della lista.

   .plan-new e' il disegno, alto quanto il suo margine e la sua riga (51); i 54 sono del solo
   comando della libreria (.plan-new-link, qui sotto), dove la richiesta li chiedeva. Li dava un
   gettone dichiarato sulla carta della libreria, che il 26/09 se n'e' andata: per un giro il
   comando e' sceso a 51, cioe' si e' rimpicciolito proprio dove andava ingrandito (verifiche del
   taglio 4a). */
.plan-new {
  display: flex;
  width: 100%;
  box-sizing: border-box;
  align-items: center;
  justify-content: center;
  gap: 11px;
  padding: 13px 18px;
  border: 0;
  border-radius: var(--r-sm);
  background: var(--accent);
  color: var(--on-accent);
  font: inherit;
  /* La stessa misura di .btn, che e' quello che gli sta accanto ovunque compaia: nel foglio della
     scheda sotto gli esercizi, e nell'allenamento. Era 15.5/600, cioe' mezzo
     pixel piu' grande e un filo piu' leggero - abbastanza da farlo leggere come un'altra famiglia
     senza che si capisca perche'. */
  font-size: 15px;
  font-weight: 650;
  line-height: 1.2;
  cursor: pointer;
}
.plan-new:hover { filter: brightness(1.06); }
/* Il comando della libreria e' un collegamento: niente sottolineatura, e i 54 punti chiesti. */
.plan-new-link { min-height: 54px; text-decoration: none; }
.plan-new-link:hover { text-decoration: none; }
/* Il cerchio non e' piu' l'accento su fondo trasparente ma un buco nell'accento: sopra il pieno
   un secondo pieno dello stesso colore sarebbe invisibile. */
/* Il segno e basta, senza niente dietro: "icone + X e penna sempre senza sfondo di nessun tipo". */
.plan-new-plus {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 25px;
  height: 25px;
  color: inherit;
  line-height: 1;
}

/* ---------- Una scheda che non esiste ancora ----------
   «Esegui» sparisce finche' non c'e' un esercizio; restano la riga che dice cosa fare, «Elimina»
   sotto di lei, e «Modifica scheda» in fondo alla carta, da cui si aggiunge il primo. */
.plan-unborn { margin-top: 16px; }

/* Full width, so it takes the whole first line and the input follows underneath
   rather than sharing the row with it. */

/* ---------- Schedule scan ----------
   Reads photos of an existing schedule - see ScheduleVisionService. The drop area
   is a <label> wrapping a hidden file input, so tapping anywhere on it opens the
   file picker without any script. */
.magic-fill-form { margin-top: 4px; }
.magic-fill-drop {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 22px 16px;
  border: 1px dashed var(--line);
  border-radius: var(--r-sm);
  color: var(--mut);
  font-size: 14px;
  text-align: center;
  cursor: pointer;
}
.magic-fill-drop:hover { border-color: var(--accent-line); color: var(--accent-text); }
.magic-fill-drop input[type="file"] {
  /* Not display:none: a hidden input is not focusable, which would drop keyboard
     access to the picker entirely. Visually hidden, still reachable by tab. */
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}
.magic-fill-status {
  margin: 10px 0 0;
  font-size: 13px;
  color: var(--accent-text);
}
/* The names of the files actually chosen: "3 files" in the native control is no help
   when a model call is about to be spent on the wrong three. */
.magic-fill-chosen {
  margin: 10px 0 0;
  font-size: 13px;
  color: var(--ink);
  word-break: break-word;
}
.magic-fill-hint { margin: 6px 0 12px; font-size: 12.5px; }

/* ---------- Tracker (workout sessions) ----------
   Reuses the builder's .plan-set row: same tick, same index, same rest. What is
   new is a second column for what was actually done, and the deviation state. */
/* ---------- rimosso: la serie su due righe ----------

   Il riepilogo di una seduta finita disegnava ogni serie su due righe - la testa con numero, piano
   e spunta, e sotto quello che era stato fatto - ed era il disegno che questa schermata aveva
   prima. Adesso e' la stessa tabella della schermata viva, in lettura: "rendi coerente lo storico
   con la nuova visione che si ha quando si clicca esegui scheda". Le due si guardano una dopo
   l'altra, e due disposizioni diverse per la stessa cosa si notano. */

/*
  ---------- la tabella delle serie: quante ne devi fare, quante ne hai fatte ----------

  "E' importante sapere quante ripetizioni sono da fare e quante ne ho fatte realmente."

  Erano due righe sopra alle scatole - "PIANO 8" e "FATTO" - e la seconda era la didascalia delle
  scatole, non uno stato, mentre accanto c'era una spunta che lo stato lo dichiarava davvero. Ogni
  scatola adesso porta tutti e due i numeri: sopra, piccolo, quello che la scheda chiede; sotto,
  grande, quello che e' stato fatto.

  I nomi delle colonne stanno in testa UNA VOLTA, invece che sotto ognuna delle dodici scatole di
  un esercizio da quattro serie. minmax(0, 1fr) e non 1fr: il minimo implicito di 1fr e'
  min-content, e un carico a tre cifre terrebbe la colonna larga quanto lui su tutte le righe.

  LE TRE COLONNE CI SONO SEMPRE. La colonna dei chili compariva solo dove un carico c'era gia', e
  su una scheda scritta senza chili non ce n'era nessuno: in palestra non c'era modo di scriverli -
  "se creo una scheda senza inserire kg, quando la seguo non posso inserire i carichi". Una colonna
  che si nasconde da sola toglie un campo proprio a chi lo deve riempire.
*/
.session-grid {
  display: grid;
  gap: 8px;
  align-items: center;
  margin-top: 12px;
}
.session-grid-kg { grid-template-columns: 22px repeat(3, minmax(0, 1fr)) 44px; }
.session-grid-h {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--mut2);
  text-align: center;
  padding-bottom: 2px;
}
.session-row-n {
  font-family: var(--cond);
  font-size: 13px;
  font-weight: 700;
  color: var(--mut2);
  text-align: center;
}
.session-row-n.is-done { color: var(--accent-text); }

/* La scatola: il numero del piano appoggiato in alto, dentro, e il campo che lo riempie tutto.
   Posizionato e non impilato, cosi' la scatola resta UNA e il tocco la prende tutta - una riga di
   testo sopra a un campo sono due bersagli, e quello piccolo sta dove va il pollice. */
.session-cell { position: relative; min-width: 0; }
.session-plan {
  position: absolute;
  top: 5px;
  left: 0;
  right: 0;
  text-align: center;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: .5px;
  color: var(--mut2);
  pointer-events: none;
}
/* Il piano si accende solo sopra al valore che e' cambiato davvero: le differenze sono tre, una per
   colonna. Con la sola isDeviated() una ripetizione in meno accendeva anche il carico e il recupero,
   che erano quelli previsti. */
.session-cell.is-changed .session-plan { color: var(--accent-text); font-weight: 700; }
/* Il trattino dove il piano non diceva niente: piu' spento del numero che sostituisce, perche' non
   e' un valore da leggere ma l'assenza di uno. */
.session-plan.is-none { color: var(--mut2); opacity: .55; }

/* input.session-box e non .session-box: la regola globale dei campi di testo e' scritta
   `input[type="text"], ... input[type="number"]`, che come peso e' classe+elemento e batte una
   classe secca - i suoi diciotto pixel di imbottitura restavano, e "62,5" usciva "62.". Stessa
   ragione per cui il nome dell'esercizio e' `textarea.plan-exercise-title`. (C'era anche uno
   <span class="session-box">, la tabella in lettura di una seduta finita: se n'e' andato il 26/09,
   perche' la carta di una seduta finita non si disegna piu'.) */
input.session-box {
  display: block;
  box-sizing: border-box;
  width: 100%;
  min-width: 0;
  height: 56px;
  margin: 0;
  padding: 15px 6px 0;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  color: var(--ink);
  text-align: center;
  /* 19px: si legge in piedi, da un metro, fra una serie e l'altra. E sopra i 16px, sotto i quali
     Safari su iPhone ingrandisce la pagina appena ci si mette a fuoco dentro. */
  font-size: 19px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}
/* Sotto i 380 punti l'imbottitura di lato scende da 6 a 2: a 360 lo spazio per il numero era 50
   punti, e «102,5» e «61,25» ne misurano 53 a 19 punti - uscivano «102,» e «61,2», lo stesso taglio
   di «62.» gia' segnalato una volta (P13, 26/09). A 390 lo spazio e' 60 e resta com'era. Non si
   prende niente alla colonna della spunta. */
@media (max-width: 379px) {
  input.session-box { padding-inline: 2px; }
}
input.session-box:focus {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  outline: none;
}
/* La scatola sbagliata si vede: le frasi stanno tutte sotto la griglia (app.js, show), quindi e' il
   bordo a dire quale serie. La regola generale [aria-invalid] pesa meno di input.session-box e
   perdeva il bordo (26/09). */
input.session-box[aria-invalid="true"] { border-color: var(--danger); }
/* La serie fatta si tinge appena: a che punto sei si vede senza contare le spunte. Su
   --accent-text e non su --accent: nel scuro sono lo stesso colore, e nel chiaro volt al 9% su
   bianco non si vedeva - la promessa qui sopra non era mantenuta (26/09). */
.session-cell.is-done input.session-box {
  border-color: color-mix(in srgb, var(--accent-text) 50%, transparent);
  background: color-mix(in srgb, var(--accent-text) 10%, var(--surface-2));
}

/*
  ---------- la spunta ----------

  Non aveva NESSUNA regola: era un <button> nudo, quindi sul tema chiaro quella premuta usciva come
  un quadratino di sistema e quella da premere come un trattino grigio da venti pixel. E' il comando
  piu' importante di questa schermata - quello che il pollice cerca fra una serie e l'altra, con il
  telefono appoggiato al rack. Segnalato con una fotografia dello schermo, dove la serie 4 sembrava
  non avere niente da premere.

  UNA CASELLA, NON UN CERCHIO, E CON DENTRO IL SEGNO ANCHE DA VUOTA: "il cerchio di fianco alla
  input che serve per indicare serie fatta non si capisce che e' un check, deve avere nello sfondo
  il simbolo e non deve essere rotondo". Un cerchio vuoto e' un bersaglio che non dice cosa fa
  premerlo - poteva essere un pallino di stato, una spia, un radio; una casella con dentro una
  spunta spenta dice "qui si spunta" prima ancora di provarci. Lo stesso raggio delle scatole che
  ha di fianco, cosi' la riga e' una fila di rettangoli e non due forme diverse.
*/
/* ALTA COME LE SCATOLE ACCANTO: la faccia 52 e il fianco del bottone 4 (la regola di tutti i
   bottoni, in fondo al foglio; il 27/09 e' stata 50 piu' 6 finche' il fianco era da sei), cioe' i
   56 della scatola, appoggiata in alto come lei. Era 44 in una fila di scatole da
   56, un bersaglio piu' basso proprio dove il pollice cerca. Larga 44 come la sua colonna: allargarla
   stringerebbe le tre scatole, e «102,5» non ci starebbe piu' (il mock la vuole 56 per 56;
   DA-FARE §23, D11). */
.plan-tick {
  box-sizing: border-box;
  display: inline-grid;
  place-items: center;
  width: 44px;
  min-width: 44px;
  height: 52px;
  align-self: start;
  justify-self: center;
  padding: 0;
  border: 1.5px solid var(--line);
  border-radius: var(--r-sm);
  color: var(--mut);
  font-size: 21px;
  line-height: 1;
}
/* Spenta ma presente: il segno dice "qui si spunta" prima ancora di provarci.
   PIU' CHIARA DI PRIMA - "schiarisci un po' le checkbox non attive, che servono a spuntare esercizio
   fatto", con le due spente cerchiate. Erano `--mut2` al 30%, cioe' un segno che a braccio teso, in
   palestra, si indovinava: il bersaglio si vedeva, il fatto che fosse una spunta no. Adesso `--mut`
   al 55%, che e' un passo e non un salto: deve restare evidente che NON e' spuntata, se no la
   risposta alla domanda "quali ho fatto" diventa un'altra domanda. Guardata in tutti e due i temi:
   su fondo bianco il segno regge, e la spuntata resta l'unica accesa. */
.plan-tick > span { opacity: .55; }
.plan-tick[aria-pressed="true"] > span { opacity: 1; }
/* Premuta: piena nell'accento, e TIENE IL FIANCO. Prima l'ombra del bagliore sostituiva quella della
   tessera, e la spunta affondava di quattro punti sotto il dito - mentre i bottoni qui non si
   muovono alla pressione (src/main/resources/CLAUDE.md). La stessa tessera di un bottone pieno, e
   disegnata dalla regola di tutti i bottoni: qui solo i due valori che quella legge, --solid (la
   faccia e il fianco si calcolano da lui) e --button-glow. Scriverci di nuovo faccia e ombre era una
   seconda copia della regola, e la regola :active dei bottoni, che pesa di piu', toglieva il bagliore
   sotto il dito (26/09, verifica delle regole B3). Il bordo e' un segno, e prende --accent-text. */
.plan-tick[aria-pressed="true"] {
  --solid: var(--accent);
  --button-glow: var(--glow-accent);
  border-color: var(--accent-text);
  color: var(--on-accent);
  font-weight: 700;
}
.plan-tick:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 3px; }

/*
  ---------- una scatola per valore ----------

  "Crea dei box piu' evidenti per carichi, rep e rest."

  Erano tre pillole nude, e l'unica cosa che diceva quale fosse quale era il segnaposto - che sparisce
  appena il campo ha un valore. Qui il campo ha SEMPRE un valore: le tre cifre arrivano gia' scritte
  dalla scheda. Quindi la didascalia non c'era mai quando serviva, e restava "10 16 60" da indovinare.

  Adesso la didascalia sta sotto il numero e non dentro: e' una <label> vera, quindi non sparisce, si
  puo' premere per mettere a fuoco il campo, e il campo dentro perde bordo e sfondo perche' il bordo
  ce l'ha la scatola. Il numero e' grande e centrato - e' la cosa che si legge da un metro, in piedi,
  fra una serie e l'altra.

  16px minimo sul campo, come ovunque: sotto quella misura Safari su iPhone ingrandisce la pagina da
  solo quando ci si mette a fuoco dentro.
*/
.set-field {
  display: flex;
  flex: 1 1 0;
  min-width: 0;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  padding: 7px 8px 5px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  cursor: text;
}
.set-field:focus-within { border-color: var(--accent-line); background: var(--accent-soft); }
.set-field input {
  width: 100%;
  margin: 0;
  padding: 0;
  border: none;
  background: none;
  border-radius: 0;
  text-align: center;
  font-size: 17px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}
.set-field input:focus { border-color: transparent; outline: none; }
.set-field-name {
  font-family: var(--cond);
  font-size: 11px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--mut2);
}

/* One Salva for the exercise, under its sets, right-aligned so it reads as the end of the block
   rather than as another row of it. */
/* Il salva dell'esercizio, a tutta larghezza in fondo alla tabella.

   Era una pillola piccola allineata a destra, mentre "Aggiungi" - che aggiunge una serie in piu',
   cosa che capita di rado - era un cerchione pieno d'accento: il peso visivo dei due era rovesciato
   rispetto a quanto si usano. Resta secondario, perche' il comando principale di questa schermata
   e' la spunta: spuntare salva gia' tutto, e questo serve per i valori scritti su serie che non si
   vogliono spuntare adesso. */
.session-exercise-save {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
}
.session-exercise-save .btn { flex: 1 1 100%; margin: 0; }

/*
  ---------- one more set than the schedule asked for ----------

  The same row as editing a set, one step quieter: a dashed top rule instead of a solid one, because
  it is an invitation rather than a record. It shares the input sizing above by reusing the
  declarations rather than restating them - two rules with the same three numbers is two rules that
  drift the first time either is touched.
*/

/* "Aggiungi un esercizio" e' il bottone pieno del costruttore, .plan-add-new: stesso comando,
   stesso disegno. Qui sotto resta solo la riga che dice cosa ne sara' dell'esercizio aggiunto. */
.session-add-hint { margin: 10px 4px 0; font-size: 12.5px; }

/*
  ---------- what was actually done ----------

  The recap of a finished workout: one row per exercise trained, its sets as chips.

  Chips and not a table. Four sets of "8 × 60 kg" as four rows is three lines of chrome for one line
  of content, and the question this answers - "what did I lift" - is read across, not down.
*/
.recap-list {
  /* Il rientro di quello che sta sotto al nome: il disco (40) e il suo spazio (9), come
     --plan-read-indent nella scheda in lettura. */
  --recap-indent: 49px;
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
}
.recap-exercise { padding: 12px 0; border-top: 1px solid var(--line-soft); }
.recap-exercise:first-child { border-top: none; padding-top: 4px; }
/* La riga della pagina 10: il disco con il numero, il nome che va a capo (qui nessun foglio lo mostra
   intero), e a destra il massimo, largo quanto il suo testo. Quello che sta sotto - i segni delle
   serie, la nota, il coach, «Trend carichi» - comincia al rientro del disco. */
.recap-head {
  display: flex;
  align-items: center;
  gap: 9px;
}
.recap-name { flex: 1 1 0; min-width: 0; font-weight: 600; font-size: 15.5px; line-height: 1.25; }
.recap-body { padding-left: var(--recap-indent); }
/* The top set, which is how a session is quoted. Accent, because it is the figure the athlete came
   back to read. */
.recap-top {
  flex: 0 0 auto;
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--accent-text);
}
.recap-sets {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 8px 0 0;
  padding: 0;
}
.recap-set {
  border: 1px solid var(--line-soft);
  background: var(--field-soft);
  border-radius: 999px;
  padding: 4px 11px;
  font-size: 13.5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.recap-note { margin: 8px 0 0; font-size: 13px; }

/*
  ---------- keep these in the schedule? ----------

  Asked once when a finished workout holds exercises the schedule does not. A checkbox row each,
  ticked by default, and two buttons - keep the ticked ones, or none of them.

  The whole row is the label, so the tap target is the row rather than the 20px box.
*/
.adopt-list { list-style: none; margin: 12px 0 16px; padding: 0; }
.adopt-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  border-top: 1px solid var(--line-soft);
}
.adopt-row:first-child { border-top: none; }
.adopt-row input[type="checkbox"] {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin: 0;
  /* La casella nel colore dell'applicazione, come ogni altra: senza, il quadratino e' quello
     azzurro del sistema operativo in mezzo a una pagina che azzurra non e'. */
  accent-color: var(--accent-text);
}
/* Il nome e' una <label for>, quindi va rimessa a posto la regola globale delle etichette - tutta:
   condensata, maiuscola e spaziata, "Prova" si leggeva PROVA. Stessa medicina di .checkbox-row. */
.adopt-name {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  font-family: var(--sans);
  font-size: 15px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
  cursor: pointer;
}
.adopt-sets {
  flex: 0 0 auto;
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
}
.badge-deviated {
  flex: 0 0 auto;
  border-radius: 999px;
  padding: 4px 11px;
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  color: var(--accent-text);
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
}

/* ---------- when a session happened ----------
   Folded away under the workout's heading: the default is right for anyone tracking at the gym,
   and only somebody writing up a past session needs to open it. Quiet when closed - a line with
   the date on it - so the card still reads as a workout rather than as a form. */
/*
  Il contatore dell'allenamento in corso.

  Una sola cifra grossa, perche' e' l'unica cosa che si legge da un metro di distanza con il telefono
  appoggiato al rack. Le altre due righe - che scheda e' e che cosa sta contando - stanno in piccolo
  sopra e sotto: servono la prima volta e poi non si guardano piu'.

  I numeri sono tabular-nums, altrimenti a ogni secondo la cifra cambia larghezza e l'orologio balla.
  Il bordo a sinistra invece di una scatola colorata: e' un valore che sta cambiando, non un avviso.

  Queste regole nude sono quelle della carta della home (fragments/running-workout.html). Nel tracker
  il contatore e' la griglia della testata, scritta piu' giu' sotto .session-top.
*/
.session-counter {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 12px;
  padding: 10px 0 10px 14px;
  border-left: 3px solid var(--accent);
}
.session-counter-eyebrow {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 8px;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--accent-text);
}
/* Quale scheda si sta eseguendo. Piu' quieto dell'occhiello che lo precede: la scheda ha gia' il suo
   titolo qui sopra, questa e' la conferma che il contatore parla di quella. */
.session-counter-plan { color: var(--mut2); letter-spacing: 1px; }
.session-counter-time {
  font-size: 38px;
  line-height: 1.05;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.session-counter-hint { font-size: 12.5px; color: var(--mut2); }

/*
  ---------- la testata del tracker: la pagina 11 del mock ----------

  L'occhiello con lo stato, il nome della scheda una volta, e sotto il tempo grande con a destra le
  serie fatte («3 / 15 serie») e la barra a tutta riga. Un markup e due stati: a seduta finita il
  tempo si ferma, sotto c'e' «Durata», e l'occhiello dice «Terminato».

  TUTTO SOTTO .session-top. .session-counter, -time e -eyebrow sono anche della carta della home, e una
  regola nuda qui cambierebbe l'aspetto di una pagina che il ridisegno non tocca: TheTrackerHeadTest
  tiene la guardia. Per lo stesso motivo la griglia RIDICHIARA quello che la regola nuda mette e qui
  non serve (il bordo a sinistra, l'imbottitura): una regola che perde perde solo quello che il
  vincitore ripete.

  I SEGNI SONO IN --accent-text, il punto e la barra: con volt nel chiaro --accent e' un giallo chiaro
  su una carta bianca, e non si vedevano.

  NON E' FERMA mentre si scorre, come la vuole il mock: con la pillola del recupero e la barra
  sarebbero tre cose ferme, la cosa di cui Davide si e' lamentato (DA-FARE §23, D1).
*/
.session-top > .page-title { margin: 0; line-height: 1.15; }
.session-top .session-live {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 5px;
  font-family: var(--cond);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  color: var(--accent-text);
}
/* Finita: lo stato e' un fatto dello storico e si spegne, come il tempo che non corre piu'. */
.session-top .session-live.is-finished { color: var(--mut2); }
/* IL PUNTO E' FERMO: una pillola che pulsa sopra a una seduta di un'ora e' un difetto, non un
   avviso (la regola della pillola del recupero; DA-FARE §23, D7). */
.session-top .session-live-dot {
  flex: 0 0 8px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent-text);
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.session-top .session-live-mark { font-size: 13px; line-height: 1; }
.session-top .session-counter {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "time sets"
    "bar  bar"
    "hint hint";
  align-items: end;
  gap: 0 12px;
  margin-top: 10px;
  padding: 0;
  border-left: 0;
}
.session-top .session-counter-time {
  grid-area: time;
  font-size: 46px;
  line-height: .95;
  letter-spacing: -.5px;
}
/* Finita: la cifra e' un dato dello storico, non piu' un valore che si muove, e smette di essere la
   cosa piu' luminosa dello schermo. */
.session-top .session-counter-done .session-counter-time { color: var(--ink-2); }
.session-top .session-sets {
  grid-area: sets;
  text-align: right;
  line-height: 1;
  white-space: nowrap;
}
.session-top .session-sets b { font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums; }
.session-top .session-sets small {
  font-size: 16px;
  font-weight: 500;
  color: var(--mut);
  font-variant-numeric: tabular-nums;
}
.session-top .session-sets-label { display: block; margin-top: 4px; font-size: 12.5px; color: var(--mut); }
/* La barra e' un <progress>: il valore e il massimo sono due attributi, e la CSP non ammette lo
   style= che una larghezza vorrebbe. Il browser lo disegna a modo suo finche' non gli si toglie
   l'aspetto; Chromium e Safari dipingono le due pseudo-parti -webkit-, Firefox la sua. */
.session-top .session-meter {
  grid-area: bar;
  display: block;
  width: 100%;
  height: 6px;
  margin-top: 12px;
  border: 0;
  border-radius: 6px;
  background: var(--track);
  -webkit-appearance: none;
  appearance: none;
  overflow: hidden;
}
.session-top .session-meter::-webkit-progress-bar { background: var(--track); border-radius: 6px; }
.session-top .session-meter::-webkit-progress-value { background: var(--accent-text); border-radius: 6px; }
.session-top .session-meter::-moz-progress-bar { background: var(--accent-text); border-radius: 6px; }
.session-top .session-counter-hint { grid-area: hint; margin-top: 8px; }

/*
  Lo stesso contatore, in home, come promemoria di un allenamento aperto.

  Qui e' un link e per questo e' una scatola: il motivo per cui esiste e' rientrare
  nell'allenamento, e un riquadro con un collegamento in fondo chiederebbe di mirare a una parola
  quando basta il riquadro. Il bordo a sinistra resta - e' lo stesso oggetto della schermata
  dell'allenamento, non un avviso nuovo da imparare.
*/
.running-workout {
  display: flex;
  text-decoration: none;
  margin-top: 14px;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  /* Si preme (porta all'allenamento), quindi dal 27/09 e' un bottone della casa: «Anche allenamento
     e carta esercizio 4px» (Luca). Faccia bombata, taglio, fianco da quattro e ombra li da'
     a.running-workout nella regola di tutti i bottoni, in fondo al foglio, con la velatura
     dell'accento come --solid; qui restano la forma e il bordo. Fino ad allora era un riquadro con
     il fianco da tre e la faccia velata. */
}
/* "Hai gia' un allenamento in corso": l'avviso che rifiuta "Esegui", ed e' il link per andarci. */
.running-blocked {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  text-decoration: none;
}
.running-blocked-go {
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1px;
  text-transform: uppercase;
  white-space: nowrap;
}

.running-workout-back {
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: .5px;
  color: var(--accent-text);
}
/* Il giorno in cui e' cominciato, al posto dell'orologio, quando l'orologio non ha piu' senso. */
.running-workout-since {
  font-size: 20px;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
/* Rimasto aperto e non in corso: resta in pagina perche' c'e' qualcosa da chiudere, ma smette di
   essere la cosa piu' luminosa dello schermo - non e' l'allenamento di adesso. */
.running-workout-stale {
  border-color: var(--line);
}
.running-workout-stale .session-counter-eyebrow,
.running-workout-stale .running-workout-back { color: var(--mut2); }

/*
  Quali risposte bloccano, dette prima del rifiuto.

  L'asterisco nell'accento accanto all'etichetta, e una legenda sopra al modulo che dice che cosa
  significa - un asterisco senza legenda e' una convenzione che si presume, e questa e' la prima
  schermata dell'applicazione. "facoltativo" a parole sugli altri due campi della stessa schermata:
  fra cinque campi obbligatori, uno non marcato si legge come uno dimenticato.

  Il titolo sul segno resta per chi legge con uno screen reader; la legenda porta aria-hidden sul suo
  asterisco perche' li' e' decorazione, il significato e' nella frase accanto.
*/
.required-legend {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin: 0 0 14px;
  font-size: 12.5px;
  color: var(--mut2);
}
.field-req {
  color: var(--accent-text);
  font-weight: 700;
  margin-left: 3px;
}
.field-optional {
  margin-left: 6px;
  font-family: var(--cond);
  font-size: 11.5px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut2);
}

/* "Niente di questo e' definitivo", sulla prima schermata della configurazione e sull'ultima. */
.setup-note {
  margin-top: 18px;
  padding-left: 12px;
  border-left: 2px solid var(--line);
  font-size: 13px;
  color: var(--mut2);
}
.setup-note a { color: var(--accent-text); }

/*
  Il selettore della distanza: due rotelle affiancate, chilometri e centinaia di metri.

  Sono due <select> nativi, quindi sul telefono sono la rotella del sistema e sul desktop due
  tendine - nessuna riga di JavaScript e nessuna dipendenza per una cosa che il browser fa gia'.
  L'unita' sta accanto e non dentro all'opzione: dentro si ripeterebbe cento volte nell'elenco.
*/
.manual-distance { display: flex; align-items: center; gap: 12px; }
.manual-wheel { display: flex; align-items: baseline; gap: 6px; }
.manual-wheel select { width: auto; min-width: 84px; margin: 0; }
.manual-wheel-unit {
  font-family: var(--cond);
  font-size: 13px;
  letter-spacing: 1px;
  color: var(--mut2);
}

/*
  La risposta del riquadro: registrata, poi il passo, la velocita' e le calorie.

  Un blocco suo e non .alert-success, che in questa applicazione e' un messaggio fisso in cima che
  svanisce in quattro secondi: giusto per "salvato", sbagliato per tre cifre da leggere. Bordo a
  sinistra nel verde delle conferme, come il promemoria dell'allenamento aperto ha il suo
  nell'accento - e' un valore, non un avviso.
*/
.manual-result {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 14px;
  padding: 10px 0 10px 12px;
  border-left: 3px solid var(--ok);
}
.manual-result-said {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--ok);
}
.manual-result-figures {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 16px;
  font-size: 17px;
  font-weight: 700;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.manual-result-note { font-size: 12.5px; color: var(--mut2); }

.session-when { margin-top: 10px; }
.session-when > summary { cursor: pointer; list-style: none; }
.session-when > summary::-webkit-details-marker { display: none; }
/* Due righe: l'etichetta con il segno della piega in fondo, e sotto la data.

   Erano sulla stessa riga, e il segno non c'era affatto: "metterei la data sotto e un simbolo
   espandi in fondo a destra della scritta quando si e' svolto". Con il nome del giorno tradotto la
   riga si allunga - "mercoledi'" - e una riga che finisce fuori dallo schermo non dice piu' che si
   apre. */
.session-when-open {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 4px 8px;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--mut2);
}
.session-when-label { min-width: 0; }
/* La data sotto, a tutta riga: e' la cosa che si legge, quindi non condivide la riga con altro. */
.session-when-value {
  grid-column: 1 / -1;
  color: var(--ink-2);
  font-size: 13.5px;
  letter-spacing: .6px;
}
.session-when[open] > summary .session-detail-mark { transform: rotate(-135deg) translateY(3px); }
.session-when form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 10px 0 0; }
.session-when input[type="datetime-local"] { flex: 1 1 auto; min-width: 0; margin: 0; }
.session-when .btn { margin-top: 0; }
.session-when-hint { margin: 8px 0 0; font-size: 12.5px; }

.session-note { margin-top: 14px; }
.session-note label, .session-note-title { display: block; margin-bottom: 6px; font-size: 13px; color: var(--mut); }
/* La nota di un esercizio finito sta sotto all'ultima serie, e senza questo ci sta attaccata. */
.session-note-done { margin-top: 18px; }
/* La nota di una seduta finita: testo, non un campo. Il colore e' quello della pagina e non
   il grigio dell'etichetta sopra - sono due cose diverse e devono leggersi come tali. */
.session-note-text { margin: 0; font-size: 15px; line-height: 1.5; color: var(--ink); white-space: pre-wrap; }
.session-note textarea { width: 100%; resize: vertical; }

/* The coach's comment: same tone as a chat bubble from the coach, because it is
   the same voice giving the same kind of answer. */
.ai-feedback { margin-top: 16px; }
.ai-feedback-body {
  margin-top: 8px;
  padding: 13px 16px;
  border-radius: 14px;
  background: var(--accent-soft);
  border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent);
  font-size: 14px;
  line-height: 1.55;
}
/*
  Il riquadro del commento, quando porta dentro anche l'ora.

  Il bordo e il fondo passano da .ai-feedback-body a questo contenitore, e il corpo li perde solo
  qui dentro: le altre tre schede che usano .ai-feedback-body - la lettura di una foto, il riassunto
  di una seduta, il commento su un esercizio - non hanno un'ora da mettere e restano come sono.
*/
.ai-feedback-box {
  margin-top: 8px;
  padding: 13px 16px;
  border-radius: 14px;
  background: var(--accent-soft);
  border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent);
}
.ai-feedback-box > .ai-feedback-body {
  margin-top: 0;
  padding: 0;
  border: none;
  background: none;
  border-radius: 0;
}
/*
  La riga in fondo al riquadro: il comando che apre a sinistra, l'ora a destra.

  L'ora se ne va a destra con un margine automatico e non con un "space-between", perche' su un
  commento corto la piega non viene stampata affatto e con un figlio solo "space-between" non ha
  niente da distanziare: l'ora finirebbe a sinistra su alcune schede e a destra su altre.

  L'allineamento in fondo e non al centro: il comando e' alto 44px, che e' quanto serve a un dito,
  e centrare l'ora contro quei 44px la staccherebbe dal bordo di sotto invece che appoggiarla.
*/
.ai-feedback-foot {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  margin-top: 4px;
}
.ai-feedback-foot > .box-advice-when { margin: 0 0 4px auto; }
/* Dentro al riquadro il comando non ha piu' niente sopra da cui staccarsi. */
.ai-feedback-foot > .advice-more { margin: 0; }

.ai-summary { margin-top: 20px; }

/* ---------- disciplines on the profile ----------
   One row per sport: the tick on the left, the weekly target on the right. The
   target keeps its place whether or not the sport is ticked, so ticking one does
   not make the whole list jump. */
.discipline-list { list-style: none; margin: 4px 0 18px; padding: 0; }
/* Two lines, always: the name and its checkbox, then the weekly target underneath.
   As one flex row it wrapped only when the label was long, so "Corsa" kept its box on the
   first line at x=128 while "Escursionismo" pushed its box onto a second line at x=37 -
   seven rows, four of them out of line with the other three, and which ones depended on
   how long the word happened to be in the current language. Fixed rows cannot do that. */
/*
  La riga di una disciplina: il nome su una riga sua, e sotto i suoi bersagli affiancati.

  Era tutto incolonnato - la spunta, poi le sedute, poi i chilometri, uno sotto l'altro e rientrati
  di trenta pixel rispetto alla casella. Tre righe per dire due numeri, e i due numeri lontani fra
  loro quando sono la stessa domanda fatta in due unita'. Riportati sulla stessa riga e allineati a
  sinistra sotto la casella, come chiesto.

  Un flex che va a capo, non una griglia: il nome e la piega prendono tutta la larghezza, i bersagli
  no e stanno accanto finche' ci stanno - su uno schermo molto stretto scendono da soli invece di
  schiacciarsi.
*/
.discipline {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0 22px;
  padding: 14px 0;
  /* Piu' marcata della riga fra due obiettivi dentro una piega: sono due livelli diversi, e quando
     una piega e' aperta finiscono uno sotto l'altro. */
  border-bottom: 1px solid var(--line);
}
.discipline:last-child { border-bottom: none; }
.discipline-pick {
  display: flex;
  align-items: center;
  gap: 10px;
  /* Riga sua: il nome sta sopra i suoi numeri, non accanto. */
  flex: 0 0 100%;
  min-width: 0;
  margin: 0;
  cursor: pointer;
}
/* accent-color come .goal-pick, .proposal-pick e .checkbox-row: senza, queste erano le uniche
   caselle dell'applicazione a restare del blu di sistema. Vale anche per la pagina obiettivi, che
   monta lo stesso elenco. */
.discipline-pick input { width: auto; margin: 0; accent-color: var(--accent-text); }

/*
  ---------- "i tuoi obiettivi", dentro la disciplina ----------

  La piega che si apre sotto una disciplina, con dentro le stesse caselle che prima erano una carta
  a se' piu' in basso. La riga che la apre e' quieta - e' dentro una riga gia' spuntabile, e un
  secondo controllo forte li' dentro competerebbe con la spunta che conta.

  Larga quanto la riga: la riga della disciplina e' una griglia di colonne strette (la spunta, le
  sedute, i chilometri) e senza questo la piega finirebbe in una di quelle.
*/
/* Tutta la larghezza: la piega apre sotto i bersagli, non accanto a uno di essi. */
.goal-fold { flex: 0 0 100%; margin-top: 10px; }
/*
  Aperta, deve staccarsi da quello che viene dopo.

  Segnalato con una freccia fra "corsa libera" - l'ultimo obiettivo della corsa - e "palestra", che
  e' la disciplina successiva: le due liste si toccavano e non si capiva dove finisse una e
  cominciasse l'altra. Due segni invece di uno solo, perche' qui si sovrappongono due livelli e lo
  spazio da solo si legge come "un po' piu' di spazio", non come "questo sta dentro quello".
*/
.goal-fold[open] { padding-bottom: 8px; }
.goal-fold > summary {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  min-height: 44px;
  cursor: pointer;
  list-style: none;
  font-family: var(--cond);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--accent-text);
}
.goal-fold > summary::-webkit-details-marker { display: none; }
.goal-fold[open] > summary .session-detail-mark { transform: rotate(-135deg) translateY(3px); }
/* Dentro la piega gli obiettivi tornano una lista normale, con la riga di separazione che avevano
   nella carta: sono le stesse righe, spostate e non riscritte. Il rientro e il binario a sinistra
   non stanno piu' qui: li mette la regola in fondo al foglio che li mette a tutte le sezioni che si
   aprono, questa compresa. */
.goal-fold .goal-list { margin: 0; }

/* Le tre righe che sono una gara a se'. Nessuna casella di sedute accanto: la riga e' la spunta e
   la sua domanda, e la domanda sta sotto e rientrata come stanno i bersagli settimanali delle
   altre - stessa colonna, stesso stacco, cosi' le sette righe si leggono come una lista sola.

   display: block e non il suo inline: su uno span in linea il margine sinistro sposta solo l'inizio
   della prima riga, non i campi dentro, e i campi restavano incollati al bordo. Misurato. */
.discipline-race .goal-detail { flex: 0 0 100%; margin: 10px 0 0; }
.discipline-race .goal-detail label { margin-top: 12px; }
.discipline-race .goal-detail label:first-child { margin-top: 0; }
/* Indented to sit under the label rather than under the checkbox, so the column of boxes
   reads as belonging to the names above them. */
/*
  Un bersaglio: l'etichetta sopra e il campo sotto, come ogni altro campo dell'applicazione.

  column-reverse e non un riordino del markup: nel markup viene prima il campo e poi la sua unita',
  che e' l'ordine giusto per chi legge con lo screen reader - il campo porta gia' il proprio nome
  in aria-label, e l'unita' lo segue. A schermo l'ordine utile e' l'opposto, e questa e' la riga che
  lo dice senza toccare nessuno dei due.

  Nessun rientro: allineati a sinistra sotto la casella di spunta, non spostati di trenta pixel.
*/
.discipline-target {
  display: flex;
  flex-direction: column-reverse;
  align-items: flex-start;
  gap: 5px;
  margin: 10px 0 0;
}
/* Narrow on purpose: a full-width box for "3" invites someone to type a sentence. */
.discipline-target input { width: 84px; margin: 0; text-align: right; }

/*
  ---------- due discipline nello stesso giorno ----------

  Stessa forma delle due caselle accanto - etichetta minuscola sopra, comando sotto - perche' e' la
  terza cosa che si dice della stessa disciplina, non un'impostazione di un altro genere. Va a capo
  da sola su una riga sua: e' l'unica delle tre che porta un nome invece di un numero, e stretta
  quanto le altre non ci starebbe "camminata (passeggiata, tragitti)".
*/
.discipline-pair {
  display: flex;
  flex-direction: column-reverse;
  align-items: flex-start;
  gap: 5px;
  margin: 10px 0 0;
  flex: 1 1 100%;
}
.discipline-pair select { margin: 0; max-width: 260px; }
.discipline-pair-label {
  margin: 0;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--mut);
}
.discipline-unit {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--mut2);
  white-space: nowrap;
}

/* ---------- setup banner ----------
   Impossible to miss, impossible to mistake for an error. It sits between the bar
   and the page, spans the full width, and the whole strip is the link so there is
   no small target to hit on a phone. */
/* Stacked when there is more than one, tightly, so two outstanding tasks read as
   a short list rather than as two separate alarms. */
/*
  ---------- la stessa larghezza di tutto il resto ----------

  "Tutti gli avvisi in home devono essere della stessa grandezza, ovvero come il secondo."

  Erano di due misure perche' arrivano da due posti. Quelli della home sono figli di .app-shell,
  quindi ereditano i suoi 520px e i suoi 16 di lato; questo contenitore invece sta a livello di
  <body>, fuori dallo shell, dove niente lo stringeva - restava largo quanto lo schermo e il testo
  toccava i bordi, tagliato a destra su "senza caricare niente a mano".

  Prende la scatola dello shell invece di inventarne una: gli stessi due numeri, cosi' i due gruppi
  non possono divergere alla prossima volta che uno dei due viene toccato. Il max-width di 720 su
  .setup-banner qui sotto resta e non fa piu' niente - dentro a 520 non arriva mai - ma vale ancora
  per gli avvisi della home, che stanno in un contenitore diverso.
*/
.setup-banners {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 520px;
  margin: 14px auto 0;
  padding: 0 16px;
}
.setup-banner {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  gap: 7px;
  max-width: 720px;
  width: 100%;
  margin: 0 auto;
  padding: 14px 16px;
  border: 1px solid var(--accent-line);
  border-radius: 16px;
  background: var(--accent-soft);
  color: var(--ink);
  text-decoration: none;
}
.setup-banner:hover { border-color: var(--accent-text); text-decoration: none; }
.setup-banner-text {
  max-width: 46ch;
  font-size: 14px;
  line-height: 1.45;
}
.setup-banner-cta {
  display: inline-flex;
  width: max-content;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  font-weight: 700;
  color: var(--accent-text);
  white-space: nowrap;
}
.setup-banner-cta::after {
  content: "›";
  font-size: 20px;
  font-weight: 500;
  line-height: .8;
}
.center-text { text-align: center; }
.mt-24 { margin-top: 24px; }
.lang-switch { display: flex; justify-content: center; align-items: center; gap: 10px; margin-top: 18px; }
.lang-switch a { display: inline-flex; align-items: center; min-height: 44px; padding: 0 6px; }

/*
  Disclosure rows reach 44px.

  Measured on the dashboard: most <summary> elements were 316px wide and 18 to 27px tall - a wide
  thin strip, which is the shape a thumb misses. Nothing here changes what they look like; the row
  is given the height it should always have had, and the content stays centred in it.

  Scoped to the ones on a card. The appearance pill in the top bar and the accordion headings that
  already size themselves are left alone.
*/
/*
  Un selettore per riga e il blocco subito sotto, senza commenti in mezzo al gruppo.

  Questa regola ha perso il suo blocco due volte, tutte e due per mano mia, tutte e due togliendo
  UN selettore dal gruppo con una sostituzione di testo. Un gruppo non e' un elenco di righe
  indipendenti: cancellarne una che sta in fondo si porta via le dichiarazioni di tutte, e quello
  che resta - quattro selettori senza corpo - si attacca alla regola successiva. Qui la successiva
  era .tiles, quindi le quattro pieghe si sono ritrovate addosso "display: grid" con le colonne
  delle piastrelle della home: da cui "RIPOSATO" e il "?" spalmati su due colonne invece che
  centrati sotto l'anello.

  Non fallisce niente e non si vede in un diff, perche' CSS valido resta - e' solo un altro CSS.
*/
.card .explain > summary,
.load-block .explain > summary,
.page-top .explain > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  /* Misurata sulla home: la maggior parte dei riassunti era larga 316 e alta fra 18 e 27 - una
     striscia sottile, che e' la forma che un pollice manca. */
  min-height: 44px;
}

/* ---------- dashboard tiles ---------- */
.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 12px;
  margin-top: 16px;
}
/*
  Tre righe condivise fra le caselle, non tre righe per casella.

  "Le cifre devono essere allineate verticalmente, non sfalsarle." Non lo erano perche' una
  etichetta sta su una riga - QUESTA SETTIMANA - e l'altra su due - BRUCIATE IN ALLENAMENTO - e la
  cifra partiva dove finiva la sua etichetta, dodici pixel piu' in basso in una delle due.

  Con subgrid le righe le decide la griglia madre e valgono per tutte e due: etichetta, cifra,
  piede. La riga dell'etichetta e' alta quanto la piu' alta delle due, quindi le cifre partono dallo
  stesso punto qualunque cosa ci sia scritto sopra. Per questo ogni casella ha esattamente tre
  figli, e per questo il piede e' un contenitore: quello che ci va dentro cambia da una casella
  all'altra, il numero di righe no.

  Dove subgrid non c'e', le caselle restano quelle di prima - impilate e leggibili, semplicemente
  non allineate: il fallback e' la pagina di ieri, non una pagina rotta.
*/
/* Le caselle dentro una carta si sollevano anche loro, ma di meno: sono appoggiate SULLA carta e
   non sulla pagina, e dargli la stessa ombra le farebbe galleggiare alla stessa altezza di cio' su
   cui poggiano. Un'ombra piu' corta, --shadow-tile - la gerarchia di altezza e' la stessa gerarchia
   che c'e' gia' fra i due elementi. Il fianco e' quello della carta, da due (era da tre, poi da
   quattro con la carta, poi "schede ecc 2px", 27/09), quindi la differenza la dice l'ombra. */
.tile {
  --solid: var(--field);
  background: var(--metal-face);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  padding: 14px 16px;
  box-shadow: var(--edge-lit), var(--lift-edge), var(--shadow-tile);
}
@supports (grid-template-rows: subgrid) {
  .tiles { align-items: stretch; }
  .tile {
    display: grid;
    grid-row: span 3;
    grid-template-rows: subgrid;
    align-content: start;
  }
}
/* Il piede: tutto quello che sta sotto la cifra, in una riga sola della griglia. */
.tile-foot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.tile-warn { border-color: var(--accent-line); box-shadow: 0 0 18px color-mix(in srgb, var(--accent) 14%, transparent); }
/*
  A tile reads as three lines: what it measures, the figure with its unit, then a
  plain-language hint. The figure and the unit sit on one baseline - the unit at
  normal weight and roughly half the size, so "173 load pts" reads as one value
  and not as two competing numbers.
*/
.tile-value {
  display: flex;
  align-items: baseline;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 6px;
}
.tile-value b {
  font-size: 27px;
  font-weight: 800;
  letter-spacing: -.3px;
  line-height: 1.1;
  color: var(--accent-text);
}
.tile-value em {
  font-family: var(--cond);
  font-size: 12.5px;
  font-style: normal;
  font-weight: 600;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--mut);
}
.tile-hint {
  display: block;
  margin-top: 4px;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--mut2);
}

/* ---------- weekly volume bars ---------- */
/*
  L'altezza appartiene alle barre, non alla colonna intera.

  Erano 160 pixel per tutto - barre piu' etichette - con le barre a "flex: 1", cioe' a prendersi
  quello che avanzava. Misurato in pagina: le etichette ne occupavano 106 e alle barre ne restavano
  55, e nella vista per disciplina, dove sotto ogni settimana ci sono tre percentuali e tre valori,
  il grafico si riduceva a una striscia di qualche pixel sopra mezza schermata di numeri.
  "Perche' il volume settimanale e' cosi' schiacciato?" - per questo.

  Adesso la zona delle barre ha la sua altezza fissa e le etichette prendono lo spazio che serve
  loro, sotto. La carta cresce di quel tanto, che e' il prezzo giusto: le etichette sono testo da
  leggere, le barre sono un disegno da confrontare, e chi decide quanto e' alto il disegno non
  possono essere le righe di testo che gli stanno sotto.
*/
.volume-bars {
  list-style: none;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 0;
  margin: 18px 0 0;
}
/* min-width: 0 e' quello che fa stare otto colonne dentro alla carta invece di farle traboccare:
   senza, ogni colonna si allarga fino al suo contenuto piu' largo - "3,0 km" - e otto di quelle
   sommate superano la larghezza disponibile, quindi l'ottava finiva fuori. */
.volume-week {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
}
/*
  Novantasei pixel, gli stessi di .day-bar.

  "Queste colonne sono troppo allungate in verticale rispetto a quella dei tuoi ultimi sette giorni,
  adeguale". Erano 140 - alzate da 55 perche' le etichette sotto se le mangiavano - e a quel punto
  erano il disegno piu' alto della pagina, davanti al grafico che l'atleta ha indicato come misura
  giusta. Una sola altezza per tutte le barre dell'applicazione: quella.
*/
.volume-bar {
  width: 100%;
  height: 96px;
  flex: 0 0 auto;
  display: flex;
  align-items: flex-end;
  position: relative;
}
/*
  ---------- the target, drawn ----------

  A dashed line at the weekly goal, across every week. The bars say how the weeks compare with each
  other; this says whether they were enough, which is the question the athlete has.

  A box the height of the target with a line on its top edge, rather than a line positioned from the
  bottom: it reuses nothing and needs no extra arithmetic, and "height" is the only geometry the bars
  themselves use. Its own height classes - line-0 to line-100 - because the bar-N classes set width
  as well and this must stay full width.

  Behind the bars (z-index 0 against their auto), so a bar that clears the target covers the line
  rather than being cut in half by it. That is also what makes the line read as a threshold: what is
  above it is drawn over it.
*/
.volume-target {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
  pointer-events: none;
  /* Il terzo colore invece di un grigio.
     La riga del 100% e' l'unica cosa del grafico che non e' un dato: e' il metro contro cui i dati
     si leggono. In grigio spariva fra le barre, ed e' diventata piu' importante da quando le
     percentuali non ci sono piu' - adesso e' l'unica cosa che dice se una settimana e' bastata.
     Nel terzo colore si distingue da tutte le barre senza confondersi con nessuna, ed e' comunque
     un colore di casa. */
  border-top: 1px dashed color-mix(in srgb, var(--accent-3) 70%, transparent);
}
.volume-bar .volume-fill { position: relative; z-index: 1; }
.line-0 { height: 0; }
.line-5 { height: 5%; }
.line-10 { height: 10%; }
.line-15 { height: 15%; }
.line-20 { height: 20%; }
.line-25 { height: 25%; }
.line-30 { height: 30%; }
.line-35 { height: 35%; }
.line-40 { height: 40%; }
.line-45 { height: 45%; }
.line-50 { height: 50%; }
.line-55 { height: 55%; }
.line-60 { height: 60%; }
.line-65 { height: 65%; }
.line-70 { height: 70%; }
.line-75 { height: 75%; }
.line-80 { height: 80%; }
.line-85 { height: 85%; }
.line-90 { height: 90%; }
.line-95 { height: 95%; }
.line-100 { height: 100%; }
.volume-fill {
  width: 100%;
  min-height: 3px;
  border-radius: 8px 8px 0 0;
  /* Both stops derive from the accent. The foot of the gradient used to be a literal pink, so a
     bar switched to green, orange or Tiffany kept a pink base and the chart was the one place on
     the page that did not follow the colour the athlete had chosen. */
  background: linear-gradient(180deg, var(--accent),
                              color-mix(in srgb, var(--accent) 35%, transparent));
  box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 25%, transparent);
}

/*
  ---------- a bar per discipline ----------

  Requested as running beside lifting rather than one total. The height of each is that
  discipline's percentage of its OWN weekly target - the only thing kilometres and sessions have in
  common - and the figure under it is the absolute one in the unit that discipline is counted in.

  Two or three thin bars in the space one used to have, with a hair of gap between them so they
  read as separate quantities rather than a stacked total. They are NOT stacked: stacking would
  imply the percentages add up to something, and 117% of a running target plus 50% of a gym target
  is not a number.
*/
.volume-bar-split { gap: 3px; }
.volume-bar-split .volume-fill { border-radius: 6px 6px 0 0; }

/*
  The colours.

  One discipline uses the accent the athlete chose, which is what .vol-accent falls through to -
  the base .volume-fill gradient already derives from --accent, so it needs no rule of its own and
  is listed here only so the intent is written down somewhere.

  Several use fixed fluo variants, one per discipline, assigned by the discipline's position in the
  athlete's own list so a colour never moves between two weeks or two visits. Every one is a
  saturated neon in the same register as the accent: this palette had to stay recognisably the same
  family, not become a pastel chart bolted onto a neon page.

  Defined as a --bar colour and consumed once, exactly like the nutrition macros above: the
  template carries a class per discipline and names no colour at all.
*/
.vol-c1 { --bar: #ff2d95; }  /* fluo pink   */
.vol-c2 { --bar: #2ee6ff; }  /* fluo cyan   */
.vol-c3 { --bar: #b06cff; }  /* fluo violet */
.vol-c4 { --bar: #38ff9e; }  /* fluo green  */
.vol-c5 { --bar: #ffb020; }  /* fluo orange */
.vol-c6 { --bar: #ffe94d; }  /* fluo yellow */
.vol-c7 { --bar: #f2f6ff; }  /* near white  */

/*
  ---------- the sports that are not training ----------

  A walk and a hike get a colour of their own, outside the positional palette. Reported from a
  screenshot of the seven-day chart: a 1,7 km walk was drawn in the accent, which is the colour
  running has, under a legend naming only Corsa and Pesi - so a walk to the shops read as a short
  run. "La camminata non deve essere letta come corsa."

  Yellow because Davide asked for yellow, and fixed by sport rather than by position because these
  turn up irregularly: a colour handed out by position would move between two visits.

  Two values per sport, one per theme, and that is the whole reason these are tokens. The bright
  yellow that reads on a black card is close to invisible on a white one - "renderò il colore giallo
  nell'elenco delle attività svolte in modalità scura e scuriscono in modalità chiara". The light
  values are darkened until they clear 4.5 : 1 on the light background, because this colour is text
  in the seven-day chart, not only a bar: #8a6a00 measures 4.65 : 1 and #5f6b00 measures 5.35 : 1.
*/
.vol-walking { --bar: #ffd400; }  /* yellow                     */
.vol-hiking  { --bar: #c9d92e; }  /* its relative, towards olive */
:root[data-theme="light"] .vol-walking { --bar: #8a6a00; }
:root[data-theme="light"] .vol-hiking  { --bar: #5f6b00; }

.volume-fill[class*="vol-c"] {
  background: linear-gradient(180deg, var(--bar),
                              color-mix(in srgb, var(--bar) 35%, transparent));
  box-shadow: 0 0 14px color-mix(in srgb, var(--bar) 25%, transparent);
}

/*
  ---------- le discipline sotto le loro colonne, e le cifre sotto ancora ----------

  La fila delle icone usa lo stesso schema della fila delle barre - stessa distanza fra gli elementi,
  stesso ordine, ogni elemento largo uguale - quindi ogni icona cade esattamente sotto la sua barra.
  Se le due file divergono e' perche' qualcuno ha cambiato il gap di una sola: sono la stessa misura
  e vanno cambiate insieme.

  Le cifre restano incolonnate una sotto l'altra e non affiancate. Cinque settimane su un telefono da
  390 px sono una sessantina di pixel a colonna, e tre quantita' di fianco - "17 km", "2 x", "2 x" -
  non ci stanno: il browser spezzerebbe "17" da "km". In colonna non si spezza niente, e l'ordine
  dall'alto in basso e' quello delle icone da sinistra a destra.
*/
.volume-icons {
  display: flex;
  gap: 3px;
  width: 100%;
  margin-top: 6px;
}
.volume-icons .volume-swatch { flex: 1 1 0; min-width: 0; }
.volume-split-figures {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  margin-top: 2px;
}

/* Era un quadratino da 7 px nel colore della colonna: una chiave che rimandava a una legenda che
   non esisteva. Adesso ci sta dentro l'icona della disciplina, colorata come la barra. */
.volume-swatch {
  width: 14px;
  height: 14px;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--bar, var(--accent));
}
/* L'icona dentro alla pastiglia prende la misura di quella, non quella di default delle icone. */
.volume-swatch .ico { width: 14px; height: 14px; }

/* Which colour is which discipline, once, under the chart. Without it the swatches tie a figure to
   a bar and nothing says which bar is running. */
.volume-legend {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  padding: 0;
  margin: 12px 0 0;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut2);
}
.volume-legend li { display: flex; align-items: center; gap: 5px; }

/* La legenda fatta di sole icone: piu' grandi e piu' distanziate.

   A 14 px l'icona e' una chiave accanto a una parola, e la parola non c'e' piu': deve reggere da
   sola. Ventidue e' la misura a cui la scarpa e il bilanciere si distinguono a colpo d'occhio senza
   diventare pulsanti - non lo sono, non si toccano. Lo scarto e' piu' largo perche' due sagome
   attaccate si leggono come una. */
.volume-legend-icons { gap: 8px 20px; }
.volume-legend-icons .volume-swatch { width: 22px; height: 22px; }
.volume-legend-icons .volume-swatch .ico { width: 22px; height: 22px; }

/* A single week has no other week to be compared against, so a bar spanning the
   whole card reads as "a lot" when it only means "the only one". Cap the width. */
.volume-week:only-child { max-width: 96px; }

/*
  Bar sizes, in 5% steps.
  These exist because a Content-Security-Policy of style-src 'self' drops style
  attributes, so `style="height:70%"` written by the template is silently
  ignored. Twenty-one classes cost about 700 bytes and keep the policy intact.
  Height for the vertical volume bars, width for the horizontal HR-zone bars -
  one set of names serves both.
*/
.bar-0   { height: 0;     width: 0; }
.bar-5   { height: 5%;    width: 5%; }
.bar-10  { height: 10%;   width: 10%; }
.bar-15  { height: 15%;   width: 15%; }
.bar-20  { height: 20%;   width: 20%; }
.bar-25  { height: 25%;   width: 25%; }
.bar-30  { height: 30%;   width: 30%; }
.bar-35  { height: 35%;   width: 35%; }
.bar-40  { height: 40%;   width: 40%; }
.bar-45  { height: 45%;   width: 45%; }
.bar-50  { height: 50%;   width: 50%; }
.bar-55  { height: 55%;   width: 55%; }
.bar-60  { height: 60%;   width: 60%; }
.bar-65  { height: 65%;   width: 65%; }
.bar-70  { height: 70%;   width: 70%; }
.bar-75  { height: 75%;   width: 75%; }
.bar-80  { height: 80%;   width: 80%; }
.bar-85  { height: 85%;   width: 85%; }
.bar-90  { height: 90%;   width: 90%; }
.bar-95  { height: 95%;   width: 95%; }
.bar-100 { height: 100%;  width: 100%; }

/* The volume bar is sized by height; its width always fills the column. */
.volume-fill[class*="bar-"] { width: 100%; }
/* The zone bar is sized by width; its height comes from the track. */
.zone-fill[class*="bar-"] { height: 100%; }
.volume-label { font-family: var(--cond); color: var(--mut2); font-size: 12px; letter-spacing: 1px; margin-top: 8px; }
/* The effort figure is the headline now, so it reads as one - the kilometres under it are the
   working, kept because a bar labelled only "82%" cannot be checked against anything. */
.volume-value { font-family: var(--cond); color: var(--ink-2); font-size: 14px; letter-spacing: 1px; }
/* nowrap: "14 km" is one quantity and a column narrow enough to split it is narrow enough to let
   the figure overhang instead. */
.volume-km { font-family: var(--cond); font-size: 12px; letter-spacing: 1px; white-space: nowrap; }
.volume-basis { margin: 12px 0 0; font-size: 12.5px; }

/* The per-session view, folded away inside the same card: same question, finer resolution. */
.session-bars { margin-top: 14px; border-top: 1px solid var(--line-soft); padding-top: 10px; }
/*
  Rimossa: .session-bars .volume-bars { height: 120px }.

  Era un'altezza sul contenitore mentre l'altezza vera sta sulla barra, e le due si sono
  contraddette appena la barra e' passata a 140: colonne di 140 dentro una scatola di 120, quindi
  venti pixel che uscivano dall'alto e finivano sopra "SEDUTA PER SEDUTA". Segnalato guardandolo -
  "il comando sotto e' coperto dalle colonne". Adesso l'altezza la decide solo la barra e il
  contenitore prende quello che serve.
*/

/* La serie mai spuntata, su una seduta finita, adesso la dice la tabella: un trattino in ogni
   colonna e la casella vuota in fondo alla riga. Qui c'era la coppia .is-skipped/.set-skipped, che
   la diceva a parole sotto ai numeri. */


/* "estimate", on the expenditure tile. Quiet, but present on the number itself rather than only in
   the note below - somebody reading the tile alone must still see it.

   Called .tile-flag and not .tile-warn, which is what it was. That name already belonged to the
   modifier forty lines above - the border and glow a tile gets when the week is spiking - and this
   rule, being later, won. So on exactly the weeks the warning was meant for, the "this week"
   tile stopped being a tile: it took display:inline-block, border-radius:999px, 9px type and 1px
   of padding, shrank to fit its own text and rendered as a pill. Two unrelated things, one class
   name, and the collision only showed above 150%. */
.tile-flag {
  display: inline-block;
  margin-top: 4px;
  padding: 1px 7px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut2);
}
/* One line per discipline under the percentage: "1 / 3 palestra", "7,5 / 12 km corsa". The
   percentage says how the week is going; these say which half of it is behind. */
/*
  ---------- the verdict, then "Espandi" ----------

  The overall reading sits above the figures it is about, so it shows its verdict and keeps the
  reasoning one tap away.

  The clamp is on the first paragraph, not on the block that holds them all. Clamping the block was
  the obvious version and it did not work: the coach's reading is a verdict, a blank line and then
  the reasoning, so what the athlete got was two lines of verdict, a gap, and the reasoning cut
  in the middle of a word - four lines, measured, where three were asked for. -webkit-line-clamp
  counts line boxes and the paragraph margin between them is not one.

  So the fold shows one thing: the sentence the prompt asks the coach to make able to stand alone.
  Three lines is its ceiling rather than its target - it is usually one or two - and the reasoning
  is what the control reveals. Folded, that reasoning is hidden from assistive technology as well as
  from the screen, which is what a disclosure is: the control is announced, and opening it is one
  press for everybody.

  :has sul contenitore perche' il comando viene dopo il testo che governa - che e' il giusto ordine
  di lettura e l'ordine sbagliato per un ~ semplice. Sul .box-comment: e' il contenitore che tiene
  insieme il consiglio e la riga per rispondere, e ogni scheda ha il suo, quindi la regola resta
  chiusa dentro una scheda sola anche con cinque commenti sulla stessa pagina.
*/
.advice-fold .ai-feedback-body > * { display: none; }
.advice-fold .ai-feedback-body > :first-child {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  margin: 0;
}
.box-comment:has(.advice-more[open]) .advice-fold .ai-feedback-body > * { display: block; }
.box-comment:has(.advice-more[open]) .advice-fold .ai-feedback-body > :first-child {
  -webkit-line-clamp: unset;
  overflow: visible;
}
/* Paragraphs of advice, told apart. The reset zeroes every margin in the document, so the coach's
   verdict and the reasoning under it were printed as one wall of text - which for the reading under
   the ring is the difference between a sentence anyone can take in and a paragraph nobody reads.
   Between paragraphs only: nothing above the first one, which would push the text off its own
   card. */
.ai-feedback-body > p + p { margin-top: 10px; }
/* One label at a time: the control says what pressing it will do. */
.advice-more .advice-more-close,
.advice-more[open] .advice-more-open { display: none; }
.advice-more[open] .advice-more-close { display: inline; }

.week-counters { display: flex; flex-direction: column; gap: 2px; margin-top: 4px; }
.week-counter { display: block; font-size: 12px; color: var(--mut); font-variant-numeric: tabular-nums; }
/* "e altre 4": lo stesso controllo della lista dei pasti, in una casella larga meta' schermo.
   Piu' piccolo di quello - qui accanto sta una riga da dodici pixel, non una lista - e comunque
   alto 44 perche' e' una cosa da toccare con un dito. */
.week-more > summary {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  cursor: pointer;
  list-style: none;
  font-family: var(--cond);
  font-size: 11.5px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--accent-text);
}
.week-more > summary::-webkit-details-marker { display: none; }
.week-more > summary:hover { color: var(--accent); }
.week-more[open] > summary .session-detail-mark { transform: rotate(-135deg) translateY(3px); }
.week-more .week-more-close,
.week-more[open] .week-more-open { display: none; }
.week-more[open] .week-more-close { display: inline; }
.week-more > .week-counter { padding-left: 0; }

.load-estimate-note { margin-top: 10px; font-size: 13px; }
.load-estimate-note a { margin-left: 6px; }

/* La piega del giorno prima, sulla carta dell'ultima sessione: dal 27/09 una riga-piega, nel blocco
   «la carta dell'ultima sessione» in fondo al foglio. */

/* The eyebrow belongs to the card, not to the block, so the first block's own heading sits directly
   under it without the gap a second card head would carry. */
.last-session > .card-eyebrow {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 8px;
  margin-bottom: 2px;
}
/* Which day the workouts under it are from. In the ink colour, not the eyebrow's muted grey: the
   eyebrow labels the card and this is a fact about the training, so it has to outrank the label
   beside it rather than read as more of it. Dal 27/09 solo nell'occhiello: la riga-piega del giorno
   prima dice il suo giorno da se' (.last-session-fold-day), e le righe degli allenamenti dicono l'ora
   nella loro riga piccola. */
.last-session-day {
  font-family: var(--cond);
  letter-spacing: 1.2px;
  color: var(--ink-2);
  text-transform: none;
}
.last-session-more .btn { margin-top: 10px; }

/* The chat page gives the thread the screen. On the dashboard it had whatever was left under a bar
   chart, which is not a place to read six sentences. */

/*
  ---------- the chat gets the screen ----------

  Measured at 390x844 before this rule: the coach's text was 228px wide. Twenty-six characters a
  line, on a 390px phone - 58% of the display - and nobody can read six sentences of coaching in a
  column that narrow.

  Nothing was wrong with any single rule. It was four paddings stacked: the shell's 16 a side, the
  card's 20 a side, the bubble's max-width of 84%, and then the bubble's own 16 a side. Each is
  reasonable for a dashboard tile beside eleven others; on the one page whose entire content is
  prose, together they left the prose a third of the screen.

  So the chat page - and only the chat page - undid them: a narrower gutter, and the bubbles taking
  almost the full width of what remains. Since the taglio 7 (26/09) there is no card at all: the
  bubbles carry their own ground, as in the mock.

  Wider than 520px on a desktop rather than "the whole window", and that is the "or nearly" part.
  Prose is read fastest at roughly 60-80 characters a line; 860px of shell works out at about 80,
  and a chat stretched across a 27-inch monitor would be harder to read than the phone was.
*/
.chat-shell { max-width: 860px; }
/* The bar has to move with it or the wordmark sits in the middle of the page above content that
   starts at the edge. :has on the body because nav.top is the layout's, outside this main. */
body:has(.chat-shell) nav.top { max-width: 860px; }

/* 88%, not 84%: at this width the difference is 30 characters a line, and the bubbles still read
   as bubbles - the gap on the far side is what says who is speaking. */
.chat-page .bubble { max-width: 88%; }

@media (max-width: 560px) {
  /*
    The gutter is 12 here, not the 16 of every other page. It was chosen when the conversation sat in
    a card, to win back characters from four stacked paddings (228px of text on a 390px phone, at the
    start). The card went with the taglio 7, and what 12 buys now is small: measured on 27/09, the
    coach's widest bubble has 325px of text at 390 and 297 at 360, against 318 and 289 with 16 - about
    one character a line. And it costs the heading: title, rows and bubbles start 4 points left of the
    logo and of the profile warning above them, and opening /chat from any other page they move.
    Kept as it was, as a decision to take (T7-D21 in DA-FARE §23): 16 everywhere, or 16 for the heading
    and the list and 12 for the thread alone.
  */
  .chat-shell { padding-left: 12px; padding-right: 12px; }
  /* No card: the shell's 12 is the whole margin, and the bubbles have the width the card took. */
  .chat-page .bubble { max-width: 96%; padding: 12px 13px; }
}

/*
  "Back to the latest", floating over the bottom of the screen.

  Hidden while the page is already at the bottom, which is most of the time - a control that is
  always there is a control that is in the way. app.js unhides it once the athlete has scrolled up
  far enough for the newest message to be off screen.

  Fixed to the viewport rather than absolute inside the thread, which is what it was when the
  thread had a bottom edge of its own. The thread is now as tall as the conversation, so its
  bottom-right corner is wherever the last message happens to fall - which on a long thread is
  several screens below the athlete. Lifted clear of the floating bottom bar.
*/
.chat-jump {
  position: fixed;
  right: 14px;
  bottom: calc(var(--bar-h) + 28px);
  /* 44, the measure of a finger (taglio 7: it was 38). */
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--accent-line);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 17px;
  line-height: 1;
  box-shadow: var(--glow-accent-soft);
  z-index: 2;
}

/* "Show earlier messages", centred at the top of the thread. Scrolls away with the conversation
   rather than floating: it is a boundary marker, and its place is where the history stops. */
.thread-earlier { display: flex; justify-content: center; margin: 0 0 4px; }
.chat-jump:hover { filter: brightness(1.06); }

/* ---------- the coach under each box ----------
   Advice, the day's questions about it, and the line the next one is typed into. Quiet throughout:
   it is a footnote to the numbers above, not a second heading competing with them. */
/*
  Il blocco del coach sotto una scheda: avviso, bottoni, attesa, consiglio.

  In colonna con un distacco, e la ragione e' il reset: "* { margin: 0 }" azzera i margini di tutto
  il documento, quindi un avviso, il bottone "riprova" e quello che chiede il parere si toccavano -
  tre comandi diversi che sembravano un blocco solo. "Troppo attaccato, stacca."

  Il gap e non un margine sui figli: i figli sono di quattro tipi diversi e compaiono a due a due a
  seconda di cosa e' successo, quindi qualunque margine scritto su uno di loro lascerebbe scoperta
  una delle combinazioni. La spaziatura appartiene alla colonna, non a chi ci sta dentro.

  Niente align-items: i figli devono restare larghi quanto la carta - il riquadro del consiglio per
  primo - e sono i bottoni dentro ai moduli a essere larghi quanto il loro testo.
*/
.box-comment {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
}
.box-comment .ai-feedback { margin: 0 0 4px; }
.box-comment-wait { font-size: 13px; margin: 0; }
/* When the advice was written. Small, under it: advice is rewritten when something happens rather
   than every day, so a sentence from Tuesday can be correct on Thursday and must say so. */
/* L'ora sta in basso a destra del messaggio, sotto il controllo che lo apre.

   Era centrata, e non per scelta: e' un blocco dentro l'eroe della home, che e' una colonna
   centrata, e l'allineamento del genitore le passava attraverso - lo stesso motivo per cui
   l'"espandi" sembrava messo a caso. text-align: right invece di margin-left: auto perche' e' un
   blocco largo quanto la carta: sono le sue parole a dover andare a destra, non la sua scatola. */
.box-advice-when {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  text-align: right;
}

/*
  ---------- removed: the exchange and the ask line ----------

  Rules for a folded question box under every card and for the one answer it kept. Both are gone
  from the markup: the home had five ways to talk to the coach and now has one, .box-chat-ask,
  which goes to the chat instead of answering in place. What is left of a box is the advice above.
*/

/* The dashboard's notes card: one note, dated, and how many others there are. The whole list, with
   its edit forms, is the subject of /memory - here it was most of the page. The card is itself the
   link, so it needs the anchor reset a card does not normally carry. */
a.memory-card { display: block; color: inherit; }
a.memory-card:hover { text-decoration: none; border-color: var(--accent-line); }
a.memory-card:hover .memory-more { color: var(--accent-text); }
.memory-more { font-family: var(--cond); font-size: 12.5px; letter-spacing: 1.2px; color: var(--mut); }
.memory-when { display: block; margin-top: 3px; font-size: 12px; }
/* The note itself, in the second ink. It shared `.memory-text` with the old tiles of /memory; the
   redesign of 26/09 took that rule away with the tiles and the home card lost it (16px, the body
   ink, a paragraph's margin) - hence scoped to the card now (verifiche del taglio 7, 27/09). */
.memory-card .memory-text { margin: 0 0 9px; font-size: 15.5px; color: var(--ink-2); }

/* ---------- profile picture ---------- */
.avatar-row { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-start; margin: 14px 0 4px; }
.avatar {
  flex: 0 0 auto;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--accent-line);
  background: var(--panel-2, var(--panel));
}
.avatar-lg { width: 96px; height: 96px; }
/* No picture: the first letter of the name, which is better than a grey silhouette and needs no
   image to load. aria-hidden, because the name is already on the page. */
.avatar-initial {
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--cond);
  font-size: 38px;
  font-weight: 700;
  color: var(--accent-text);
}
.avatar-actions { flex: 1 1 200px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.avatar-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.avatar-form label { margin: 0; cursor: pointer; }
/* The input is driven by the label above it, and parked off-screen rather than hidden so it stays
   in the tab order - the same reasoning as the drawer's checkbox. */
.avatar-input { position: absolute; left: -9999px; }

/* ---------- coach tone (taglio 7, mock 22) ----------

   Two controls of three pills (`.programme-pill` in a `.programme-kinds` row, the pills of the house) and
   under each the line of the chosen level: three lines in the markup, the stylesheet shows the one whose
   radio is checked. `:has()` - without it all three show, which is what they were before. The pill
   chosen takes the accent's soft ground, so the chosen level reads as chosen with every palette. */
.coach-tone-card .programme-pill:has(input:checked) { background: var(--accent-soft); }
.coach-tone-card:has(input[value="easy"]:checked) .tone-what:not([data-tone-what="easy"]),
.coach-tone-card:has(input[value="balanced"]:checked) .tone-what:not([data-tone-what="balanced"]),
.coach-tone-card:has(input[value="strict"]:checked) .tone-what:not([data-tone-what="strict"]) { display: none; }
.tone-what { margin: 12px 2px 0; font-size: 14.5px; line-height: 1.45; color: var(--ink-2); text-wrap: pretty; }
.coach-tone-why { margin: -4px 0 10px; font-size: 13.5px; line-height: 1.45; }
.app-shell .coach-tone-save { width: 100%; margin: 20px 0 0; }
/* The note last, with its sign: the mock's shield is not among the icons, and `info` is (T7-D5). */
.coach-tone-limits { display: flex; align-items: flex-start; gap: 10px; margin-top: 18px; }
.coach-tone-limits > .ico { flex: 0 0 auto; width: 18px; height: 18px; margin-top: 1px; color: var(--accent-text); }



/* ---------- activity detail ---------- */
/* Le caselle di questa pagina e quelle dell'ultima seduta sono LA STESSA COSA - stessa griglia,
   stesse classi, stessi dati (distanza, durata, passo, frequenza) - e per mesi sono state scritte
   due volte, qui e nella sezione dell'ultima seduta trecento righe piu' in basso. Due regole con la
   stessa specificita': vinceva la seconda, e questa era gia' mezza morta senza che si vedesse.
   Il tentativo di dare la faccia dell'accento alle caselle e' finito qui e non e' comparso a
   schermo, il che e' esattamente il modo in cui un duplicato si fa pagare.

   Una definizione sola, e sta dove sta il componente: cerca `.metric-grid` nella sezione
   "ultima seduta". Qui non resta niente. */
.chart-box { position: relative; height: 210px; margin-top: 18px; }
.chart-hint { font-size: 12.5px; margin-top: 12px; }

/* I lap: la tabella di Garmin, righe sottili e numeri incolonnati a destra, il totale in grassetto
   sopra un filo. Le cifre tabulari tengono 5:17.7 e 4:26.8 sulla stessa colonna. */
.lap-table {
  width: 100%;
  margin: 12px 0 0;
  border-collapse: collapse;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.lap-table th,
.lap-table td { padding: 9px 4px; text-align: right; }
.lap-table th:first-child,
.lap-table td:first-child { text-align: left; width: 3.2em; }
.lap-table thead th {
  font-family: var(--cond);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut);
  vertical-align: bottom;
}
.lap-unit { display: block; font-size: 10.5px; color: var(--mut2); text-transform: none; }
.lap-table tbody tr + tr td { border-top: 1px solid var(--line-soft); }
.lap-table tfoot th,
.lap-table tfoot td { border-top: 1px solid var(--line); font-weight: 650; }

.zone-list { list-style: none; padding: 0; margin: 16px 0 0; }
.zone { display: grid; grid-template-columns: 1fr auto; gap: 5px 10px; align-items: center; margin-bottom: 14px; }
.zone-name { font-family: var(--cond); font-size: 14.5px; letter-spacing: 1.4px; text-transform: uppercase; }
.zone-range { color: var(--mut); font-size: 12.5px; }
.zone-bar { grid-column: 1 / 2; height: 9px; border-radius: 999px; background: var(--line-soft); overflow: hidden; }
.zone-fill {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, color-mix(in srgb, var(--accent) 35%, transparent), var(--accent));
  box-shadow: 0 0 12px color-mix(in srgb, var(--accent) 35%, transparent);
}
.zone-pct { font-size: 13px; color: var(--mut); }

/* ---------- import ---------- */
/* Le righe degli import sono righe della casa dal 26/09 (.record-tile.job-row, taglio 5), e gli esiti
   di un caricamento hanno la forma della loro riga dello stato: le regole stanno con le altre del
   taglio, in fondo al foglio. Qui resta la pastiglia che usa la memoria del coach. */
.badge {
  flex: 0 0 auto;
  border-radius: 999px;
  padding: 5px 13px;
  border: 1px solid var(--line);
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--mut);
}


/* ---------- chat ---------- */
.thread { display: flex; flex-direction: column; gap: 12px; margin: 18px 0; }
.bubble {
  border: 1px solid var(--line-soft);
  border-radius: 18px;
  padding: 13px 16px;
  max-width: 84%;
  background: var(--card2);
}
.bubble-coach {
  align-self: flex-start;
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 26%, transparent);
}
/*
  The athlete's own messages sit on the right, the coach's on the left, which is
  what every messaging interface has taught people to read.

  .chat-day has to be a flex column for that to work. Grouping the thread by day
  put the bubbles inside a plain <div>, so align-self had no flex parent to align
  against and every bubble silently went back to the left - a layout regression
  introduced by a change that had nothing to do with layout.
*/
.chat-day { display: flex; flex-direction: column; gap: 12px; }
.bubble-athlete {
  align-self: flex-end;
  background: var(--field);
  border-color: var(--line);
}
/* The label reads right-to-left on a right-hand bubble; the text stays
   left-aligned, because centred or right-aligned prose is harder to read. */
.bubble-athlete .bubble-who { justify-content: flex-end; }
.bubble-who { margin-bottom: 5px; letter-spacing: 2px; font-size: 12px; }
.bubble-coach .bubble-who { color: var(--accent-text); }
.bubble-text { font-size: 16.5px; color: var(--ink-2); }
.bubble-text p { margin: 0 0 8px; }
.bubble-text p:last-child { margin-bottom: 0; }
.bubble-text ul, .bubble-text ol { margin: 6px 0; padding-left: 20px; }
/*
  ---------- una risposta con dentro delle sezioni ----------

  Le risposte del coach erano prosa e basta: il prompt vietava titoli ed elenchi. Ora li chiede -
  "le interazioni e la qualita' delle risposte devono essere simili a questa come approfondimenti,
  lunghezza e utilita'" - quindi la bolla deve saperli disegnare, altrimenti arrivano e sembrano
  testo qualunque.

  h4 e non h3: il ripulitore consente h4, h5 e h6 e butta via gli altri, quindi un "###" del modello
  perderebbe il tag e resterebbe una riga di testo indistinguibile. Il prompt chiede quattro cancelli
  per questo, e queste due regole sono l'altra meta' dello stesso accordo.

  Piu' aria sopra che sotto: un titolo appartiene a quello che introduce, non a quello che lo
  precede, e la distanza e' come si vede senza leggere.
*/
.bubble-text h4, .bubble-text h5, .bubble-text h6 {
  margin: 18px 0 6px;
  font-family: var(--cond);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .6px;
  color: var(--ink);
}
.bubble-text > h4:first-child { margin-top: 0; }
.bubble-text li { margin: 0 0 5px; }
.bubble-text li:last-child { margin-bottom: 0; }
/* L'etichetta in neretto che apre ogni punto: e' quella che rende scorribile un elenco di cinque. */
.bubble-text strong { color: var(--ink); font-weight: 700; }
.bubble-text code {
  background: var(--track);
  padding: 1px 6px;
  border-radius: 6px;
  font-size: 13.5px;
}

/*
  I collegamenti rapidi sotto a una risposta del coach.

  Sono la seconda meta' di quello che il coach dice quando l'atleta annuncia una decisione - "voglio
  perdere 4kg" - e vanno letti come parte della risposta, non come una barra di navigazione: quindi
  dentro alla bolla, sotto al testo, staccati da un filo.

  Pastiglie con il bordo e non bottoni pieni: il bottone pieno di una scheda e' quello che comincia
  qualcosa e su questa pagina non ce ne sono, ma due bottoni accesi sotto a ogni risposta sarebbero
  la cosa piu' rumorosa del filo. Vanno a capo da soli, perche' "piano di allenamento AI" accanto a
  "scheda alimentare" su un telefono da 390 pixel non ci sta.

  Alti 36 e non 44: la riga di sotto e' un'altra pastiglia e non del testo, quindi il dito non ha
  niente di sbagliato da colpire qui intorno, e 44 sotto a ogni risposta allungherebbe il filo.
*/
.bubble-links {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--line-soft);
}
.bubble-link {
  display: inline;
  color: var(--accent-text);
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-transform: none;
  text-decoration: underline;
  text-decoration-color: var(--accent-line);
  text-underline-offset: 3px;
}
/* The accent to read, not the bare one: with volt in the light theme the bare accent is yellow on white,
   and the link vanished under the pointer (verifiche del taglio 7, 27/09). */
.bubble-link:hover {
  text-decoration-color: currentColor;
}
.bubble-link:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 3px;
}

/* A pending coach write has two unambiguous choices, kept beside the proposal. */
.chat-action-choices {
  width: min(100%, 280px);
  margin: 12px 0 4px;
}
/* The row is the fieldset's: it is there so that one hx-disabled-elt puts both buttons out (taglio 7,
   D5), and a bare fieldset brings a border, a padding, a margin and a min-inline-size of its own. */
.chat-action-choices fieldset {
  display: flex;
  gap: 10px;
  min-inline-size: 0;
  margin: 0;
  padding: 0;
  border: 0;
}
.chat-action-choices .btn {
  flex: 1 1 0;
  width: auto;
  margin: 0;
}

/*
  scroll-margin-bottom, and it is load-bearing rather than cosmetic.

  app.js brings the conversation's end into view by scrolling this form to the bottom of the
  viewport - the page's own bottom is past the list of earlier conversations, below the newest
  message. Without a margin the browser tucks the form exactly against the bottom edge, which is
  where the floating bottom bar sits, so the input the athlete was sent to would be underneath it.
*/
/*
  Il posto dove si scrive, largo quanto il messaggio qui sopra.

  Era una riga di tre cose affiancate: un campo stretto, la macchina fotografica e una pastiglia
  con scritto INVIA. Su un telefono il campo restava largo la meta' della bolla che gli stava sopra,
  e la parola INVIA si prendeva il quarto di riga che mancava al campo.

  Adesso e' una scatola sola, larga quanto la conversazione: il testo occupa tutta la prima riga e i
  due comandi stanno nell'angolo in basso a destra, dove li mette qualunque applicazione di messaggi.
  Niente da imparare e niente da leggere.
*/
.chat-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 16px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  /* The mock's box, drawn on the two floors of before: the sheet's ground and a fixed radius. A pill
     (999) cut the corners of two lines of text (critica della pagina, E1). */
  border-radius: 24px;
  background: var(--panel);
  scroll-margin-bottom: calc(var(--bar-h) + 24px);
}
/* Tutta la prima riga per se': e' il pezzo che si legge mentre si scrive. */
.chat-form #chat-input {
  flex: 1 1 100%;
  margin: 0;
  padding: 6px 4px;
  border: none;
  background: none;
  border-radius: 0;
  resize: none;
  overflow-y: auto;
  /* Due righe esatte e non una di piu': oltre, la conversazione sparisce sotto a cio' che si sta
     scrivendo. app.js alza la scatola fino a qui e poi la lascia scorrere.
     3.8em = due interlinee (1.5 ciascuna) piu' i 12 pixel di spaziatura sopra e sotto, che a 16px
     fanno 0.75em. Misurato: vuota 35, due righe 57, e da li' non sale piu'. */
  max-height: 3.8em;
  line-height: 1.5;
}
.chat-form #chat-input:focus-visible { outline: none; }
/* Il fuoco si vede sulla scatola intera, non sul campo che dentro non ha bordi suoi. */
.chat-form:focus-within { border-color: var(--accent-line); }
/*
  Le foto scelte, e la riga che dice che ci si puo' scrivere accanto.

  Tutte e due su una riga propria sotto alla casella: la barra della chat e' una griglia di tre
  colonne - testo, graffetta, invio - e un quarto elemento in linea stringerebbe proprio il campo di
  testo, che e' la cosa per cui la barra esiste. flex-basis 100% le manda a capo dentro alla stessa
  scatola, cosi' restano dentro al bordo che si accende quando la barra ha il fuoco.

  Il nome del file e' testo dell'atleta: 12.5px come le altre note, e mai innerHTML - app.js lo
  scrive con textContent.
*/
.chat-chosen,
.chat-photo-hint {
  flex: 0 0 100%;
  margin: 6px 4px 0;
  font-size: 12.5px;
  line-height: 1.35;
}
.chat-chosen { color: var(--accent-text); }

/* I due comandi, in fondo a destra. */
.chat-form .chat-clip { margin-left: auto; }
.chat-send {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin: 0;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--accent-line);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}
/* Nessun alone qui. L'alone e' il segno di "questa e' la cosa da premere" e sulla pagina ne esiste
   uno solo per volta: il bottone pieno di una scheda, e quello che riporta in fondo alla chat.
   Questo e' gia' pieno, tondo e nel colore dell'accento - si vede senza. Alla pressione non si muove,
   come ogni bottone dal 25/09 (stringeva, fino al taglio 7). Spento mentre la domanda viaggia
   (hx-disabled-elt), e si vede: prima spento era uguale ad acceso. */
.chat-send:hover { filter: brightness(1.08); }
.chat-send:disabled { opacity: .45; filter: none; cursor: default; }

/*
  ---------- the clip in the chat composer ----------

  A <label> holding a hidden file input, because a file input cannot be styled into a 44px round
  control and this row is already three items wide on a 390px screen. The label IS the button: a click
  anywhere on it opens the sheet, which on a phone offers the camera and the library together.

  The input is moved out of sight rather than display:none - a hidden input is still focusable and
  still announced, and display:none takes it out of the tab order entirely.
*/
.chat-clip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  margin: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--field);
  color: var(--mut);
  cursor: pointer;
}
.chat-clip:hover, .chat-clip:focus-within { color: var(--accent-text); border-color: var(--accent-text); }
.chat-clip input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
/*
  ---------- a photograph offered as a note ----------

  In the sheet «Aggiungi una nota», under the box, because it fills it: the reading comes back with the
  sentence already in the box and the athlete presses the button that was already there. A button of
  the note's own form since 26/09 (the box is the caption, and a form of its own lost it without the
  script).
*/
.memory-sheet input[type="file"] { margin-top: 4px; }
.memory-photo-hint { font-size: 12.5px; margin-top: 8px; }
.memory-sheet .memory-photo-read { width: 100%; margin-top: 12px; }
.memory-photo-reading { margin-top: 14px; }
.memory-photo-nothing { font-size: 12.5px; margin-top: 8px; }
.htmx-indicator { display: none; margin-top: 12px; font-size: 13.5px; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { display: block; }

/*
  ---------- the waits that are long enough to be worth drawing ----------

  Four animations, one per wait that genuinely takes seconds: the coach writing, a meal photo being
  read, a schedule photo being read, a finished session being analysed. Everything else in the
  application that shows a pending state is a swap of a fifth of a second, and it keeps its plain
  sentence - an animation there would advertise a wait nobody had noticed, which makes the app feel
  slower rather than friendlier.

  Themed rather than generic on purpose. Shoes while the coach reads your running, a barbell while
  it reads your gym, a fork while it reads your lunch: the animation is saying what is happening,
  which is the difference between craft and decoration.

  All motion is here, none of it is JavaScript, and there is not a byte of network in it - the
  content security policy allows no inline script or style, and these need neither.
*/
/*
  A label for a screen reader and for nobody else.

  It was already being used - the chat input's label carries `class="sr-only"` - and the class had
  never been written. So the label was fully visible above the composer, in the styling of a form
  label, reading "??chat.label_it??" because the message key did not exist either. Two halves of
  the same omission, on the page people use most.

  Not display:none and not visibility:hidden: both remove the element from the accessibility tree,
  which is exactly the thing this class exists to keep. Same technique as the hidden file inputs
  above, for the same reason.
*/
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/*
  ---------- when a wait is on screen, and when it is not ----------

  Three rules, and the order of the middle one is the whole thing.

  The first version had only `.waiting-wrap { display: flex }`. It sits below
  `.htmx-indicator { display: none }` in this file and has exactly the same specificity - one class
  each - so the later rule won and every indicator was permanently visible. The nutrition card said
  "sto stimando" with a fork animating beside it on a page where nothing had been uploaded; the
  chat said "Hybrx sta scrivendo" with nobody writing. An animation that is always running is not a
  loading state, it is a decoration that lies.

  So the hidden state is restated at two classes, which beats the flex, and the shown state at
  three, which beats them both. Specificity all the way up rather than an !important, because the
  next person adding a state to this element needs somewhere above it to stand.
*/
.waiting-wrap { display: flex; align-items: center; gap: 10px; }
/* An indicator is hidden until HTMX says otherwise, and .waiting-wrap must not undo that. */
.htmx-indicator.waiting-wrap { display: none; }
/* In flight: flex, so the animation and its sentence sit on one line. */
.htmx-request .waiting-wrap.htmx-indicator,
.htmx-request.waiting-wrap.htmx-indicator { display: flex; }
.waiting {
  width: 52px;
  height: 26px;
  flex: 0 0 auto;
  overflow: visible;
  color: var(--accent-text);
}
.waiting-label { font-size: 13.5px; color: var(--mut); }

/* The stride. Each shoe lifts and settles, half a cycle apart, so the pair reads as running
   rather than as two things bouncing together. */
.waiting-shoes .shoe { animation: shoe-step 620ms ease-in-out infinite; }
.waiting-shoes .shoe-front { animation-delay: 310ms; }
.waiting-shoes .ground { opacity: .35; animation: ground-pass 620ms linear infinite; }
.waiting-shoes .shoe-front .ground { animation-delay: 310ms; }
@keyframes shoe-step {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  35% { transform: translateY(-5px) rotate(-8deg); }
  70% { transform: translateY(-1px) rotate(2deg); }
}
@keyframes ground-pass {
  0% { opacity: .05; transform: translateX(3px); }
  50% { opacity: .4; }
  100% { opacity: .05; transform: translateX(-3px); }
}

/* The press. The bar travels and the plates flex a little at the ends, which is what a loaded bar
   does - it is what makes the weight legible without drawing somebody holding it. */
.waiting-barbell .bar { animation: bar-press 1.15s ease-in-out infinite; }
.waiting-barbell .plate { animation: plate-flex 1.15s ease-in-out infinite; }
.waiting-barbell .rack { opacity: .28; }
@keyframes bar-press {
  0%, 100% { transform: translateY(3px); }
  45% { transform: translateY(-4px); }
}
@keyframes plate-flex {
  0%, 100% { transform: scaleY(1); }
  45% { transform: scaleY(.88); }
}

/* The fork moves and the plate does not: the food is the subject, the reading is the activity. */
.waiting-fork .fork { animation: fork-dip 1.1s ease-in-out infinite; transform-origin: 52px 6px; }
.waiting-fork .plate-rim { opacity: .5; }
.waiting-fork .plate-inner { opacity: .25; animation: plate-pulse 1.8s ease-in-out infinite; }
@keyframes fork-dip {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  40% { transform: translate(-13px, 4px) rotate(-14deg); }
  60% { transform: translate(-13px, 2px) rotate(-14deg); }
}
@keyframes plate-pulse {
  0%, 100% { opacity: .18; }
  50% { opacity: .4; }
}

/* The fallback, for a wait with no subject of its own. Quietest of the four by design. */
.waiting-dots .dot { animation: dot-rise 1.05s ease-in-out infinite; }
.waiting-dots .dot-2 { animation-delay: 150ms; }
.waiting-dots .dot-3 { animation-delay: 300ms; }
@keyframes dot-rise {
  0%, 100% { transform: translateY(0); opacity: .35; }
  40% { transform: translateY(-5px); opacity: 1; }
}

/*
  Motion off, animation still there.

  Not display:none. Somebody who has asked their system for less movement still needs to know the
  coach is working, and the shape beside the sentence is what says so - it just stops moving. The
  wording next to it carries the meaning either way, which is why none of these is the only thing
  telling the athlete anything.
*/
@media (prefers-reduced-motion: reduce) {
  .waiting *, .waiting { animation: none !important; }
}

/* A request in flight has to be visible even where no indicator element exists.
   Without this, pressing Remove on a schedule did nothing at all for as long as the
   round trip took: no spinner, no dimming, no disabled button. On a phone that reads
   as a dead button, so the athlete pressed another one - and the first swap landing a
   moment later looked like the second press had caused it. The row was never late;
   there was simply nothing on screen saying anything was happening. */
form.htmx-request { opacity: .55; }
form.htmx-request button,
button.htmx-request { cursor: progress; }
/* Pressed and waiting: the button keeps its size (no layout jump) and pulses. */
form.htmx-request button, button.htmx-request { animation: pending 1s ease-in-out infinite; }
@keyframes pending { 50% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) {
  form.htmx-request button, button.htmx-request { animation: none; }
}

/* The earlier conversations, rows of the house (taglio 7): the title cut with dots, the day on the right.
   Under them the cap said, and «Nuova conversazione» at full width. */
.chat-conversations-cap { margin: 10px 2px 0; font-size: 12.5px; }
.chat-conversations > .chat-new { display: flex; justify-content: center; width: 100%; margin: 14px 0 0; }
/* «Conversazioni», at the end of the line under the title: a finger's 44 as a box, with the same
   margins taken back so the line keeps its height and the word its place (84×20 until the checks of
   27/09). */
.chat-top-list {
  display: inline-flex;
  align-items: center;
  min-width: 44px;
  min-height: 44px;
  margin: -12px -8px;
  padding: 0 8px;
  color: var(--accent-text);
  white-space: nowrap;
}

/* ---------- coach memory (taglio 7, mock 24) ----------

   A note is a row of the house (`.record-tile.memory-row`, in the group of the rows further down). What
   it has more: THE NOTE WHOLE, on as many lines as it takes - the content, not a name, on the page of
   the transparency owed to the athlete; an address pasted without spaces breaks where it must (T7-D9) -
   and «Modifica» at the end of the small line, in the accent, as on the dates of the home. */
.record-tile.memory-row .record-what {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  overflow-wrap: anywhere;
  font-size: 15.5px;
  font-weight: 500;
  line-height: 1.4;
}
.record-tile.memory-row .record-ico { align-self: flex-start; }
.record-tile.memory-row > .record-open { align-items: flex-start; }
/* Chi, quando e «Modifica»: a 360 punti con la X accanto non ci stanno in una riga, e «Modifica» si
   tagliava a «MOD» (misurato il 27/09). Va a capo, e resta a destra. */
.memory-row-sub { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px .6em; }
.memory-row-sub > * { flex: none; }
.memory-row-when::before { content: "\00b7\00a0"; }
/* «Modifica» e' la tessera con la penna, come sulle date (.event-row-edit, 27/09): qui la X sta in cima alla
   riga, perche' una nota puo' andare a capo, e la penna le sta accanto alla stessa altezza. Il collegamento le
   lascia il posto, cosi' che il testo della nota non le passi sotto. */
.memory-row-edit { color: var(--accent-text); position: absolute; top: 6px; right: 0; width: 44px; height: 44px; font-size: 0; }
.record-tile.memory-row > .record-open { position: relative; padding-right: 54px; }
.memory-row-anchor { display: block; height: 0; scroll-margin-top: 90px; }
.record-tile.memory-row > .record-erase { align-self: flex-start; padding: 6px 4px 0 0; }
.record-tile.memory-row .orb-x { width: 44px; height: 44px; min-width: 44px; min-height: 44px; }
/* A note no longer true stays on the page - it is the athlete's, and the day a pain began is worth
   knowing after it ended - but stops weighing like the others: struck through, quieter, in a section of
   its own under the open ones, which answer first the question "what holds now". */
.memory-row.is-closed .record-what { color: var(--mut); text-decoration: line-through; text-decoration-color: var(--mut2); }
.memory-row.is-closed > .record-erase { align-self: center; }
/*
  "Forget" and its kind: a quiet pill, not underlined red text.

  Underlined danger-coloured text read as a broken link and shouted louder than
  the note it belonged to. It is a small, reversible action on a line of metadata,
  so it should look like the badge next to it and only turn red on approach.
*/
.link-button {
  flex: 0 0 auto;
  border-radius: 999px;
  padding: 5px 12px;
  border: 1px solid var(--line);
  background: none;
  color: var(--mut);
  cursor: pointer;
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  text-decoration: none;
  transition: border-color .15s ease, color .15s ease;
}
.link-button:hover, .link-button:focus-visible {
  border-color: rgba(255, 92, 92, .5);
  color: var(--danger);
}

/* ---------- footer ---------- */
.site-footer {
  position: relative;
  z-index: 1;
  margin-top: 40px;
  border-top: 1px solid var(--line-soft);
  background: linear-gradient(180deg, var(--field-soft), transparent);
}
.footer-inner {
  max-width: 520px;
  margin: 0 auto;
  padding: 26px 16px 34px;
  text-align: center;
}
.footer-brand { display: flex; align-items: baseline; justify-content: center; gap: 10px; }
/* Il marchio nel pie' di pagina: lo stesso file di tutti gli altri, solo piu' piccolo. Le regole
   che lo scrivevano a mano - peso 800, colore dell'accento, gradiente ritagliato sul testo - se ne
   sono andate con la parola che vestivano. */
.footer-brand .logo-mark { height: 19px; }
.footer-tagline {
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 2.2px;
  text-transform: uppercase;
  color: var(--mut2);
}
.footer-links {
  display: flex;
  justify-content: center;
  gap: 18px;
  margin-top: 14px;
  font-family: var(--cond);
  font-size: 13px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
}
/* "EN" is two characters, and it was a 16x20 target. The row keeps its look; each link gets the
   44px box a thumb needs, which is also what stops EN and IT being one mis-tap apart. */
.footer-links a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 6px;
  color: var(--mut);
}
.footer-links a:hover { color: var(--accent-text); text-decoration: none; }
.footer-note { margin-top: 14px; font-size: 12.5px; color: var(--mut2); line-height: 1.6; }
.footer-copy { margin-top: 10px; font-size: 12px; color: var(--mut2); }

/* ---------- hamburger menu ---------- */
/* Smooth scrolling for the in-page anchors, with room for the sticky bar. */
html { scroll-behavior: smooth; }
/* Sotto la barra appiccicata, che adesso e' dieci pixel piu' alta. E le due ancore del menu su
   /plans, che dal 26/09 non stanno piu' su una <section>: #nuova e' il comando stesso, e senza lo
   scarto atterrava sotto la barra, coperto (verifiche del taglio 4a). E ogni foglio con un id: senza
   script un foglio aperto dal server e' un pannello nel flusso, e l'indirizzo porta alla sua ancora -
   l'occhiello, il titolo e la X finivano dietro la barra, 16 casi su 16 col dito a 360 e 390 (verifica
   del browser del taglio 6, D1, 26/09). E le frasi dove un rifiuto senza script riporta (taglio 7): quella
   del check-up era a 736 punti su 800, sotto la barra in basso; quella della chat e delle note, e l'ultimo
   messaggio dopo una risposta. */
section[id],
dialog[id],
details#pasto,
#nuova,
#schede,
#checkin-errore,
#chat-errore,
#chat-ultimo,
#memory-errore { scroll-margin-top: 90px; }
/* Il rifiuto di un esercizio del tracker, dove il redirect senza script porta (26/09): a un terzo
   dello schermo e non sotto la barra, dove atterrava coperto, cosi' sopra si vedono le serie da
   correggere, o sotto il bottone del coach appena premuto. */
.session-refusal { scroll-margin-top: 40vh; }

/*
  The bar is sticky, so whatever scrolls under it must not read through it.
  A translucent background plus backdrop-filter looked right until you scrolled a
  heading behind it - and backdrop-filter is exactly the property that is missing
  or disabled on the widest range of devices, so the fallback has to stand on its
  own. Nearly-opaque background, with the blur left in as decoration for browsers
  that have it.
*/
nav.top {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--bar);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-soft);
}

.rbtn {
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--mut);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.rbtn:hover { border-color: var(--accent-line); color: var(--accent-text); }

/* Lo spazio si apre prima del tema, non prima del profilo: cosi' i due controlli stanno insieme a
   destra e il marchio ha tutta la sinistra. Con l'auto sull'ultimo dei due la luna restava
   appiccicata al logo, in mezzo al niente. */
.top .appearance { margin-left: auto; }

/* ---------- qui c'erano le tre righe dell'hamburger ----------

   Se ne sono andate con lui: il cassetto si apre dalla barra in basso, e li' le tre righe sono un
   tracciato SVG come le altre quattro icone accanto - tre <span> colorati fra quattro tracciati si
   leggerebbero come un segno di un'altra famiglia. La <label> che apre il cassetto e' rimasta una
   <label>, quindi il menu continua ad aprirsi senza una riga di JavaScript. */

/*
  Side drawer.

  Slides in from the right over a dimmed page. Driven entirely by the checkbox:
  no script, so it survives a blocked or failed app.js, and it needs no inline
  handler that the Content-Security-Policy would have to allow.

  Transform + visibility rather than `display`, so the slide can be animated and
  so the panel is genuinely non-interactive while closed - `visibility: hidden`
  takes it out of hit-testing and out of the tab order, which `opacity: 0` alone
  would not.
*/
.menu-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
/* Focusing the hidden checkbox must still show on the button the user sees - che adesso e' la
   voce del menu nella barra in basso. */
.menu-toggle:focus-visible ~ .bottom-bar .bar-menu {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.menu-scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: var(--scrim);
  opacity: 0;
  visibility: hidden;
  transition: opacity .22s ease, visibility .22s;
  cursor: pointer;
}

.menu-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 41;
  width: min(300px, 84vw);
  padding: 18px 16px calc(24px + env(safe-area-inset-bottom, 0px));
  overflow-y: auto;
  /* Lo scorrimento resta nel cassetto: trascinato oltre la fine portava con se' la pagina sotto (verifiche
     del taglio 9, 27/09). Come i fogli. */
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-left: 1px solid var(--line);
  background: var(--panel);
  box-shadow: var(--shadow-panel);
  transform: translateX(100%);
  visibility: hidden;
  transition: transform .24s ease, visibility .24s;
}

.menu-toggle:checked ~ .menu-scrim { opacity: 1; visibility: visible; }
.menu-toggle:checked ~ .menu-panel { transform: translateX(0); visibility: visible; }

@media (prefers-reduced-motion: reduce) {
  .menu-scrim, .menu-panel { transition: none; }
}

.menu-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}
/* La foto del profilo in testata, grande quanto la X che chiude: e sotto l'iniziale, che resta
   quando la foto non c'e'. Il titolo prende lo spazio in mezzo e la X resta sul bordo destro. */
.menu-avatar {
  position: relative;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--surface-2);
  display: grid;
  place-items: center;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 18px;
  font-weight: 700;
}
.menu-avatar-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.menu-head .menu-title { flex: 1 1 0; }
.menu-title {
  font-family: var(--cond);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--mut2);
}
.menu-close { margin: 0; }

.menu-panel a, .menu-logout, .menu-panel .menu-group > summary {
  display: block;
  width: 100%;
  padding: 12px 12px;
  border: none;
  border-radius: 10px;
  background: none;
  color: var(--mut);
  font-family: var(--cond);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  text-align: left;
}
/*
  Il passaggio del dito, il fuoco da tastiera - e la pagina in cui sei gia'.

  "Quando apro il menu la pagina corrente, se presente nel menu, deve essere evidenziata come se
  fossi in hover." Sono lo stesso aspetto perche' dicono la stessa cosa - "questa qui" - e darle due
  aspetti diversi sarebbe stato inventare un secondo linguaggio per un'informazione sola.

  Una differenza c'e', ed e' voluta: la voce corrente porta anche il pallino acceso sul ramo. Il
  passaggio del dito e' una cosa che succede e finisce; dove sei e' una cosa che resta, e resta anche
  quando il dito e' passato oltre e ha acceso un'altra riga.

  IL FILO SUL FIANCO NON C'E' PIU'. Era un'ombra interna da tre pixel sul bordo sinistro, e dentro
  una pastiglia con gli angoli tondi si leggeva come una parentesi aperta: "togli quella parentesi e
  lascia solo il pallino colorato che ricordi che pagina c'e' aperta ora". Aveva anche una ragione
  piu' vecchia per andarsene: quel filo era nato quando il cassetto non aveva un albero, cioe'
  quando nessun altro segno diceva dove si era. Adesso il pallino lo dice, e lo dice meglio - sta
  sul ramo, quindi dice anche dentro cosa.
*/
.menu-panel a:hover, .menu-logout:hover,
.menu-panel a:focus-visible,
.menu-panel a[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--ink);
  text-decoration: none;
}
/*
  IL COLORE DICE IL LIVELLO, IL FONDO DICE "SEI QUI", e i due non si possono scambiare.

  "Attivita' programmate e' sotto Allenamenti: perche' e' rossa? Non e' coerente." Aveva ragione, ed
  e' un difetto di grammatica e non di gusto: in questo cassetto l'accento vuol dire UN SOLO LIVELLO
  - le voci di primo livello sono tutte accese, le sottovoci tutte spente - e la pagina corrente
  prendeva l'accento qualunque fosse il suo livello. Una sottovoce accesa si legge come una voce di
  primo livello, cioe' l'albero dice una cosa e il colore un'altra.

  Adesso "sei qui" lo dicono il fondo, il filo sul fianco e - da quando c'e' l'albero - il pallino
  acceso sul ramo. Il testo torna a dire solo a che altezza si e': acceso se e' di primo livello,
  chiaro se e' una sottovoce, spento se non e' nessuna delle due. Tre segni per una domanda sola e
  nessuno che ne risponde a due.
*/
.menu-panel .menu-top:hover,
.menu-panel .menu-top:focus-visible,
.menu-panel .menu-top[aria-current="page"] { color: var(--accent-text); }

/*
  Le icone accanto alle voci di primo livello: "lascia le icone a lato delle voci nel menu
  laterale", l'unica cosa del ridisegno tenuta insieme alla foto. Sono quelle dell'applicazione, dal
  frammento delle icone, e sempre del colore del testo - bianche nel tema scuro, nere nel chiaro -
  perche' il colore di una voce qui dice gia' il suo livello, e un'icona d'accento accanto a una
  scritta d'accento sarebbe lo stesso segno due volte. Le sottovoci restano senza: e' l'albero a
  legarle alla voce che le apre.
*/
.menu-panel .menu-top {
  display: flex;
  align-items: center;
  gap: 12px;
}
.menu-panel .menu-top > .ico {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  display: block;
  color: var(--ink);
}
.menu-panel .menu-top > .menu-label { flex: 1 1 0; min-width: 0; }

/* ---------- the drawer's eleven entries ----------

   One line each, and each of them a link out of the menu. This was briefly a tree of <details>
   with numbers down the side; it read as a table of contents, the longer labels wrapped, and
   opening a section shifted everything below it while the athlete was reaching for something else.

   Nothing here wraps. The two longest labels - "Piano di allenamento AI", "I tuoi dati e
   abbonamento" - are what the sizing is set against: slightly tighter letter-spacing than the rest
   of the interface. nowrap rather than an ellipsis, because a menu entry that has been cut off is
   not a menu entry.

   There was a second style here, .menu-soon, for an entry listed before it was built: text with a
   badge instead of a link. Every section it was written for has shipped, so nothing rendered it any
   more - forty lines of stylesheet, a message key and a test guarding a state the application can no
   longer be in. Gone. If a section is ever listed early again it is a badge and a span, which is
   less work than reading dead rules for the rest of the project. */
.menu-panel a {
  white-space: nowrap;
  letter-spacing: 1.2px;
  font-size: 14px;
}

.menu-sep { display: block; height: 1px; margin: 10px 4px; background: var(--line-soft); }
.menu-langs { display: flex; gap: 4px; }
.menu-langs a {
  width: auto;
  min-height: 44px;
  min-width: 44px;
  padding: 8px 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.menu-logout {
  display: flex;
  align-items: center;
  min-height: 44px;
  margin-top: auto;
  color: var(--danger);
  cursor: pointer;
}
.menu-panel form { margin: 0; }

/*
  Il promemoria dell'installazione, in fondo al menu.

  Scritto per intero e non dietro un bottone che lo apre: nel menu non c'e' niente che si pieghi -
  e' la regola rimasta da quando le voci erano un sommario di sezioni numerate - e comunque tre
  righe brevi occupano meno di quanto occuperebbe il comando per farle comparire.

  Non e' un collegamento, e non per pigrizia: la pagina che spiega come si installa e' la vetrina,
  e la vetrina rimanda al cruscotto chiunque abbia gia' un accesso, cioe' chiunque possa aprire
  questo menu. Quindi la spiegazione sta qui.
*/
.menu-install { padding: 4px 12px 2px; }
.menu-install-title {
  margin: 0 0 7px;
  color: var(--accent-text);
  font-family: var(--cond);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 1.3px;
  text-transform: uppercase;
}

/* Piu' piccolo delle voci e piu' fitto: e' una nota a pie' di menu, non una sedicesima riga da
   leggere ogni volta che il cassetto si apre. */
.menu-install-steps {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 12.5px;
  line-height: 1.42;
  color: var(--mut);
}

/*
  Dentro l'applicazione installata il promemoria non c'e' piu'.

  "display-mode: standalone" e' vero soltanto li', cioe' esattamente quando invitare a installare
  vuol dire invitare a rifare una cosa gia' fatta. Nessuno stato da salvare e niente da spuntare:
  cio' che il promemoria chiede di fare e' anche cio' che lo spegne, e lo spegne su ogni telefono
  senza che il server sappia niente di nessuno di loro.
*/
@media (display-mode: standalone) {
  .menu-install { display: none; }
}

/* ---------- section headers and chips ---------- */
.card-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.status {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--cond);
  font-size: 11.5px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--accent-text);
}
.status .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
}
/* "All" is four characters and was a 38x20 target in the corner of a card. The type stays the
   size it is; the box around it reaches the thumb minimum. */
.link-more {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 4px;
  font-family: var(--cond);
  font-size: 13px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
}

/* The .chip rules lived here: a pill with a halo, used by the coach card's three suggested
   questions and by nothing else. The card is gone, so they are. */

/* The native file input renders a grey system button that ignores the theme.
   ::file-selector-button is the standards-track way to restyle it - no wrapper
   markup, no JavaScript, and the input stays a real input for accessibility. */
input[type="file"] {
  border-radius: 999px;
  padding: 10px 10px 10px 16px;
  color: var(--mut);
  cursor: pointer;
}
input[type="file"]::file-selector-button {
  margin-right: 14px;
  padding: 10px 18px;
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent-text);
  font-family: var(--cond);
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  cursor: pointer;
}
input[type="file"]::file-selector-button:hover {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  box-shadow: 0 0 16px color-mix(in srgb, var(--accent) 20%, transparent);
}
input[type="file"]:hover { border-color: var(--accent-line); }

/* ---------- colour selector, top right ---------- */
/*
  Closed it is one small pill: the accent in force and the mode in force, which is all the athlete
  needs to see from the top bar. Open it holds the four colours and the switch.

  A <details>, so it opens with no JavaScript. The panel is absolutely positioned and the <details>
  is the containing block, which is what keeps the bar from growing taller when it opens - a top bar
  that changes height pushes the whole page down.

  Every rule here is nested under .appearance, and that is not tidiness: these are buttons inside
  nav.top, and "nav.top button" scores one class plus two elements, which beats a bare ".swatch" of
  one class. Measured the hard way - the swatches first rendered as the bar's dark pills with no
  colour at all, because the generic rule won.
*/
/* NON posizionato, ed e' la correzione di un difetto vero: "aggiusta l'editor palette perche' e'
   sbordato".

   Era position: relative, quindi il pannello appeso sotto si misurava su QUESTO controllo - largo
   una quarantina di pixel e appoggiato al bordo destro della barra. Ancorato a destra, cresceva
   verso sinistra: con sette pastiglie da quarantaquattro pixel l'una arrivava a trecentotrenta, e su
   un telefono da trecentonovanta il suo bordo sinistro finiva FUORI dallo schermo. Nessun valore era
   sbagliato: era sbagliato il righello.

   Senza position, il pannello si misura su nav.top - la barra intera, larga al massimo 520 e mai
   piu' del telefono - e left/right a zero lo fanno largo quanto lei. Da li' non puo' uscire, perche'
   non c'e' piu' un "fuori": il suo contenitore E' la pagina. */
.appearance {
  margin: 0 4px 0 0;
}

/*
  ---------- the language, beside the colours ----------

  The same pill as the colour control, and deliberately so: two controls that do the same kind of thing
  - change how the application presents itself - should look like two of one thing rather than two
  inventions. It takes the auto margin that used to push the colour pill right, so the pair sits
  together at the end of the bar.

  It reuses .appearance-panel for the dropdown. One definition of "a small panel hanging off a control
  in the top bar", so the two cannot drift apart by a pixel.
*/
/* A thin outline, because the white band of either flag would otherwise bleed into a light page. */
.flag { display: block; border: 1px solid var(--line); border-radius: 2px; }
.appearance > summary {
  display: flex;
  align-items: center;
  min-height: 44px;
  gap: 8px;
  /* Quattordici ai lati e non dieci: con dieci il pallino toccava il bordo della pillola, e su un
     controllo tondo due cerchi che si sfiorano si notano prima di qualunque altra cosa. */
  padding: 5px 14px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--field);
  color: var(--mut);
  cursor: pointer;
  list-style: none;
}
.appearance > summary::-webkit-details-marker { display: none; }
.appearance > summary:hover { border-color: var(--accent-line); color: var(--accent-text); }
.appearance[open] > summary { border-color: var(--accent-line); color: var(--accent-text); }

/*
  Il pannello del tema si appende sotto al suo pulsante, e non sta nel flusso della pagina.

  Questa regola era scritta per due controlli - il tema e la lingua - con i due selettori
  raggruppati. Togliendo la lingua ho cancellato il blocco intero insieme al suo secondo selettore,
  e il pannello e' rimasto senza position: absolute: apriva dentro la barra, spingendo il marchio e
  i colori in mezzo alla pagina.

  E' il rischio di cancellare CSS con un'espressione regolare: un selettore raggruppato non e' una
  riga, e una riga sola di quel gruppo si porta via le dichiarazioni di tutti. Adesso il selettore
  e' uno, quindi la prossima potatura non puo' fare lo stesso danno.
*/
.appearance .appearance-panel {
  position: absolute;
  /* Larghi quanto la barra, non quanto il pulsante: vedi il commento su .appearance. Otto pixel per
     parte e non zero: il contenitore e' la barra, e la barra arriva al bordo dello schermo - un
     pannello incollato al vetro si legge come tagliato anche quando e' intero. */
  left: 8px;
  right: 8px;
  top: calc(100% + 8px);
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--panel);
  box-shadow: var(--shadow-panel);
}

/* No gap: each button already carries 13px of padding on every side, so the dots sit 26px apart
   with 44px of target between their centres and nothing overlaps.

   E va a capo, che e' la seconda meta' della correzione dello sbordamento. Sette pastiglie stanno in
   una riga su un telefono stretto, otto no - ed era esattamente con otto che il pannello e' uscito
   dallo schermo. Con il ritorno a capo una tavolozza in piu' aggiunge una riga al pannello invece di
   allargarlo oltre la pagina: il difetto non puo' tornare aggiungendo un colore. Centrate, perche'
   una seconda riga di tre allineata a sinistra si legge come una fila interrotta. */
.appearance .appearance-row {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0;
}

/* The dots carry their colour as a literal hex rather than var(--accent): each one has to show the
   colour it *would* switch to, and reading them from the current accent would paint four identical
   dots. They are the only place in the stylesheet that names a colour outside the palette. */
/*
  The dot stays 18px; the box around it is 44.

  A coloured dot the size of a shirt button is fine to look at and bad to hit with a thumb - and
  these sit four in a row, so a miss picks the wrong colour rather than nothing. Padding gives the
  button its 44px, and background-clip keeps the colour inside the 18px core, so nothing on screen
  changes. Scoped to the buttons in the panel: the same class marks the dot inside the closed pill,
  which is a span and must stay small.
*/
/* Sedici e non diciotto: il pallino accompagna la luna, non compete con lei. */
.appearance .swatch {
  width: 16px;
  height: 16px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  cursor: pointer;
}
/* Dentro il pannello restano grandi: li' sono il controllo da premere, non un'indicazione. */
.appearance-panel button.swatch {
  width: 18px;
  height: 18px;
  position: relative;
  box-sizing: content-box;
  padding: 13px;
  border: none;
  background-clip: content-box;
  background-origin: content-box;
}
/* Solo il pallino, senza il disco. La faccia metallica di tutti i bottoni (la regola su button[class] e la sua
   ombra) disegnava un disco scuro di 44 pixel dietro a ogni pallino, e i dischi si toccavano: una
   fila di bottoni tondi invece di una fila di colori. Il 25/09: "togli il bordo ai colori, lascia
   solo i pallini colorati, che devono avere il loro margine di distanza fra di loro". La distanza e'
   il bersaglio da 44 che resta, invisibile: 26 pixel fra un pallino e l'altro. */
.appearance-panel button.swatch { box-shadow: none; }
/* The ring on the active one is drawn around the core rather than the padding, or it would circle
   the whole 44px target. */
.appearance-panel button.swatch.is-current { box-shadow: none; }
.appearance-panel button.swatch.is-current::after {
  content: "";
  position: absolute;
  inset: 10px;
  border-radius: 50%;
  box-shadow: 0 0 0 1.5px var(--ink-2);
}
.appearance .swatch:hover { transform: scale(1.12); }
/* The active one keeps a ring in the page's own ink, which reads on both surfaces - a ring in the
   accent itself would vanish against the dot it surrounds. */
.appearance .swatch.is-current {
  box-shadow: 0 0 0 2px var(--panel), 0 0 0 3.5px var(--ink-2);
}
/* In the closed pill the ring would collide with the border, and there is nothing to distinguish it
   from anyway: it is the only dot there. */
.appearance > summary .swatch.is-current { box-shadow: none; cursor: inherit; }
/*
  I quattro pallini, e il secondo posto da cui si guardano.

  .accent-choice e' il gruppo delle pagine pubbliche: stessa forma e stessi colori del pannello
  dell'aspetto, perche' e' la stessa scelta fatta prima di avere un account invece che dopo. Il
  selettore e' aggiunto qui e non riscritto sotto, cosi' i quattro valori restano scritti una volta
  sola - sono gia' gli unici colori nominati fuori dalla tavolozza.
*/
.appearance .swatch-pink,
.accent-choice .swatch-pink { background: #ff009f; }
.appearance .swatch-green,
.accent-choice .swatch-green { background: #2bff88; }
.appearance .swatch-orange,
.accent-choice .swatch-orange { background: #ff7a1a; }
.appearance .swatch-tiffany,
.accent-choice .swatch-tiffany { background: #2ee6df; }
/* PIENI, come tutti gli altri. Erano mezzo neri e mezzo colorati perche' allora volt e ice portavano
   anche un fondo loro - l'asfalto e l'ardesia - e il mezzo cerchio lo diceva. Quei fondi sono usciti
   da un pezzo ("cambia tutti gli sfondi in antracite") e il disegno era rimasto a raccontare una cosa
   che non succedeva piu': "sistema queste due con pallino pieno del colore". Un pallino che promette
   un cambio di pagina che non arriva e' peggio di uno che non promette niente. */
.appearance .swatch-volt,
.accent-choice .swatch-volt { background: #d7ff2e; }
.appearance .swatch-ice,
.accent-choice .swatch-ice { background: #4fe3b0; }
/* E il bianco e nero, che e' letteralmente meta' e meta': lo stesso mezzo cerchio dei due qui sopra,
   ed e' anche l'unico pallino che disegna esattamente quello che la palette fa - il nero da una
   parte, il bianco dall'altra, e quale dei due sia l'accento dipende dal tema. */
.appearance .swatch-mono,
.accent-choice .swatch-mono { background: linear-gradient(135deg, #16161c 50%, #ffffff 50%); }

/* In the compact header icon, keep the diagonal fill out of the translucent border. Otherwise the
   coloured half leaks through as two small arcs where the diagonal meets the circle. */
.appearance > summary .swatch-mono { background-clip: padding-box; }

/*
  La fila di pallini delle pagine pubbliche: forma, misura e anello.

  Sta qui e non nel foglio della vetrina perche' la stessa fila e' anche nel form di registrazione,
  che carica solo questo foglio. Sono <label> attaccate a dei radio, non bottoni come nel pannello
  dell'aspetto: senza JavaScript un bottone dovrebbe inviare un form per farsi sentire e un radio
  no, ed e' l'unica differenza fra le due.
*/
.accent-choice { display: flex; align-items: center; }
/*
  Il pallino resta 18, la zona da premere e' 44 - lo stesso conto del pannello dell'aspetto e per
  la stessa ragione: quattro cerchi in fila grandi come un bottone di camicia si sbagliano, e
  sbagliarli qui non prende niente, prende il colore accanto. Il colore lo mette la classe
  .swatch-* qui sopra, e background-clip lo tiene dentro i 18 invece di riempire i 44.
*/
.accent-choice .swatch {
  position: relative;
  display: block;
  box-sizing: content-box;
  width: 18px;
  height: 18px;
  padding: 13px;
  border: none;
  border-radius: 50%;
  background-clip: content-box;
  background-origin: content-box;
  cursor: pointer;
  transition: transform .18s ease;
}
.accent-choice .swatch:hover { transform: scale(1.1); }
/*
  L'anello del colore scelto, disegnato attorno al pallino e non attorno ai 44px, altrimenti
  cerchierebbe tutta la zona da premere. Nell'inchiostro della pagina e non nell'accento: un anello
  del colore del pallino che lo circonda sparisce dentro il pallino stesso.

  Su ::after e non come box-shadow sull'elemento, cosi' non dipende dal colore che ha dietro - la
  stessa fila sta sulla barra della vetrina e su una carta nella registrazione.
*/
.accent-pick:checked + .swatch::after,
.accent-pick:focus-visible + .swatch::after {
  content: "";
  position: absolute;
  inset: 10px;
  border-radius: 50%;
  box-shadow: 0 0 0 1.5px var(--ink-2);
}
/* Il radio e' fuori schermo, quindi il fuoco da tastiera lo deve mostrare la label: senza questo
   chi naviga con il tab non vede su quale colore si trova. Un alone piu' largo dell'anello sopra,
   cosi' "ho il fuoco qui" e "questo e' quello scelto" restano due cose diverse. */
.accent-pick:focus-visible + .swatch {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ink-2) 40%, transparent);
}
@media (prefers-reduced-motion: reduce) {
  .accent-choice .swatch { transition: none; }
  .accent-choice .swatch:hover { transform: none; }
}

/* Named, not an icon: inside an open panel there is room for a word, and "Light" says what pressing
   it does in a way a sun cannot. */
.appearance .mode-toggle {
  min-height: 44px;
  padding: 7px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--field);
  color: var(--ink-2);
  font-family: var(--cond);
  font-size: 13px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  cursor: pointer;
}
.appearance .mode-toggle:hover { border-color: var(--accent-line); color: var(--accent-text); }

/*
  ---------- lo sfondo, e i suoi tre bottoni che non ci sono piu' ----------

  Qui stavano "quanto sfondo": tre passi - come disegnato, meta', spento - sotto l'interruttore del
  tema. I bottoni sono usciti dal documento con d89b28d, "togli selettore sfondi impostandolo in
  automatico su spento per ora, poi generero' un'immagine da mettere in sfondo successivamente":
  tre intensita' di niente sono tre bottoni che non fanno niente.

  Quel commit ha dichiarato cosa teneva - colonna, enum, CHECK e le due regole che dipingono
  l'artwork - e queste non erano nell'elenco: erano lo stile di bottoni gia' cancellati, rimaste
  indietro. Quando il controllo tornera', con l'immagine nuova dietro, si riscrive insieme a quella.
*/

/* One of each pair is shown, decided by the attribute on <html> - so flipping that attribute flips
   the icon and the label with it, which is what makes the switch instant instead of a page load. */
.appearance .icon-dark, .appearance .icon-light { display: none; }
:root[data-theme="dark"] .appearance .icon-dark { display: inline; }
:root[data-theme="light"] .appearance .icon-light { display: inline; }
/* Sulla vetrina l'attributo resta "dark" per sempre - il chiaro li' e' una casella di spunta - e
   senza queste due righe si vedrebbero luna e sole insieme. */
:root:has(.lp-theme-light:checked) .appearance .icon-light { display: inline; }
:root:has(.lp-theme-light:checked) .appearance .icon-dark { display: none; }

@media (max-width: 380px) {
  .appearance > summary { padding: 4px 8px; gap: 5px; }
  .appearance .swatch { width: 16px; height: 16px; }
}

/* ---------- bottom bar with central microphone ---------- */
/*
 * From the reference design: a fixed bar with home and profile at the edges and
 * dictation as the large glowing button in the middle. Blurred rather than
 * opaque so content scrolling underneath stays visible.
 */
/* Floating: lifted off the bottom edge and rounded, rather than a strip welded to it.
   Two reasons beyond looks. A bar flush with the edge collides with the phone's own home
   gesture area, and one that spans the full width reads as part of the browser chrome
   instead of part of the app. */
/* The bar sits on the bottom of what the athlete can actually see, which on a phone is not the
   bottom of the page's own viewport.

   Reported from production: "quando scrollo in basso la barra rimane bloccata a metà schermo e
   quando scorro in alto torna a posto". Both halves of that are one cause. Scrolling down hides
   the browser's address bar, which grows the visible area without changing the viewport the page
   was laid out against, so a bar pinned to the layout viewport's bottom edge is left behind - and
   scrolling up puts the address bar back and the two agree again. --viewport-bottom is the gap
   between the two, measured by app.js from window.visualViewport and zero everywhere the question
   does not arise (a desktop browser, or scripting off).

   Centred with auto margins rather than left:50% and a translate. A transform on a fixed element
   is correct CSS, but it also hands the element to the compositor, and a composited fixed layer is
   exactly what mobile browsers reposition a frame late during a scroll. Two auto margins centre it
   with no layer at all. */
/* ---------- la barra in fondo ----------

   RIDISEGNATA: "un po' piu' raffinata e meno AI generated, in stile dinamico con box piu' squadrato
   e inclinato cosi' /, fagli prendere tinta della palette, dagli un po' piu' di profondita', il
   microfono inglobato dentro e lascialo a risalto."

   Era una pastiglia bianca galleggiante con un cerchione rosa sopra: la forma che esce per prima da
   qualunque generatore, e il cerchio grosso che sfonda il bordo la faceva sembrare due oggetti messi
   uno sull'altro invece di un comando solo.

   INCLINATA CON UNO skewX, e il contenuto controinclinato. E' l'unico modo di avere i fianchi
   obliqui senza disegnarli: un clip-path darebbe la stessa sagoma ma taglierebbe via le ombre, e
   l'ombra e' meta' della profondita' che e' stata chiesta. Otto gradi: abbastanza da vedersi sui
   fianchi corti, abbastanza poco da non far ballare le icone quando le si raddrizza.

   LA TINTA VIENE DALLA PALETTE. Non un rosa scritto a mano: color-mix fra l'accento e il fondo della
   barra, quindi rosa con il rosa, verde con il verde, e sulle tavolozze quasi grigie - volt, mono -
   resta quasi grigia da sola, senza un caso particolare da scrivere. */
.bottom-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(18px + var(--viewport-bottom, 0px) + env(safe-area-inset-bottom, 0px));
  z-index: 30;
  /* PIU' STRETTA DI PRIMA, e il motivo e' l'inclinazione. Uno skew non allarga la scatola, ma
     sposta gli angoli: a otto gradi su un blocco alto sessanta pixel l'angolo in basso a sinistra e
     quello in alto a destra escono di circa quattro pixel per parte. Con dodici pixel di margine
     arrivavano a sbavare sul bordo dello schermo; con ventidue restano dentro con un margine che si
     vede. */
  width: calc(100% - 44px);
  max-width: 460px;
  margin-inline: auto;
  /* L'INCLINAZIONE LA DISEGNA UNO PSEUDO-ELEMENTO, non questa barra.

     Un transform su un elemento fisso e' CSS corretto e consegna l'elemento al compositore, che sui
     browser mobili viene riposizionato in ritardo durante lo scorrimento: la barra balla. C'e' un
     test che lo sorveglia - BottomBarAndSavedTest - e ha fermato la prima versione di questo
     disegno, che inclinava la barra stessa.

     Quindi qui non c'e' nessun transform e nessuno sfondo: la superficie inclinata, con il suo
     bordo e le sue ombre, e' ::before. Un transform su uno pseudo-elemento non fisso non consegna
     niente a nessuno. */
  /* Two icons, the microphone, two icons. Symmetry is the requirement, not the aesthetic:
     the microphone is the one control that has to be hittable without aiming, so it sits
     dead centre, and an odd number of icons around it puts it off centre.

     Flex, not grid, and that is the fix for a real bug. With five named grid columns, an
     item that is display:none vacates its column instead of collapsing it: on every page
     where the microphone was hidden, the four icons packed into columns 1-4 and left an
     empty column on the right. Flex distributes whatever children are actually there, so
     the bar cannot end up lopsided again if one of them ever goes away. */
  display: flex;
  justify-content: space-around;
  align-items: center;
  padding: 8px 18px;
}
/* La superficie: squadrata e inclinata, la tinta presa dalla palette, e la profondita' in tre strati.

   LA TINTA VIENE DALL'ACCENTO, non da un rosa scritto a mano: color-mix fra l'accento e il fondo
   della barra, quindi rosa con il rosa, verde con il verde, e sulle tavolozze quasi grigie resta
   quasi grigia da sola, senza un caso particolare da scrivere.

   TRE STRATI E NON UN'OMBRA SOLA: una luce sottile sul bordo alto, come se la luce venisse
   dall'alto; un'ombra corta e stretta che la stacca dal fondo; una lunga e larga che la solleva
   davvero. Una sola ombra grande fa una macchia, tre fanno un oggetto. */
.bottom-bar::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 13px;
  transform: skewX(-8deg);
  border: 1px solid color-mix(in srgb, var(--accent) 70%, transparent);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  /* ---------- lo spessore: la barra e' un solido sollevato, non una sagoma incollata ----------

     "La barra non va ancora bene, sembra ancora appiccicata li' e non una superficie solida
     rialzata: come fosse un render deve avere sfumature e lievi ombre."

     IL DIFETTO ERA LA LUCE, e veniva da due posti contemporaneamente. Il fianco stava in alto a
     sinistra - quindi la luce arrivava da in basso a destra - mentre le ombre cadevano verso il
     basso, quindi la luce arrivava dall'alto. Nessun oggetto reale fa cosi', e l'occhio se ne
     accorge molto prima di saper dire perche': smette di leggere un volume e legge un contorno.
     Tutte le misure del mondo su uno spessore incoerente non lo raddrizzano, ed e' il motivo per cui
     passare da sette a quattro pixel non aveva risolto niente.

     ADESSO C'E' UNA LUCE SOLA, dall'ALTO A SINISTRA, che e' anche quella di tutte le carte della
     pagina. Da li' discende tutto il resto, e ogni pezzo qui sotto e' una conseguenza e non una
     scelta di gusto:

     - IL FIANCO sta in BASSO A DESTRA, che e' il lato in ombra. Quattro pixel ci stanno: la barra e'
       a diciotto pixel dal bordo inferiore.
     - E' SPAZZATO e non copiato: quattro sagome a un pixel l'una dall'altra invece di una sola a
       quattro. Il passo corto le tiene sempre in contatto, anche lungo le curve, quindi la loro
       unione e' un volume continuo e gli angoli si chiudono da soli. Con una copia sola, dove il
       bordo curva le due sagome si staccavano e restavano due monconi - segnati in rosso su uno
       screenshot: "unisci gli angoli".
     - OGNI PASSO E' PIU' SCURO, dal contrasto pieno accanto alla faccia fino a meta' strada verso il
       nero: e' come un fianco vero prende la luce, piu' chiaro dove affaccia e piu' scuro dove
       rientra. Con un colore piatto resta una striscia; con la sfumatura diventa uno spigolo.
     - LA FACCIA SCHIARISCE VERSO L'ALTO A SINISTRA. Era una sfumatura quasi piatta, cioe' un colore:
       una superficie illuminata di sbieco ha un chiaro e uno scuro, e sono quelli a dire che e'
       piana e non stampata.
     - IL FILO CHIARO SUL BORDO SUPERIORE e quello scuro su quello inferiore sono lo spessore del
       bordo che prende e perde luce. Due righe da un pixel, ed e' la differenza fra un oggetto
       ritagliato e uno che finisce.
     - LE OMBRE SONO TRE E CADONO IN BASSO A DESTRA, come le carte: contatto corto e quasi netto -
       l'unica che dichiara l'altezza - poi la propria, poi l'ambiente larga e leggera. Una sola
       ombra grande dice "c'e' del buio qui sotto" e non dice a che altezza sta la cosa.

     Tutto su ::before perche' la barra non puo' avere un transform: lo consegnerebbe al compositore,
     che i browser mobili riposizionano un fotogramma tardi durante lo scorrimento. Il vantaggio
     secondario e' che il fianco eredita lo skew della faccia, ed e' quello che lo fa leggere come un
     solido inclinato invece che come una barra dritta dietro una storta.

     IL FIANCO E' NERO E SPESSO SEI PIXEL: "la barra abbia uno spessore di 6px e di colore nero".
     Era --accent-2, il secondo colore della tavolozza, per la stessa ragione per cui le tessere
     hanno il fianco del proprio colore - e su questo oggetto non funzionava. La barra e' l'unica
     superficie a tinta piena della pagina, e un fianco colorato accanto a una faccia colorata sono
     due colori che litigano invece che un solido; il nero non e' un colore in competizione, e'
     assenza di luce, quindi si legge come il fianco di qualcosa e non come una seconda barra.

     NESSUNA RAMPA QUI, a differenza delle tessere, e non e' una dimenticanza: la rampa serve a dare
     uno spigolo a un fianco colorato, che altrimenti resta una striscia piatta. Un fianco nero e'
     gia' al fondo della scala - non c'e' niente sotto il nero verso cui sfumare - e il distacco dal
     colore pieno della faccia fa da solo il lavoro che li' fa la sfumatura.

     Sei passi da un pixel e non uno da sei, come sempre: il passo corto tiene le sagome in contatto
     anche lungo le curve, quindi gli angoli si chiudono da soli invece di lasciare due monconi. */
  background:
    linear-gradient(
      145deg,
      color-mix(in srgb, var(--accent) 88%, #fff),
      var(--accent) 55%,
      color-mix(in srgb, var(--accent) 90%, #000));
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #fff 34%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #000 20%, transparent),
    1px 1px 0 0 #000,
    2px 2px 0 0 #000,
    3px 3px 0 0 #000,
    4px 4px 0 0 #000,
    5px 5px 0 0 #000,
    6px 6px 0 0 #000,
    2px 4px 5px -1px rgb(0 0 0 / .42),
    4px 9px 14px -4px rgb(0 0 0 / .40),
    6px 18px 34px -10px rgb(0 0 0 / .45);
}
/* ---------- e su fondo chiaro il fianco e' bianco, non nero ----------

   "Qua, se lo sfondo e' chiaro, lo spessore deve essere bianco con ombreggiatura - dinamica anche
   sul bordo stesso, se no bianco su bianco non si vedrebbe nulla."

   Il nero era giusto per una ragione sola - non e' un colore in competizione con la faccia - e su
   una pagina chiara quella ragione si rovescia: un fianco nero sotto una barra arancione appoggiata
   su una carta bianca non e' l'ombra di un oggetto, e' una fascia di inchiostro. Gli oggetti di
   questa pagina, in tema chiaro, sono chiari: il fianco di una tessera bianca e' bianco appena
   sporcato, ed e' cosi' che si legge come spessore.

   E QUI LA RAMPA SERVE, al contrario del nero. Un fianco nero e' gia' al fondo della scala e non ha
   dove sfumare; un fianco bianco su una pagina quasi bianca, se resta bianco per sei pixel, non ha
   un bordo - sparisce nel fondo e lo spessore non c'e'. La rampa scende dal bianco pieno accanto
   alla faccia fino a un grigio medio sul bordo esterno: e' la faccia che si volta, ed e' anche
   l'unica cosa che dice dove finisce l'oggetto. Senza, e' esattamente il "bianco su bianco" del
   report.

   L'ultimo passo e' il piu' scuro di proposito: e' il punto piu' lontano dalla luce, e serve da
   contorno - il lavoro che sul tema scuro fa il fondo della pagina. */
:root[data-theme="light"] .bottom-bar::before {
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, #fff 70%, transparent),
    inset 0 -1px 0 color-mix(in srgb, #000 12%, transparent),
    1px 1px 0 0 #ffffff,
    2px 2px 0 0 color-mix(in srgb, #fff 94%, #000),
    3px 3px 0 0 color-mix(in srgb, #fff 87%, #000),
    4px 4px 0 0 color-mix(in srgb, #fff 79%, #000),
    5px 5px 0 0 color-mix(in srgb, #fff 71%, #000),
    6px 6px 0 0 color-mix(in srgb, #fff 62%, #000),
    2px 4px 5px -1px rgb(16 16 28 / .14),
    4px 9px 14px -4px rgb(16 16 28 / .12),
    6px 18px 34px -10px rgb(16 16 28 / .14);
}

/* Le icone stanno sopra la superficie. Niente z-index negativo sullo pseudo-elemento: finirebbe
   dietro allo sfondo di un antenato invece che dietro ai fratelli. */
.bottom-bar > * { position: relative; z-index: 1; }

/* Le icone stanno sul colore pieno, quindi prendono --on-accent: e' per definizione "il colore che
   si legge sull'accento", quindi resta leggibile anche sulle tavolozze con l'accento scuro. Un po'
   attenuate, perche' sono destinazioni e non comandi da premere adesso. */
.bar-icon {
  width: 46px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  color: color-mix(in srgb, var(--on-accent) 62%, transparent);
}
.bar-icon:hover { color: var(--on-accent); text-decoration: none; }
/* Il cassetto si apre da una <label>, che e' il trucco che lo fa funzionare senza JavaScript - e
   che quindi si prende la regola globale dei <label> dei moduli, "margin: 16px 0 8px". Dentro una
   riga di cinque icone allineate al centro, un margine verticale asimmetrico spinge questa sola di
   quattro pixel piu' in basso delle altre quattro. E' la stessa trappola che l'hamburger aveva gia'
   pagato quando stava in testata; si e' portata dietro anche il trasloco. */
.bar-menu { margin: 0; cursor: pointer; }

/* ---------- e le icone restano PIATTE, dopo tre tentativi di darle un volume ----------

   Bassorilievo con drop-shadow (disegnava un labbro che sporge, perche' una drop-shadow dipinge per
   forza fuori dalla sagoma), bassorilievo vero con un filtro SVG (corretto e illeggibile: "sporca
   troppo e sembrano solo icone sfocate"), rilievo con spessore e ombra. Poi: "torna a icone piatte".

   PERCHE' NON FUNZIONA SU QUESTE, ed e' la cosa da ricordare prima di riprovarci. Un volume si legge
   su una superficie: una tessera ha una faccia larga abbastanza da mostrare un fianco e un'ombra
   senza che quelli coprano cio' che c'e' sopra. Un glifo da ventiquattro pixel e' quasi tutto bordo:
   due pixel di spessore e una sfocatura d'ombra sono la meta' del tratto, quindi non aggiungono un
   volume alla sagoma - la ingrossano. Il volume in questa barra ce l'hanno gli OGGETTI - la barra
   stessa, il tasto del microfono - e le icone ci stanno sopra come segni.

   Restano pero' le due cose chieste a parte e tenute: ventiquattro pixel e tratto 2,4, cioe' un filo
   piu' grandi e piu' spesse di com'erano ("possiamo ingrandire un po' le icone e farle leggermente
   piu' spesse"). Quella richiesta non e' stata annullata, e il rilievo non c'entrava. */

/* Il microfono: DENTRO la barra, non appoggiato sopra.

   Sfondava il bordo alto con un anello del colore della barra attorno - il ritaglio che serviva
   proprio perche' stava fuori - e da li' si leggeva come due oggetti messi uno sull'altro. Chiesto:
   "il microfono inglobato dentro e lascialo a risalto".

   A RISALTO SENZA SPORGERE. Non e' piu' grosso degli altri: e' l'unico pieno, l'unico con la tinta
   dell'accento e l'unico che ha un'ombra sua, e quelle tre cose insieme lo staccano piu' di quanto
   facessero venti pixel di sporgenza.

   E PORTA L'INCLINAZIONE DELLA BARRA, mentre il microfono disegnato dentro si raddrizza. E' la
   differenza fra "dentro" e "appoggiato sopra": un tasto dritto su una barra storta si legge come
   due oggetti, che e' il difetto da cui si partiva. Qui il transform si puo' usare - questo non e'
   un elemento fisso, e non trascina nessuno nel compositore. */
.mic-fab {
  position: relative;
  width: 58px;
  height: 44px;
  border-radius: 9px;
  transform: skewX(-8deg);
  border: none;
  /* IN NEGATIVO rispetto alla barra: "inverti colore glifo microfono e barra - barra colore pieno,
     icona microfono attenuato". Prima il tasto era l'unica cosa accesa su una barra pallida; adesso
     e' l'unica cosa spenta su una barra accesa. Stacca uguale - e' sempre l'unico diverso - e la
     barra ha smesso di essere un contorno per diventare l'oggetto. */
  background: linear-gradient(165deg, var(--bar), color-mix(in srgb, var(--bar) 90%, var(--ink)));
  color: color-mix(in srgb, var(--ink) 60%, transparent);
  display: flex;
  align-items: center;
  justify-content: center;
  /* La luce sul bordo alto e' la stessa della barra, ma dentro l'accento: e' cio' che lo fa sembrare
     un tasto e non un rettangolo colorato. Sotto, un'ombra corta nel colore dell'accento - non nera:
     un tasto acceso proietta la propria luce, e l'ombra nera lo avrebbe spento. */
  /* L'ombra e' scura e non piu' colorata: un tasto chiaro incassato in una superficie accesa proietta
     ombra, non luce. */
  /* Anche il tasto obbedisce alla luce da alto-sinistra: ombra in basso a destra, filo chiaro in
     cima. E' l'unico oggetto che sta SOPRA la barra, quindi se la sua ombra cadesse da un'altra
     parte tradirebbe tutto il resto - due oggetti sullo stesso piano con due soli diversi e' la
     cosa che fa leggere una scena come un collage. */
  /* ---------- e adesso e' in rilievo come le tessere ----------

     "Box del microfono in rilievo." E' l'oggetto giusto a cui darlo: e' una superficie, non un
     segno, quindi ha una faccia larga abbastanza perche' un fianco si veda senza mangiarsi cio' che
     porta sopra - che e' esattamente il motivo per cui sulle icone non funzionava.

     Lo spessore e' del SUO colore, non nero: e' la regola del domino, il fianco di una tessera e' la
     stessa materia vista dove prende meno luce. Qui la faccia e' scura, quindi il fianco va verso il
     nero di poco per volta - tre passi da un pixel, spazzati, cosi' la sagoma sfalsata resta in
     contatto con quella sopra e gli angoli arrotondati si chiudono da soli.

     In basso a destra come ogni altra ombra e ogni altro fianco della pagina: la luce viene
     dall'alto a sinistra, e questo e' l'unico oggetto che sta SOPRA la barra - se il suo fianco
     cadesse da un'altra parte tradirebbe tutto il resto. */
  --solid: var(--bar);
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--ink) 8%, transparent),
    1px 1px 0 0 color-mix(in srgb, var(--solid) 88%, #000),
    2px 2px 0 0 color-mix(in srgb, var(--solid) 76%, #000),
    3px 3px 0 0 color-mix(in srgb, var(--solid) 64%, #000),
    2px 4px 4px -1px rgb(0 0 0 / .34),
    4px 8px 14px -4px rgb(0 0 0 / .30);
}
/* Lo scatto alla pressione deve portarsi dietro la controinclinazione, se no il tasto si raddrizza
   di colpo mentre lo si preme. */
.mic-fab:active { transform: skewX(-8deg) scale(.94); }
/* ---------- e adesso anche i segni sono inclinati, non solo le superfici ----------

   "Dai inclinazione alle icone della barra come la barra."

   La barra e' inclinata di otto gradi e il tasto del microfono pure; le cinque icone dentro no. Il
   microfono aveva perfino una controinclinazione apposta per restare dritto - c'era scritto "solo il
   microfono si raddrizza, non il tasto che lo contiene" - e le quattro destinazioni non erano mai
   state toccate. Il risultato era una superficie inclinata con sopra cinque segni dritti: l'occhio
   legge due piani invece di uno, ed e' la stessa cosa che fa sembrare una scena un collage.

   Adesso tutto quello che sta sulla barra ha la sua stessa inclinazione. La controinclinazione del
   microfono e' sparita: il tasto e' gia' inclinato, quindi al glifo basta smettere di raddrizzarsi.

   SUI GLIFI E NON SULLA BARRA. Un transform sull'elemento fisso lo consegna al compositore, che i
   browser mobili riposizionano un fotogramma in ritardo durante lo scorrimento - la barra balla, e
   c'e' BottomBarAndSavedTest che lo sorveglia. Questi sono figli, non l'elemento fisso. */
.bar-icon > svg { transform: skewX(-8deg); }
/* E il menu non ha nessun caso speciale, dopo due tentativi che ce l'avevano dato.

   Uno skew sposta la x in proporzione alla y: piega i tratti verticali e lascia piatti quelli
   orizzontali, spostandoli. Su tre righe piatte il segno che ne esce e' il TAGLIO della pila - la
   riga di sopra un po' piu' a destra di quella di sotto - e su dieci pixel di altezza, a otto gradi,
   fa un pixel e quattro in tutto. Discreto, ma e' esattamente quanto pende la barra.

   Provato a farlo piu' visibile disegnandolo nel tracciato, prima inclinando le righe e poi
   sfalsandole di due pixel l'una: la seconda versione sono ventidue gradi, quasi il triplo della
   barra, ed e' stata segnalata con due righe tracciate sopra la schermata che non erano parallele.
   La regola che ne resta: quando il segno giusto e' discreto, la cura non e' esagerarlo. */
/* It is an <a> in the markup - a link to the coach that script upgrades into a dictation
   control - so it needs the link decorations turned off. */
.mic-fab, .mic-fab:hover {
  color: color-mix(in srgb, var(--ink) 60%, transparent);
  text-decoration: none;
}

/* Recording state. Movement, not just colour: a ring that keeps expanding is
   what actually reads as "it is listening right now". */
/* Mentre ascolta il tasto si accende davvero: e' l'unico momento in cui deve tirare l'occhio piu'
   della barra che lo contiene. */
.mic-fab.listening {
  background: var(--ink);
  color: var(--bar);
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / .2),
    0 0 18px color-mix(in srgb, var(--accent) 70%, transparent),
    0 0 48px color-mix(in srgb, var(--accent) 30%, transparent);
}
/* Un'icona per volta: microfono da spento, la freccia dell'invio mentre ascolta. Il cambio e' qui
   e non in app.js, che si limita ad accendere e spegnere la classe - due disegni che compaiono e
   scompaiono sono un lavoro da foglio di stile. */
.mic-fab-send { display: none; }
.mic-fab.listening .mic-fab-mic { display: none; }
.mic-fab.listening .mic-fab-send { display: block; }
.mic-pulse { position: absolute; inset: 0; border-radius: 9px; pointer-events: none; }
.mic-fab.listening .mic-pulse {
  border: 2px solid var(--accent);
  animation: mic-ring 1.4s ease-out infinite;
}
@keyframes mic-ring {
  0% { transform: scale(1); opacity: .9; }
  100% { transform: scale(2); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .mic-fab.listening .mic-pulse { animation: none; border-color: var(--accent-text); }
  html { scroll-behavior: auto; }
}

.mic-status {
  position: fixed;
  left: 50%;
  bottom: 92px;
  transform: translateX(-50%);
  z-index: 31;
  padding: 6px 14px;
  border-radius: 999px;
  background: var(--bar);
  border: 1px solid var(--accent-line);
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--accent-text);
}

/*
  Room so the fixed bottom bar never covers anything - e una volta sola.

  Lo spazio per la barra serve a chi sta in fondo alla pagina, e in fondo alla pagina c'e' sempre il
  pie': e' nel guscio comune, senza condizioni, quindi ogni pagina ce l'ha. Il guscio del contenuto
  invece non tocca mai la barra, perche' fra i due c'e' il pie' - lo spazio che si teneva era una
  seconda riserva per un pericolo che aveva gia' qualcun altro, e a schermo erano centottanta pixel
  di niente fra l'ultima scheda e il pie'.

  Riportato guardando la home: "quando arrivi in fondo alla home... far finire correttamente la
  home". Adesso il guscio tiene solo il respiro che gli serve per staccarsi dal pie'.

  --bar-h e' l'altezza vera della barra (10 + 44 + 14 piu' il bordo), e l'inserto di sicurezza copre
  la barretta di casa su iOS.
*/
.app-shell { padding-bottom: 56px; }
.site-footer { padding-bottom: calc(var(--bar-h) + 28px + env(safe-area-inset-bottom, 0px)); }
/* And the floating «Salva» too, once it shows (app.js puts the class on the body): it sits 44 points
   above the bar and is 56 tall. Until 27/09 the last command cleared it only because the footer's own
   lines happen to be taller than that - nobody had sized them for it - and when the bar appears over a
   pill, app.js lifts the page, which needs room below. So while it is there the end of the page keeps
   its room by construction, 44 + 56 and 12 of air (verifiche del taglio 7, 27/09). */
body.has-save-float .site-footer {
  padding-bottom: calc(var(--bar-h) + 112px + env(safe-area-inset-bottom, 0px));
}

/*
  ---------- rimosso: html { overscroll-behavior-y: none } ----------

  C'era per il rimbalzo di fine pagina: "quando arrivi in fondo alla home fa scorrere ancora e
  sposta la tab rapida". Trascinando oltre l'ultimo pixel il browser sposta tutta la pagina, e con
  lei quello che sta fisso sopra, che si stacca dal fondo dello schermo e sale.

  Toglierla era il prezzo, e il commento di allora lo diceva: "si perde il trascinamento per
  ricaricare, ed e' un prezzo che si paga volentieri". Non lo era: "perche' non funziona piu' il
  refresh scrollando in basso la scheda, e rimettilo".

  E non c'e' una via di mezzo. Il rimbalzo in fondo e il trascinamento per ricaricare in cima sono
  lo stesso comportamento del browser visto ai due capi della pagina, e overscroll-behavior li
  governa insieme: "none" li spegne tutti e due, "contain" toglie comunque il trascinamento per
  ricaricare, e solo il valore predefinito li lascia tutti e due. Quindi resta il predefinito, che e'
  nessuna regola.

  Se la barra in basso dovesse tornare a sollevarsi in fondo alla home, la strada e' compensare il
  rimbalzo dentro a --viewport-bottom - dove oggi lo scarto negativo viene azzerato di proposito,
  vedi gap() in app.js - e non spegnere di nuovo un gesto del telefono.
*/

/* ---------- logo mark ---------- */
.logo { display: inline-flex; align-items: center; min-height: 44px; gap: 10px; }
/*
  ---------- the mark ----------

  Replicated from the official logo: a ring whose stroke runs from the accent at its foot to the
  second brand colour at its head, beside "Hybrx" with the same run across the last two letters.

  The ring is an inline SVG rather than a bordered box, because a border cannot hold a gradient
  without a masking trick that behaves differently in three browsers. The gradient stops read the CSS
  custom properties, so the mark follows the athlete's palette with nothing duplicated per colour.

  Mixed case, not HYBRX. The official mark is "Hybrx", and the application was shouting it.
*/
/*
  ---------- LA CORSA DELL'ANELLO, NEI COLORI SCELTI DALL'ATLETA ----------

  Non si chiamano piu' --mark-*: il marchio e' un'immagine e questi colori non lo toccano piu'. Li
  usa l'anello della condizione fisica, e basta lui.

  Per mezza giornata sono stati i colori campionati dal logo, scritti a mano. Era la correzione di un
  difetto vero - il marchio a schermo e quello consegnato avevano colori diversi - ma applicata a un
  posto sbagliato: l'anello del punteggio non e' il marchio, e "l'anello deve prendere il gradiente
  come selezionato dall'utente". Con l'accento arancione l'anello restava rosa e viola, cioe' l'unica
  cosa sulla pagina che ignorava una scelta appena fatta.

  Quattro fermate e non due, perche' con due il mezzo dell'anello e' la mescola esatta fra i capi -
  un lilla spento che su 156 px e' quasi tutto quello che si vede. La forma della corsa e' quella del
  marchio: un colore tenuto, una meta', una fine.

  E la fermata di mezzo pesa 72 e non 45. A 45 era ancora troppo vicina al punto esatto di mezzo, che
  e' il posto dove il lilla spento abita: fra due tinte lontane sulla ruota la mescola in sRGB passa
  per il grigio, e quel grigio era la meta' dell'anello. Il numero e' stato scelto affiancando la
  corsa alla parola del marchio - che tiene il rosa per tutta la "Hy" e vira solo sulla "br" - non a
  tavolino: a 60 virava ancora presto, a 80 il passaggio al celeste diventava uno scalino.

  Vale per tutte e sette le tavolozze e nessuna ci perde, perche' tenere l'accento piu' a lungo alza
  la saturazione e basta: il verde passa da 81 a 82, l'arancio da 82 a 86, il rosa da 46 a 72. E le
  due tavolozze neutre restano neutre - tenere piu' a lungo un bianco da' un bianco.
*/
:root {
  --ring-1: var(--accent);
  /* Il ripiego, dichiarato per primo: una mescola in sRGB, che e' quello che si vedeva prima. Non e'
     sbagliata, e' solo piu' spenta - e dove la riga sotto non si puo' leggere, resta questa. */
  --ring-2: var(--accent);
  --ring-3: color-mix(in srgb, var(--accent) 72%, var(--accent-2));
  --ring-4: var(--accent-2);
}

/*
  ---------- l'anello gira intorno alla ruota, invece di tagliarla ----------

  "L'anello deve avere questi colori", con l'anello del marchio a fianco. E i colori erano quelli
  giusti ai due capi - li avevamo appena presi dal file - ma in mezzo mancava il VIOLA, che
  nell'anello del marchio occupa un quarto abbondante del giro.

  Il motivo e' geometrico e non di gusto. Mescolare rosa e celeste in sRGB vuol dire tirare una corda
  fra due punti lontani della ruota, e la corda passa vicino al centro, dove abita il grigio: per
  quanto si sposti il peso, il mezzo resta smorto. Il marchio invece percorre l'ARCO - rosa, magenta,
  viola, pervinca, celeste - e l'arco e' fatto di tinte, non di mescole.

  In oklch si interpola la tinta, quindi la corsa e' l'arco. Misurato sul rosa: #ff009f, #cb6aff,
  #7ba5ff, #39cdfe contro il #ea32a1, #bf4bf6, #9069f8, #6fcbfe campionati sull'anello del marchio.

  E l'arco e' quello CORTO fra i due colori dell'atleta, quindi la rotazione si adatta da sola: il
  rosa dista centotrenta gradi dal suo celeste e ci mette in mezzo un viola; l'arancio dista quaranta
  gradi dal suo giallo e ci mette un arancio piu' chiaro. Una rotazione fissa avrebbe messo il verde
  in mezzo all'arancio - provata, e infatti scartata.
*/
@supports (color: color-mix(in oklch, red, blue)) {
  :root {
    --ring-2: color-mix(in oklch, var(--accent) 67%, var(--accent-2));
    --ring-3: color-mix(in oklch, var(--accent) 33%, var(--accent-2));
  }

  /*
    LE DUE TAVOLOZZE NEUTRE RESTANO FUORI, ed e' l'unico caso particolare qui dentro.

    "volt" e' un giallo che sfuma nel bianco e "mono" un bianco che sfuma nel grigio: il loro secondo
    colore non ha una tinta, ha un residuo di tinta - qualche millesimo di croma che in un esadecimale
    ci finisce per forza. Interpolare verso una tinta che e' rumore da' un risultato che e' rumore:
    volt passava per un verde menta, cioe' un colore che quella tavolozza non contiene.

    Non e' una tavolozza che si dimentichera' di aggiungere qui, come sarebbe un valore per ognuna:
    e' la definizione di "neutra". Se un giorno ne arriva una terza, si aggiunge a questa riga.
  */
  :root[data-accent="volt"],
  :root[data-accent="mono"],
  :root:has(.accent-pick[value="volt"]:checked),
  :root:has(.accent-pick[value="mono"]:checked) {
    --ring-2: var(--accent);
    --ring-3: color-mix(in srgb, var(--accent) 72%, var(--accent-2));
  }
}

/* Il marchio in barra. Un'immagine, quindi si misura in altezza e la larghezza segue: vedi
   fragments/brand per il perche' non e' piu' disegnato. */
.logo-mark { display: block; height: 30px; width: auto; }

/* Le fermate della corsa, adesso solo per l'anello della condizione fisica: e' l'unico disegno
   rimasto che la porta, ed e' stato chiesto uguale a quello del marchio. */
.gauge .mark-stop-foot { stop-color: var(--ring-1); }
.gauge .mark-stop-hold { stop-color: var(--ring-2); }
.gauge .mark-stop-mid  { stop-color: var(--ring-3); }
.gauge .mark-stop-head { stop-color: var(--ring-4); }



/*
  ---------- the training icons ----------

  The two icons that mean "a workout" - the heartbeat and the barbell - take the second brand colour
  rather than the accent, which is the light blue of the logo on the default palette. Asked for in
  those words, and it earns its keep beyond taste: on a page where the accent marks everything the
  athlete can act on, a training icon in a different colour reads as a category rather than as a
  control. It follows the palette, so it is never a colour the athlete did not choose.

  Two declarations, because an icon's colour is set from several places. Written as colour alone this
  looked correct and painted nothing: `.card-title-row > .ico` and `.metric-label > .ico` are more
  specific, so every icon inside a card heading or a tile label stayed the accent - which is most of
  them. Measured in a browser, not read off the source.

  So it also sets a tint, which the rules that colour an icon read as `var(--ico-tint, var(--accent))`.
  A custom property set on the element itself wins wherever it is read, with no specificity race and
  no !important, and a second tinted family later is one line rather than four.
*/
.ico-training {
  --ico-tint: var(--accent-2);
  color: var(--ico-tint);
}

/*
  La terza famiglia, e la ragione per cui ce n'e' una terza.

  "Diamo un po' di varieta': una variante aggiunta in qualche elemento." Con due colori le icone si
  dividevano in due mucchi - cio' su cui si puo' agire e l'allenamento - e tutto il resto finiva nel
  primo per esclusione, compreso il diario alimentare, che non e' un comando. Il terzo colore gli da'
  un mucchio suo: forchetta, carboidrati, proteine, grassi, acqua.

  Stesso meccanismo di sopra, una riga: --ico-tint vince ovunque sia letto, senza gare di specificita'
  e senza !important. Ed e' la ragione per cui aggiungere la terza famiglia e' costato una regola e
  non quattro.
*/
.ico-intake {
  --ico-tint: var(--accent-3);
  color: var(--ico-tint);
}

/* ---------------------------------------------------------------------------
   Il "+" dentro a un cerchio: disegnato, non scritto.

   Erano cinque cerchi con dentro il carattere "+" del font, centrati da una flex. Una flex centra
   la RIGA DI TESTO, non l'inchiostro: il segno "+" di questo font sta un terzo di pixel fuori dal
   centro in orizzontale e un terzo in verticale, e il cerchio e' piccolo abbastanza perche' si
   veda. Su quelli che RUOTANO - "aggiungi esercizio" e "aggiungi un'attivita'" diventano una X
   quando la piega si apre - lo scarto ruota con loro e si legge come una X storta: "tutti i + del
   app che se cliccati diventano x con l'animazione non sono centrati rispetto il cerchio".

   Disegnato con due barre in posizione assoluta e `margin: auto`, il segno e' centrato per
   costruzione: a qualunque misura, in qualunque font, e ruotando resta centrato perche' ruota
   intorno al centro del cerchio. Il "+" nel markup resta (aria-hidden) e sparisce con font-size: 0,
   cosi' senza il foglio di stile c'e' comunque un segno.

   Misurato rendendo e contando i pixel dell'inchiostro, non a occhio - a occhio "non e' centrato"
   e' l'invito a spostarlo di un pixel, che centra un caso e rompe il successivo.
   --------------------------------------------------------------------------- */
.plan-new-plus,
.plan-set-plus,
.manual-entry-plus,
.agenda-add,
.story-plus,
.meal-log-plus,
.page-top-plus {
  position: relative;
  font-size: 0;
}
.plan-new-plus::before, .plan-new-plus::after,
.plan-set-plus::before, .plan-set-plus::after,
.manual-entry-plus::before, .manual-entry-plus::after,
.agenda-add::before, .agenda-add::after,
.story-plus::before, .story-plus::after,
.meal-log-plus::before, .meal-log-plus::after,
.page-top-plus::before, .page-top-plus::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  background: currentColor;
  border-radius: 999px;
}
/* Barra orizzontale e barra verticale: lunghezza e spessore per misura di cerchio. */
.plan-new-plus::before { width: 11px; height: 2.2px; }
.plan-new-plus::after { width: 2.2px; height: 11px; }
.plan-set-plus::before { width: 15px; height: 2.6px; }
.plan-set-plus::after { width: 2.6px; height: 15px; }
.plan-set-more-empty .plan-set-plus::before { width: 13px; height: 2.4px; }
.plan-set-more-empty .plan-set-plus::after { width: 2.4px; height: 13px; }
.manual-entry-plus::before { width: 13px; height: 2.6px; }
.manual-entry-plus::after { width: 2.6px; height: 13px; }
.agenda-add::before { width: 10px; height: 1.8px; }
.agenda-add::after { width: 1.8px; height: 10px; }
.story-plus::before { width: 17px; height: 2.4px; }
.story-plus::after { width: 2.4px; height: 17px; }
.meal-log-plus::before { width: 16px; height: 2px; }
.meal-log-plus::after { width: 2px; height: 16px; }
.page-top-plus { display: block; width: 20px; height: 20px; }
.page-top-plus::before { width: 18px; height: 2.2px; }
.page-top-plus::after { width: 2.2px; height: 18px; }

/* ---------------------------------------------------------------------------
   La scheda in sola lettura, e il foglio che la modifica.

   La pagina si apre per guardare la scheda - tre volte a settimana, per mesi - e si modifica
   quando lo si chiede: "la scheda e' solo in visualizzazione poi clicco modifica scheda in basso
   ed entro in modifica come succede per check-up". Il foglio riusa le classi del check-up
   (.checkin-dialog, .checkin-form, .checkin-dialog-head, .checkin-save-row, .checkin-submit) e non
   delle copie: "stesso stile stessi font" vuol dire lo stesso foglio di stile, o e' la stessa cosa
   scritta due volte che il giorno dopo diverge.
   --------------------------------------------------------------------------- */
.plan-read-list {
  /* Il rientro di quello che sta sotto al nome: il disco del numero (40) e lo spazio che lo separa
     dal nome (9). Un gettone solo, perche' le quattro righe sotto al nome - le serie, «Nessuna
     serie», «Come si esegue» e la sua nota - devono cominciare nello stesso punto, e quattro numeri
     scritti a mano si allontanano al primo disco che cambia misura. */
  --plan-read-indent: 49px;
  display: grid;
  gap: 10px;
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
  counter-reset: none;
}
/* Il filetto in accento sul fianco sinistro: "un pizzico di colore, deve sembrare piu' app per
   cellulare". Un bordo intero in accento farebbe quattro riquadri che gridano; un filetto da tre
   pixel dice "questa e' una riga di questa applicazione" e lascia il resto tranquillo. */
.plan-read-item {
  display: grid;
  gap: 9px;
  padding: 14px 16px;
  border: 1px solid var(--line-soft);
  border-left: 3px solid var(--accent-line);
  border-radius: var(--r-sm);
  background: var(--field);
}
.plan-read-top {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}
/* Il numero dell'esercizio in un disco: dice l'ordine, che e' l'unica cosa che la lista non
   diceva, e da' alla riga il segno di partenza che una scheda su carta ha sempre. 40 punti, la
   misura del segno a sinistra di ogni riga di elenco (mock 08, taglio 4a): era 24. Nell'accento
   tenue e non pieno - quindici dischi pieni gridano, "un bordo intero in accento avrebbe fatto
   quattro riquadri che gridano" - e con --accent-text, che nel chiaro si scurisce.
   Lo stesso disco sulla carta di un esercizio del tracker e nel suo riepilogo (.session-exercise-n,
   taglio 4b): un disco, una misura, una regola. */
.plan-read-index,
.session-exercise-n {
  display: inline-grid;
  place-items: center;
  width: 40px;
  height: 40px;
  flex: 0 0 40px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent-text);
  font-family: var(--cond);
  font-size: 16px;
  font-weight: 700;
}
.plan-read-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 16.5px;
  font-weight: 700;
  line-height: 1.25;
  color: var(--ink);
}
/* Le colonne occupano la riga, e ogni numero sta in mezzo alla sua.

   Erano strette quanto il loro contenuto e tutte spinte a sinistra, per non far attraversare un
   vuoto all'occhio fra "8" e "60". Il vuoto pero' si e' spostato dall'altra parte, e li' si vede:
   "e fianco gli esercizi c'e' troppo spazio, occupa piu' spazio verso destra" - tre colonne
   ammassate sotto il nome e mezza carta bianca accanto.

   Quindi tre colonne uguali che si dividono la larghezza, con il numero centrato nella sua: il
   titolo di colonna sta sopra il suo valore, e la distanza fra due celle e' la stessa ovunque.
   Il numero della serie resta a sinistra, in una colonna sua e stretta, perche' e' la voce che dice
   dove si e' arrivati e non uno dei tre valori. */
.plan-read-grid {
  display: grid;
  grid-template-columns: 18px repeat(3, minmax(0, 1fr));
  gap: 5px 8px;
  padding-left: var(--plan-read-indent);
  font-size: 15.5px;
  color: var(--ink);
}
/* L'icona accanto al nome della colonna: piccola, in accento, e mai da sola - la parola resta. */
.plan-read-lbl {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  font-family: var(--cond);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .7px;
  text-transform: uppercase;
  color: var(--mut2);
}
/* L'accento per tutte e tre, e detto cambiando la TINTA e non il colore.

   Il bilanciere porta ovunque il secondo colore del marchio, quello dell'allenamento: e' cosi' che
   una schermata piena di icone dice a colpo d'occhio di che famiglia e' una riga. Qui pero' le tre
   non sono tre famiglie - sono i titoli di tre colonne della stessa tabella, e una delle tre in un
   altro colore si legge come una colonna a parte.

   Scritto come `color: var(--accent)` sarebbe la regola che BrandLookTest conta e vieta: una
   regola che dipinge un'icona di accento *ignorando* la tinta rimanda all'accento qualunque icona
   di categoria ci finisca dentro, in silenzio e per sempre. Qui la tinta viene riscritta, quindi
   l'eccezione e' dichiarata in un posto solo e vale solo dentro questa etichetta. */
.plan-read-lbl > .ico {
  /* --accent-text e non --accent: con volt nel chiaro l'accento pieno e' un giallo chiaro su una
     carta bianca, e le tre icone non si vedevano (26/09). */
  --ico-tint: var(--accent-text);
  width: 12px;
  height: 12px;
  color: var(--ico-tint, var(--accent));
  opacity: .9;
}
.plan-read-n {
  align-self: center;
  font-family: var(--cond);
  font-size: 12.5px;
  color: var(--mut2);
}
.plan-read-value { text-align: center; font-variant-numeric: tabular-nums; }
.plan-read-none { padding-left: var(--plan-read-indent); color: var(--mut2); font-size: 14px; }
/* La nota, ripiegata: si legge una volta e poi occuperebbe meta' della riga per mesi. */
/* Alta 44: e' un comando, e una riga di testo condensato da 11 punti non prende un dito. */
.plan-read-how > summary {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding-left: var(--plan-read-indent);
  list-style: none;
  cursor: pointer;
  font-family: var(--cond);
  font-size: 11.5px;
  letter-spacing: .6px;
  text-transform: uppercase;
  color: var(--accent-text);
}
.plan-read-how > summary > .ico { width: 13px; height: 13px; }
.plan-read-how > summary::-webkit-details-marker { display: none; }
.plan-read-how > summary::marker { content: ""; }
.plan-read-how p {
  margin: 6px 0 0;
  padding-left: var(--plan-read-indent);
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--mut2);
}
.plan-edit-open {
  width: 100%;
  margin-top: 16px;
}

/* Il foglio: fuori sta un <dialog> che porta anche le classi del check-up, quindi misura,
   raggio, animazione e sfondo arrivano da li'. Qui dentro ci va solo cio' che il check-up non
   poteva sapere: che il corpo e' fatto di carte, e dentro a un foglio una carta dentro a una
   carta e' un bordo di troppo. */
.plan-edit-body {
  min-height: 0;
  padding: 14px 20px 16px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
}
.plan-edit-body > .card {
  margin: 14px 0 0;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
}
.plan-edit-body > .card:first-child { margin-top: 0; }
/* Il rifiuto di un comando del foglio (la scheda piena), in cima al suo corpo: con il foglio modale
   riaperto dopo lo scambio, la frase in cima alla pagina stava dietro allo sfondo (26/09). */
.plan-edit-error { margin: 0 0 12px; }
/* Senza script il foglio arriva aperto come pannello, e ci si arriva con l'ancora (#plan-edit, o
   #exercise-… dopo un comando): fermo sotto la barra in alto e non dietro, come le sezioni con un id.
   E la carta del tracker, dove porta il redirect di una spunta o di un salva senza script
   (#session-exercise-…), e la nota della seduta: arrivavano col bordo alto sotto la testata fissa,
   e a schermo c'era il fondo della carta (26/09, verifica browser D2). */
.plan-edit-dialog,
.plan-builder-exercise,
.session-exercise,
#session-note { scroll-margin-top: 90px; }
.plan-edit-field-name { display: grid; gap: 6px; }
input.plan-name-input {
  width: 100%;
  margin: 0;
}
.plan-edit-close { color: var(--mut); }

@media (max-width: 520px) {
  .plan-edit-body { padding-left: 16px; padding-right: 16px; }
}

/* ---------- text must never overflow its card ---------- */
/* clip, not hidden. The two look identical - neither shows the overflow, neither offers a
   sideways scrollbar - but `hidden` makes the element a scroll container, and a scroll container
   on <body> is what several mobile browsers treat as a reason to stop honouring position: fixed
   on the page. `clip` cuts the overflow off without creating one. */
/*
  ---------- la schermata non si sposta e non si ingrandisce ----------

  "Assolutamente non deve essere permesso spostare o zoomare la schermata."

  Tre cose diverse, e vanno dette separate perche' due si risolvono e una no.

  LO SPOSTAMENTO LATERALE si chiude qui: clip e non hidden - i due sembrano uguali, ma hidden rende
  l'elemento un contenitore di scorrimento, e un contenitore di scorrimento su <body> e' cio' che
  diversi browser da telefono leggono come motivo per smettere di onorare position: fixed. clip
  taglia l'eccedenza senza crearne uno.

  IL DOPPIO TOCCO che ingrandisce si chiude con touch-action: un tocco doppio diventa due tocchi
  invece che una lente, ed e' l'ingrandimento che capita per sbaglio scorrendo in fretta.

  IL PIZZICO A DUE DITA NO, e non e' una dimenticanza: dalla decima versione iOS Safari ignora
  deliberatamente user-scalable=no, perche' togliere a chi ci vede poco l'unico modo di leggere una
  pagina non e' una scelta che si lascia fare a chi la pagina la scrive. Nessuna riga di CSS o di
  meta la riporta indietro. Quello che si puo' fare e' non provocarlo: vedi la regola dei 16 px sui
  campi, poco piu' sotto, che e' la causa vera dell'ingrandimento che parte da solo.
*/
html { touch-action: manipulation; }
/*
  SULLA RADICE E NON SOLO SUL BODY, ed e' la correzione.

  "La chat permette di scorrere a destra e non va bene": la pagina si trascinava di lato, barra in
  alto compresa. C'era gia' `overflow-x: clip` sul body, e in teoria basta - il viewport prende
  l'overflow del body quando la radice e' `visible`. In pratica quella propagazione vale per
  `hidden` ed e' incostante per `clip`, e il telefono su cui e' stato visto e' un iPhone.

  `clip` e non `hidden`: `hidden` su un asse costringe l'altro a diventare un contenitore di
  scorrimento, e questa pagina scorre in verticale e si porta da sola in fondo alla conversazione.
  `clip` toglie lo scorrimento orizzontale e lascia il verticale esattamente com'era.
*/
html { overflow-x: clip; }
body { overflow-x: clip; }
.card, .bubble { min-width: 0; }
.bubble-text, .muted, p {
  overflow-wrap: anywhere;
  word-break: break-word;
}
.bubble-text pre { overflow-x: auto; }
/*
  E la cosa che si allargava. Le risposte del coach sono markdown reso in HTML, quindi dentro una
  bolla ci puo' finire una tabella - che non ha nessun motivo di stare in 350 px e non si spezza
  come il testo. Era l'unico elemento di quelli che il coach puo' produrre senza un limite di
  larghezza: il testo lungo aveva overflow-wrap, il codice aveva il suo scorrimento, la tabella no.

  display: block perche' una tabella non si lascia tagliare: e' l'unico modo di darle un riquadro
  con lo scorrimento suo. Perde il comportamento di tabella sulla larghezza delle colonne, che a
  350 px non serviva comunque.
*/
.bubble-text table { display: block; max-width: 100%; overflow-x: auto; }
.bubble-text img { max-width: 100%; height: auto; }


/* ---------- readiness ring ---------- */
/*
  The ring on the left of its card, its words on the right (mock 01, 26/09): what it measures, the
  state, the check-up door. It sat alone at the top, centred, with everything under it - side by
  side with the load figures it had competed with them; beside its own three words it does not,
  and the card is a screen shorter.

  `minmax(0, 1fr)` for the words, or the longest state word would keep the column as wide as itself
  and push the card off the screen (the `1fr` trap in CLAUDE.md). The coach's reading is outside
  this grid, under it, at the card's full width - which is also what keeps that block one width
  whether it is folded or open: in the old centred column it was sized to its own content and
  changed shape as it opened, "the card looks broken".
*/
.readiness {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 12px;
}
.readiness-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  min-width: 0;
}
.gauge { position: relative; width: 156px; height: 156px; flex: 0 0 auto; }

/*
  A soft halo behind the whole ring, not just the arc.

  The arc has always carried its own drop-shadow, but on a low score the arc is a stub and the rest
  of the circle is unlit grey - so the one graphic the page is built around read as flat, which is
  what "put the glow back on the rest circle" was describing. This lights the circle itself: one
  wide, weak layer at 14%, behind everything, hit-testing nothing. Weak on purpose. The reading in
  the middle sits on top of it and has to stay crisp.
*/
.gauge::before {
  content: "";
  position: absolute;
  inset: 4%;
  border-radius: 50%;
  box-shadow: 0 0 26px color-mix(in srgb, var(--accent) 14%, transparent);
  pointer-events: none;
}

/*
  The hero ring. Bigger than a card gauge because it is the first thing on the page, but capped
  against the viewport so it never crowds out the words beside it on a small phone.
*/
/*
  156px, down from 228.

  The ring is the page's one graphic and it was taking 27% of the first screen on a phone - for a
  number that reads 100/100 for everybody who has just signed up. At 156, when it was centred at the
  top of the page, both rows of load tiles were on the first screen with it, and that was the
  argument: the score and the figures it is made of belong on screen together.

  DAL 26/09 QUELLA RAGIONE NON BASTA PIU', e lo si scrive invece di lasciarla dire il falso. Con il
  mock 01 l'anello sta a sinistra delle sue parole, e fra lui e «I tuoi numeri» ci sono la lettura del
  coach e, quando c'e', l'allenamento in corso: misurato a 360 e a 390 punti senza avvisi, «I tuoi
  numeri» comincia a 645 punti e la prima fila di caselle finisce a 892, sotto il primo schermo (800
  e 844). Resta 156 lo stesso: un anello piu' piccolo non le porterebbe su - l'altezza e' quella del
  coach - e uno piu' grande spingerebbe giu' la pastiglia del check-up, che deve stare sotto la
  parola dello stato. Still the largest thing on the page by some way, and the stroke goes up as the
  circle comes down so the arc keeps its weight rather than thinning into a hairline.
*/
.gauge-hero { width: min(156px, 44vw); height: min(156px, 44vw); }

/*
  ---------- l'anello NON ha spessore ne' ombra propria, ed e' una decisione ----------

  E' stato provato: spessore spazzato con drop-shadow incatenati e un'ombra staccata, come le
  tessere. "Non ci siamo, l'anello e' orribile cosi': annulla lo spessore e l'ombra dell'anello."

  PERCHE' NON FUNZIONA QUI, che e' la parte che vale la pena ricordare. Le tessere sono superfici
  piane: hanno una faccia rivolta a chi guarda e un fianco, e un fianco disegnato sotto la faccia e'
  quello che si vedrebbe davvero. L'anello non e' una superficie piana - e' un anello - quindi
  "sotto" non e' un posto solo: la spazzata in basso a destra scava l'arco da una parte e lo
  ingrossa dall'altra, e sulla meta' in ombra il colore proprio dell'anello si mescola al nero
  producendo un marrone che non e' in nessuna tavolozza. Il gradiente del marchio, che e' la cosa per
  cui questo anello esiste, veniva sporcato dal suo stesso spessore.

  E l'ombra staccata di un anello e' un anello: cadendo di sedici pixel finisce sopra il numero al
  centro, che e' il dato che tutta la pagina esiste per mostrare.

  Quindi l'anello resta come era: il suo alone morbido (vedi .gauge::before) e il drop-shadow che
  l'arco ha sempre avuto. Non e' un'omissione - e' che un oggetto curvo e cavo non si solleva con gli
  strumenti con cui si solleva una tessera.
*/

.gauge-hero .gauge-track, .gauge-hero .gauge-arc, .gauge-hero .gauge-pulse { stroke-width: 9; }

/*
  L'anello a vuoto: c'e' il solco, non c'e' niente da festeggiare.

  Quando non ci sono ancora allenamenti l'arco e' lungo zero - lo scostamento vale l'intera
  circonferenza - e restano solo il battito e la scintilla, che celebrerebbero il completamento di un
  disegno che non e' stato disegnato. Un anello vuoto che pulsa non dice "non ho dati", dice che
  qualcosa sta caricando e non arriva mai.

  Il numero al centro diventa un trattino, e il trattino non ha bisogno del peso di una cifra: e' un
  segnaposto, non una lettura.
*/
.gauge-empty .gauge-pulse, .gauge-empty .gauge-spark { display: none; }
.gauge-score-none { color: var(--mut2); }
.gauge-hero .gauge-score { font-size: clamp(30px, 9.5vw, 40px); }
.gauge-hero .gauge-outof { font-size: clamp(12px, 3.4vw, 15px); }
/*
  overflow: visible is load-bearing, not tidying.

  An <svg> clips to its own box by default, and the arc's pink drop-shadow needs
  about 30px of room while the viewBox leaves it 6. The glow was being sliced off
  square, so a circular gauge sat inside a visible pink rectangle. Letting it
  overflow is correct: a glow is decoration, it has nothing to collide with, and
  the alternative - padding the viewBox - shrinks the ring to make space for
  something that is not part of it.
*/
.gauge svg { width: 100%; height: 100%; overflow: visible; transform: rotate(-90deg); }
.gauge-track {
  fill: none;
  stroke: var(--track);
  stroke-width: 10;
}
/* Il gradiente del marchio invece del colore pieno: l'anello della condizione e' l'anello del logo,
   chiesto cosi'. I due capi restano gli stessi token, quindi segue l'accento come faceva prima. */
.gauge-arc {
  fill: none;
  stroke: url(#gaugeRun);
  stroke-width: 10;
  stroke-linecap: round;
  filter: drop-shadow(0 0 12px color-mix(in srgb, var(--accent) 70%, transparent))
          drop-shadow(0 0 30px color-mix(in srgb, var(--accent) 28%, transparent));
  transition: stroke-dashoffset .6s ease;
}
/*
  ---------- l'anello si disegna, e sulla testa scocca una scintilla ----------

  "Fai una specie di esplosione di stelline quando arriva alla fine, ovviamente coerente con lo
  stile, nulla di troppo bambinesco."

  Due cose, e la prima serve alla seconda: l'anello arrivava gia' disegnato - il valore e' scritto
  nell'attributo dal server - quindi non esisteva nessun momento in cui "arriva alla fine". Adesso si
  disegna in sei decimi, insieme al numero che sale al centro, e quando la testa dell'arco si ferma
  la scintilla scocca li'.

  Sei raggi sottili e tre punte a quattro braccia, tutti del colore dell'accento. Niente coriandoli,
  niente stelle a cinque punte, niente di dorato: e' lo stesso rosa dell'anello che si spegne, che e'
  il modo in cui questa applicazione ha sempre segnato una cosa compiuta.

  Mezzo secondo e non si ripete. Un anello che scintilla a ogni sguardo diventa un'insegna, e questa
  e' la prima cosa che si legge aprendo la giornata.

  La "from" senza "to" nel disegno dell'arco non e' una dimenticanza: senza il secondo fotogramma il
  valore d'arrivo e' quello calcolato sull'elemento, cioe' il punteggio vero scritto dal server. E'
  l'unico modo di animare fino a un numero che il foglio di stile non conosce.
*/
/* Dentro alla regola del movimento, come tutto il resto. Stava fuori, ed era un difetto vero: chi
   ha chiesto meno movimento si vedeva comunque l'anello disegnarsi. Trovato contando le animazioni
   in pagina con la preferenza attiva - ne restava una. */
@media (prefers-reduced-motion: no-preference) {
  /*
    Due secondi e mezzo, chiesti guardandolo: "animazione anello iniziale 2,5 sec". Era un secondo,
    ed e' il primo disegno che si vede aprendo l'applicazione: un arco che si chiude in un secondo
    e' un'informazione che compare, in due e mezzo e' una misura che si forma.

    Tutto cio' che viene dopo slitta con lui e non e' un dettaglio: la scintilla deve scoccare
    quando l'arco SI FERMA - se restasse a 0,95s scoccherebbe a meta' disegno, e il battito che la
    segue partirebbe sopra un anello ancora in movimento.
  */
  .gauge-hero.is-visible .gauge-arc { animation: gauge-draw 2.5s cubic-bezier(.2, .75, .3, 1); }
}
@keyframes gauge-draw { from { stroke-dashoffset: 389.6; } }

/*
  ---------- e nell'istante in cui si ferma, l'anello da' un colpo ----------

  "Quando finisce di caricare cerchio, contestualmente all'apparizione delle scintille, cerchio deve
  fare come una sorta di battito: aumentare il raggio e poi riportarlo a valore predefinito."

  Un colpo solo, non il polso che viene dopo. Il polso e' .gauge-pulse, comincia a 3,4 e non finisce
  mai; questo dura sei decimi, parte a 2,45 - lo stesso istante dei raggi - e serve a una cosa
  precisa: e' l'anello che spinge fuori le scintille, non l'anello che respira. Sale in fretta e
  torna piano, come una cosa colpita.

  Sei per cento e non di piu'. La scala allarga anche il tratto, quindi il bordo esterno passa da
  136,5 a 140,8 unita' del disegno: oltre, l'anello arriverebbe sotto la base dei raggi, che e' la
  cosa che questa animazione doveva evitare.

  transform-box: view-box perche' l'origine sia il centro del disegno - (70, 70) - e non l'angolo
  del riquadro che contiene i tre cerchi.
*/
.gauge-ring { transform-box: view-box; transform-origin: 70px 70px; }
@media (prefers-reduced-motion: no-preference) {
  .gauge-hero.is-visible .gauge-ring { animation: gauge-beat .6s cubic-bezier(.2, .8, .3, 1) 2.45s; }
}
@keyframes gauge-beat {
  0% { transform: scale(1); }
  30% { transform: scale(1.06); }
  100% { transform: scale(1); }
}

/*
  ---------- e poi l'anello batte ----------

  "Una volta renderizzato il cerchio deve pulsare, come fosse sangue che scorre."

  Non un respiro ma un battito, che e' una cosa diversa e si riconosce: due colpi vicini e una pausa
  lunga - il secondo piu' debole del primo, come il secondo tono del cuore. Un'onda regolare avanti e
  indietro legge come "sta caricando"; questa legge come un polso, che e' esattamente cio' che
  l'anello misura.

  A 52 battiti al minuto, cioe' un ciclo ogni 1,15 secondi. Non e' un numero preso a caso: e' il
  polso a riposo di chi corre, e su una scheda che si chiama condizione fisica un ritmo da sessanta
  sarebbe stato quello di chi e' seduto.

  Comincia dopo la scintilla, quando l'anello ha finito di disegnarsi e di festeggiare: prima
  sarebbero tre cose che si muovono insieme sulla stessa figura.

  A pulsare e' un secondo arco sovrapposto, e a pulsare di lui e' solo l'opacita' - l'unica cosa che
  un browser sa animare senza ridisegnare nulla. L'alternativa era far respirare il filtro dell'arco
  vero, cioe' ricalcolare due sfocature sessanta volte al secondo per sempre, sulla pagina che resta
  aperta piu' a lungo di tutte.
*/
.gauge-pulse {
  fill: none;
  stroke: url(#gaugeRun);
  stroke-width: 10;
  stroke-linecap: round;
  opacity: 0;
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--accent) 90%, transparent))
          drop-shadow(0 0 26px color-mix(in srgb, var(--accent) 55%, transparent));
}
@media (prefers-reduced-motion: no-preference) {
  .gauge-hero.is-visible .gauge-pulse { animation: gauge-heartbeat 1.15s ease-out 3.4s infinite; }
}
@keyframes gauge-heartbeat {
  0% { opacity: 0; }
  5% { opacity: .6; }   /* il primo tono */
  13% { opacity: .07; }
  19% { opacity: .34; } /* il secondo, piu' debole */
  30% { opacity: 0; }
  100% { opacity: 0; }  /* e la pausa, che e' i due terzi del battito */
}

/* Lo stesso alone dell'anello, cosi' la scintilla e' fatta della stessa luce e non incollata
   sopra. Sul gruppo e non sui singoli pezzi: nove filtri in un disegno da 140 unita' sono nove
   passaggi di sfocatura per qualcosa che dura mezzo secondo. */
.gauge-spark {
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--accent) 60%, transparent));
  /* view-box, cosi' l'origine dello scoppio e' il centro dell'anello - (70, 70) - e non l'angolo
     del riquadro che contiene raggi e punte. */
  transform-box: view-box;
  transform-origin: 70px 70px;
}
.gauge-ray, .gauge-star { fill: var(--accent); opacity: 0; }
/* fill-box, o "left" e' il bordo sinistro dell'intero disegno e il raggio partirebbe da fuori. */
.gauge-ray { transform-box: fill-box; transform-origin: left center; }
.gauge-star { transform-box: fill-box; transform-origin: center; }

/*
  Lo scoppio, sul gruppo intero.

  "Rendile un po' piu' stile fuochi d'artificio." Un fuoco d'artificio non e' fatto di pezzi che
  compaiono e si spengono sul posto: e' una cosa che si allontana dal centro mentre si spegne. Quindi
  la partenza la danno i singoli raggi, come prima, ma il gruppo che li contiene si allarga per tutta
  la durata - e siccome l'origine e' il centro dell'anello, allargarlo vuol dire spingere fuori tutto
  quanto insieme.

  Ed e' anche la seconda meta' della richiesta: mentre l'anello si gonfia le scintille se ne vanno,
  quindi non c'e' nessun istante in cui il cerchio arriva addosso a loro.
*/
@media (prefers-reduced-motion: no-preference) {
  .gauge-hero.is-visible .gauge-spark { animation: gauge-burst 1.1s cubic-bezier(.1, .7, .3, 1) 2.45s; }

  /* Tutto parte quando l'arco si ferma: 2,45 contro i 2,5 esatti del disegno.

     La durata del disegno e' stata regolata tre volte - mezzo secondo, poi uno, ora due e mezzo -
     e ogni volta questi ritardi sono slittati con lei. Non sono numeri indipendenti: sono "un
     soffio prima della fine dell'arco", scritti in secondi perche' il CSS non sa sommare. Chi
     cambia i 2,5s sopra deve rifare anche questi, altrimenti la scintilla scocca a meta' disegno.
     Il battito comincia dopo, a 3,4, quando l'anello ha finito di disegnarsi e di festeggiare. */
  .gauge-hero.is-visible .gauge-ray { animation: gauge-ray .9s cubic-bezier(.12, .7, .25, 1) 2.45s; }
  /* Tre tempi invece di due. Dodici trattini che partono insieme sono un lampo; a coppie erano
     qualcosa che si apre; a terzine, con otto centesimi fra l'uno e l'altro, e' una salva - che e'
     il modo in cui uno scoppio si sente davvero, a ondate e non tutto in una volta. */
  .gauge-hero.is-visible .gauge-rays > g:nth-child(3n + 2) .gauge-ray { animation-delay: 2.53s; }
  .gauge-hero.is-visible .gauge-rays > g:nth-child(3n) .gauge-ray { animation-delay: 2.61s; }
  .gauge-hero.is-visible .gauge-star { animation: gauge-star 1s cubic-bezier(.2, .8, .3, 1) 2.55s; }
  .gauge-hero.is-visible .gauge-star--2 { animation-delay: 2.68s; }
  .gauge-hero.is-visible .gauge-star--3 { animation-delay: 2.81s; }
}
/* Tutto si allontana dal centro, e i sedici per cento sono presi sulla distanza dal centro, non
   sulla lunghezza del raggio: a x = 142 vuol dire dodici unita' piu' in fuori. */
@keyframes gauge-burst {
  0% { transform: scale(1); }
  100% { transform: scale(1.16); }
}
/*
  Il raggio parte corto e acceso, si allunga andandosene e muore sottile: e' una scia, non un
  trattino che compare. Niente translateX negativo in partenza - era il pezzo che finiva sotto
  l'anello quando questo si gonfia.
*/
@keyframes gauge-ray {
  0% { transform: translateX(0) scaleX(.25); opacity: 0; }
  12% { opacity: 1; }
  55% { transform: translateX(8px) scaleX(1.15); opacity: .9; }
  100% { transform: translateX(20px) scaleX(.45); opacity: 0; }
}
/* La punta ammicca due volte prima di spegnersi: e' quello che distingue una scintilla che si
   spegne da una stellina che sfuma. */
@keyframes gauge-star {
  0% { transform: scale(0) rotate(-40deg); opacity: 0; }
  28% { transform: scale(1.15) rotate(0deg); opacity: 1; }
  48% { transform: scale(.7) rotate(12deg); opacity: .45; }
  68% { transform: scale(1) rotate(22deg); opacity: .9; }
  100% { transform: scale(.3) rotate(40deg); opacity: 0; }
}

/*
  Two jobs, two elements. The outer box centres inside the ring; the inner line
  sits "64" and "/100" on a shared baseline.

  They cannot be the same element: `align-items: baseline` on a flex container
  aligns items *within* their line, it does not centre the line in the cross
  axis - so the reading rendered against the top of the ring instead of in the
  middle of it.
*/
.gauge-inner {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
}
.gauge-reading { display: flex; align-items: baseline; gap: 3px; }
.gauge-score {
  font-size: 46px;
  font-weight: 800;
  line-height: 1;
  color: var(--accent-text);
}
.gauge-outof { font-size: 17px; font-weight: 600; color: var(--mut); }
/* What the ring measures, under the ring. Quieter than the state below it: it names the
   measurement once and should not compete with the reading, which is the part that changes. */
.gauge-caption {
  margin: 0;
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 2.4px;
  text-transform: uppercase;
  color: var(--mut2);
}

/* The reading, and the word the card is about: bigger than the caption over it (mock 01 makes it
   the card's title), still condensed and in capitals. Measured, not guessed: beside a 156-point
   ring on a 360-point phone the column is 122 points, and "ATTENZIONE" with its "?" fits at 14
   with a third of a point of spacing - at 20 it ran 47 points past the card, at
   15 still 7. "DATI ASSENTI" goes on two lines, which is why it is not a single-line label. */
.gauge-state {
  margin: 0;
  font-family: var(--cond);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .3px;
  line-height: 1.15;
  text-transform: uppercase;
  color: var(--ink);
}

/* ---------- section explainers ---------- */
/*
  Tap a section heading and it explains itself.

  Built on <details>/<summary>: the browser handles open/close state, keyboard
  access and screen-reader semantics, it works with scripts blocked, and it needs
  no inline handler - which matters, because our CSP allows none.

  The explanation flows *below* the heading rather than floating over the page.
  A floating panel was the first attempt and it could not be made to fit: anchored
  to a "?" sitting mid-card, on a 390px screen it ran 60px past the edge, and no
  amount of max-width fixes that without knowing where the "?" landed. Flowing
  inline, it is always exactly as wide as the card and can never be clipped. The
  cost is that opening one nudges the page down, which is the normal, expected
  behaviour of an accordion.
*/
.explain { flex: 1 1 auto; min-width: 0; }

.explain > summary {
  display: flex;
  align-items: center;
  gap: 10px;
  list-style: none;
  cursor: pointer;
}
.explain > summary::-webkit-details-marker { display: none; }
.explain > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.explain-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--field);
  color: var(--mut2);
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  user-select: none;
}
.explain > summary:hover .explain-mark,
.explain[open] .explain-mark { border-color: var(--accent-line); color: var(--accent-text); }

/*
  ---------- whether Strava is pushing, on the connections card ----------

  A small dot and two words, with the same "?" disclosure as the readiness ring. Not a hover
  tooltip: this is a phone, there is no hover, and a title attribute is an explanation nobody can
  reach with a thumb.

  The dot is decoration and says nothing on its own - the words beside it carry the state, which is
  why it is aria-hidden. It is not green/red either: neither state is an error. Push off means
  workouts arrive when the athlete presses the button, which is slower and perfectly fine, so "off"
  takes the muted colour the card uses for quiet facts and "on" borrows the accent.
*/
.strava-push { margin: 10px 0 2px; }
.strava-push > summary { gap: 8px; min-height: 32px; }
.push-state { font-size: 13.5px; color: var(--mut); }
.strava-push.is-live .push-state { color: var(--ink-2); }
.push-dot {
  width: 8px;
  height: 8px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--mut2);
}
.strava-push.is-live .push-dot {
  background: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}

.explain-body {
  margin: 12px 0 2px;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-soft);
  background: var(--field-soft);
  color: var(--mut);
  font-size: 13.5px;
  line-height: 1.65;
  text-align: left;
}

/* The readiness state: a summary with a body like every other explainer. Never a flex item sized to
   its own "?" - that is what let the text spill off both edges of the screen.

   OPEN, THE BODY TAKES THE WHOLE CARD, over what is under it. Since mock 01 the state sits in the
   column beside the ring, 122 points wide on a 360-point phone: a paragraph laid out in there is
   seventeen letters a line and fifteen lines long. So the open body leaves the column - positioned
   against `.readiness`, the card's full width, starting where it would have started - on the
   card's own opaque surface with a border, a note laid over the card and closed by the same "?".
   Opaque, not --panel: at 99% the coach's "Riprova" still showed through. */
.readiness-state { width: 100%; }
/* E APRENDO, LA PAROLA NON SI MUOVE. Il binario generico delle pieghe aperte (details.explain[open],
   piu' giu': un filo dell'accento a sinistra e sedici punti di rientro) qui spostava lo stato e il
   suo «?» di sedici punti a destra, con un filo dell'accento accanto, e a 360 punti il «?» usciva
   dal bordo della carta (verifiche del 26/09). Il corpo di questa piega non sta sotto il titolo ma
   sopra la carta, quindi il binario non abbraccerebbe niente: qui non c'e'. La specificita' e' quella
   del binario piu' una classe, cosi' vince dovunque stia. */
details.explain.readiness-state[open] { padding-left: 0; border-left: 0; }
details.explain.readiness-state[open] > summary { margin-left: 0; padding-left: 0; }
.readiness-state[open] > .explain-body {
  position: absolute;
  left: 0;
  right: 0;
  z-index: 2;
  margin-top: 8px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  box-shadow: var(--shadow-card);
}

/* Heading row: the explainer takes the space, any chip or link is pushed to the
   far end. */
.card-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.card-top > .status, .card-top > .microlbl, .card-top > .link-more { margin-left: auto; }

/* ---------- «I tuoi numeri», right under the ring ---------- */
/*
  A section of its own since mock 01 (26/09), straight after the ring card: the tiles keep their
  tile styling - each one is still a bordered box - and the wrapper adds no second border around
  them, which would put a frame around the frames. The heading is a card heading's size, on the
  left like every other.
*/
.load-block { margin-top: 18px; }
.load-heading { width: 100%; }
.load-heading h3, h3.load-heading { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -.2px; }
.load-block .tiles { margin-top: 10px; }
.load-block .alert { text-align: left; }

/*
  ---------- what is left of the day, in two numbers ----------

  In the drawer, above the eleven destinations. It was on the home first - a block, then a row under
  the state - and both times the objection was the same: it pushed the load figures, the ones the
  ring is made of, down the page. Here it pushes nothing at all, and there is room to set the two
  numbers large enough to read at a glance.

  The figures live inside the <summary>, which is the part that is always visible: opening the menu
  has to show them, and the "?" is there to explain them. Put them in the body and they would only
  appear after a press, and a counter that hides is a counter that does not exist.
*/
.ai-left {
  margin: 0 4px 14px;
  padding: 13px 15px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-soft);
  background: var(--field-soft);
}
.ai-left > summary { flex-wrap: wrap; gap: 8px; }
.ai-left-head {
  font-family: var(--cond);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 2.2px;
  text-transform: uppercase;
  color: var(--mut);
}
/* Su tutta la riga successiva: e' un <span> e non un <div> perche' sta dentro a <summary>, che
   accetta solo contenuto di testo. */
/*
  ---------- due misuratori, uno per riserva ----------

  "Deve essere una cosa del genere, graficamente come e' su Claude", con la schermata d'uso a
  fianco: ogni riserva e' una riga larga quanto il pannello - il nome a sinistra, "N% utilizzato" a
  destra - e sotto una barra piena per tutta la larghezza. La prima versione erano due colonnine
  strette con una barretta ciascuna: aveva preso l'idea di quella schermata e non la forma, e due
  barre larghe cinquanta pixel non si confrontano con niente.

  La barra si riempie con quello che e' stato SPESO. Una che si svuota legge come una batteria, che
  e' una cosa che si possiede; una che si riempie legge come un contatore, che e' una cosa che si
  consuma. Qui e' la seconda.

  Su tutta la riga successiva al titolo, e in colonna: sono <span> e non <div> perche' stanno dentro
  a <summary>, che accetta solo contenuto di testo.
*/
.ai-left-meters { flex: 0 0 100%; display: flex; flex-direction: column; gap: 14px; margin-top: 10px; }
.ai-left-meter { display: flex; flex-direction: column; gap: 7px; }
.ai-left-line { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.ai-left-what { font-size: 13.5px; color: var(--ink); }
.ai-left-pct {
  font-size: 12.5px;
  color: var(--mut);
  /* Le percentuali non devono ballare da 5% a 100%. */
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.ai-left-track {
  display: block;
  width: 100%;
  height: 6px;
  border-radius: 999px;
  background: var(--track);
  overflow: hidden;
}
.ai-left-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
}
/*
  E il colore avvisa, in tre gradini e non con una sfumatura: il punto di un colore qui e' che si
  noti senza essere letto, e una tinta che scivola dell'uno per cento alla volta e' una tinta che
  nessuno nota. Il giallo a settanta, il rosso a novanta - dove "ne resta parecchio" ha smesso di
  essere vero per la riserva di una giornata.
*/
.ai-left-fill--low { background: var(--warn); }
.ai-left-fill--spent { background: var(--danger); }
/* Una volta sola, sotto tutte e due: le riserve si riazzerano insieme. */
.ai-left-reset { font-size: 12px; line-height: 1.3; color: var(--mut2); }
.ai-left .explain-body { margin-top: 10px; }

/* The state sentence under the ring and its words, when the coach has not written today: the
   fallback of the coach's reading, in its place - full width across the ring card, left, like the
   reading it stands in for (mock 01, 26/09; it was a centred caption under a centred ring). */
.readiness-note {
  margin: 14px 0 0;
  font-size: 13px;
  line-height: 1.6;
}

/* ---------- chat thread: day separators ---------- */
/*
  The thread has no height and no scrollbar of its own. It is a column of messages as tall as the
  conversation, and the page is what scrolls.

  It used to be a scroll container - a fixed dvh height with overflow-y: auto - and that was
  reported after using it: reading the chat on a phone meant dragging a small window inside a page
  that would not move, where a flick starting on a bubble did something different from a flick
  starting two centimetres lower. A nested scroller on a touch screen is a fault however carefully
  it is built.

  The height was there for a real reason and the reason still stands: a page scroller starts at the
  top, so a months-old conversation opens at its first message with the input far below the fold.
  That is now solved where it belongs, in app.js, which puts the page at the end on load and after
  every reply - the same thing it already did to the thread, pointed at the window instead.

  Nothing else embeds this fragment, so there is one arrangement rather than a default and an
  override. If something ever does embed it, it will need a height of its own and app.js will need
  to be told which element scrolls.
*/
/* Day separator: a centred label with a rule running through it. */
.chat-day + .chat-day { margin-top: 4px; }
.day-sep {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 14px 0 10px;
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 2.4px;
  text-transform: uppercase;
  color: var(--mut2);
}
.day-sep::before, .day-sep::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line-soft);
}
.chat-day:first-child .day-sep { margin-top: 2px; }

/* Time of a message, beside the sender. Quieter than the name: it is there when
   looked for and out of the way when not. */
.bubble-who { display: flex; align-items: baseline; gap: 8px; }
.bubble-time {
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 1.2px;
  color: var(--mut2);
}

/* An optimistically added bubble, before the server has confirmed it. Slightly
   faded so the difference is visible without being alarming; the swap that brings
   the real thread back replaces it. */
.bubble-pending { opacity: .55; }
/* A refused question that could not go back into a box already written in again: it stays on screen,
   and says it did not leave (taglio 7, D1; app.js, rimettiLaDomanda). */
.bubble-not-sent { border-style: dashed; }
.bubble-not-sent .bubble-who { color: var(--danger-ink); }

/* ---------- native dropdowns and pickers ---------- */
/*
  A <select> popup is drawn by the browser on its own surface, not inside the
  card, so it does not inherit the page's background - it composites whatever
  background-color the control actually has. Ours was rgba(255,255,255,.03): a
  nearly transparent *white*, which looks dark over a dark card and renders as a
  white sheet in the popup. The closed control and the open list looked like they
  belonged to two different applications.

  The fix is an opaque colour plus explicitly styled options. Both come from
  tokens, so the light theme gets a light popup without another rule.
*/
select {
  background-color: var(--panel);
  background-image: none;
}
select option {
  background-color: var(--panel);
  color: var(--ink);
}

/*
  color-scheme tells the browser which way to draw the parts we cannot style at
  all: the date picker's calendar, the scrollbar inside a long dropdown, the
  spinner on a number field. It is set on :root, but `appearance: none` stops some
  browsers applying it to the widget, so it is repeated where it is needed.
*/
input, select, textarea { color-scheme: inherit; }
/* The calendar icon is drawn in black by default and vanishes on a dark field. */
:root:not([data-theme="light"]) input[type="date"]::-webkit-calendar-picker-indicator,
:root:not([data-theme="light"]) input[type="time"]::-webkit-calendar-picker-indicator {
  filter: invert(1) opacity(.65);
}

/* A validation message added by app.js reads exactly like a server-rendered one:
   the athlete should not be able to tell which side rejected their input. */
.field-error-live { animation: field-error-in .16s ease-out; }
@keyframes field-error-in {
  from { opacity: 0; transform: translateY(-2px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .field-error-live { animation: none; }
}
/* The offending control gets a red edge, so the message and the field agree. */
[aria-invalid="true"] { border-color: rgba(255, 92, 92, .55); }

/*
  ---------- una lettura che sta per essere sostituita ----------

  Mentre il coach riscrive, quella vecchia resta sullo schermo - e' meglio del vuoto se la chiamata
  fallisce - ma non deve leggersi come quella di adesso. Attenuata e basta: la riga sopra dice a
  parole cosa sta succedendo, e sovrapporle un secondo segnale sarebbe rumore.

  Attenuata e non sbarrata: e' ancora l'ultima cosa che il coach ha detto, e finche' non arriva la
  nuova e' l'informazione migliore disponibile.
*/
.ai-feedback.is-superseded { opacity: .5; }

/*
  ---------- "perche' hai saltato?" ----------

  Il giorno dopo una seduta non fatta. Una scheda che fa una domanda, quindi si legge come una
  domanda: il titolo, la seduta di cui si parla, e le cinque risposte una sotto l'altra.

  Ogni risposta e' una <details>. Il riquadro che si apre NON si distanzia con gap: il contenuto di
  un details vive in una scatola anonima (::details-content) e il gap separa solo il riassunto dal
  contenuto, mai i figli fra loro. Quindi margini, come ovunque qui dentro.
*/
/*
  Di quale allenamento si tratta: icona, disciplina, giorno, quanto era previsto.

  "Metti data, tipo logo e tipo di allenamento (esempio: corsa 06/09 5 km)." Era una riga di testo
  sotto il titolo e si perdeva; e' la cosa che l'atleta deve riconoscere per prima, perche' due corse
  nella stessa settimana si distinguono solo per il giorno e per la distanza.
*/
.skip-box .skip-what {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 6px;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -.2px;
}
.skip-box .skip-what > .ico { flex: 0 0 auto; color: var(--ico-tint, var(--accent)); }
/* Il giorno e la quantita' sono l'identita' della seduta, non una decorazione: stessa riga, un
   gradino sotto come peso, e cifre incolonnate perche' sono numeri. */
.skip-box .skip-when,
.skip-box .skip-howmuch {
  font-family: var(--cond);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: .6px;
  color: var(--mut);
  font-variant-numeric: tabular-nums;
}
.skip-box .skip-intro { margin-top: 8px; font-size: 13px; }

.skip-option {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}
/*
  La prima voce e' un <button> e le altre quattro un <summary>: devono leggersi uguali.

  Era un .btn - centrato, maiuscoletto, largo quanto la scheda - e a colpo d'occhio sembrava
  l'azione principale invece che la prima delle cinque risposte. Qui si pareggiano: stesso riquadro,
  stesso allineamento a sinistra, stesso peso. L'unica differenza resta quella vera, cioe' che non
  si apre.
*/
.skip-option-plain {
  text-align: left;
  font: inherit;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}
.skip-option > summary {
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
.skip-option > summary::-webkit-details-marker { display: none; }
.skip-option[open] > summary { color: var(--accent-text); }
.skip-option label { display: block; margin-top: 12px; }
.skip-option input, .skip-option textarea { margin-top: 6px; }
.skip-option .skip-hint { margin-top: 6px; font-size: 12.5px; }
.skip-option .btn { margin-top: 12px; }

/* ---------- tracker: plan vs done ----------
   A bare "10" beside an editable "10" reads as the same number twice, which is what
   made the tracker look like it was editing the schedule rather than logging today.
   The labels are what tell the two apart. */
.set-label {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--mut2);
}

/* "Nota salvata", per i due secondi dopo che una nota si e' salvata da sola: sulla pagina non
   cambia nient'altro quando si esce dal campo, quindi senza questo non si saprebbe. Il disegno e'
   quello dell'avviso in cima alla pagina, piu' sotto, insieme agli altri due: qui non resta niente,
   perche' ogni riga che c'era la riscriveva quella. */

/*
  ---------- "scheda salvata", "esercizio salvato" ----------

  Asked for from production: "quando salvo un esercizio o una scheda deve apparire 'esercizio
  salvato', 'scheda salvata'". Both saves answer with the same fields the athlete had just filled
  in, so a page that saved and a page that did not are pixel for pixel the same - the only way to
  find out which had happened was to leave and come back.

  Written by the server into the fragment, not by a script: both actions swap the markup they are
  in, so anything the browser had put on screen would be swapped away with it.

  It leaves on its own after a few seconds. A confirmation that stays is furniture within a minute,
  and the athlete stops reading it - which is the same as not having it. In ok green rather than the
  accent, because the accent is what marks things to act on and this is not one.
*/
/*
  ---------- "scheda salvata", in cima e non di fianco ----------

  Stava accanto al bottone, in una colonna larga due parole, spezzata su due righe e sotto il pollice
  che aveva appena premuto - cioe' esattamente dove non si guarda dopo aver premuto, e dove il dito
  la copre. Chiesto come un toast in alto, ed e' il posto giusto: la conferma di un'azione si legge
  dove la pagina comincia, non dove finisce.

  position: fixed e non sticky: la conferma non appartiene alla barra di salvataggio ne' alla riga
  dell'esercizio - viene da li' nel markup solo perche' e' il server a scriverla dentro il frammento
  che rimanda indietro, ed e' li' che deve stare per sopravvivere allo scambio. A schermo e' un
  avviso della pagina.

  Sotto la barra in alto, non sopra: quella e' fissa e la coprirebbe.
*/
/*
  One success language everywhere. Page-level saves used .alert-success while the plan builder and
  exercise tracker used .saved-flash, so the same completed action moved around and changed colour
  between screens. All transient save confirmations now share the plan builder's green top toast.
  Its z-index 100 counts only inside <main>: .app-shell makes a stacking context (z-index 2, above the
  footer), so the toast stays under the sticky bar (30) and the drawer (40/41), which is where it is
  meant to sit - the old sentence here said it was above them all (checks of cut 4a, 26/09).
*/
.alert-success,
.note-saved,
.saved-flash {
  position: fixed;
  top: calc(var(--bar-h) + 10px);
  left: 12px;
  right: 12px;
  z-index: 100;
  width: fit-content;
  max-width: calc(100% - 24px);
  margin: 0 auto;
  padding: 13px 18px;
  border: 1px solid color-mix(in srgb, var(--ok) 45%, transparent);
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--ok) 14%, var(--panel));
  box-shadow: var(--shadow-panel);
  font-size: 15px;
  font-weight: 600;
  text-align: center;
  color: var(--ok);
  pointer-events: none;
  animation: saved-fade 4s ease-out forwards;
  /* IN TONDO, con la sola iniziale maiuscola: "i testi del toast non devono essere [maiuscoli], ma
     solo la prima lettera". Uno di questi tre arrivava da una regola piu' in su che lo faceva
     condensato e tutto maiuscolo - NOTA SALVATA - mentre gli altri due erano una frase normale:
     lo stesso avviso cambiava voce a seconda di chi lo mandava. Scritto qui e non lasciato
     all'assenza di una regola, perche' l'assenza e' precisamente cio' che non aveva funzionato. */
  font-family: var(--sans);
  letter-spacing: normal;
  text-transform: none;
}
@keyframes saved-fade {
  0% { opacity: 0; transform: translateY(-8px); }
  8%, 65% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translateY(-8px); }
}
/* For anybody who has asked for less movement it simply stays: a message that never fades is a
   smaller imposition than one that does, and this one is three words. */
/*
  ---------- sette secondi, non quattro ----------

  "Il toast che appare qui quando fai 'leggi quello che ho scritto' deve rimanere per almeno 7
  secondi."

  Ha ragione, e il motivo e' che questo non e' un "salvato". Gli altri avvisi a comparsa confermano
  un gesto appena fatto e si leggono in una parola; questo porta l'elenco degli obiettivi che il
  coach ha spuntato al posto tuo, e va confrontato con quello che avevi scritto. Quattro secondi
  sono il tempo di accorgersi che c'e' un elenco, non di leggerlo.

  Curva sua e non solo una durata piu' lunga: allungando saved-fade le percentuali restano
  proporzionali, quindi otto secondi darebbero comunque quattro secondi e mezzo di lettura e il resto
  in dissolvenza. Qui invece resta pieno fino all'88% - circa sei secondi e mezzo - e sfuma solo alla
  fine.
*/
.goal-suggested { animation: goal-read-fade 7.5s ease-out forwards; }
@keyframes goal-read-fade {
  0% { opacity: 0; transform: translateY(-8px); }
  4%, 88% { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translateY(-8px); }
}

@media (prefers-reduced-motion: reduce) {
  .alert-success,
  .note-saved,
  .saved-flash,
  /* Anche questo: chi ha chiesto meno movimento se lo tiene fermo, ed e' il piu' lungo da leggere
     dei tre - restare e' un'imposizione minore che sparire mentre lo si legge. */
  .goal-suggested { animation: none; }
}

/* Exercise names already stored in lower case keep displaying with a capital, without a
   migration. New ones are capitalised on the way in (TrainingPlanService#exerciseName);
   this covers what is already in the database. ::first-letter, not text-transform:
   capitalize, which would make "flat bb press" into "Flat Bb Press" and "RDL" into "Rdl". */
.plan-builder-exercise h3::first-letter,
.session-exercise h3::first-letter { text-transform: uppercase; }

/* The × that removes a logged workout. Deliberately quiet and at the end of the row:
   destructive, so it must be reachable but never the thing the thumb lands on when the
   athlete meant to open the workout. */
/* Il modulo della X dello storico: un <form> che non aggiunge niente alla riga, e stende la X per
   tutta l'altezza (la colonna e la misura dei comandi stanno con le righe del taglio 5, in fondo al
   foglio). */
.history-delete { flex: 0 0 auto; margin: 0; display: flex; align-items: stretch; }

/*
  ---------- a record, marked ----------

  The trophy and the distance, on the row of the workout that holds the athlete's best time. Quiet on
  purpose: it is a reward, not a warning, and a list where one row shouts is a list that reads as an
  error. The accent's own colour with a soft fill, so it belongs to the palette and follows the one the
  athlete chose.

  The word travels with the icon - never the trophy alone. Recognising a shape is not the same as being
  told, and this is the kind of detail an athlete will want to be sure of.
*/
.history-pb {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 6px;
  padding: 2px 8px 2px 6px;
  border-radius: 999px;
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  color: var(--accent-ink);
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 1.1px;
}
.history-pb .ico { width: 14px; height: 14px; }
/* Dentro alla riga sotto al nome il bollo non puo' essere un bollo: un bordo e un fondo alzano
   quella riga, e alzarla su UNA tessera vuol dire una tessera piu' alta delle altre - lo scalino
   che la regola vieta. Resta la corona con la parola accanto, nell'accento: "mai la coppa da
   sola". */
.record-sub .history-pb {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  gap: 3px;
  font-size: inherit;
  letter-spacing: inherit;
  color: var(--accent-text);
}
.record-sub .history-pb .ico { display: block; width: 12px; height: 12px; }
/* `line-height: 1` e `vertical-align: middle`, e sono la differenza fra tessere alte uguale e no:
   una scatola in linea alta quanto la riga si appoggia alla linea di base e sporge sotto, quindi la
   riga cresce di due pixel - su UNA tessera, quella con il record. Misurato: 67, 69, 67, 67. */
.record-sub .history-pb { line-height: 1; vertical-align: middle; }

/* La riga piccola dello storico in pezzi che non cedono (taglio 5, 26/09): il giorno e l'ora; su una
   riga con un record, la corona con «Record» al posto dell'ora e poi il giorno, che c'e' intero o non
   c'e' - una riga sola alta una riga, con il resto a capo dove non si vede, come la riga piccola di una
   gara (.event-row-bits). Giorno e ora sono la riga piccola piu' lunga dell'applicazione, undici
   caratteri; dopo di loro «RECORD 10K» a 360 e 390 non ci stava mai (verifiche del 26/09). Due classi
   nel selettore: `.record-sub`, mille righe piu' giu', pesa quanto `.history-sub` e rimetterebbe la sua
   spaziatura. Misurato su tutte le righe a 360, la piu' stretta con «16,0 km». */
.record-sub.history-sub {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  column-gap: .5em;
  height: 1.4em;
  letter-spacing: .4px;
}
/* Ogni pezzo alto quanto la riga: la corona e «Record» hanno una riga di un em (`.record-sub .history-pb`),
   e da soli sulla prima riga la facevano piu' bassa - la cima del giorno, mandato a capo, si vedeva sotto
   (visto nel browser dopo le verifiche del 26/09). */
.record-sub.history-sub > * { flex: none; height: 1.4em; }
/* Sulla riga con un record il giorno viene dopo, e il punto che lo separa lo scrive il foglio di stile
   sul giorno: se il giorno non ci sta, se ne va con lui. */
.history-pb + .history-day::before { content: "\00b7\00a0"; }

/* Un <svg> in linea si siede sulla linea di base, e la riga tiene sotto di lui lo spazio per le
   pance delle lettere che non ci sono: il segno risulta alto nella sua cella. display:block toglie
   la riga - e' la trappola scritta in CLAUDE.md. */
/* Il colore non sta qui: lo dava `button.history-share { color: var(--accent) }`, che pesa 0-1-1
   esattamente quanto `button.orb-x` - e quella arriva seimila righe piu' giu' e vince a parita'.
   L'icona usciva nell'inchiostro della pagina. Adesso lo decide una regola sola, dopo l'orb-x:
   cerca «l'icona condividi e' sempre colorata». */
.history-share .ico { display: block; width: 20px; height: 20px; }

/* ---------- last session card ----------
   Four figures in a 2x2 grid: each one has room to be read at arm's length, which a row of
   four never does on a phone. */
/*
  Where a session came from - STRAVA, and one day GARMIN and the rest.

  Tiffany, and fixed rather than following the athlete's accent. It is not a control and it is not
  about them: it says who recorded this workout, and a badge in the same pink as every button on the
  page reads as something to press. The same reasoning as the training icons, which is also why it is
  the same colour as them.
*/
/*
  Both pills, one rule, because they had to be exactly the same height: they stood in the right-hand
  column of a workout on the last-session card. Davide asked for that in those words - "esattamente
  alto quanto il bottone del dispositivo" - and two rules with the same numbers written twice is two
  rules that drift apart the first time one of them is touched. Everything that decides the height
  lives here; only the colour differs below. Dal 27/09 la carta non le usa piu' (l'origine sta nella
  riga piccola, l'eliminazione e' la X): il badge resta a /diet, la pillola rossa nel costruttore delle
  schede.
*/
.badge-synced,
.badge-delete {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--cond);
  font-size: 12px;
  line-height: 1.2;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  border-radius: 999px;
  padding: 4px 10px;
  white-space: nowrap;
}
.badge-synced {
  color: var(--tiffany);
  border: 1px solid var(--tiffany-line);
}
/*
  "Aggiunto": an exercise the schedule did not have, added during the workout.

  It shares the pill above rather than restating its numbers, for the reason written there. The
  accent colour, not the Tiffany one: Tiffany means "this came from somewhere else" - a device, a
  file - and this came from the athlete, in the gym, a minute ago.
*/
.badge-added {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--cond);
  font-size: 12px;
  line-height: 1.2;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  border-radius: 999px;
  padding: 4px 10px;
  white-space: nowrap;
  color: var(--accent-text);
  border: 1px solid var(--accent-line);
}
/* The delete: the same pill in red, and it asks before it does anything. */
.badge-delete {
  width: auto;
  margin: 0;
  /* The tokens the rest of the application already uses for danger, so this follows the theme
     rather than carrying two colours of its own. */
  color: var(--danger-ink);
  background: none;
  border: 1px solid var(--danger);
  cursor: pointer;
}
.badge-delete:hover { color: var(--danger); border-color: var(--danger); }
/* L'origine accanto al nome di un esercizio del tracker, con «aggiunto» o «modificato»: si allinea
   da sola al titolo. */
.session-source {
  display: inline-flex;
  align-items: center;
}
.metric-grid {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
/* La tessera: la faccia della pagina, il fianco del suo stesso colore, l'ombra corta di una
   casella appoggiata sulla carta.

   PROVATA COL COLORE DELL'ACCENTO E ANNULLATA. Erano rosa, verdi, arancioni a seconda della
   tavolozza, con etichetta e icona nell'inchiostro che ci si legge sopra; l'atleta le ha viste e ha
   chiesto di rimetterle com'erano. Restano qui le due righe che erano il lavoro vero e che valgono
   comunque, il giorno in cui si riprovasse: l'etichetta si attenua con la STESSA tinta a
   un'opacita' piu' bassa, mai con un grigio - su una faccia colorata un grigio e' un terzo colore -
   e l'icona non puo' essere dell'accento, perche' un'icona del colore del fondo su cui sta e'
   un'icona che non c'e'.

   --solid e' --surface-2, cioe' la faccia che queste caselle hanno sempre avuto. La dichiarazione
   diceva var(--field), ma non e' mai stata in vigore - il var() dentro --metal-face si risolveva su
   :root - e adesso che il meccanismo funziona quella riga cambierebbe l'aspetto invece di
   confermarlo. Fra la dichiarazione e cio' che si vede da mesi vince cio' che si vede; e' scritta
   qui per intero perche' il prossimo che legge "com'era prima" non la ripristini all'incontrario.

   IL FIANCO E' QUELLO DELLA CARTA (27/09): era da tre, e la regola di Luca vuole i riquadri che non
   si premono tutti con lo stesso bordo, da due ("schede ecc 2px"). L'ombra resta quella corta di
   una casella appoggiata, --shadow-tile, che vale per i due temi: prima era scritta a mano qui e ripetuta sotto per il chiaro. */
.metric {
  --solid: var(--surface-2);
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  padding: 12px 14px;
  background: var(--metal-face);
  border: 1px solid var(--line-soft);
  border-radius: 12px;
  box-shadow: var(--edge-lit), var(--lift-edge), var(--shadow-tile);
}
.metric-label {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.3px;
  text-transform: uppercase;
  color: var(--mut2);
}
.metric-value {
  display: block;
  font-size: 15px;
  font-weight: 800;
  margin-top: 5px;
  letter-spacing: -.3px;
  font-variant-numeric: tabular-nums;
}
/* Il riquadro che c'e' anche senza un valore: la griglia della palestra ha sempre quattro riquadri
   allo stesso posto, e dove manca un numero scrive che manca. Tenue, e non in grassetto: e' uno
   stato, non una misura, e letto accanto a tre cifre non deve sembrare la quarta. */
.metric-value.metric-missing {
  font-weight: 500;
  letter-spacing: 0;
  color: var(--mut);
}

/*
  The one figure on this card that is an opinion: BUONA, OTTIMA, SCARSA.

  In the same ink as the three figures beside it, not in the accent. It was accent-coloured, and the
  athlete's verdict was that it broke the continuity of the row: four tiles side by side are four
  readings of one session, and colouring one of them makes it read as a badge or a link rather than
  as the fourth thing to read. The size and the weight are what mark it out; the colour is what tied
  it back to the rest.

  No colour declaration at all, deliberately, so it inherits the card's ink and follows the light and
  dark themes the way every other value does.

  Condensed and letter-spaced like the other display type in the interface, so a five-letter word
  and a nine-letter one both look deliberate in a tile 45% of a phone wide.
*/
.metric-grade {
  font-family: var(--cond);
  font-size: 19px;
  font-weight: 700;
  letter-spacing: 1.4px;
}
/* While the coach is deciding. Small and quiet: it sits beside three figures that are already
   readable, and it is replaced by the word itself a moment later. */
.metric-grade-wait { font-size: 12px; line-height: 1.35; }


/* ---------- nutrition monitor ----------
   The one place in the application where an icon is not monochrome. Calories, carbohydrate,
   protein and fat are four quantities read at a glance, and a colour tells them apart faster than
   a word does. Defined here and nowhere else: the template carries a class per row and names no
   colour at all.

   LE CALORIE PRENDONO IL TEMA, i carboidrati un verde fisso (Davide, 25/09). La barra delle calorie
   segue la cifra grande, che e' dell'accento; i carboidrati lo erano, e sopra di loro due barre
   dello stesso colore si sarebbero lette come una. Il verde e' scuro apposta: e' quello che resta
   piu' lontano da tutti e sette gli accenti - 25 di distanza percepita dal verde del tema verde, 20
   dal ghiaccio, il minimo - e da proteine e grassi.

   L'accento DA LEGGERE, come la cifra grande che la barra segue: con volt nel chiaro l'accento nudo e'
   giallo pallido sul bianco, e la barra e il quadratino «Calorie» non si vedevano (verifica del browser
   del taglio 6, 26/09). Nel buio e' lo stesso colore. */
.macro-kcal    { --macro: var(--accent-text); }
.macro-carbs   { --macro: #16a34a; }
.macro-protein { --macro: #2ee6ff; }
.macro-fat     { --macro: #ffc233; }

.nutrition-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-top: 12px;
}
.nutrition-title { font-size: 16px; font-weight: 600; }
.nutrition-kcal { flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.nutrition-kcal-value { color: var(--accent-text); font-size: 20px; font-weight: 600; }
.nutrition-kcal-target {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.3px;
  color: var(--mut2);
}
/*
  Le tre righe dei giorni con un allenamento dentro: il netto grande e sopra, i due addendi sotto.

  UNA GRIGLIA E NON TRE RIGHE FLESSIBILI, ed e' il motivo per cui si vede la sottrazione: "scritte
  allineate a sx, numeri allineati a destra ma devono essere tutti allineati sul loro bordo
  sinistro". Con tre righe indipendenti ogni etichetta e ogni numero trovano il proprio posto e le
  cifre finiscono sfalsate - 1509, 1900 e 391 partono da tre punti diversi e non si leggono piu'
  come una colonna. Due colonne condivise dalle tre righe fanno l'unica cosa che qui conta: le
  etichette hanno tutte lo stesso margine sinistro, e i numeri pure.

  Il blocco intero resta a destra (justify-content: end) perche' la riga che lo contiene ha la
  spiegazione a sinistra; dentro, la colonna dei numeri e' allineata a sinistra.

  align-items: baseline tiene l'etichetta sulla linea del numero anche dove i due corpi sono
  diversi, che e' proprio la riga del netto.
*/
/*
  ---------- il riquadro dei giorni con un allenamento dentro ----------

  LA GRIGLIA E' LA TESTATA, non un blocco sotto di lei, e questo e' il perno di tutto il disegno:
  "la cifra deve essere allineata al titoletto". Il titolo occupa la prima cella e la cifra grande
  la seconda, quindi "Calorie effettive" e 1509 stanno sulla stessa linea di base; le due righe
  piccole si impaginano sotto, nelle stesse due colonne, e le tre cifre restano incolonnate fra
  loro. Con il blocco separato sotto al titolo la cifra grande finiva una riga piu' in basso, con
  mezza carta vuota alla sua sinistra.

  La spiegazione occupa la riga intera (grid-column: 1 / -1) perche' aperta sono quattro paragrafi,
  e dentro a una colonna larga il 60% della carta sarebbero quattro colonne di parole singole. La
  cifra ci sta sopra, nella sua cella, e la copre: per questo il <summary> e' fit-content e non
  tutta la riga - largo quanto la riga, il bersaglio del tocco starebbe anche sotto al numero, e
  toccare 1509 aprirebbe la spiegazione.
*/
.nutrition-head-split {
  display: grid;
  grid-template-columns: 58% minmax(0, 1fr);
  align-items: baseline;
  column-gap: 10px;
  row-gap: 3px;
}
.nutrition-head-split > .nutrition-explain { grid-column: 1 / -1; grid-row: 1; }
.nutrition-head-split > .nutrition-explain > summary { width: fit-content; }
/* Il blocco si scioglie nella griglia della testata: i suoi figli ne diventano celle. */
.nutrition-head-split > .nutrition-kcal-split { display: contents; }
.nutrition-kcal-split {
  display: grid;
  /*
    minmax(0, 1fr) e non auto sulle etichette. Il minimo implicito di una colonna e' il suo
    contenuto, quindi con `auto auto` le due colonne sommano la parola piu' lunga
    ("CALORIE CONSUMATE") e la cifra piu' lunga ("1900 / 2000 KCAL"), e su un telefono da 360 il
    totale e' piu' largo della carta. Non si vedrebbe nemmeno: `body { overflow-x: clip }` taglia
    invece di far scorrere, quindi il numero sparirebbe fuori dal bordo destro e la carta
    sembrerebbe a posto. E' la stessa trappola di `1fr` gia' scritta in CLAUDE.md, dall'altro lato.

    La prima colonna e' META' DELLA CARTA ESATTA e la seconda comincia dove finisce lei: le
    etichette partono dal bordo sinistro del riquadro, le cifre da una riga invisibile a meta' -
    "le scritte devono essere allineate al bordo sx del box, i numeri immagina come ci fosse una
    linea invisibile al centro del box, devono essere allineati a quella".

    Una percentuale e non una colonna a contenuto, ed e' la differenza fra una riga di mezzo e una
    che sembra tale: a contenuto il punto in cui cominciano le cifre lo deciderebbe la piu' lunga
    fra loro, quindi si sposterebbe da un giorno all'altro - 391 e 1509 non mettono il confine
    nello stesso posto.
  */
  /*
    Dove comincia la colonna delle cifre, e perche' proprio li'.

    "I numeri allineati alla prima cifra ma piu' spostato verso bordo dx" - chiesto due volte, e il
    limite non e' un gusto ma una misura: su una carta larga 292, cioe' un telefono da 360, quello
    che resta a destra deve tenere "1509 / 2000" con la cifra a 24px. Provato al 64%: "/ 2000"
    andava a capo da solo sotto al numero. Al 58% ci sta, e la colonna comincia comunque ben oltre
    la meta' del riquadro.

    E' anche il motivo per cui il tetto e' scritto una volta sola, accanto alla cifra grande: sulla
    riga delle assunte erano altri quaranta pixel spesi per ripetere lo stesso 2000.
  */
  grid-template-columns: 58% minmax(0, 1fr);
  align-items: baseline;
  column-gap: 10px;
  row-gap: 3px;
}
/* La riga non e' un contenitore: display: contents la scioglie e le sue due parti diventano celle
   della griglia sopra, che e' cio' che le fa incolonnare con quelle delle altre righe. Il <span>
   resta nel markup perche' e' li' che si legge cosa sta insieme a cosa. */
.nutrition-kcal-row { display: contents; }
/* Tutte e due le celle partono dal proprio bordo sinistro: e' cio' che incolonna le cifre fra
   loro, e le etichette fra loro, invece di appoggiarle ognuna alla fine del proprio testo. */
.nutrition-kcal-row > * { justify-self: start; }
/* Il netto non ha etichetta - il titolo della carta e' la sua - quindi si mette da se' nella
   seconda colonna, dove ci sono le altre cifre. Senza questo finirebbe in prima e la colonna dei
   numeri avrebbe un buco proprio sulla riga che si legge per prima. */
/* Sulla riga del titolo, seconda colonna: e' la cella accanto a "Calorie effettive". */
.nutrition-kcal-net { grid-column: 2; grid-row: 1; justify-self: start; }
/* Piu' grossa della cifra dei giorni senza allenamento, perche' qui e' l'unica cosa accesa in un
   riquadro che ne ha tre: "essere piu' grossa". */
.nutrition-kcal-split .nutrition-kcal-value { font-size: 24px; }
/* La spaziatura del tetto si stringe: sono i pixel che decidono se "/ 2000" resta sulla riga del
   numero o ci va sotto. */
.nutrition-kcal-net .nutrition-kcal-target { letter-spacing: .6px; }
.nutrition-kcal-label {
  font-family: var(--cond);
  font-size: 11px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--mut);
}
/* Gli addendi: l'inchiostro normale, non l'accento e non il grigio dei suggerimenti - chiesto
   "nero non grassettato", cioe' nero o chiaro secondo il tema, che e' quello che fa --ink. Il
   colore dell'accento resta al netto e basta: due numeri accesi accanto a uno acceso non dicono
   piu' quale dei tre e' la risposta. */
.nutrition-kcal-partvalue {
  color: var(--ink);
  font-size: 14px;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}
.nutrition-no-target { margin: 8px 0 0; font-size: 12.5px; }

/* Inside the head the explainer is a row, not a card heading. */
.nutrition-explain > summary { display: flex; align-items: center; gap: 8px; cursor: pointer; }

/* ---------- the athlete's own ceilings, in their sheet ---------- */
.macro-edit-form input { margin-bottom: 10px; }
.macro-edit-hint { margin: 2px 0 14px; font-size: 12.5px; line-height: 1.5; }

.macro-list { list-style: none; margin: 16px 0 0; padding: 0; }
/* Two rows in a three-column grid: icon, name, amount on the first; the track spans all
   three on the second. A bar under its own label is easier to scan down a column than one
   squeezed to the right of it. */
.macro {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 6px 10px;
  padding: 9px 0;
}
.macro + .macro { border-top: 1px solid var(--line-soft); }
.macro-icon {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  background: var(--macro);
}
.macro-name { font-size: 14px; min-width: 0; }
.macro-amount {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.1px;
  color: var(--mut);
  font-variant-numeric: tabular-nums;
}
/* Il numero oltre l'obiettivo, in tutte e quattro le righe: la barra e' gia' piena e non puo' dirlo
   da sola. Il numero e basta, non "/ 2300 kcal": e' lui ad aver passato il segno. */
.macro-amount .macro-over { color: var(--over); }
.macro-track {
  grid-column: 1 / -1;
  height: 4px;
  border-radius: 999px;
  background: var(--field);
  overflow: hidden;
}
/*
  ---------- le colonne dei grafici crescono dal basso ----------

  "Anima anche queste colonne, devono crescere in 1 secondo, solo quando sono circa al centro dello
  schermo... animate solo la prima volta che le vedi o quando ricarichi o torni in home, non
  sempre."

  Le due carte a colonne - i sette giorni e il volume settimanale - salgono da terra in un secondo.
  Come per le barre dei macro l'altezza resta quella della classe che il server scrive, e
  l'animazione va da zero a quella: senza script le colonne sono semplicemente alte come devono.

  L'origine e' il fondo, dichiarata: senza, una colonna crescerebbe dal proprio centro, cioe' verso
  l'alto E verso il basso attraverso la linea di base del grafico.

  Una volta per apertura, non a ogni passaggio: chi guarda scorre su e giu' per la stessa pagina, e
  colonne che ripartono ogni volta smettono di essere un ingresso e diventano un tic. Se ne occupa
  app.js, che smette di osservare l'elemento appena la classe e' messa - ricaricare o rientrare in
  home sono pagine nuove, e li' ricominciano.
*/
.day-fill, .volume-fill { transform-origin: bottom center; }
@media (prefers-reduced-motion: no-preference) {
  .day-bars.is-visible .day-fill,
  .volume-bars.is-visible .volume-fill {
    animation: colonna-cresce 1s cubic-bezier(.2, .75, .3, 1);
  }
}
/* Solo il "from", come l'anello e le barre: il valore d'arrivo e' quello calcolato sull'elemento. */
@keyframes colonna-cresce { from { transform: scaleY(0); } }

/* Una etichetta per volta sulla piega dei pasti: il conto quando e' chiusa, "riduci" quando e'
   aperta. Stessa regola della piega del consiglio, scritta accanto a cio' che governa. */
.meal-more .meal-more-close,
.meal-more[open] .meal-more-open { display: none; }
.meal-more[open] .meal-more-close { display: inline; }

.macro-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--macro);
  /* Cresce dal proprio bordo sinistro. Senza un'origine dichiarata si allargherebbe dal centro,
     che su una barra di progresso e' il movimento sbagliato: dice "si sta gonfiando" invece di
     "si sta riempiendo". */
  transform-origin: left center;
}
/*
  ---------- e le barre si riempiono ----------

  "Le linee del monitor nutrizionale devono crescere da sx verso dx con le stesse tempistiche
  dell'anello all'inizio - portale a 1 sec tutte", poi "falle caricare in due secondi anziche' in un
  secondo, ma solo quelle", e infine "aumenta tempo a 2,5 secondi".

  Due secondi e mezzo, quindi, mentre l'anello resta a uno. La stessa curva pero' si', perche' e' quella a
  dare il carattere del movimento: quello che cambia e' che una barra ha una lunghezza da percorrere e
  la si guarda percorrerla, mentre l'anello e' un numero che si posa.

  Tutte e quattro insieme: sono i quattro pezzi di una giornata sola, e sfalsarle direbbe che uno
  viene prima dell'altro.

  La classe la mette app.js quando la lista entra nello schermo - la scheda alimentare sta sotto alla
  piega, e una barra che si riempie mentre nessuno la guarda e' una barra che nessuno vede riempirsi.
  Senza script la classe non arriva, non c'e' nessuna animazione, e la barra e' piena come e' sempre
  stata: e' per questo che si aggiunge una regola invece di toglierla.
*/
@media (prefers-reduced-motion: no-preference) {
  .macro-list.is-visible .macro-fill { animation: macro-grow 2.5s cubic-bezier(.2, .75, .3, 1); }
}
/* Solo il "from": il valore d'arrivo e' quello calcolato sull'elemento, cioe' la larghezza che la
   classe fill-N gli ha dato. Come per l'anello, e' l'unico modo di animare fino a un numero che il
   foglio di stile non conosce. */
@keyframes macro-grow { from { transform: scaleX(0); } }
/* Width from a class, never a style attribute: script-src/style-src 'self' with no
   'unsafe-inline' blocks an inline style, and every bar would sit at zero. Five per cent
   steps are finer than the eye reads on a 4px bar.

   Non piu' legate a .macro-fill: le usa anche la riserva giornaliera nel menu, ed erano l'unica
   cosa che avrebbe dovuto essere scritta due volte. Una famiglia di larghezze per tutta
   l'applicazione, e chi ne aggiunge una terza non deve copiare ventuno righe. */
.fill-0 { width: 0%; }
.fill-5 { width: 5%; }
.fill-10 { width: 10%; }
.fill-15 { width: 15%; }
.fill-20 { width: 20%; }
.fill-25 { width: 25%; }
.fill-30 { width: 30%; }
.fill-35 { width: 35%; }
.fill-40 { width: 40%; }
.fill-45 { width: 45%; }
.fill-50 { width: 50%; }
.fill-55 { width: 55%; }
.fill-60 { width: 60%; }
.fill-65 { width: 65%; }
.fill-70 { width: 70%; }
.fill-75 { width: 75%; }
.fill-80 { width: 80%; }
.fill-85 { width: 85%; }
.fill-90 { width: 90%; }
.fill-95 { width: 95%; }
.fill-100 { width: 100%; }

/*
  La riga che registra un pasto: la macchina fotografica e il campo, e nella piega della home (27/09)
  l'invio in fondo. Nel foglio di /diet il salva e «Analizza foto» stanno nella barra in fondo, come ogni
  salva. Il campo prende quello che resta: «il box di scrittura deve essere largo quanto il box totale,
  meno un bordo a dx uguale al bordo che c'e' a sx». Otto punti fra l'uno e l'altro: il fianco da quattro
  della macchina fotografica cade nel vuoto, non sul campo.
*/
.meal-row-fields {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* Un bottone della casa dal 27/09: la materia la da' la regola comune (label.meal-photo, in fondo al
   foglio); qui la forma, 44 per 44, e il segno nell'accento. */
.meal-photo {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin: 0;
  border: 0;
  border-radius: 12px;
  color: var(--accent-text);
  cursor: pointer;
}
.meal-photo:hover { filter: brightness(1.08); }
.meal-photo input[type="file"] {
  /* Not display:none: a hidden input is not focusable, which would drop keyboard access to
     the camera entirely. Visually hidden, still reachable by tab. */
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}
/* flex-basis 0 e non auto: con la base automatica il campo parte largo quanto il proprio segnaposto e
   spinge fuori la macchina fotografica. Da zero, si prende quello che resta. */
.meal-field { flex: 1 1 0; min-width: 0; position: relative; display: flex; align-items: center; }
.meal-form input[type="text"] { flex: 1 1 0; min-width: 0; margin: 0; }
/* La X sta DENTRO alla casella, all'estremo destro, e il testo le lascia il posto invece di
   passarci sotto. Il padding vale solo quando c'e' una foto: a casella vuota quei trenta pixel
   sarebbero un rientro senza motivo. Due classi e un elemento, quindi batte la regola globale
   input[type="text"], che e' una classe in meno - e' la trappola di casa sulla specificita', e
   qui si vince nominando l'antenato invece di allungare il nome della classe. */
.meal-field input.has-photo { padding-right: 32px; }
/* Grigia e piccola, come chiesto: e' una via d'uscita, non un comando da premere per primo.
   L'antenato nel selettore non e' un vezzo: button[class] da' a ogni bottone con una classe la
   faccia metallica e pesa esattamente quanto .meal-photo-clear da solo, e a parita' vince quella
   scritta dopo - che sta mille righe piu' in giu'. */
.meal-field .meal-photo-clear {
  position: absolute;
  right: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  margin: 0;
  border: none;
  border-radius: 50%;
  background: none;
  box-shadow: none;
  color: var(--mut);
  cursor: pointer;
}
.meal-field .meal-photo-clear:hover { color: var(--ink); }
/* display: block toglie lo spazio dei discendenti sotto all'icona: in linea, una svg da 14px vive
   in una riga da ~19 e il centraggio del contenitore centra la riga, non il disegno. */
.meal-field .meal-photo-clear svg { display: block; }
/* Con una foto dentro, la casella smette di suggerire e dice cosa porta: il segnaposto passa
   dal grigio dei suggerimenti all'inchiostro della pagina - nero su fondo chiaro, chiaro su fondo
   scuro, che e' quello che fa --ink in tutti e due i temi. La classe la mette app.js quando il
   file viene scelto, e la toglie quando viene levato; senza script il segnaposto resta quello che
   era e il modulo funziona come prima. */
.meal-form input.has-photo::placeholder { color: var(--ink); opacity: 1; }
/* La textarea della correzione, nel suo foglio: una frase con due alimenti e i loro grammi. */
.meal-edit-form textarea {
  width: 100%;
  resize: vertical;
  min-height: 88px;
  font: inherit;
  line-height: 1.4;
}
.meal-edit-hint { margin: 2px 0 0; font-size: 12px; }

/* What logging costs, under the input that spends it. Small and grey: it is a standing fact about
   the control above, not a warning about what just happened. */
.nutrition-cost { margin: 6px 0 0; font-size: 12px; line-height: 1.45; }
/*
  The coach's sentence about the meal just logged. Shown once, on the swap that logged it, and never
  again - which is why it is styled as something that arrived rather than as part of the card: a left
  rule in the accent, the same shape as the coach's boxes elsewhere.
*/
.meal-advice {
  margin: 10px 0 0;
  padding: 8px 10px;
  border-left: 2px solid var(--accent-text);
  border-radius: 0 8px 8px 0;
  background: var(--field);
  font-size: 13px;
  line-height: 1.5;
  color: var(--txt);
}
.box-ask-cost {
  display: block;
  margin-top: 10px;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
}

/* ---------- the week behind, in its sheet ---------- */
.nutrition-history-list { list-style: none; margin: 4px 0 0; padding: 0; }
.nutrition-history-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 7px 0;
  border-top: 1px solid var(--line-soft);
  font-variant-numeric: tabular-nums;
}
.nutrition-history-day {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut2);
}
.nutrition-history-empty { font-size: 12px; color: var(--mut2); }
.nutrition-history-figures { display: flex; flex-wrap: wrap; gap: 10px; font-size: 12.5px; }
.nutrition-history-kcal { font-weight: 600; }
/* The three macros keep the colours they have on the bars above, so a column of numbers reads as
   the same three quantities without repeating their names seven times. Darkened in the light theme
   (--macro-shade, half and half with black, like --accent-2-text): the cyan and the yellow of a bar are
   figures of 12.5 px here, on the white of a sheet - 1.5 to 1 before (verifica del browser, 26/09). */
.nutrition-history-figures .macro-carbs,
.nutrition-history-figures .macro-protein,
.nutrition-history-figures .macro-fat { color: color-mix(in srgb, var(--macro), black var(--macro-shade)); }

/* ---------- goals ---------- */
.goal-list { list-style: none; margin: 4px 0 0; padding: 0; }
.goal { padding: 10px 0; border-bottom: 1px solid var(--line-soft); }
.goal:last-child { border-bottom: none; }
/* Le sagome accanto alle discipline e agli obiettivi, nell'accento da leggere: Luca, «Le icone delle
   discipline devono avere il colore dell'accento ovunque, tranne nel calendario mensile». Erano
   --accent-2, e il taglio 6 le aveva portate al suo gemello da leggere (--accent-2 nudo con volt nel
   chiaro e' rgb(242,244,247): bianche su bianco, qui e nell'iscrizione, che usa le stesse classi); la
   verifica delle regole (M5, 26/09) ha rimesso la richiesta scritta. La tinta si dichiara qui, perche'
   vinca anche su .ico-training e .ico-intake, che ne portano una loro. */
.discipline-pick .ico,
.goal-pick .ico {
  --ico-tint: var(--accent-text);
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  color: var(--ico-tint);
}

.goal-pick {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  font-family: var(--sans);
  font-size: 14.5px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
  cursor: pointer;
}
.goal-pick input { width: auto; margin: 0; accent-color: var(--accent-text); }
/* Indented under the label it belongs to, and in the flow rather than revealed by script: a
   field that only exists when JavaScript runs is a field that does not exist for everybody. */
.goal-target { display: block; margin: 10px 0 0 30px; }
/* Il peso target adesso e' un campo della carta e non piu' il dettaglio di una riga: sta sotto le
   caselle, allineato al loro testo, con un filo d'aria sopra che lo stacca dall'ultima.

   Il nome non e' .weight-target perche' quello esiste gia' - e' la didascalia della pagina del peso,
   tremila righe piu' in giu' - e due regole con lo stesso nome sono due comportamenti che dipendono
   da quale si legge per prima. StylesheetClashTest l'ha rifiutato, ed e' esattamente il suo lavoro. */
.goal-target-weight {
  margin: 16px 0 0 30px;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}
.goal-target label { margin: 0 0 6px; }
.goal-target input { width: 140px; margin: 0; }
.goal-unit {
  margin-left: 8px;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--mut2);
}
.goal-hint { display: block; margin-top: 6px; font-size: 12.5px; }
.goals-reminder { margin-top: 12px; font-size: 13px; }

/* The boundary of what this application does, so it reads as a statement and not as a notice
   to be dismissed: no close button, no accent colour, nothing that looks interactive. */
.disclaimer {
  border-color: var(--line-soft);
  background: none;
}
.disclaimer p { margin: 0; font-size: 12.5px; line-height: 1.55; color: var(--mut); }

/* ---------- start again ---------- */
/* What goes and what stays, as two lines rather than a paragraph: this is the part somebody
   actually reads before pressing the button, and a list is read where prose is skimmed. */
.reset-list { list-style: none; margin: 12px 0; padding: 0; font-size: 14px; }
.reset-list li {
  padding: 8px 0 8px 14px;
  border-left: 2px solid var(--line);
  color: var(--ink-2);
  line-height: 1.5;
}
.reset-list li + li { margin-top: 6px; }


/* ---------- the schedule builder's one Save ---------- */
/*
  Sticky above the bottom bar. A schedule of five exercises is four or five screens, and a Save
  that lives at the end of it is a Save the athlete has to go and find after every change - which
  is most of what "my edits did not save" was actually about.

  bottom is the floating bar's height plus its gap, so the two never overlap; the safe-area inset
  keeps it clear of the home indicator on a phone without one.
*/
/* Il bottone da solo occupa la riga: la conferma se n'e' andata in cima, e cio' che resta accanto
   e' il "sto salvando", che c'e' solo mentre la richiesta e' in volo. */
/* Largo quanto la barra: era stretto perche' doveva dividere la riga con la conferma, e la
   conferma adesso e' in cima. */

/* =========================================================================
   Card heads, from the Emergent prototype.

   One pattern for every section: a small condensed eyebrow saying what kind of
   thing this is, then the title with its icon, then anything that belongs on
   the right - a status, a source badge, a control.

   What the prototype does that the cards did not: it names the *category*
   above the *subject*. "ULTIMA SESSIONE / Run" reads at a glance where "Ultima
   sessione — Corsa" is one line to parse, and it lets the title be the thing
   the athlete actually cares about. The icon is decoration next to a word,
   never the word itself.

   Two colours, not three. The prototype pairs pink with a cyan; the accent
   here stays the athlete's single chosen one and the second colour is the
   page's own grey, which is what keeps four accents working instead of one.
   ========================================================================= */
.card-head { margin-bottom: 14px; }
.card-eyebrow {
  display: block;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--mut2);
  margin-bottom: 2px;
}
.card-title-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 34px;
}
.card-title-row h2,
.card-title-row h3 {
  margin: 0;
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -.2px;
  min-width: 0;
}
/* The icon takes the accent; the words stay in the page's ink. Colour on the
   glyph and not on the text is what stops a wall of accent-coloured headings. */
.card-title-row > .ico {
  flex: 0 0 auto;
  width: 21px;
  height: 21px;
  color: var(--ico-tint, var(--accent));
}
.card-title-row > .card-head-end { margin-left: auto; flex: 0 0 auto; }

/* Every icon from fragments/icons, wherever it lands. */
.ico { width: 18px; height: 18px; flex: 0 0 auto; vertical-align: -3px; }

/* ---------- metric tiles with an icon on the label ---------- */
.metric-grid .metric-label,
.tile .tile-label {
  display: flex;
  align-items: center;
  gap: 6px;
}
.metric-label > .ico,
.tile-label > .ico {
  width: 13px;
  height: 13px;
  color: var(--ico-tint, var(--accent));
  opacity: .85;
}

/* ---------- rimosso: la pastiglia "online" ----------

   Veniva dal prototipo e non e' mai arrivata in una pagina: nessun template la nomina e nessuno la
   compone a runtime. Un pallino verde che dice "in linea" a un atleta che sta guardando la sua
   applicazione non risponde comunque a nessuna domanda. */

/* ---------- removed: the coach card ----------

   Three suggested questions, a line to type a fourth into and a button opening the chat used to
   sit under the hero, and the rules for all three were here. The card is gone and so are they.

   The reason is the count, not the card: the home had five separate ways to talk to the coach -
   this one, the line under the readiness comment, and an ask fold under each of the other boxes -
   so the first thing the page asked an athlete was which of five identical inputs to use. The chat
   now has two doors, the bottom bar and the line under the coach's own reading of the week, and
   .box-chat-ask below is what draws the second.
*/

.macro-name { display: flex; align-items: center; gap: 7px; min-width: 0; }
.macro-name > .ico { width: 14px; height: 14px; color: var(--mut); }
.set-label > .ico { width: 13px; height: 13px; color: var(--ico-tint, var(--accent)); }

/* ---------- what is left of the week ---------- */

/* Rest is the whole card when it applies, so it gets the weight of a statement
   rather than of a row. */
.next-rest {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 10px 0 0;
  font-size: 15px;
  line-height: 1.55;
  color: var(--ink-2);
}
.next-rest > .ico { flex: 0 0 auto; margin-top: 2px; color: var(--ico-tint, var(--accent)); }

/* ---------- rimosso: la spinta alla scheda ferma ----------

   "Non apri questa scheda da tre settimane", con il bottone per eseguirla, sotto il prossimo
   allenamento. La carta e' stata tolta ("drop the idle-schedule nudge") e le sue sei regole erano
   rimaste qui, insieme alle quattro chiavi che le davano le parole. Nessuna delle due meta' serviva
   piu' all'altra. */

/* ---------- the schedule library, as a list of titles ---------- */
/*
  Names and a count, and the detail behind a tap. The card used to print the
  first four exercises of every schedule with their reps and rests, which on
  three schedules was thirty lines of a dashboard that already has six other
  cards - the athlete scrolled past their whole training week to reach what
  they had eaten.
*/
.plan-list { list-style: none; margin: 12px 0 0; padding: 0; }
.plan-entry-row + .plan-entry-row { border-top: 1px solid var(--line-soft); }
/* La riga e' un collegamento alla scheda: dentro alla carta c'era la scheda intera aperta a
   fisarmonica, e mezza home era quella. Il colore lo mettono i figli (--ink il nome, --mut2 il
   conteggio), quindi qui serve solo spegnere quello dei link; e la sottolineatura al passaggio va
   tolta con un peso maggiore di `a:hover`, altrimenti si sottolinea tutta la riga. */
.plan-entry-link {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  min-height: 52px;
  padding: 12px 0;
  color: inherit;
}
.plan-entry-link:hover { text-decoration: none; }
.plan-entry-main { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 8px; min-width: 0; }
.plan-entry-name { font-size: 16.5px; font-weight: 700; color: var(--ink); }
/* The word carries the meaning and the accent only emphasises it, so this still
   reads for somebody who cannot tell the two colours apart. */
.plan-entry-last {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--accent-ink);
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  padding: 1px 8px;
  white-space: nowrap;
}
.plan-entry-count {
  flex: 0 0 auto;
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--mut2);
  white-space: nowrap;
}
/* Un segno che dice "si va di la'". Girava, quando la riga si apriva sul posto; adesso non gira
   piu' perche' non c'e' niente da aprire, e le regole della rotazione se ne sono andate con la
   fisarmonica. */
.plan-entry-link .plan-entry-count::after,
.plan-today .plan-entry-count::after {
  content: " \203A";
  display: inline-block;
  color: var(--accent-text);
}

/* Two tiles now, not four, so they share the row the way the four used to share
   two. Full width for the percentage was tried and rejected: it pushed the
   energy tile into a single 130px column beside it, where "bruciate in
   allenamento" wraps onto two lines and the pair stops looking like a pair. */
.load-block .tile-label { align-items: flex-start; }

/*
  ---------- le frecce che spostano una scheda nella libreria ----------

  Nate per spostare un esercizio nella scheda, che adesso si trascina; il nome e' rimasto. Larghezza
  fissa e non automatica: una freccia e' un carattere solo, e senza larghezza i due bottoni ballano
  di qualche pixel a seconda del glifo.
*/
.exercise-move-btn {
  width: 38px;
  min-height: 38px;
  padding: 0;
  font-size: 16px;
  line-height: 1;
}

/*
  ---------- planned sessions ----------

  The agenda page, and the one line the dashboard borrows from it. The third kind of training this
  application holds: not a session that happened, not a routine with no date, but an intention with
  a day on it.

  Read as a list of days, not a table of fields. The question the page answers is "which day am I
  training and what am I doing", so the weekday is the loudest thing in a row and everything else
  sits under it.
*/
/*
  Una riga di campi affiancati (il modulo «Modifica» di una seduta): due o tre dove sono corti - un
  giorno accanto a un'ora - e a capo invece che stretti sui telefoni piu' piccoli, perche' un campo
  data sotto i 120 pixel nasconde il suo bottone del calendario.

  gap su tutte e due gli assi, non solo su quello orizzontale: tre campi su uno schermo stretto
  vanno a capo, e senza spaziatura verticale la seconda riga finisce appiccicata alla prima.

  align-items: start, perche' i campi non devono stirarsi all'altezza del piu' alto: quello che
  conta e' che comincino tutti dallo stesso punto, che e' esattamente cio' che l'atleta guarda -
  "devono essere allineati, attualmente le input non lo sono".
*/
.planned-row { display: flex; flex-wrap: wrap; align-items: start; gap: 12px; }
.planned-field { display: block; flex: 1 1 130px; min-width: 130px; }
.planned-field input, .planned-field select { width: 100%; }

/*
  ---------- today has an edge ----------

  A 3px bar down the left of the dashboard's next-session card when that session is today: the
  cheapest possible answer to "which of these is the one I have to do now" - the eye finds a coloured
  edge before it reads a single date. The badge saying "oggi" stays, so nothing here is colour on its
  own carrying meaning. The bar joins the border the card already has, so only the left edge changes
  weight. (The agenda's list had the same bar until the 26/09; today is never in that list now - it
  is in the week grid, whose column is lit.)
*/
.next-planned.planned-is-today {
  border-left-width: 3px;
  border-left-color: var(--accent-text);
  padding-left: 12px;
}

/* The day line. The weekday carries the weight; the date and the hour are its detail. */
.planned-when { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 8px; }
.planned-day {
  font-family: var(--cond);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink);
}
/* La data in grassetto come il nome del giorno: "grassetta anche la data".

   Sono la stessa cosa detta due volte - "MARTEDI'" e "22/09" - e con due pesi diversi la seconda si
   leggeva come una nota a margine della prima, cioe' come qualcosa di meno importante. In una lista
   in cui le righe si distinguono per il giorno, il giorno intero e' il titolo della riga.

   Resta piu' piccola e piu' smorzata: il nome si legge da lontano, la cifra si legge quando serve
   sapere QUALE martedi'. Quello che cambia e' il peso, non la gerarchia. */
.planned-date { font-family: var(--cond); font-size: 13px; font-weight: 700; color: var(--mut2); }
.planned-time { font-family: var(--cond); font-size: 13px; color: var(--mut2); }
.planned-what { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; margin-top: 4px; }
.planned-sport { font-size: 15.5px; font-weight: 600; color: var(--ink); }
.planned-figure, .planned-plan { font-family: var(--cond); font-size: 13px; color: var(--mut2); }
.planned-note { font-size: 13px; margin: 4px 0 0; }

.planned-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.planned-actions form { margin: 0; }
.planned-edit { margin-top: 10px; }
.planned-edit summary {
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut2);
  cursor: pointer;
}
.planned-edit form { margin-top: 8px; }

/*
  The dashboard's one line from all this, above the weekly shortfall: the more specific answer to
  the same question. A link rather than a card of its own - the agenda is where anything is done
  about it.
*/
.next-planned {
  display: block;
  text-decoration: none;
  padding: 12px 14px;
  /* Dodici sopra e non zero: qui sopra c'e' il verdetto della settimana, che e' un riquadro con un
     bordo suo, e i due si toccavano - due scatole attaccate si leggono come una scatola sola divisa
     male. Sotto ce n'erano gia' quattordici e restano: e' lo stesso stacco, adesso da tutt'e due i
     lati. */
  margin-top: 12px;
  margin-bottom: 14px;
  border-radius: 12px;
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  /* METALLO VELATO (27/09, Luca: "Pannelli del giorno velato di metallo"). Un riquadro che non si
     preme - e' il pannello che il giorno della settimana apre - quindi la faccia di metallo delle carte,
     con sopra la velatura dell'accento che aveva da sola fino ad allora: il metallo si vede sotto il
     velo, e il colore resta quello del giorno scelto. Il filo di luce in alto e a sinistra, il fianco
     dei riquadri da due e l'ombra corta di una casella, in basso a destra come le altre.
     --solid e' la faccia della carta su cui poggia: il velo e' trasparente, e la lastra sotto e' della
     stessa materia della carta. Le righe grigie dentro sono --mut e non --mut2 (sotto,
     .next-planned-what): la fascia di luce cade proprio su di loro. */
  --solid: var(--surface);
  background:
    linear-gradient(color-mix(in srgb, var(--accent) 8%, transparent), color-mix(in srgb, var(--accent) 8%, transparent)),
    var(--metal-face);
  box-shadow: var(--edge-lit), var(--lift-edge), var(--shadow-tile);
}
.next-planned-eyebrow {
  display: block;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--accent-text);
}
/* L'occhiello e il collegamento del pannello si staccano dalla sua faccia di un quinto (27/09): nel
   buio verso il bianco, nel chiaro verso il nero. Con il pannello di metallo la fascia di luce cade
   sull'occhiello e lo spegnimento sul collegamento: il rosa nel buio, che sulla velatura stava a 4,51 a
   1, scendeva a 4,29, e volt nel chiaro da 4,33 a 4,28. Cosi' tornano sopra il 4,5; gli altri accenti
   erano gia' fra 5,3 e 13. */
:root:not([data-theme="light"]) .next-planned-eyebrow,
:root:not([data-theme="light"]) .next-planned-edit {
  color: color-mix(in srgb, var(--accent-text) 80%, #fff);
}
:root[data-theme="light"] .next-planned-eyebrow,
:root[data-theme="light"] .next-planned-edit {
  color: color-mix(in srgb, var(--accent-text) 80%, #000);
}
.next-planned-when { display: block; font-size: 15.5px; font-weight: 700; color: var(--ink); margin-top: 2px; }
.next-planned-when .muted { font-weight: 400; font-size: 13.5px; }
/* ---------- la colonna che si tocca, e il riquadro che apre ----------

   "Cliccando le varie giornate nella home deve aprirmi un box uguale a quello «in programma oggi»
   ma con scritto «in programma mercoledi'» coi dettagli dell'attivita' programmata."

   L'etichetta si stende sopra la colonna invece di contenerla: un <li> non puo' essere un <label>, e
   mettere il contenuto dentro un'etichetta vorrebbe dire rifare la disposizione della colonna dentro
   di lei. Cosi' la tessera non cambia di un pixel e dentro non c'e' niente di cliccabile da coprire.

   Il margine azzerato perche' e' un <label>: la regola globale dei moduli - label { margin: 16px 0
   8px } - lo raggiunge, ed e' gia' costata una volta, sul cerchio delle sedute su /planned. */
.week-day-open {
  position: absolute;
  inset: 0;
  margin: 0;
  border-radius: inherit;
  cursor: pointer;
}
/* Il giorno aperto ha il bordo acceso, come ce l'ha quello di oggi: e' l'unica cosa che dice quale
   delle sette colonne sta parlando nel riquadro qui sotto. Il selettore passa dal riquadro e non
   dalla colonna perche' il radio sta sotto la striscia, e nessun combinatore guarda all'indietro:
   quindi lo dice lo script, con la stessa classe che usa l'agenda. */
/* Il giorno aperto: il contorno E la faccia tinta. Il solo contorno non bastava - il giorno di oggi
   ne ha gia' uno uguale, e con due colonne contornate di rosa quale delle due stesse parlando nel
   riquadro era una domanda. La faccia tinta ce l'ha una sola colonna alla volta. */
.week-day.is-open {
  box-shadow: inset 0 0 0 1.5px var(--accent);
  --solid: color-mix(in srgb, var(--accent) 14%, var(--field));
  background: var(--plain-face);
}

/* I riquadri: uno per giorno della finestra, uno solo visibile.

   "+" e non "~": sono tutti fratelli qui dentro, e "~" prende ogni fratello successivo - aprirne uno
   aprirebbe anche tutti quelli dopo di lui. E' lo stesso inciampo evitato sui pannelli di /planned.

   Il radio e' fuori schermo e non "hidden": hidden lo toglierebbe dall'ordine di tabulazione, e con
   lui il solo modo di aprire un giorno da tastiera. */
.week-plan-toggle { position: absolute; left: -9999px; }
.week-plan { display: none; }
.week-plan-toggle:checked + .week-plan { display: block; }
.week-plan-toggle:focus-visible + .week-plan {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* Il collegamento alla programmazione settimanale, in fondo al riquadro: "un link «modifica o sposta
   attivita'» che rimanda alla programmazione settimanale per poterla spostare, annullare o
   modificare nei suoi dettagli".

   Una riga e non un bottone: il riquadro dice cosa c'e' da fare, e questo e' il modo di cambiarlo -
   una cosa che si fa ogni tanto, non ogni volta che si guarda la giornata. */
.next-planned-edit {
  display: inline-block;
  margin-top: 8px;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--accent-text);
  text-decoration: none;
}
.next-planned-edit:hover { text-decoration: underline; }

/* Cosa e' previsto, dentro il riquadro della home: la stessa riga - e lo stesso peso - che il
   pannello su /planned mostra da ieri. "Toccare un'attivita' dalla settimana in home deve mostrare
   le stesse informazioni che vengono mostrate toccandola in programmazione settimanale": due
   riquadri che parlano dello stesso venerdi' non possono dirne due cose diverse. */
.next-planned-plan {
  display: block;
  margin-top: 1px;
  font-family: var(--cond);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.45;
}

/* La frase sopra la tendina dei giorni: e' un'etichetta e va a capo come una frase, non come
   un'insegna - le etichette di questo foglio sono maiuscole condensate, e "SPOSTA L'ICONA O SCEGLI
   IN CHE GIORNO SPOSTARLA" su due righe si legge una lettera per volta. */
.agenda-move-hint {
  text-transform: none;
  letter-spacing: .2px;
  font-size: 12.5px;
  line-height: 1.45;
}

/* Una riga per seduta, e adesso possono essere piu' d'una: "piu' attivita' programmate nella stessa
   giornata vanno condensate in una singola pillola". Il giorno resta scritto una volta sopra; qui
   sotto ci sono le discipline, una per riga. */
.next-planned-what {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin-top: 2px;
  font-family: var(--cond);
  font-size: 13px;
  /* --mut e non --mut2 dal 27/09: con il pannello di metallo la fascia di luce cade su queste righe, e
     con --mut2 "Corsa 9 km 50 min" scendeva da 4,51 a 4,3 a 1 (tiffany e ice, scuro). */
  color: var(--mut);
}
/* Fra una seduta e l'altra, un filo d'aria in piu' del ritorno a capo di una riga sola: due
   discipline attaccate si leggono come una frase unica, e "camminata 2 km palestra" non e' niente. */
.next-planned-what + .next-planned-what { margin-top: 4px; }

/*
  La scheda prevista oggi, in cima alla carta delle schede.

  Stessa forma della seduta pianificata qui sopra - bordo e fondo nell'accento, occhiello piccolo e
  nome grosso - perche' e' la stessa cosa detta nella carta accanto: e' il collegamento fra il giorno
  e quello che c'e' da fare. Un'altra forma per la stessa idea sarebbe solo un'altra cosa da imparare.
*/
/* Il riquadro porta anche il conteggio della scheda di oggi, a destra: prima la stessa scheda era
   nominata due volte di fila, qui e nella prima riga della lista, e quella riga non aggiungeva
   altro che il numero. Allineati sulla linea di base invece che al centro, perche' a destra c'e'
   una maiuscoletta di dodici punti e a sinistra due righe: centrandoli, il numero galleggia. */
.plan-today {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  text-decoration: none;
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: 12px;
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.plan-today:hover { text-decoration: none; }
.plan-today-text { min-width: 0; }
.plan-today-eyebrow {
  display: block;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--accent-text);
}
.plan-today-name {
  display: block;
  margin-top: 2px;
  font-size: 15.5px;
  font-weight: 700;
  color: var(--ink);
}

/*
  ---------- the week the coach proposes ----------

  A card that has to read as "not yours yet". Same neon family as everything else, but outlined in
  the accent rather than filled: it is a suggestion sitting on the page next to the athlete's own
  plan, and the two must not look like one list.
*/
.planned-propose { display: flex; flex-direction: column; gap: 6px; margin-top: 18px; }
.planned-propose-cost { font-size: 12.5px; }

.proposal { border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
.proposal-rationale { font-size: 14.5px; line-height: 1.5; margin: 0 0 4px; }

/*
  Seven day rows, one per day of the coming week.

  Rest is stated by the layout: an empty row IS a rest day, and no paragraph can claim otherwise.
  The empty rows are also what a session is dropped onto - a target you cannot see is not a target.
*/
.proposal-week { list-style: none; margin: 16px 0 0; padding: 0; }
.proposal-day {
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
  border-radius: 10px;
}
.proposal-day:last-child { border-bottom: none; }
.proposal-day-head { display: flex; align-items: baseline; gap: 8px; }
/* The "rest" badge is in the markup on every row and shown only on the empty ones. CSS rather than
   Thymeleaf, so a row that becomes empty by dragging its session away says so immediately - the
   script toggles one class on the row and the badge, the dimming and the rest line all follow. */
.proposal-day-free {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut2);
}
.proposal-day:not(.proposal-day-rest) .proposal-day-free { display: none; }
/* A day with nothing on it recedes: what the athlete reads is the training. */
.proposal-day-rest .proposal-day-head { opacity: .6; }

/* The day a dragged session would land on. Outlined rather than filled, so the row's own content
   stays readable underneath the mark. */
.proposal-day.is-target {
  outline: 2px dashed var(--accent);
  outline-offset: 2px;
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}

/*
  A proposed session is a thing you move, not text you select.

  Reported from a phone: long-pressing the grip to drag started the browser's own text-selection
  gesture instead - selection handles across the card and "Copia | Cerca con Google" over the week.
  The drag worked underneath it, which made it worse: two gestures at once, one of them nobody asked
  for.
    - user-select: none on the row, not only on the grip. The browser expands a selection from the
      touch point into the nearest text, so making the grip unselectable was not enough.
    - -webkit-touch-callout: none is what suppresses the iOS callout menu specifically; it is not
      implied by user-select, and without it Safari still offers Copy.
  The notes and figures stop being selectable, which costs nothing: there is nothing on these rows
  anybody copies, and the session they belong to does not exist yet.
*/
.proposal-item {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
/*
  The session being dragged, lifted off the page and following the finger.

  pointer-events: none is the load-bearing line, and it is not obvious. The dragged element sits
  under the pointer by definition, so hit-testing to find the day being dropped onto returns the
  dragged session itself - and therefore the day it came FROM. Every drop landed back where it
  started until this was added.
*/
.proposal-item.is-dragging {
  position: relative;
  z-index: 5;
  opacity: .9;
  pointer-events: none;
  box-shadow: 0 6px 18px rgb(0 0 0 / .45);
}

/*
  The grip. touch-action: none on this and nothing else: without it the browser claims the gesture
  for scrolling and the drag never starts, and with it on the whole row the page could not be
  scrolled by touching a session. 44px tall because it is a tap target on a phone.
*/
/* UNA REGOLA PER LE DUE PRESE RIMASTE. "La sezione schede deve avere icona per spostare le schede
   uguale a quella nella programmazione settimanale": e' la stessa presa per lo stesso gesto, e due
   copie degli stessi undici valori sono due prese che prima o poi si somigliano soltanto.

   Erano tre e la terza era quella dell'agenda, che stava in coppia con la libreria delle schede.
   L'agenda non ha piu' una presa - li' si trascina l'icona - quindi la coppia si e' ricomposta qui,
   fra le due che restano. Quello che cambia fra loro e' solo come si appoggiano alla riga che le
   contiene, ed e' scritto sotto una per una. */
.proposal-grip,
.plan-grip {
  touch-action: none;
  cursor: grab;
  min-width: 32px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--mut2);
  font-size: 18px;
  letter-spacing: -2px;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
.proposal-grip { align-self: center; }
/* Nessun order: dove sta la presa lo dice la riga che la contiene. Nella libreria e' la prima cosa
   nel markup, quindi sta a sinistra da se'; nella riga di un esercizio viene dopo il nome, per
   essere l'ultima cosa che un lettore di schermo incontra, e la riga la riporta a sinistra con un
   order negativo - "metti a sinistra l'icona per spostare", chiesto per tutte e due. Era order: 9
   per tutte, e il 26/09 nella riga nuova della libreria mandava la presa in fondo, dopo «Esegui». */
.plan-grip { flex: 0 0 auto; }
/* The dots are drawn by the stylesheet rather than written in the markup: the content of a
   pseudo-element is not part of the document, so there is no text under the finger for a long press
   to latch onto in the first place. */
/* U+28FF, the six-dot braille cell: it reads as a grip, which is what the markup used to
   hold before the dots moved in here. */
.proposal-grip::before,
.plan-grip::before { content: "\28FF"; }
.proposal-grip:active,
.plan-grip:active { cursor: grabbing; }

/* While a drag is running, nothing anywhere is selectable. The row's own rule covers the session
   being moved; this covers the day rows it passes over, which is where a stray selection appeared
   after the first fix. Set and removed by app.js, so it lasts exactly as long as the drag. */
body.is-dragging-session,
body.is-dragging-session * {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.proposal-move-by-hand { margin-top: 12px; }
.proposal-move-by-hand summary {
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut2);
  cursor: pointer;
}

/* The whole row is the tick target. A 20px checkbox on a phone is a miss waiting to happen, and the
   athlete is being asked to make one decision per row - the row is the decision. */
.proposal-pick {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0;
  padding: 12px 0;
  min-height: 44px;
  cursor: pointer;
  flex: 1;
}
.proposal-pick input { width: 20px; height: 20px; margin-top: 2px; flex: 0 0 auto; accent-color: var(--accent-text); }
/* An unticked row recedes, so what will actually be added is readable at a glance. */
.proposal-pick:not(:has(input:checked)) .proposal-body { opacity: .5; }
.proposal-body { display: flex; flex-direction: column; gap: 2px; }

.proposal-actions { margin-top: 16px; }
.proposal-discard { margin-top: 10px; }

/* The rest days, computed from the proposal rather than claimed in its paragraph. Quiet when there
   are some; in the warning ink when there are none, because that is a contradiction the athlete
   should see without counting rows. */
.proposal-rest {
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut2);
  margin: 14px 0 0;
}
.proposal-rest-none { color: var(--danger-ink); }

/*
  ---------- the scales ----------

  The reading is large because it is the thing being looked up, and the direction is beside it in
  words rather than as a signed number: "-1,2 kg" reads as a quantity with a typo in front of it.

  The chart reuses .day-bars from the dashboard - one drawing of "a bar per day" in this application,
  not two. What differs is only that there can be forty columns instead of seven, so they are allowed
  to be narrow and the labels are turned to fit.
*/
.weight-note { margin-top: 8px; font-size: 12px; line-height: 1.5; }

.weight-now { display: flex; align-items: baseline; gap: 6px; margin: 0 0 10px; }
.weight-now-value { font-size: 40px; font-weight: 700; color: var(--accent-text); line-height: 1; }
.weight-now-unit { font-family: var(--cond); font-size: 14px; color: var(--mut); }

.weight-empty { margin: 0 0 16px; }

/*
  Il grafico delle pesate: punti uniti da una linea, su un asse fisso da 0 a 100 kg.

  Le coordinate stanno negli attributi dell'SVG - le calcola WeightChart - e qui restano soltanto i
  colori e gli spessori, che e' l'unica parte che deve cambiare col tema. La larghezza e' quella
  della carta e l'altezza la decide il viewBox, quindi il disegno si adatta al telefono senza che
  nessun numero sia scritto due volte.
*/
.weight-chart { display: block; width: 100%; height: auto; margin: 4px 0 0; overflow: visible; }
/* Le righe dell'asse stanno dietro: sono un riferimento, non un dato. */
.weight-grid { stroke: var(--line-soft); stroke-width: 1; }
.weight-grid-label {
  fill: var(--mut2);
  font-family: var(--cond);
  font-size: 10px;
  letter-spacing: .5px;
}
/* La linea non ha riempimento: e' una spezzata aperta, e senza questo il browser la chiude e la
   colora di nero. La linea e i punti nell'accento da leggere (26/09, taglio 6, D8): l'accento nudo
   con volt nel chiaro e' rgb(215,255,46) sul bianco, con tiffany rgb(46,230,223). Nel buio e' lo
   stesso colore di prima. */
.weight-line {
  fill: none;
  stroke: var(--accent-text);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.weight-dot { fill: var(--accent-text); stroke: var(--bg); stroke-width: 1.5; }
/*
  L'obiettivo, in verde, piu' sottile della linea del peso, e tratteggiato.

  Verde perche' e' l'unico colore di questa applicazione che vuol dire "arrivato" e non appartiene a
  nessuna disciplina. Piu' sottile e un po' trasparente perche' e' una soglia, non una seconda serie
  di dati.

  TRATTEGGIATO DAL 26/09 (taglio 6, D8): con la linea del peso nell'accento da leggere, la tavolozza
  verde nel chiaro da' #168044 alla linea e #1a7f37 all'obiettivo, e il colore era l'unica cosa che le
  distingueva. Il tratteggio serve anche a disegnarla da sinistra a destra (pathLength="100" e lo
  scostamento da 100 a 0, come la linea del peso), quindi e' uno solo, scritto qui: venticinque tratti
  da 2 su 2 - i primi cento - e poi un vuoto di cento. Con lo scostamento a 100 si vede il vuoto, a 0 i
  tratti: la riga corre da sinistra a destra con i suoi tratti, e da ferma e' tratteggiata. Qui e non
  nell'attributo, che una regola del foglio vince.

  Il colore non passa dall'accento: l'accento cambia con il tema scelto dall'atleta, e un obiettivo
  che diventa rosa o arancione a seconda della giornata smette di essere riconoscibile a colpo
  d'occhio.
*/
.weight-target-line {
  stroke: var(--ok);
  stroke-width: 1.5;
  stroke-dasharray: 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
    2 2 2 2 2 2 2 2 2 2 0 100;
  opacity: .85;
}

/*
  ---------- la linea corre da sinistra a destra e accende i punti che incontra ----------

  "Crea animazione della linea del grafico che scorre da sx verso dx toccando i vari punti, in 2 sec."

  Il disegno vero e' il tratteggio: la linea porta un trattino lungo quanto se stessa, e spostarlo
  da un capo all'altro la scopre da un'estremita'. Quello che rende la cosa possibile senza sapere
  quanto e' lunga - la lunghezza dipende da quante pesate ci sono e da quanto salgono e scendono - e'
  pathLength="100" nel markup: il percorso dichiara di essere lungo cento, e cento e' un numero che
  un fotogramma CSS puo' scrivere per chiunque.

  Il fotogramma ha solo "from". Il valore d'arrivo e' quello scritto nell'attributo, cioe' zero, cioe'
  la linea intera: e' lo stesso espediente dell'anello della condizione fisica, ed e' anche cio' che
  tiene il disegno giusto da fermo. Chi ha chiesto meno movimento, chi ha gli script spenti e chi
  arriva a pagina gia' scorsa vede la linea completa, non una linea a meta'.

  Lineare e non ammorbidita: e' una cosa che avanza a velocita' costante lungo un asse del tempo,
  non un oggetto che parte e si ferma. Un'accelerazione qui farebbe sembrare che i giorni al centro
  siano passati piu' in fretta.
*/
@media (prefers-reduced-motion: no-preference) {
  /* La riga dell'obiettivo corre con quella del peso: "che corre da sx a dx come la linea del
     peso". Stessa durata e stessa andatura - sono la stessa cosa vista due volte, dove sei e dove
     volevi essere, e due andature diverse le farebbero leggere come due grafici sovrapposti. */
  .weight-chart.is-visible .weight-line,
  .weight-chart.is-visible .weight-target-line { animation: weight-draw 2s linear; }
}
@keyframes weight-draw { from { stroke-dashoffset: 100; } }

/*
  E i punti si accendono quando la linea li raggiunge.

  Il ritardo e' una classe, non uno stile in linea, perche' la nostra Content-Security-Policy non
  ammette il secondo: ventuno regole, una ogni cinque per cento dei due secondi, che e' un decimo di
  secondo - piu' fine di cosi' non lo vede nessuno. E' lo stesso espediente delle altezze "line-N"
  che tutti gli altri grafici usano qui dentro, per la stessa ragione.

  Da fermi i punti sono opachi, come la linea: l'animazione li porta da invisibili a visibili, quindi
  senza animazione ci sono e basta.
*/
@media (prefers-reduced-motion: no-preference) {
  .weight-chart.is-visible .weight-dot { animation: weight-dot-in .25s ease-out backwards; }
  .weight-chart.is-visible .lights-0 { animation-delay: 0s; }
  .weight-chart.is-visible .lights-5 { animation-delay: .1s; }
  .weight-chart.is-visible .lights-10 { animation-delay: .2s; }
  .weight-chart.is-visible .lights-15 { animation-delay: .3s; }
  .weight-chart.is-visible .lights-20 { animation-delay: .4s; }
  .weight-chart.is-visible .lights-25 { animation-delay: .5s; }
  .weight-chart.is-visible .lights-30 { animation-delay: .6s; }
  .weight-chart.is-visible .lights-35 { animation-delay: .7s; }
  .weight-chart.is-visible .lights-40 { animation-delay: .8s; }
  .weight-chart.is-visible .lights-45 { animation-delay: .9s; }
  .weight-chart.is-visible .lights-50 { animation-delay: 1s; }
  .weight-chart.is-visible .lights-55 { animation-delay: 1.1s; }
  .weight-chart.is-visible .lights-60 { animation-delay: 1.2s; }
  .weight-chart.is-visible .lights-65 { animation-delay: 1.3s; }
  .weight-chart.is-visible .lights-70 { animation-delay: 1.4s; }
  .weight-chart.is-visible .lights-75 { animation-delay: 1.5s; }
  .weight-chart.is-visible .lights-80 { animation-delay: 1.6s; }
  .weight-chart.is-visible .lights-85 { animation-delay: 1.7s; }
  .weight-chart.is-visible .lights-90 { animation-delay: 1.8s; }
  .weight-chart.is-visible .lights-95 { animation-delay: 1.9s; }
  .weight-chart.is-visible .lights-100 { animation-delay: 2s; }
}
/* Un soffio piu' grande nell'istante in cui la linea lo tocca, e poi la sua misura: e' cio' che fa
   leggere il punto come acceso dalla linea invece che comparso li' per conto suo. */
@keyframes weight-dot-in {
  from { opacity: 0; r: 1; }
  60% { opacity: 1; r: 5; }
}
.weight-span {
  display: flex;
  justify-content: space-between;
  margin: 4px 0 0;
  font-family: var(--cond);
  font-size: 12px;
  color: var(--mut);
}

/*
  ---------- the written eating plan ----------

  Read in a kitchen: the food down the left, how much of it across on the right, and nothing between
  them competing for attention. The meal heading carries the hour and what the meal comes to, because
  those are the two things somebody checks before deciding whether they have time to cook it.
*/
.diet-lead { margin: 0 0 12px; font-size: 13px; line-height: 1.5; }
/* Il filo del messaggio di Davide nell'accento da leggere, che segue la tavolozza (26/09, taglio 6,
   D8): era --tiffany scritto a mano, con ogni tavolozza. */
.diet-disclaimer {
  margin: 14px 0 0;
  padding: 10px 12px;
  border-left: 2px solid var(--accent-text);
  border-radius: 0 8px 8px 0;
  background: var(--field);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--mut);
}
/* L'icona della carta «Chi scrive un piano»: il segno del cibo porta il terzo colore (.ico-intake), che
   con volt nel chiaro e' quasi bianco. Una sagoma generica prende l'accento del testo (26/09, taglio 6). */
.diet-professional .card-title-row > .ico { --ico-tint: var(--accent-text); }
.diet-totals {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  margin: 0 0 14px;
  padding: 0;
  list-style: none;
  font-size: 13px;
  color: var(--mut);
}
.diet-totals li > span:first-child { color: var(--accent-text); font-weight: 600; }

/*
  ---------- what to eat today ----------

  One line per meal above the plan itself: the name and the hour on the first line, the dishes on the
  second. The plan underneath carries the grammages in a proper list, so this is deliberately the
  cheaper layout - it answers "what am I eating at one o'clock", and the card below answers "how
  much".

  The next meal is the only thing marked, in the accent, because that is the one line somebody opens
  this page to read. Marking every meal would mark nothing.
*/
.diet-today-list { list-style: none; margin: 0; padding: 0; }
.diet-today-meal { padding: 10px 0; border-top: 1px solid var(--line-soft); }
.diet-today-meal:first-child { border-top: none; }
.diet-today-when { display: flex; align-items: baseline; gap: 8px; }
.diet-today-name { font-size: 15px; font-weight: 600; }
.diet-today-at { font-family: var(--cond); font-size: 12px; color: var(--mut); }
.diet-today-dishes {
  display: block;
  margin-top: 2px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink-2);
}
.diet-today-now {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--accent-text);
}
.diet-today-meal.is-next .diet-today-name { color: var(--accent-text); }

.diet-meal { padding: 12px 0; border-top: 1px solid var(--line-soft); }
.diet-meal:first-of-type { border-top: none; }
.diet-meal-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; }
.diet-meal-name { font-size: 16px; font-weight: 600; }
.diet-meal-at { font-family: var(--cond); font-size: 12px; color: var(--mut); }
.diet-meal-kcal {
  margin-left: auto;
  font-family: var(--cond);
  font-size: 12px;
  color: var(--accent-text);
}
.diet-dishes { list-style: none; margin: 0; padding: 0; }
.diet-dishes li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 5px 0;
  font-size: 14px;
  line-height: 1.45;
}
.diet-food { flex: 1 1 auto; min-width: 0; }
.diet-amount {
  flex: 0 0 auto;
  font-family: var(--cond);
  font-size: 13px;
  color: var(--accent-text);
  white-space: nowrap;
}
/* The swap, folded, with the chevron every other disclosure here uses. */
.diet-alt > summary {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  cursor: pointer;
  list-style: none;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut);
}
.diet-alt > summary::-webkit-details-marker { display: none; }
/* -135 e non 90: la freccina di base e' gia' ruotata di 45 - e' un quadrato con due lati -
   quindi 90 non la gira, la riscrive, e da aperta veniva fuori una "L". Le altre pieghe
   usano questo valore da sempre; queste tre no, e si vedeva.
   diet-alt: */
.diet-alt[open] > summary .session-detail-mark { transform: rotate(-135deg) translateY(3px); }
.diet-alt p { margin: 0 0 6px; font-size: 13.5px; line-height: 1.5; color: var(--mut); }
.diet-notes {
  margin: 14px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
  font-size: 13px;
  line-height: 1.55;
  color: var(--mut);
}
/* Nessun margine proprio: e' una sezione della pagina e segue il passo delle altre. */
.diet-empty { font-size: 13px; }
/*
  ---------- the week, as seven rows ----------

  A row per day whether anything is on it or not: that is what makes a free day visible, and it is
  the whole reason this exists beside the list below. Today's row carries an edge in the accent, so
  it is found without reading seven dates.

  The grip is the only thing with touch-action: none. On the whole row the page could not be
  scrolled by touching a session, which is a worse problem than a drag that needs aiming.
*/
/* Ventidue e non dodici: lunedi' era troppo attaccato alla frase sopra. La sua riga non e' un
   paragrafo che segue un altro paragrafo, e' l'inizio di una lista - e una lista che comincia alla
   stessa distanza a cui vanno a capo le righe della frase sopra sembra l'ultima riga della frase. */
/* QUATTORDICI E NON DODICI: "aumenta dimensioni, deve vedere bene, occupera' le due righe piene".

   Dodici era la misura delle righe di servizio - quelle che spiegano un campo e che si leggono solo
   se qualcosa non torna. Questa non e' una di quelle: da quando i pallini non ci sono piu', e' la
   SOLA cosa che dice che le icone si trascinano. Una funzione che non si vede non esiste, e un
   promemoria scritto nel corpo dei piedi di pagina e' un promemoria che si salta.

   Due righe piene e non due righe e mezzo: alla misura giusta la frase riempie le due righe che
   occupa gia', invece di finire a meta' della seconda - che e' la forma in cui un paragrafo sembra
   un avanzo. */
/* ---------- di quale settimana si tratta, e le due frecce per cambiarla ----------

   "Metti anche comandi <> ai lati e sopra il recap «settimana scorsa», «questa settimana» con
   accento, «settimana 05/12 ottobre» e cosi' via."

   Le frecce sono le stesse della striscia della home - stessa classe, stesso disegno - ma qui NON
   sono in posizione assoluta: la' galleggiano sopra a una pista che scorre, qui sono due elementi
   della riga, uno per lato del nome. La regola generale le mette absolute, quindi qui si rimettono
   static, o finirebbero tutte e due incollate all'angolo della carta. */
/*
  ---------- QUI IL DITO FA UNA COSA SOLA: SPOSTA UN ALLENAMENTO ----------

  "Elimina la possibilita' di scorrere sia la settimana che il mese in attivita' programmate col
  dito. Scorreranno solo con le frecce. Elimina qualsiasi interazione di scorrimento da qualsiasi
  elemento che non siano le icone nella programmazione settimanale."

  Su questa pagina il trascinamento orizzontale ha gia' un significato: porta una seduta da un
  giorno all'altro. Averne un secondo - una pista che sfoglia sotto lo stesso gesto - vuol dire che
  il browser deve indovinare quale dei due si intendeva, e indovina guardando i primi pixel. Il
  cerchio e' largo trentasei pixel, il dito lo prende di sbieco, e quello che parte due pixel fuori
  sfogliava la settimana invece di spostare la seduta: su sette colonne strette era la maggior
  parte dei tentativi. Riportato tre volte, l'ultima cosi': "le icone proprio non si muovono".

  Ci sono stati due tentativi di farli convivere e nessuno dei due ha tenuto. `overflow-x: hidden`
  sulla pista toglie il gesto, ma un contenitore nascosto su un asse diventa un contenitore di
  SCORRIMENTO sull'altro - "ora il mese scorre male e anche in verticale". `touch-action: pan-y`
  non ha quel difetto e ne ha uno peggiore: il valore che vale per un dito e' l'INTERSEZIONE fra
  quello dell'elemento toccato e quelli dei suoi antenati, quindi il `pan-y` della pista risaliva
  addosso alla seduta e il trascinamento moriva con un `pointercancel`.

  Quindi le piste non ci sono piu', ne' per la settimana ne' per il mese: un pannello solo, servito
  dal server, e le frecce sono collegamenti. Niente da intersecare, niente da indovinare. Resta il
  gesto che l'atleta ha chiesto di salvare.

  Il costo e' l'animazione: sfogliare ricarica la pagina invece di far scivolare il pannello. E'
  stato deciso cosi' - "sacrifichiamo l'eleganza per mantenere la funzionalita'". La striscia della
  home tiene il dito e il suo carosello, perche' li' non c'e' niente da trascinare.
*/
/*
  ---------- il gesto lo prende IL CERCHIO, e nient'altro ----------

  `touch-action: none` sta su .agenda-disc e su nient'altro. Ci ho messo sopra anche .agenda-item,
  ragionando che i quattro pixel di bordo intorno al cerchio si perdevano; non ha risolto niente e
  ha allargato a tutto il blocco un'eccezione che la pagina paga in scorrimento. Rimesso com'era la
  mattina del 21/09, che e' l'ultima forma di cui si sa per certo che il trascinamento funzionava.

  Vedi .agenda-disc piu' in giu', dove l'elemento e' disegnato: dichiararla due volte fa vincere in
  silenzio la seconda, e StylesheetClashTest lo rifiuta.
*/

/* Le due frecce della settimana dell'agenda: sulla riga del nome, una per lato. NON assolute come
   quelle della home - la' galleggiano sopra a una pista che scorre, qui sono due elementi della
   riga - e piu' grandi delle sue, perche' erano state notate come "a rischio di passare
   inosservate". */
.agenda-week-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 14px;
}
/* LE FRECCE DELLA SETTIMANA E DEL MESE: 44 punti di bersaglio, 32 di ingombro. Erano 32 per 32 -
   sotto la misura di un dito, la lezione della home (verifiche del 26/09) - e il margine negativo
   tiene la riga com'era: con 44 pieni, a 360 punti la pastiglia «SETTIMANA PROSSIMA» tornava a capo
   (misurato il 21/09). Una regola per tutte e due le righe, che sono la stessa riga. */
.agenda-week-nav .week-nav,
.agenda-month-nav .week-nav { position: static; flex: 0 0 auto; width: 44px; height: 44px; margin: -6px; }
.agenda-week-nav .week-nav .ico,
.agenda-month-nav .week-nav .ico { width: 20px; height: 20px; }
/* Al bordo della finestra la freccia resta al suo posto, spenta: due frecce che compaiono e
   spariscono sono una riga che cambia forma da sola. Senza href non e' nemmeno raggiungibile da
   tastiera, quindi la sola cosa che manca e' dirlo a chi guarda. */
.week-nav.is-spent { opacity: .28; pointer-events: none; }
.agenda-week-when {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  margin: 0;
  text-align: center;
}
/* Dodici pixel e una spaziatura stretta, e sono misure e non gusto: fra le due frecce, su una
   carta larga 256 dentro - un telefono da 360 - "QUESTA SETTIMANA" nella sua pastiglia andava a
   capo in mezzo alla parola. Visto renderizzando. */
.agenda-week-name {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-2);
}
/* Questa settimana e' accesa, le altre no: e' l'unica differenza che si legge senza leggere, ed e'
   la stessa pastiglia della striscia della home - dove e' nata da un equivoco di chi costruisce
   l'applicazione, che aveva scambiato la domenica scorsa per oggi.

   L'inchiostro e' --on-accent, quello che si legge sul riempimento: era scritto a mano (#12000a), e
   con la tavolozza mono nel tema chiaro l'accento e' nero - la parola era nero su nero. La stessa
   lezione del cerchio pieno della striscia della home. */
.agenda-week-now .agenda-week-name {
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
}
.agenda-week-range { font-size: 12px; color: var(--mut2); }

/* La piega della carta: il titolo a sinistra e il segno all'estremo destro, come in ogni altra
   piega di questa applicazione. La riga del titolo si prende lo spazio (flex: 1), altrimenti
   justify-content: space-between spinge il titolo verso il centro e la carta sembra intitolata
   di sbieco. */
.agenda-week-fold > summary {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
  list-style: none;
  cursor: pointer;
}
.agenda-week-fold > summary > .card-title-row { flex: 1 1 auto; min-width: 0; }
.agenda-week-fold > summary .session-detail-mark { flex: 0 0 auto; }
.agenda-week-fold > summary::-webkit-details-marker { display: none; }

.agenda-hint { margin: 0 0 22px; font-size: 14px; line-height: 1.55; }

/* ---------- gli allenamenti gia' fatti, sotto la griglia ----------

   La colonna li mostra come sagoma - in un settimo di telefono ci sta quello e non ci sta un
   comando - e questa lista e' dove si aprono e si eliminano. Stessa divisione che la pagina fa
   gia' per le sedute programmate: il cerchio sopra, i bottoni sotto. */
.agenda-done-h {
  margin: 24px 0 4px;
  font-family: var(--cond);
  font-size: 13px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--mut);
}
.agenda-done-hint { margin: 0 0 10px; font-size: 13px; }
/* ---------- la settimana come blocchi in fila ----------

   "Anziche' le sedute in verticale da spostare (scomodo) metti dei blocchi orizzontali come in home,
   col comando per spostare le singole icone degli allenamenti nei vari giorni."

   Sette righe erano uno schermo e mezzo: portare il lungo dal sabato al mercoledi' voleva dire
   trascinare oltre il bordo e aspettare che la pagina scorresse da sola, con la seduta invisibile
   sotto il dito. In colonna il tragitto sta dentro uno schermo.

   grid-auto-flow: column e non repeat(7, 1fr), perche' le colonne NON sono sempre sette - la griglia
   parte da oggi. Con sette tracce fisse, la domenica avrebbe una colonna disegnata e sei corsie
   vuote a destra; cosi' le colonne rimaste si dividono la larghezza e la carta resta piena. */
.agenda-week {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-auto-flow: column;
  /* minmax(0, 1fr) e non 1fr: il minimo implicito di 1fr e' min-content, quindi la parola "RIPOSO"
     dentro una colonna vuota teneva tutte e sette le colonne larghe quanto lei e la griglia usciva
     dalla carta - sette giorni disegnati, cinque visibili. Con il minimo a zero le colonne si
     dividono la larghezza che c'e' e il contenuto si adatta a loro, non il contrario. */
  grid-auto-columns: minmax(0, 1fr);
  gap: 4px;
  /* Le colonne si allungano fino alla piu' alta: una settimana con un giorno doppio non deve
     diventare una fila di blocchi di sei altezze diverse. */
  align-items: stretch;
}
.agenda-day {
  min-width: 0;
  /* Perche' il puntino della data segnata possa stare in un angolo invece che in fila con il resto:
     vedi .agenda-day-event qui sotto. */
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 8px 2px;
  border-radius: 12px;
  border: 1px solid var(--week-outline);
  /* Dichiarata qui e non su :root: le composite che la leggono sono dichiarate su "*" apposta,
     perche' un var() dentro una custom property si risolve dove la property e' DICHIARATA. */
  --solid: var(--field);
  /* Senza la luce del metallo, come la colonna della home (27/09, --plain-face); due pixel con il filo di luce
     e l'ombra, come lei. */
  background: var(--plain-face);
  box-shadow: var(--edge-lit), var(--lift-edge-xs), 0 1px 2px rgba(0, 0, 0, .20);
}
.agenda-day-today { border-color: var(--accent); }

/* ---------- la colonna con una gara, un test, un rientro ----------

   "Su home risulta la gara fissata, in attivita' programmate no." La striscia della home le aveva da
   sempre e il calendario del mese anche; questa griglia no, e la domenica della gara diceva RIPOSO.

   Il secondo colore del marchio e non l'accento, come nella striscia della home: qui dentro
   l'accento vuol dire "allenamento" - il cerchio della seduta aperta, il bordo di oggi - e una data
   segnata e' un'altra famiglia di cose. La faccia tinta si porta dietro il fianco tinto: e' la
   stessa materia, ed e' tutto il senso dello spessore del proprio colore. */
/* DUE NOMI E NON UNO, e la prima stesura ne usava uno solo per tutti e due: il puntino era
   .agenda-day-event come la colonna che lo contiene. Il risultato non e' stato un colore sbagliato,
   e' stata la colonna della domenica larga sette pixel e in posizione assoluta sopra il titolo della
   carta - perche' le regole del puntino le prendeva anche lei. Visto rendendo, in un colpo d'occhio.
   La striscia della home tiene i due nomi separati da sempre (.week-day-event e .week-event), ed e'
   la ragione per cui li' non e' mai successo. */
.agenda-day-mark {
  position: absolute;
  left: -1px;
  top: -1px;
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--accent-2-text);
}
.agenda-day-event {
  border-color: color-mix(in srgb, var(--accent-2-text) 55%, transparent);
  --solid: color-mix(in srgb, var(--accent-2-text) 9%, var(--field));
  background: var(--plain-face);
}
/* La sagoma della gara, nel colore della stella: una gara di domenica non e' una seduta programmata
   per domenica, e con lo stesso rosa si leggerebbe come un allenamento in piu' da fare. */
.agenda-event-sport {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--accent-2-text);
}
.agenda-event-sport .ico { width: 17px; height: 17px; }
/* Il giorno sotto il dito mentre si trascina. Il bordo non basta piu' come nella lista - a quaranta
   pixel di larghezza un bordo acceso e' un filo - quindi la faccia si tinge. Nell'accento, che segue
   la tavolozza: era --tiffany scritto qui, e con pink il giorno di oggi era rosa e quello d'arrivo
   azzurro (verifiche del 26/09). */
.agenda-day.is-target {
  border-color: var(--accent);
  --solid: color-mix(in srgb, var(--accent) 14%, var(--field));
  background: var(--plain-face);
}

/* Il nome del giorno e la sua cifra, incolonnati come nella striscia della home: e' la stessa
   settimana e si legge con lo stesso colpo d'occhio. */
.agenda-day-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  line-height: 1.1;
}
.agenda-col-day {
  font-family: var(--cond);
  font-size: 11px;
  letter-spacing: .4px;
  text-transform: uppercase;
  color: var(--mut);
}
.agenda-col-num {
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.agenda-day-today .agenda-col-day { color: var(--accent-text); }

/* ---------- il cerchio della seduta ----------

   La stessa misura e lo stesso disegno del cerchio della home, di proposito: e' la stessa settimana
   vista due volte, e due disegni diversi sono due settimane da imparare. */
.agenda-disc {
  /* Azzerato perche' e' un <label>, e la regola globale dei moduli - label { margin: 16px 0 8px } -
     lo raggiunge: ventiquattro pixel di aria intorno a ogni cerchio, cioe' due sedute dello stesso
     giorno lontane il doppio del necessario e la colonna alta un terzo di piu'. Non si vede come un
     errore: si vede come "un po' spaziato". */
  margin: 0;
  position: relative;
  width: 30px;
  height: 30px;
  flex: 0 0 auto;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1.5px solid var(--line);
  color: var(--ink-2);
  /* Il cerchio e' anche la presa: "togli pallini di spostamento e metti un piccolo reminder, tocca e
     trascina le icone per spostare gli allenamenti".

     touch-action: none, e solo qui. Senza, il browser si prende il movimento per scorrere e il
     trascinamento non parte mai su un telefono. Con lo scorrimento tolto a tutta la colonna la
     pagina non si potrebbe piu' muovere toccando un giorno - e' la ragione per cui questa riga sta
     sul cerchio di trenta pixel e non su .agenda-day.

     grab e non pointer: con un gesto solo il puntatore diceva "premi", che e' meta' della verita'. */
  cursor: grab;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
.agenda-disc:active { cursor: grabbing; }
/* Un giorno passato non si sposta piu': il cerchio resta, il gesto no. */
.agenda-day-past .agenda-disc { cursor: default; touch-action: auto; }
.agenda-disc .ico { width: 17px; height: 17px; }
.agenda-disc-icon { display: inline-flex; }
/* Una disciplina senza sagoma propria tiene il nome corto dentro lo stesso cerchio: tre lettere ci
   stanno dove una parola intera non ci starebbe. */
.agenda-disc-name {
  font-family: var(--cond);
  font-size: 10px;
  letter-spacing: .3px;
  text-transform: uppercase;
}
.agenda-day .agenda-disc:hover { border-color: var(--accent); }
.agenda-disc-tick {
  position: absolute;
  right: -3px;
  bottom: -3px;
  font-size: 11px;
  line-height: 1;
  color: var(--ink);
}

/* Il piu': l'ultima cosa della colonna, e la piu' quieta. Programmare a mano e' quello che si fa
   quando il programma non ha gia' risposto, non il gesto principale di questa carta. */
.agenda-add {
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px dashed var(--line);
  color: var(--mut);
  font-size: 16px;
  line-height: 1;
  text-decoration: none;
}
.agenda-add:hover { border-color: var(--accent); color: var(--accent-text); }
/* IL BERSAGLIO CRESCE, il segno resta 26: lo <span> dentro al collegamento (il "+" scritto, che
   font-size: 0 rende invisibile) si allarga di nove punti per lato - 44 sulla carta - e prende il dito
   per lui. Misurato con elementFromPoint (verifiche del 26/09): 39x42 a 360 punti, dove la colonna e'
   larga 40 e il cerchio sopra vince, 42x42 a 390. Piu' di cosi' prenderebbe la colonna accanto. I due
   pseudo-elementi del + sono gia' le sue barre, quindi il bersaglio lo porta il figlio, senza
   lettera: il "+" scritto, spostato nell'angolo del bersaglio, si vedeva accanto al segno. Il cerchio
   di una seduta sta sopra (.agenda-item, z-index): dove i due bersagli si toccano, un dito sul bordo
   del cerchio comincia il trascinamento e non apre il foglio «Nuova seduta». */
.agenda-add > span { position: absolute; inset: -9px; font-size: 0; }

/* The days of this week that have already gone.
   Drawn, because they are what the week amounts to - a Saturday grid that started at today hid the
   four sessions that made the week - and drawn quieter, because they are a record rather than
   somewhere to plan. Faded rather than removed: nothing here is hidden from anybody, it is just not
   the part being decided. The drag script reads data-past and refuses them as drop targets, so the
   dimming and the behaviour say the same thing. */
/* Indietro, ma leggibile. Era .55 quando un giorno passato mostrava il PROGRAMMA - roba scaduta, e
   l'opacita' diceva "non ci puoi fare niente". Adesso mostra il consuntivo, cioe' una cosa che
   l'atleta viene qui a guardare: sotto un certo punto non si distingue piu' una spunta da una riga
   barrata, e la meta' della richiesta si perde. */
.agenda-day-past { opacity: .78; }

/*
  ---------- il mese, come calendario ----------

  Sotto le sette righe della settimana, al posto delle sette della settimana prossima. Quelle
  comparivano solo il sabato e la domenica ed erano sette giorni scelti dal momento in cui uno
  guardava; questo mostra il mese intero a chiunque, in qualunque giorno.

  Sette colonne uguali, quindi grid e non flex: le colonne devono restare incolonnate riga dopo
  riga, ed e' l'unica cosa che un flex non fa da solo.
*/
.agenda-month { margin-top: 14px; }
/* ---------- il calendario che si sfoglia, SOLO con le frecce ----------

   "Settimana e mese nella sezione attivita' programmate devono scorrere SOLO tramite frecce."

   La stessa riga di .agenda-week-nav qui sopra: freccia, nome del mese, freccia. Non le frecce
   assolute della striscia della home - li' galleggiano sopra a una pista che scorre e devono stare
   fuori dal flusso; qui la pista non c'e' piu' e sono tre elementi di una riga.

   IL NOME DEL MESE STA IN MEZZO e non a sinistra: e' l'unica cosa fra le due frecce, e un titolo a
   sinistra finirebbe sotto quella di prima. E' anche la forma che la settimana ha gia'.

   Niente margine laterale: le frecce stanno su questa riga e nient'altro, quindi la griglia sotto
   e' larga quanto la carta. La prima stesura tolse ventisei pixel per parte "per non toccare le
   frecce" e strinse tutte e sette le colonne - i segni delle sedute finirono addosso ai numeri. */
.agenda-month-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 12px;
}
.agenda-month-nav .agenda-month-h { flex: 1 1 auto; min-width: 0; margin: 0; text-align: center; }
.agenda-month-h {
  margin-bottom: 12px;
  font-family: var(--cond);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--accent-text);
}
.agenda-month-grid {
  display: grid;
  /*
    minmax(0, 1fr) E NON 1fr, ed e' la trappola scritta in CLAUDE.md nella sua forma esatta.

    Il minimo implicito di `1fr` e' il contenuto, quindi da quando la casella porta le sagome delle
    discipline - fino a tre, con i loro stacchi - la colonna non poteva piu' stringersi sotto quella
    larghezza: la griglia misurava 453 pixel su uno schermo da 390. Misurato, renderizzando la
    carta vera in un browser.

    E NON SI VEDEVA COME UN TRABOCCAMENTO: `body { overflow-x: clip }` taglia invece di far
    scorrere, quindi il mese usciva dalla carta a destra e quello che restava sullo schermo era la
    sua parte sinistra - cioe' le colonne sbagliate, che e' come si e' presentato ("apre la pagina
    su settimana e mese scorso").
  */
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 3px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.agenda-month-weekday {
  padding-bottom: 4px;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1px;
  text-align: center;
  color: var(--mut2);
}
/* La casella e' quadrata e il collegamento la riempie tutta: la zona da premere e' il giorno
   intero, non il numero dentro. */
.agenda-month-cell { aspect-ratio: 1; }
.agenda-month-cell > * {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: 10px;
  background: var(--field);
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-2);
  text-decoration: none;
}
.agenda-month-cell a:hover { background: var(--track); }
/* I giorni degli altri due mesi restano nel calendario perche' completano le settimane, ma non
   sono questo mese e non devono pesare come i suoi. */
.agenda-month-out > * { background: none; color: var(--mut2); }
.agenda-month-past > * { opacity: .5; }
/* Oggi: un anello, non un riempimento. Il riempimento e' gia' il segno di "qui c'e' qualcosa". */
.agenda-month-today > * { box-shadow: inset 0 0 0 1.5px var(--accent); color: var(--ink); }
/* Un giorno con qualcosa dentro, e quante cose. Il numero sta in basso a destra e non al centro:
   al centro c'e' gia' il giorno, e due cifre sovrapposte non si leggono ne' l'una ne' l'altra. */
.agenda-month-busy > * { background: var(--accent-soft); color: var(--ink); }
/* ---------- la casella con una gara, un test, un rientro, un intervento ----------

   "Anche li' evidenzia dove ho fissato un evento". Un calendario del mese senza la gara e' un
   calendario a cui manca proprio la casella per cui lo si apre.

   Secondo colore, come sulla striscia: il rosa qui dentro dice gia' "ci sono sedute" - e' il
   riempimento di .agenda-month-busy e il numero in basso a destra - e una gara non e' una seduta.
   Il segno sta in alto a SINISTRA perche' in basso a destra c'e' gia' il conto delle sedute, e i
   due possono capitare sullo stesso giorno. */
.agenda-month-event > * {
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--accent-2-text) 70%, transparent);
  color: var(--ink);
}
/* Oggi resta oggi: l'anello dell'accento vince su quello della data segnata quando cadono insieme,
   perche' "dove sono" si legge prima di "cosa c'e'". */
.agenda-month-today.agenda-month-event > * { box-shadow: inset 0 0 0 1.5px var(--accent); }
/* La stella del giorno con una data segnata. Era un puntino, che diceva "qui c'e' qualcosa" senza
   dire cosa - e nella stessa casella c'e' gia' un altro pallino, quello che conta le sedute: due
   punti di due colori in un quadratino da quaranta pixel sono due cose da imparare.

   IN ALTO A SINISTRA E FUORI DAL FLUSSO. In fila con il numero lo spingeva fuori centro, e il
   numero e' la cosa per cui la casella esiste. L'angolo in basso a destra e' preso dal conto delle
   sedute, e i due possono capitare sullo stesso giorno. */
/* FIGLIO DIRETTO, e non un discendente qualunque: la stella e' scritta dentro alla casella, le
   sagome delle discipline stanno tre livelli piu' in fondo. Con `.agenda-month-cell .ico` questa
   regola le prendeva tutte e due, e delle due dichiarazioni in conflitto - misura e posizione -
   la regola delle sagome piu' in giu' rifaceva solo la MISURA: il `position: absolute; left: 3px;
   top: 3px` restava addosso a ogni disciplina, che finiva inchiodata all'angolo della sua cella
   invece di stare al centro. Riferito cosi': "l'icona della disciplina deve essere centrata, cosi'
   le icone sono compresse male". Non si vedeva come un errore di CSS: si vedeva come icone
   piccole e storte.

   IN ALTO A DESTRA, perche' l'angolo di sinistra adesso e' del numero del giorno. */
.agenda-month-cell > * > .ico {
  position: absolute;
  right: 3px;
  top: 3px;
  width: 11px;
  height: 11px;
  color: var(--accent-2-text);
}
/* ---------- le discipline in fondo alla casella, al posto del pallino col numero ----------

   Il pallino portava un conto - "2" - e un conto non dice se quel giorno sono due corse o una
   corsa e la palestra, che e' l'unica cosa per cui si apre un calendario del mese. Le sagome lo
   dicono, e le dicono nella lingua che tutto il resto dell'applicazione parla gia'.

   In fila sul fondo e non in un angolo: una sagoma sola sta dov'era il pallino, due stanno
   affiancate, e la casella non cambia altezza in nessuno dei due casi.

   Dieci pixel, che e' piccolo per un'icona: e' quanto ne resta in una casella larga trentacinque
   su un telefono, ed e' il motivo per cui le sagome erano state ricalcate invece che disegnate a
   mano - a questa misura una linea storta si vede. */
/* ---------- il numero in un angolo, le sagome al centro ----------

   "Le icone non stanno bene messe cosi': devono essere piu' grandi, col colore rispettivo e piu'
   centrate nei quadratini; piuttosto sposta in alto a sinistra il numero del giorno e fallo
   leggermente piu' piccolo ma sempre leggibile."

   E' anche la correzione di un difetto: le sagome erano appoggiate al fondo della casella in
   posizione assoluta, e nell'ultima riga finivano FUORI dalla griglia - "le icone del mese
   seguente non devono essere mostrate fuori dal box in basso". Al centro e nel flusso normale non
   possono uscire da nessuna parte: e' il contenitore a contenerle, non una coordinata.

   Il numero prende il posto che era loro: in alto a sinistra, undici pixel invece di quattordici.
   Undici e non nove - "sempre leggibile" - e in alto a sinistra perche' e' dove si legge per primo
   e perche' l'angolo in alto a destra e' gia' della stella delle date segnate. */
/* ---------- il numero si fa da parte, la sagoma prende il centro ----------

   "L'icona della disciplina deve essere centrata e il giorno del mese decentrato, cosi' le icone
   sono compresse male."

   Erano in colonna, una sopra l'altra: due righe dentro a un quadrato da trentasei pixel vuol dire
   che nessuna delle due ne ha piu' di sedici, e la sagoma - che e' la cosa che si guarda - ne
   prendeva quattordici. Il numero del giorno invece si legge anche piccolo e anche in un angolo,
   perche' la sua posizione nella griglia lo dice gia' quasi tutto.

   Quindi il numero esce dal flusso e va nell'angolo, e la sagoma resta sola al centro della
   casella intera: da sedici pixel di altezza disponibile passa a trentasei, e ci sta a venti.

   Si sfiorano? No, e la ragione e' la diagonale: il numero occupa l'angolo in alto a sinistra
   (circa dieci pixel per dieci), la sagoma sta al centro. Fra i due c'e' sempre lo spazio che
   separa un angolo dal centro di un quadrato, che alla peggio - sulla casella da ventotto di un
   telefono da 320 - sono ancora quattro pixel. Guardato in rendering a 360 e a 390, che e' l'unico
   modo di saperlo. */
.agenda-month-cell > * { padding: 0; }
.agenda-month-num {
  position: absolute;
  top: 2px;
  left: 3px;
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
}
.agenda-month-sports {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  /* Si puo' stringere: senza, e' questa riga a decidere quanto e' larga la colonna, ed e' il modo
     in cui il minimo implicito della griglia torna a essere il contenuto da un'altra porta. */
  min-width: 0;
  pointer-events: none;
}
.agenda-month-sport { flex: 0 0 auto; }
/* Venti e non quattordici: la sagoma non divide piu' la casella con il numero, quindi l'altezza
   che ha a disposizione e' tutto il quadrato - trentasei su un telefono da 360 - invece della meta'.
   `position: static` perche' la regola della stella qui sopra e' un figlio diretto e questa no, ma
   la riga costa nulla e dice a chi legge che qui dentro non si sta appesi a un angolo.

   display: block sull'svg: in linea si porterebbe dietro lo spazio dei discendenti che non ha, e
   una sagoma da venti pixel starebbe in una riga da venticinque, centrata male dentro a un
   contenitore che centra la riga e non lei. E' la trappola scritta in CLAUDE.md. */
.agenda-month-sport .ico { display: block; position: static; width: 18px; height: 18px; }
/* In due si stringono un po', in tre diventano un'indicazione piu' che un disegno.

   I numeri li ha decisi la misura, non l'occhio: la casella su un telefono da 360 e' un quadrato
   da 34, e tre sagome con due stacchi da due devono starci dentro. A undici facevano 37 e uscivano
   dai bordi - misurate, non viste: escono nella zona dove il riquadro e' gia' finito, quindi a
   occhio la casella sembra solo un po' piena. A nove fanno 31 e restano dentro con tre pixel di
   margine. */
.agenda-month-sports:has(.agenda-month-sport:nth-child(2)) .ico { width: 14px; height: 14px; }
.agenda-month-sports:has(.agenda-month-sport:nth-child(3)) .ico { width: 9px; height: 9px; }
/* Dalla quarta in poi non si disegna, si conta: "+2" accanto alle tre che ci stanno. */
.agenda-month-sports[data-more]::after {
  content: "+" attr(data-more);
  font-family: var(--cond);
  font-size: 9px;
  color: var(--mut);
}
/* Only on an empty row, and always rendered: a row emptied by dragging its session away has to be
   able to say "riposo" without the server drawing the page again. */
.agenda-day-rest {
  display: none;
  font-family: var(--cond);
  /* Nove e non dodici, e senza spaziatura fra le lettere: in una colonna larga quaranta pixel
     "riposo" spaziato non ci sta, e quello che non ci sta allarga la colonna. */
  font-size: 9px;
  text-transform: uppercase;
  color: var(--mut2);
}
.agenda-day-free .agenda-day-rest { display: inline; }

/* La seduta dentro la colonna: il cerchio, e sotto la presa per spostarlo.

   Niente riquadro attorno. La colonna e' gia' una tessera con il suo bordo e il suo spessore, e un
   secondo riquadro largo trenta pixel dentro al primo non separa niente da niente - fa solo due
   cornici concentriche. Quello che separa due sedute dello stesso giorno e' lo spazio fra loro. */
.agenda-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  /* Sopra al bersaglio del + (vedi .agenda-add > span), che arriva a tre punti dal bordo basso del
     cerchio: dove si toccano vince il cerchio. */
  position: relative;
  z-index: 1;
}
.agenda-item.is-dragging {
  border-color: var(--accent);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .45);
  position: relative;
  z-index: 2;
  /*
    pointer-events: none while it is being dragged, and it is load-bearing rather than cosmetic.
    The row follows the finger, so it sits under the pointer - and document.elementFromPoint then
    returns the row itself, whose closest(".agenda-day") is the day it started in. Every drop read
    as "back where it came from" and moved nothing. Same line, same reason, as the proposal above.
  */
  pointer-events: none;
}
.agenda-item-done { opacity: .6; }

/*
  ---------- un giorno passato: il consuntivo, non il programma ----------

  "Mostra sempre settimana intera con attivita' completate come in homepage."

  La sagoma resta quella del cerchio della seduta - stessa misura, stesso disegno - perche' e' la
  stessa settimana vista due volte e due disegni diversi sono due settimane da imparare. Cambia cosa
  ci si puo' fare: niente presa, niente cursore da trascinamento, niente bordo che si accende al
  passaggio. Non e' decorazione, e' la meta' della richiesta che questa griglia aveva perso: i giorni
  passati erano stati tolti proprio perche' mostravano un comando che rifiutava ogni pressione.
*/
.agenda-disc-still {
  cursor: default;
  touch-action: auto;
  border-color: var(--line-soft);
}
.agenda-day .agenda-disc-still:hover { border-color: var(--line-soft); }
/* Saltata, o passata senza che succedesse niente: spenta e con la riga in diagonale, la stessa che
   la striscia della home mette sulle sue - vedi .week-sport-missed, ed e' copiata da li' apposta. */
/* Spenta nel colore, non nell'opacita': la colonna passata e' gia' in secondo piano tutta insieme,
   e due velature una sopra l'altra fanno sparire proprio il segno che deve dire "questa non l'hai
   fatta". */
.agenda-disc-missed .agenda-disc-icon { position: relative; color: var(--mut2); }
.agenda-disc-missed .agenda-disc-icon::after {
  content: "";
  position: absolute;
  left: -3px;
  right: -3px;
  top: 50%;
  height: 2px;
  border-radius: 2px;
  background: var(--mut2);
  transform: rotate(-18deg);
}
/*
  ---------- salva modifiche ----------

  "Metti un bottone in sovraimpressione fisso, piccolo in basso al centro con scritto salva
  modifiche."

  Da quando il trascinamento non spedisce piu' da solo, la settimana sullo schermo puo' essere
  diversa da quella salvata, e questa e' l'unica cosa che lo dice. Fissa al centro in basso, perche'
  li' guarda chi ha appena lasciato la seduta e li' arriva il pollice.

  Sollevata sopra la barra rapida come il "torna in fondo" della chat, e con lo scarto fra i due
  viewport che usa la barra stessa: senza, su un telefono che nasconde la barra degli indirizzi si
  appoggerebbe su un bordo che non e' piu' li'. Piu' in alto di quel controllo pero', perche' quello
  sta in un angolo e questo sta al centro, dove il microfono esce dalla barra e sale.

  Nascosta finche' non c'e' niente da salvare - hidden nel markup, tolto da app.js al primo
  spostamento - quindi chi apre la pagina per leggerla non se la trova mai davanti.
*/
.save-float {
  position: fixed;
  display: grid;
  grid-template-columns: auto minmax(64px, .72fr) minmax(100px, 1.08fr);
  align-items: center;
  gap: 5px;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(var(--bar-h) + 44px + var(--viewport-bottom, 0px) + env(safe-area-inset-bottom, 0px));
  z-index: 6;
  width: min(292px, calc(100vw - 32px));
  box-sizing: border-box;
  margin: 0;
  padding: 5px;
  border-radius: 999px;
  background: var(--panel);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-panel);
}
/*
  ---------- i due comandi della seduta, nella carta in alto ----------

  "Non mi piace molto che si sovrappongono timer e chiudi allenamento / fine: sposta fine
  allenamento o termina in alto, sotto a quando si e' svolto."

  ERANO FISSI SOPRA LA BARRA, e ci sono stati finche' sopra la barra c'era una cosa sola. Con il
  recupero che parte da solo diventavano tre oggetti impilati sullo stesso angolo - recupero,
  comandi, barra rapida - e insieme coprivano mezzo schermo: la carta "come e' andata" stava sotto a
  tutti e tre. Il motivo per cui erano saliti li' resta valido (in fondo alla pagina si arrivava
  scorrendo davanti a tutto l'allenamento appena fatto) e la carta in cima lo soddisfa uguale: e'
  l'inizio della pagina, cioe' l'altro posto che si raggiunge senza attraversare niente.

  NIENTE PANNELLO INTORNO. Qui sono dentro a una carta, e una pastiglia con bordo, fondo e ombra
  dentro a una carta e' una superficie dove non ce n'e' bisogno: la carta ce l'ha gia'.

  I DUE PESI SONO DIVERSI di proposito: "termina" prende quello che resta, "elimina" solo la sua
  larghezza. Due pastiglie uguali per un'ora di allenamento vorrebbero dire premere prima o poi
  quella sbagliata, e una delle due non si disfa.
*/
.session-actions-head {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 14px;
}
.session-actions-head .session-actions-finish { flex: 1 1 auto; min-width: 0; }
.session-actions-head .btn {
  width: 100%;
  min-width: 0;
  min-height: 44px;
  margin-top: 0;
  white-space: nowrap;
}
.session-actions-head .session-actions-delete { flex: 0 0 auto; }
.session-actions-head .session-actions-delete .btn {
  padding-inline: 14px;
  font-size: 12px;
  letter-spacing: .55px;
}
/* L'attesa mentre il coach scrive il riepilogo non sta dentro alla pillola: la allargherebbe a
   meta' pressione. Sta sopra, dove c'e' posto. */
.session-actions-head .htmx-indicator { display: none; }
.session-actions-head .htmx-indicator.htmx-request {
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% + 8px);
  text-align: center;
  font-size: 12px;
}

/*
  E la riserva sotto all'ultima carta se n'e' andata con la pillola fissa: i comandi adesso stanno
  nella carta in cima e scorrono con la pagina, quindi non coprono niente. Quello che resta fisso
  sopra la barra e' solo il recupero, che dura il tempo di un recupero e si chiude da se'.
*/

/*
  ---------- il recupero, che parte da solo ----------

  "Farei partire un mini timer quando spunti la check, dopo 3/5 secondi, con tempo di recupero
  segnato per quella riga - ovviamente puoi stoppare. Perche' altrimenti devo vedere timer sopra,
  scomodo, o usare altro."

  L'UNICA COSA FISSA SOPRA LA BARRA, e prende il posto che era dei due comandi della seduta: quelli
  sono saliti nella carta in cima, perche' tre oggetti impilati nello stesso angolo - recupero,
  comandi, barra - coprivano mezzo schermo. Stesso calcolo del fondo della barra: due oggetti nello
  stesso angolo misurati in due modi si sovrappongono il giorno che uno dei due cresce.

  NIENTE transform PER IL VERTICALE, come la barra: un elemento fisso composto viene riposizionato
  un fotogramma tardi durante lo scorrimento e si vede ballare. Il translateX centra e basta, ed e'
  l'asse su cui nessuno scorre.
*/

/*
  ---------- l'esercizio finito si spegne ----------

  "Quando ho spuntato tutte le serie deve esserci un'icona vicino al nome esercizio per far capire
  fatto" - e poi, sulla spunta che ne era uscita: "non mi piace tanto". Aveva ragione due volte: era
  un simbolo in piu' da imparare, ed era la stessa cosa che ogni riga dentro alla carta dice gia'.

  QUELLO CHE E' FATTO SI ABBASSA DI TONO, cosi' l'unica cosa accesa nella pagina e' quello che resta
  da fare - che e' l'informazione che si cerca scorrendo una scheda da otto esercizi.

  IL TONO DA SOLO NON BASTA, ed e' il motivo del filo sul fianco: il grigio in questa applicazione
  vuol dire anche "non disponibile", e uno stato non puo' rispondere a due domande. Il filo e'
  nell'accento, cioe' il colore di tutto cio' che e' stato fatto qui dentro, e dice che quel grigio
  e' un grigio soddisfatto. (Per chi non vede nessuno dei due, la parola c'e' comunque: sr-only
  accanto al nome.)

  SOLO LA TESTATA si spegne, non la carta intera: aperta, una tabella di serie al 60% si legge come
  disabilitata, e quelle righe restano modificabili fino alla fine della seduta.
*/
.session-exercise.is-done > .session-exercise-head { opacity: .6; }
.session-exercise.is-done::after {
  content: '';
  position: absolute;
  left: 0;
  top: 14px;
  bottom: 14px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  /* --accent-text: con volt nel chiaro l'accento pieno e' un filo giallo chiaro su bianco. */
  background: var(--accent-text);
}

.rest-timer {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: calc(var(--bar-h) + 30px + var(--viewport-bottom, 0px) + env(safe-area-inset-bottom, 0px));
  z-index: 7;
  display: flex;
  align-items: center;
  gap: 8px;
  width: min(430px, calc(100vw - 32px));
  box-sizing: border-box;
  /* "Lo renderei leggermente piu' grande": un gradino, non una scatola nuova - il numero da 19 a
     22, l'anello da 36 a 40, e l'aria che serve a tenerli. Piu' di cosi' e la pillola comincia a
     contendere lo spazio alla carta che sta leggendo. */
  padding: 9px 9px 9px 11px;
  border-radius: 999px;
  border: 1px solid var(--accent-line);
  background: var(--panel);
  box-shadow: var(--shadow-panel);
}
.rest-timer[hidden] { display: none; }

/* L'anello e' il tempo che resta, e lo disegna un conic-gradient su una variabile che lo script
   riscrive: --rest-progress va da 1 a 0. Un secondo elemento interno fa il buco, perche' un anello
   fatto con un bordo non si puo' riempire per gradi.

   IL VUOTO SI DEVE VEDERE - "il cerchio deve svuotarsi mano mano". La pista dietro era
   --line-soft, che su fondo scuro e' sei centesimi di bianco: l'anello sembrava pieno per meta'
   recupero e poi finiva di colpo, cioe' il contrario di uno che si svuota. La pista e' l'accento
   spento, che si vede da subito e dice dove arrivera' il vuoto. */
.rest-timer-ring {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  /* --accent-text: con volt nel chiaro l'anello pieno era giallo chiaro su una pillola bianca, e il
     vuoto che avanza non si vedeva (26/09). Nel scuro e' l'accento stesso. */
  background: conic-gradient(var(--accent-text) calc(var(--rest-progress, 1) * 360deg),
                             color-mix(in srgb, var(--accent-text) 26%, transparent) 0);
}
/* Il buco prende il fondo della pillola, non un colore scritto a mano: la pillola e' --panel e
   l'anello ci sta sopra. */
.rest-timer-ring > span {
  width: 29px;
  height: 29px;
  border-radius: 50%;
  background: var(--panel);
}
.rest-timer-text {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* Occhiello e numero: la riga di sopra dice di quale esercizio e' il recupero, quella di sotto il
   tempo e la serie. Una riga sola per parte e tagliata con i puntini - nella pillola niente va a
   capo, o la pillola cambia altezza mentre la si guarda. */
.rest-timer-eyebrow {
  font-family: var(--cond);
  font-size: 10.5px;
  /* Spaziatura corta: e' un nome, non un'etichetta di due parole, e ogni decimo di pixel per
     lettera su venticinque lettere sono due caratteri in piu' prima dei puntini. "Panca inclinata
     manubri" ci sta intero a 390; da li' in su si taglia, e si taglia perche' il nome intero e'
     sulla carta due dita piu' su. */
  letter-spacing: .2px;
  line-height: 1;
  text-transform: uppercase;
  color: var(--mut2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* La riga del tempo: il numero grande e, accanto, di che serie e'. Allineati sulla base, o il
   numero piccolo galleggia a meta' di quello grande. */
.rest-timer-line {
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
}
/* tabular-nums: senza, "1:11" e "1:00" sono larghi diverso e il numero balla a ogni secondo. */
.rest-timer-n {
  font-family: var(--sans);
  font-size: 22px;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
/* La serie, piccola accanto al tempo. Non cede: e' due parole, e se cedesse il primo taglio
   sarebbe proprio il numero. */
.rest-timer-set {
  flex: 0 0 auto;
  font-family: var(--cond);
  font-size: 11.5px;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--mut2);
  white-space: nowrap;
}
.rest-timer-cmd {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 6px;
}
/* .rest-timer .btn e non .rest-timer-cmd .btn scritto piu' corto: due classi battono il
   button[class] che da' la faccia metallica a ogni bottone con una classe, che vale quanto una
   classe piu' un elemento e vincerebbe per ordine, mille righe piu' in giu'. */
.rest-timer .btn {
  /* I DUE COMANDI SONO LARGHI UGUALE - "il +30 deve essere stessa grandezza del bottone di fianco".
     Due pastiglie appaiate di larghezza diversa si leggono come una principale e una secondaria, e
     qui non lo sono: una allunga il recupero, l'altra lo chiude. Un minimo e non una larghezza
     fissa, cosi' la parola piu' lunga delle due decide per tutte e due invece di uscire.

     Sessantaquattro e non settantadue: quello che si toglie qui e' larghezza che va al nome
     dell'esercizio, e il bersaglio resta sopra i quaranta pixel per lato. */
  width: auto;
  min-width: 64px;
  min-height: 36px;
  margin-top: 0;
  padding: 0 10px;
  font-size: 12.5px;
  letter-spacing: .4px;
  white-space: nowrap;
  position: relative;
}
/* Disegnati a 36, presi a 44: uno pseudo-elemento trasparente allarga il bersaglio di cinque punti
   sopra e sotto, e la pillola resta alta com'e' - piu' alta coprirebbe la carta che si sta leggendo.
   Cinque e non quattro: si misura dal bordo interno, e il filo di «+30s» gliene toglieva uno per lato
   (42, contro i 44 di «Salta»: 26/09, verifica browser D5). Solo in verticale: fra «+30s» e «Salta» ci
   sono sei punti, e il dito non deve prendere l'altro. */
.rest-timer .btn::after { content: ''; position: absolute; inset: -5px 0; }
/* Finita: l'anello si spegne e il numero prende l'accento, insieme alla parola che sta al posto
   della serie. Nessun lampeggio - una pillola che pulsa sopra a una seduta di un'ora e' un
   difetto, non un avviso. */
.rest-timer.is-done { border-color: var(--accent-text); }
.rest-timer.is-done .rest-timer-n,
.rest-timer.is-done .rest-timer-set { color: var(--accent-text); }
.save-float .btn {
  width: 100%;
  min-width: 0;
  min-height: 44px;
  margin-top: 0;
  padding-inline: 9px;
  white-space: nowrap;
  font-size: 12px;
  letter-spacing: .55px;
}
.save-float-warn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  min-width: 0;
  height: 28px;
  padding: 0 7px 0 2px;
  border-right: 1px solid var(--line);
  font-family: var(--cond);
  font-size: 9.75px;
  letter-spacing: .55px;
  text-transform: uppercase;
  color: var(--mut);
  white-space: nowrap;
}
.save-float-dot {
  width: 6px;
  height: 6px;
  flex: 0 0 6px;
  border-radius: 50%;
  background: var(--accent);
}
@media (max-width: 340px) {
  .save-float {
    width: min(284px, calc(100vw - 24px));
    grid-template-columns: auto minmax(60px, .68fr) minmax(94px, 1.04fr);
    gap: 4px;
  }
  .save-float .btn { padding-inline: 7px; font-size: 11.5px; }
  .save-float-warn { padding-right: 5px; font-size: 9.25px; letter-spacing: .4px; }
}
/*
  ---------- la scheda della seduta, sotto la griglia ----------

  L'etichetta che la apre e' il cerchio, la' sopra nella sua colonna; la scheda sta qui, larga quanto
  la carta. Sono due elementi lontani nel documento e vanno bene cosi': "for" attraversa il documento
  e "+" no, quindi la coppia che il foglio di stile deve tenere insieme e' casella + corpo, ed e'
  quella che sta quaggiu' attaccata.

  "+" E NON "~", e la differenza non e' di stile: "~" prende TUTTI i fratelli che seguono, e qui le
  schede sono tutte fratelli fra loro - aprirne una avrebbe aperto anche tutte quelle dopo di lei.

  La casella e' fuori schermo e non hidden: hidden la toglierebbe dall'ordine di tabulazione, e
  questo comando deve restare raggiungibile da tastiera.

  DAL 26/09 E' DISEGNATA COME IL FOGLIO DEL MOCK 03b, ma resta nel flusso: una tessera con il filo
  (la regola di una tessera dentro a una carta) e il bordo nell'accento, perche' parla del cerchio
  acceso la' sopra. Non un foglio modale: il velo coprirebbe proprio quel cerchio.
*/
.agenda-panels { margin-top: 10px; }
.agenda-manage-toggle { position: absolute; left: -9999px; }
/* Sotto la barra appiccicata, come section[id]: un rifiuto torna su #seduta-ID (l'ancora di refuse()
   nel controller), e senza margine la testata del pannello - il giorno, il nome, la X - finiva sotto
   la barra, con la frase subito sotto (verifiche del 26/09). */
.agenda-manage-body { display: none; scroll-margin-top: 90px; }
.agenda-manage-toggle:checked + .agenda-manage-body {
  display: block;
  margin-top: 10px;
  padding: 12px 14px 14px;
  border: 1px solid var(--accent-line);
  border-radius: 16px;
}
/* Il cerchio della seduta aperta, acceso nella settimana.

   "La icona della seduta che sto modificando si deve evidenziare nella settimana; chiudendo editor
   si toglie evidenziazione." Il pannello sta sotto la griglia e dice il giorno a parole, ma con
   quattro sedute nella stessa settimana "giovedi' 17/09, Corsa" si legge e poi si cerca lo stesso.

   Pieno e non contornato: il contorno dell'accento e' gia' il passaggio del dito (:hover) e il
   giorno di oggi, e un terzo uso dello stesso segno non si distingue dagli altri due. Pieno vuol
   dire "questa", e in una settimana ce n'e' al massimo una. */
.agenda-item.is-editing .agenda-disc {
  border-color: var(--accent);
  background: var(--accent);
  /* --on-accent e non --ink: l'inchiostro non si sceglie in base al tema, si sceglie in base a cosa
     c'e' sotto. E' la stessa lezione - e la stessa variabile - del cerchio pieno della striscia
     della home, che l'ha imparata andando in produzione con una sagoma bianca su un verde chiaro. */
  color: var(--on-accent);
}

/* La testata della scheda, come quella di un foglio: il giorno e l'ora nell'occhiello, il nome nel
   titolo, la X all'estremo destro. Il margine negativo mette il bersaglio da 44 della X nell'angolo
   senza allontanare il titolo dal bordo. */
.agenda-sheet-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  margin: -6px -10px 8px 0;
}
.agenda-sheet-head > div { min-width: 0; padding-top: 6px; }
.agenda-sheet-when {
  margin: 0 0 3px;
  font-family: var(--cond);
  font-size: 11.5px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut);
}
/* Un antenato in piu': `.card h3` (una classe e un elemento) vincerebbe su una classe sola. */
.agenda-sheet .agenda-sheet-title { margin: 0; font-size: 19px; font-weight: 700; line-height: 1.2; color: var(--ink); }
.agenda-sheet select { width: 100%; min-height: 44px; margin: 4px 0 6px; }
/* I numeri come tessere, DUE COLONNE anche a 360 punti: con il minimo da 130 della home, dentro al
   pannello (244 punti) le due tessere andavano una sotto l'altra, alte il doppio. Piu' strette e
   piu' basse di quelle della home: sono due numeri, non il cruscotto. */
.agenda-sheet .agenda-sheet-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 4px 0 0; gap: 10px; }
.agenda-sheet-facts .tile { padding: 10px 12px; }
.agenda-sheet-facts .tile-value b { font-size: 22px; }
/* Cosa e' previsto: la nota della seduta, subito sotto i numeri.

   In grassetto e nell'inchiostro della pagina invece che in quello smorzato: e' la cosa che
   l'atleta e' venuto a leggere aprendo il pannello - "quando apro un'attivita' deve dirmi cosa e'
   previsto nell'allenamento". */
.agenda-sheet-plan {
  margin: 12px 0 0;
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.45;
  color: var(--ink);
}
.agenda-sheet-split { display: flex; flex-wrap: wrap; gap: 2px 12px; margin: 4px 0 0; font-size: 13px; }
/* Come e' finita: lo stato nel suo colore, e dopo quello che e' stato registrato, piu' quieto. Il
   punto fra i pezzi lo scrive il foglio di stile sul pezzo che separa. */
.agenda-sheet-state {
  margin: 0 0 10px;
  font-family: var(--cond);
  font-size: 12.5px;
  font-weight: 650;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.agenda-sheet-state > span + span { color: var(--mut2); }
.agenda-sheet-state > span + span::before { content: "\00b7\00a0"; }
.agenda-sheet .agenda-move-hint { margin-top: 14px; }

/* I tre comandi in fila. "Sposta, salta ed elimina sulla stessa riga."

   Sono tre MODULI - tre azioni diverse sul server - e tre moduli si mettono in fila solo se sono
   fratelli nella stessa riga. Da qui il display: contents sul gruppo che arriva dal frammento
   condiviso: i suoi due moduli diventano figli di questa riga invece di restare chiusi in un blocco
   loro. Larghi uguali, come le tre tessere del mock (flex 1 1 0); quando la seduta e' fatta resta il
   solo «Elimina», a tutta riga.

   «Modifica» va a capo a tutta larghezza (flex-basis 100%): e' una piega con un modulo di sette
   campi, e in un terzo di riga sarebbe una colonna di parole. Il suo «Salva» sta dentro al corpo
   della pagina, non fermo in fondo come nei fogli: e' il prezzo di "Modifica resta fuori e sotto". */
.agenda-panel-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
.agenda-panel-controls > .planned-actions { display: contents; }
.agenda-panel-controls > form,
.agenda-panel-controls > .planned-actions > form { flex: 1 1 0; min-width: 0; margin: 0; }
.agenda-panel-controls .btn { width: 100%; min-height: 48px; margin: 0; padding-inline: 6px; }
.agenda-panel-controls > .planned-edit { flex: 1 0 100%; margin-top: 4px; }
/* «Modifica» e' un comando e prende un dito: era 244x19, largo quanto il pannello e alto una riga di
   testo (verifiche del 26/09). Il margine dentro e non una scatola intorno: il segno della piega e
   il binario restano quelli di ogni piega. */
.agenda-panel-controls > .planned-edit > summary { min-height: 44px; padding-block: 12px; box-sizing: border-box; }
/* E il suo Salva si stacca dal campo Nota: stavano a zero punti, e con l'ombra il bottone sembrava
   sopra al campo. */
.agenda-panel-controls .planned-edit form > .btn { margin-top: 16px; }

/* La regola, dove si legge nel momento in cui serve: quando si sta per toccare un secondo cerchio. */
.agenda-panel-note {
  margin: 12px 0 0;
  font-family: var(--cond);
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--mut2);
}
/* Il fuoco da tastiera: il radio e' fuori schermo, quindi senza questa riga non si vedrebbe dove si
   e' arrivati tabulando. Sulla X, che e' l'etichetta che chiude. */
.agenda-manage-toggle:focus-visible + .agenda-manage-body .agenda-sheet-head .orb-x {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* "e altri 4": the rest of the day's meals, and the count is the reason to press it. */
.meal-more > summary {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  cursor: pointer;
  list-style: none;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut);
}
.meal-more > summary::-webkit-details-marker { display: none; }
.meal-more > summary:hover { color: var(--accent-text); }
/* -135 e non 90: la freccina di base e' gia' ruotata di 45 - e' un quadrato con due lati -
   quindi 90 non la gira, la riscrive, e da aperta veniva fuori una "L". Le altre pieghe
   usano questo valore da sempre; queste tre no, e si vedeva.
   meal-more: */
.meal-more[open] > summary .session-detail-mark { transform: rotate(-135deg) translateY(3px); }

/* The scanner's own note, and the badge saying who wrote the plan on screen. */
.diet-scan-note { margin: 12px 0 0; font-size: 12.5px; line-height: 1.5; }
.diet-source { margin-left: auto; }

/* ---------- the confirmation dialogue ----------

   One dialogue for every deletion in the application (layout.html, app.js). The browser's own
   confirm() said "hybrx-production.up.railway.app dice" above the question and offered its own two
   words underneath, which reads as a fault rather than as a question. This is the same question in
   the application's type and colours, with "Annulla" and "Conferma" from the message bundle.

   ::backdrop is the platform's, so the page behind it dims without a div pretending to be one. */
.confirm-dialog {
  /* Centred by hand. A modal <dialog> is laid out by the browser as inset:0 with margin:auto, which
     centres it - unless something in the page's own reset has given dialogs a top or a position, and
     then it lands in a corner. It did: it opened against the top-left, which reads as a panel that
     failed to load rather than as a question. Four lines that cannot be argued with. */
  position: fixed;
  inset: 0;
  margin: auto;
  height: fit-content;
  width: min(340px, calc(100vw - 40px));
  padding: 0;
  border: 1px solid var(--accent-line);
  border-radius: 18px;
  background: var(--panel);
  color: var(--ink);
  box-shadow: 0 18px 48px rgba(0, 0, 0, .45);
}
.confirm-dialog::backdrop { background: rgba(0, 0, 0, .55); }

.confirm-form { padding: 22px 20px 18px; }

.confirm-question {
  margin: 0 0 20px;
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink);
}

/* Side by side while they fit, stacked when the wording is long: an Italian confirmation runs to
   two words where the English runs to one, and a button whose label wraps is a button that looks
   broken. */
.confirm-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.confirm-actions .btn {
  flex: 1 1 130px;
  margin: 0;
  width: auto;
}

/* ---------- the overall reading's way into the chat ----------

   Asked for by Davide, for the space directly under the coach's comment at the top of the page: a
   line to type a question into that lands in the chat already sent.

   It was drawn to match the coach card's own ask line, which sat one screen below it; that card is
   gone now and this is the only ask line left on the home, so these rules are the whole of it. */
.box-chat-ask {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px 0 0;
}

/*
  Aperto il consiglio, la riga per rispondere entra nel riquadro.

  "Una volta espanso voglio che il box scrittura venga inglobato nel box del commento subito sotto,
  mentre da ridotto deve rimanere come visibile subito sotto, fuori."

  Ha ragione ed e' la stessa cosa detta due volte. Da chiuso il consiglio e' un riassunto e la riga
  sotto e' un'altra cosa - si chiede quello che si vuole. Da aperto il consiglio finisce con una
  domanda, e la riga e' il posto dove si risponde a QUELLA: un campo staccato sembra un secondo
  comando invece della seconda meta' della stessa frase.

  Fatto senza una riga di JavaScript e senza toccare l'ordine nel documento: la riga sta gia' subito
  sotto al riquadro, e quando la piega e' aperta - :has(), lo stesso meccanismo con cui la vetrina
  cambia colore - prende i bordi che al riquadro qui sopra tolgo. Bordo inferiore via da uno,
  superiore via dall'altro, e i due si leggono come una scatola sola.

  Dove :has() non c'e', la regola non si applica affatto e resta tutto com'e' oggi: il peggio che
  puo' succedere e' la pagina di ieri.
*/
.box-comment:has(.advice-more[open]) .ai-feedback { margin-bottom: 0; }
.box-comment:has(.advice-more[open]) .ai-feedback-box {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  border-bottom: none;
  padding-bottom: 10px;
}
.box-comment:has(.advice-more[open]) .box-chat-ask {
  margin: 0;
  padding: 0 14px 13px;
  border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent);
  border-top: none;
  border-radius: 0 0 14px 14px;
  background: var(--accent-soft);
}
/* La stessa riga in fondo all'allenamento, con la sua etichetta sopra.

   L'etichetta c'e' perche' li' la riga non segue nessun consiglio: sulla home sta sotto al commento
   della giornata e si capisce a cosa risponde, qui sta in fondo a una seduta finita e senza una
   parola sarebbe una barra di ricerca. .microlbl e' l'etichetta di casa - maiuscoletto condensato -
   la stessa che porta la nota della sessione due carte piu' su. */
.session-ask { margin-top: 24px; }
.session-ask .box-chat-ask { margin-top: 8px; }
/* La domanda gia' scritta («Come è andato il mio allenamento «Forza B — tirata» oggi?») e' piu' lunga
   della casella, e il campo la tagliava a meta' lettera, «allenamentc» (26/09, verifica browser D6).
   I puntini, come il mock: «…allenamento «Forz…». Solo qui: e' l'unica casella che arriva con una
   frase gia' scritta, quella della home arriva vuota. */
.session-ask .box-chat-ask-input { text-overflow: ellipsis; }

.box-chat-ask-input {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  border-radius: 999px;
  padding: 11px 15px;
  /* Sedici, per la stessa ragione dei campi qui sopra: sotto, iOS ingrandisce la pagina al fuoco. */
  font-size: 16px;
}
.box-chat-ask-input::placeholder { color: var(--mut2); opacity: 1; }
.box-chat-ask-send {
  /* 44px, like every other tap target in this application. */
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  /* The arrow is text, so it takes the text token rather than the raw accent: over its own pale
     fill the raw accent measures below 3:1 on the light theme. */
  color: var(--accent-text);
  font-size: 18px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.box-chat-ask-send:hover { background: var(--accent); color: var(--on-accent); }

/* ---------- making every fold look like something you can press ----------

   Reported by Davide: "rendi tutte le interazioni di espansione e compressione più evidenti,
   rischiamo non sia comprensibile a primo impatto". He is right, and the cause is that these
   controls were designed to be quiet: 12px condensed grey, the same treatment as a caption, with a
   chevron the size of a comma beside it. Quiet was the goal - a page of five open forms was the
   problem they solved - but quiet was taken far enough that they stopped reading as controls.

   Rather than invent a look, this promotes the one already in the stylesheet: .macro-edit's summary,
   a bordered pill in the accent line with accent text. It is the one disclosure on the nutrition
   card nobody has ever had to be told about.

   Two changes, and between them they cover every fold in the application:

   1. The shared chevron becomes a round bordered badge. That mark is used by the session details,
      the card folds, the plan entries, the meal list, the diet alternatives, the agenda's move
      control and the goals - six families from one rule.
   2. The folds that draw their own caret get the pill.

   Nothing gets bigger than 44px and nothing moves, so the page keeps its shape; what changes is that
   the control now has an edge. */

/* 1. The chevron is a badge now, and the change is made in its ONE rule above rather than in a
      second one down here. A class defined twice is a class whose behaviour depends on which
      declaration a reader happens to find first, and StylesheetClashTest refuses it - correctly:
      that is exactly the bug this stylesheet had with the nutrition pill.

/* 2. Le pieghe di solo testo: la stessa cosa delle pieghe delle carte, non una seconda.

      "Gli espandi devono avere tutti questo stile, no border ecc, ovviamente del colore coerente
      al tema." Erano pillole: bordo, fondo, un'altezza propria. Adesso sono quello che e' gia' il
      controllo delle carte - etichetta condensata in maiuscolo nel colore dell'accento, freccina
      che gira, niente altro - allineate a destra e con la stessa area da toccare.

      Una regola sola per tutte e cinque le famiglie. Un controllo che compare in cinque punti e ha
      cinque regole e' un controllo che diverge al primo che se ne tocca una.

      Dal 27/09 la piega del giorno prima dell'ultima sessione ne e' uscita: non e' piu' un'etichetta
      allineata a destra ma una riga, il giorno a sinistra e la freccia in fondo (mock A, Luca). Da
      qui prende solo la freccina, che e' lo stesso disegno; la riga la dispone il suo blocco, «la
      carta dell'ultima sessione», in fondo al foglio. */
.card-fold > summary,
.advice-more > summary,
.session-bars > summary {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  width: auto;
  min-height: 44px;
  padding: 0;
  border: none;
  background: none;
  border-radius: 0;
  cursor: pointer;
  list-style: none;
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  /* Il colore dell'accento, quindi cambia col tema come tutto il resto. */
  color: var(--accent-text);
  text-align: right;
}
.card-fold > summary::-webkit-details-marker,
.advice-more > summary::-webkit-details-marker,
.last-session-more > summary::-webkit-details-marker,
.session-bars > summary::-webkit-details-marker { display: none; }
.card-fold > summary:hover,
.advice-more > summary:hover,
.session-bars > summary:hover { color: var(--accent); }
.card-fold > summary:focus-visible,
.advice-more > summary:focus-visible,
.last-session-more > summary:focus-visible,
.session-bars > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Le quattro che non avevano una freccina se la prendono qui: il segno e' del controllo, non della
   famiglia. .session-detail-mark, dove c'e' nel markup, e' esattamente lo stesso disegno.

   .advice-more e' uscita da qui per un giorno, con una freccia grossa e disegnata tutta sua che
   doveva dire "sotto ce n'e' dell'altro". Detto guardandola: "sta freccia e' orribile". E' rientrata
   e la v e' tornata quella di tutte le altre - la parola accanto, "leggi tutto", basta da sola a
   dire cosa succede a premerla. */
.advice-more > summary::after,
.last-session-more > summary::after,
.session-bars > summary::after {
  content: "";
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-3px);
  transition: transform .15s ease;
}
.advice-more[open] > summary::after,
.last-session-more[open] > summary::after,
.session-bars[open] > summary::after { transform: rotate(-135deg) translateY(3px); }
@media (prefers-reduced-motion: reduce) {
  .advice-more > summary::after, .last-session-more > summary::after { transition: none; }
}

/*
  Il <details> resta un blocco normale, e il riassunto si allinea da solo.

  C'era qui una colonna flex allineata in fondo, messa per spingere l'"espandi" a destra. Faceva il
  suo lavoro e ne rompeva un altro: in una colonna allineata cosi' ogni figlio si restringe sul
  proprio contenuto, quindi l'elenco dei sette giorni e il blocco della seduta precedente uscivano
  larghi meta' carta e spostati a destra. Un align-self: stretch avrebbe dovuto rimediare, e in
  effetti risultava applicato - ma la larghezza usata restava quella del contenuto, e a quel punto
  si stava rattoppando un meccanismo che non serviva.

  Non serve perche' il riassunto e' gia' un blocco largo quanto la carta con
  justify-content: flex-end dentro: sono le sue parole ad andare a destra, non la sua scatola. E'
  esattamente come funziona .card-fold, che infatti non ha mai avuto questo problema. Tolto il
  flex, il contenuto aperto torna a occupare tutta la carta da solo.
*/

/*
  La "cosa alleni?" della pagina obiettivi: una carta intera piegata, che pero' porta con se'
  l'intestazione della sezione. Per questo tiene la misura di un titolo invece dei 13px qui sopra.

  E per lo stesso motivo non segue le altre pieghe nel resto: la regola comune manda tutto a destra
  e mette il conteggio prima dell'etichetta, che va bene per un controllo che dice solo "espandi" e
  non va bene qui, dove l'etichetta e' il titolo. Veniva fuori "TOCCA PER MODIFICARE ^ Cosa
  alleni?": la riga letta al contrario, ammucchiata a destra e addosso al paragrafo sotto.

  Qui l'ordine e' quello di una intestazione - titolo a sinistra, suggerimento e freccia all'altro
  capo - ed e' dichiarato invece che lasciato al markup, perche' nel markup la freccia viene per
  prima, dove serve a tutte le altre pieghe.

  Valeva anche per la piega «Importa una scheda» della libreria, che il 26/09 e' diventata la terza
  strada della creazione guidata, con un pannello suo.
*/
.discipline-card > summary {
  justify-content: flex-start;
  text-align: left;
  font-size: 16.5px;
  font-family: var(--sans);
  letter-spacing: 0;
  text-transform: none;
  font-weight: 700;
  color: var(--ink);
}
.discipline-card > summary .session-detail-mark {
  order: 2;
}
.discipline-card > summary .card-fold-count {
  order: 1;
  margin-left: auto;
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--accent-text);
}

/*
  L'intestazione dell'elenco delle discipline dentro la richiesta di una settimana. Non c'e' nella
  pagina obiettivi, dove l'elenco e' gia' il contenuto della sua carta; qui viene dopo tre domande,
  e senza una riga che lo separi le caselle sembravano una quarta domanda.
*/
/*
  ---------- chiedere una settimana: da chiusa la riga E' il bottone ----------

  Il riassunto porta le classi del bottone primario, quindi da chiuso quello che si vede e' il
  bottone rosa che stava in fondo alla pagina - largo, con il suo alone, impossibile da non vedere.
  "Il bottone deve rimanere cosi'": e' l'invito principale della pagina, e travestito da riga di
  intestazione non si vedeva piu'.

  Un <summary> porta un marcatore suo, che va tolto o compare un triangolino dentro la pillola.

  Da aperto smette di essere un bottone: fondo via, alone via, testo dell'inchiostro normale. Il
  rosa torna in fondo al modulo, dove sta quello che invia davvero - due bottoni rosa identici sullo
  stesso schermo, uno che apre e uno che spende un'interazione, sarebbero indistinguibili.
*/
/* Dodici sotto: «Programma una seduta» viene subito dopo, e con zero punti il fianco del bottone
   chiuso cadeva sulla faccia dell'altro - due bottoni incollati, misurati col banco (27/09, con il
   fianco da sei; da quattro servono ancora, e dodici e' l'aria fra due comandi di questa pagina). */
.propose-card { margin: 18px 0 12px; }
.propose-open { margin-top: 0; cursor: pointer; list-style: none; }
.propose-open::-webkit-details-marker { display: none; }
.propose-card[open] > .propose-open {
  justify-content: space-between;
  /* Sedici a sinistra e non quattro: da aperta la piega ha il binario dell'accento addosso, e il
     titolo ci si appoggiava contro - "la scritta e' troppo attaccata al bordo sinistro". Sedici e'
     esattamente il rientro del contenuto qui sotto (14 di spazio piu' i 2 del binario), quindi il
     titolo non si stacca e basta: si incolonna con cio' che apre. */
  padding-inline: 16px 4px;
  background: none;
  box-shadow: none;
  color: var(--ink);
}
/* La freccia guarda in giu' da chiusa e in su da aperta, come tutte le altre. currentColor perche'
   sul rosa deve prendere l'inchiostro del bottone: l'accento sull'accento sparisce. */
.propose-card[open] > .propose-open .session-detail-mark { transform: rotate(-135deg) translateY(3px); }

.propose-load-h {
  margin: 20px 0 10px;
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
}

/* ---------- the week, as seven columns ----------

   Drawn by Davide, and rebuilt on his second look: "è terribile... la spunta deve essere una sola
   non una per ogni attività". The first version stacked a mark per session, which on a column forty
   pixels wide is a list with no room to be one - and on a day whose gym session had been recorded
   twice it drew the same workout as two separate marks.

   One mark per day now, and the column is a tile rather than a stripe: the state colours the whole
   tile instead of only the badge inside it, so the week reads as a row of days at a glance and not
   as a row of symbols to decode.
*/
/* ---------- il carosello: tre settimane, una pista, due frecce ----------

   "Scorrendo a sinistra si deve poter vedere la settimana seguente, scorrendo a destra devo poter
   retrocedere e vedere la settimana passata... la settimana deve scorrere dinamicamente in base al
   tocco dell'utente."

   IL GESTO LO FA IL BROWSER. scroll-snap su un contenitore che scorre in orizzontale: il dito
   trascina, la settimana segue, l'inerzia e il rimbalzo sono quelli del sistema. Scritto a mano
   sarebbe un'imitazione peggiore di una cosa che ogni telefono fa gia' bene, e sarebbe l'unico
   pezzo della pagina che smette di funzionare se lo script non arriva. */
.week-carousel { position: relative; }
.week-track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* La barra di scorrimento sparisce: qui sotto ci sono le frecce e il gesto, e una barra grigia
     sotto sette tessere si legge come un difetto di allineamento. */
  scrollbar-width: none;
  -ms-overflow-style: none;
  /* La pista non e' un contenitore di scorrimento verticale: il dito che scende deve muovere la
     pagina, non restare impigliato qui dentro. */
  overscroll-behavior-x: contain;
}
.week-track::-webkit-scrollbar { display: none; }
.week-panel {
  flex: 0 0 100%;
  min-width: 0;
  scroll-snap-align: center;
  scroll-snap-stop: always;
}
/* Di quale settimana si tratta. Dentro il pannello, quindi scorre con le sue colonne e nessuno
   script deve tenerla in pari con quello che si sta guardando. */
/* L'etichetta della settimana, che adesso e' due righe e una delle tre e' accesa.

   Era una micro-etichetta come tutte le altre, e su una striscia di sette colonne tutte uguali era
   l'unica cosa che dicesse in che settimana si fosse: "evidenzia maggiormente quale settimana e',
   perche' mi sono confuso persino io che sono il founder". Il nome sopra, l'intervallo di giorni
   sotto - un nome si legge di sfuggita e si scambia, "8 - 14 set" no. */
.week-panel-when {
  margin: 0 0 2px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  font-family: var(--cond);
  text-transform: uppercase;
  color: var(--mut);
}
.week-panel-name {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 1.4px;
}
/* L'intervallo non e' maiuscolo e non e' spaziato: e' una data, e una data spaziata si legge peggio
   di una data scritta normale. Cifre tabulari cosi' le tre settimane non ballano mentre si scorre. */
.week-panel-range {
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: .2px;
  text-transform: none;
  color: var(--mut2);
  font-variant-numeric: tabular-nums;
}
/* Quella di oggi, accesa. Una pastiglia e non solo un colore: il colore da solo si perde fra sette
   colonne che sono gia' dell'accento, mentre una forma piena si riconosce prima di leggerla - ed e'
   l'unica delle tre a portarla, che e' il punto. */
.week-panel-now .week-panel-name {
  color: var(--on-accent);
  background: var(--accent);
  border-radius: 999px;
  padding: 3px 11px;
}
.week-panel-now .week-panel-range { color: var(--accent-text); }
.week-panel-here .week-panel-when { color: var(--accent-text); }

/* ---------- a che punto del viaggio ----------

   "Settimana 4 di 12 - Accumulo volume", sopra le sette colonne e sotto il nome della settimana.

   PIU' PICCOLA E PIU' SPENTA DI CIO' CHE STA SOPRA, deliberatamente. Il nome della settimana risponde
   a "che settimana sto guardando" e deve reggere un'occhiata di sfuggita; questa risponde a "dove
   sono arrivato", che e' una domanda che ci si fa fermandosi. Della stessa misura, le due si
   contenderebbero lo stesso sguardo e la striscia avrebbe tre intestazioni invece di una.

   Un filo sopra invece di uno spazio: separa senza aggiungere aria a un pannello che ne ha poca, e
   dice che la riga appartiene alle colonne sotto e non all'etichetta sopra. Largo quanto il testo
   (width: fit-content con il margine automatico) perche' un filo da bordo a bordo taglierebbe il
   pannello in due carte.

   Non e' dell'accento: l'accento in questo pannello ha gia' un lavoro - la pastiglia della settimana
   corrente - e un secondo oggetto acceso vicino al primo toglie significato a tutti e due. */
.week-cycle {
  width: fit-content;
  max-width: 100%;
  margin: 4px auto 6px;
  padding-top: 5px;
  border-top: 1px solid var(--line-soft);
  font-family: var(--cond);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  text-align: center;
  color: var(--mut2);
  font-variant-numeric: tabular-nums;
}

/* Le frecce, sulla riga dell'etichetta e non a meta' altezza.

   A meta' altezza coprivano la prima e l'ultima colonna: su un telefono una colonna e' larga
   cinquanta pixel, e una freccia da ventisei gliene mangiava meta'. La riga dell'etichetta invece e'
   una scritta centrata con due spazi vuoti ai lati - il posto dove stanno senza togliere niente a
   nessuno, ed e' anche dove uno le cerca, accanto al nome della settimana. */
.week-nav {
  position: absolute;
  top: -3px;
  z-index: 2;
  width: 24px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 7px;
  /* L'accento e non il grigio: vedi il commento sotto, con la frase che l'ha chiesto. */
  color: var(--accent-text);
  font-size: 18px;
  line-height: 1;
  text-decoration: none;
}
/* ---------- le frecce che sfogliano, nel colore dell'accento ----------

   "Evidenzia maggiormente le frecce per scorrere settimane, ora rischiano di passare inosservate:
   usa icona come in foto rivolta a dx e a sx, colore accento scelto, sia qua che in homepage."

   Erano grigie e due caratteri tipografici: accanto a una pastiglia accesa non si leggevano come
   comandi. Adesso sono il segno disegnato e prendono --accent-text, che sul tema chiaro e' l'accento
   leggibile e sul tema scuro e' l'accento stesso - la stessa distinzione che i collegamenti fanno
   gia' ovunque, e la ragione per cui --accent crudo non si usa per una cosa piccola. */
.week-nav .ico { display: block; width: 18px; height: 18px; }
.week-nav:hover, .week-nav:focus-visible { color: var(--accent-text); filter: brightness(1.15); }
.week-nav-prev { left: 0; }
.week-nav-next { right: 0; }

.week-strip {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
}
.week-day {
  /* Le due misure della colonna, scritte una volta sola.

     TUTTO IL RESTO SI RAPPORTA A QUESTE. La spunta e' una frazione del cerchio, quella piccola una
     frazione dell'icona sotto, e la voce sotto e' larga quanto il cerchio - se no le due spunte
     cadono su due verticali diverse. Con due numeri scritti qui, cambiare la misura del cerchio
     porta dietro tutto; con le misure sparse, cambiarla vuol dire ritrovare e correggere quattro
     regole, e la quarta la si dimentica. */
  --week-disc: 28px;
  --week-icon: 19px;
  min-width: 0;
  /* Perche' il segno della data segnata possa stare in un angolo invece che in fila con gli altri:
     vedi .week-event qui sotto. */
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 10px 3px 8px;
  border-radius: 12px;
  border: 1px solid var(--week-outline);
  --solid: var(--field);
  /* Senza la luce del metallo (27/09, --plain-face): la colonna e' larga una quarantina, piu' corta
     della fascia di luce, che cadeva sul nome del giorno - il «DOM» di oggi nel rosa da 4,2 a 3,6. */
  background: var(--plain-face);
  /* Due pixel, il filo di luce e l'ombra, senza la luce del metallo sulla faccia (Luca, 27/09: «le tessere
     dei giorni della settimana dagli 2px di spessore, ombre e luci senza effetto metallico»; la prova da un
     pixel della sera stessa e' superata). */
  box-shadow: var(--edge-lit), var(--lift-edge-xs), 0 1px 2px rgba(0, 0, 0, .20);
}

/* ---------- il giorno in cui c'e' una gara, un test, un rientro, un intervento ----------

   "Rendi evidente dove ho fissato un evento". Una gara di domenica cambia il mercoledi', e sette
   colonne tutte uguali non avevano modo di dirlo.

   IL SECONDO COLORE DEL MARCHIO, non l'accento. L'accento qui dentro vuol dire "allenamento": e' la
   spunta, il bordo del giorno fatto, il riempimento della casella occupata. Una data segnata e'
   un'altra famiglia di cose - non e' una seduta e non si spunta - e darle lo stesso rosa la
   farebbe leggere come una seduta in piu'. E' la stessa divisione che ico-training e ico-intake
   fanno gia' altrove.

   IN UN ANGOLO, non in colonna. Le sette colonne tengono cerchi e giorni incolonnati fra loro, e un
   elemento in piu' in cima a una sola di esse sposterebbe quella di sei pixel: la striscia si legge
   scorrendo i sette cerchi in fila, e un cerchio fuori riga la rompe. */
/* Il giorno con una data segnata ha la faccia tinta, quindi ha il fianco tinto: e' la stessa
   materia, ed e' tutto il senso dello spessore del proprio colore. */
.week-day-event {
  border-color: color-mix(in srgb, var(--accent-2-text) 55%, transparent);
  --solid: color-mix(in srgb, var(--accent-2-text) 9%, var(--field));
  background: var(--plain-face);
}
.week-event {
  position: absolute;
  left: -1px;
  top: -1px;
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--accent-2-text);
}

/* ---------- il cerchio: la disciplina e cosa ne e' stato, in un segno solo ----------

   Copiato dal campione che e' stato mandato: la lettera del giorno in cima, sotto un cerchio, e
   dentro al cerchio il manubrio o la scarpa - oppure, dove non c'e' niente in programma, il numero
   del giorno nel mese.

   ERANO DUE SEGNI E ADESSO E' UNO. Prima c'era un cerchio con dentro una spunta o una croce e,
   sotto, le icone delle discipline: il cerchio diceva se il giorno era andato, le icone cosa c'era,
   e per leggere una colonna bisognava metterli insieme da se'. Adesso il cerchio dice tutte e due -
   dentro la disciplina, e il riempimento cosa ne e' stato.

   Misura fissa, sempre, che il giorno abbia qualcosa o no: sette cerchi in fila si leggono senza
   leggere, e uno fuori misura rompe la fila. */
.week-disc {
  position: relative;
  width: var(--week-disc);
  height: var(--week-disc);
  flex: 0 0 auto;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1.5px solid var(--line);
  background: transparent;
  color: var(--ink-2);
}
/* La sagoma dentro al cerchio: poco piu' di meta', cosi' resta il bordo di respiro attorno. */
/* display:block per la stessa ragione scritta sotto, su .week-sport-icon .ico: in linea, la sagoma
   si porta dietro lo spazio della linea di base e resta alta di un paio di pixel nel cerchio. */
.week-disc .ico {
  display: block;
  width: calc(var(--week-disc) * 0.57);
  height: calc(var(--week-disc) * 0.57);
}
.week-disc-icon { display: inline-flex; }
/* Una disciplina senza icona propria (bici, nuoto, trekking) tiene il nome corto, dentro lo stesso
   cerchio: tre lettere ci stanno dove una parola intera non ci starebbe. */
.week-disc-name {
  font-family: var(--cond);
  font-size: 10px;
  letter-spacing: .3px;
  text-transform: uppercase;
}
/* Il numero del giorno nel mese, dove il cerchio sarebbe vuoto. */
.week-daynum {
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--mut);
}

/* ---------- i tre stati, dettati guardando la striscia ----------

   "Attivita' programmate icona bianca senza sfondo, effettuate icona nera in cerchio colorato con
   piccola spunta verde in basso a destra, non effettuate in grigio barrate."

   Prima i tre stati erano tre gradazioni della stessa cosa - cerchio pieno, cerchio contornato,
   cerchio rosso - quindi si distinguevano solo confrontandoli fra loro, e una colonna da sola non
   diceva niente. Adesso ognuno ha un mezzo diverso: il pieno dice fatto, il niente dice da fare, la
   riga addosso dice saltato. Una colonna si legge senza guardare le altre sei. */

/* FATTA: il cerchio si riempie e la sagoma dentro prende l'inchiostro che si legge SUL RIEMPIMENTO.

   ---------- e qui c'e' un errore mio, andato in produzione e riferito ----------

   Era --on-accent. Poi e' diventato --ink, su richiesta: "voglio icona bianca nel pallino colorato
   per tema scuro e icona nera per tema chiaro; non voglio questa differenza nelle icone" - la
   differenza essendo che dentro il cerchio la sagoma era scura mentre le discipline in piu' sotto,
   che prendono --ink, erano bianche.

   Con il rosa funzionava. Con il verde, il lime, il menta e il bianco no: --ink sul tema scuro e'
   bianco, e una sagoma bianca dentro un cerchio verde chiaro non si vede. "Per le tonalita' piu'
   chiare torna al nero nell'icona se no e' invisibile: metti il colore che risalta meglio, fra
   bianco e nero, in base alle tonalita' e allo sfondo."

   LA LEZIONE, ed e' il motivo per cui questo commento e' lungo: l'inchiostro non si sceglie in base
   al TEMA, si sceglie in base a COSA C'E' SOTTO. --ink e' l'inchiostro della pagina, giusto su una
   tessera; --on-accent e' l'inchiostro sul riempimento pieno, e qui sotto c'e' quello. La
   "differenza fra le icone" che sembrava un difetto era la cosa giusta: due sagome su due fondi
   diversi devono avere due colori, o una delle due sparisce - ed e' sparita.

   --on-accent non e' "nero": e' "il colore che si legge sull'accento". Vale scuro per tutti e sei i
   fluorescenti, che sono chiari, e diventa chiaro da solo sull'unica tavolozza con l'accento scuro
   (mono in tema chiaro, dove l'accento e' il nero quasi pieno del testo). Una regola sola, nessuna
   tavolozza da ricontrollare a mano, e il caso limite gia' coperto. */
.day-done .week-disc {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}
/* ---------- le settimane passate sono grigie ----------

   "I cerchi delle icone della settimana passata rendili grigi, cosi' si capisce sicuro che sono
   cose scadute e vecchie."

   Nasce dallo stesso equivoco dell'etichetta: guardando un pannello arretrato si legge la domenica
   barrata come se fosse oggi. L'etichetta adesso lo dice a parole, e questo lo dice senza parole -
   che e' il canale che si legge per primo su una striscia di sagome.

   UN FILTRO E NON UNA TAVOLOZZA PARALLELA. Gli stati sono tre - fatto, da fare, saltato - e ognuno
   ha il suo colore, piu' il secondo accento delle date segnate: riscriverli tutti in grigio
   vorrebbe dire quattro regole da tenere in pari con quelle vere per sempre, e la quinta che
   qualcuno aggiunge domani resterebbe colorata in mezzo alle altre. Il filtro toglie il colore a
   QUALUNQUE cosa ci sia dentro, compresa quella di domani.

   L'opacita' e' la meta' del messaggio: sbiadito vuol dire passato in un modo che il solo grigio
   non dice - il grigio da solo si legge anche come "disattivato".

   SOLO ALL'INDIETRO. Le settimane future restano a colori: non sono scadute, devono ancora arrivare,
   ed e' il contrario di cio' che questa regola vuole dire. Il selettore prende gli scostamenti che
   cominciano per meno, che sono tutti e soli quelli passati. */
/* Sui FIGLI della colonna e non sulla colonna: il filtro deve togliere il colore ai segni - il
   cerchio, la spunta, le discipline sotto, la stella della data segnata - e non alla tessera, che
   e' la stessa materia delle altre settimane e non ha ragione di sbiadire. Un filtro sul contenitore
   si porterebbe dietro anche la faccia e il suo spessore. */
/* UN CERCHIO VUOTO, non un cerchio scolorito.

   Sono due tentativi che questa regola sostituisce, e valeva la pena scriverlo perche' fallivano
   entrambi per la stessa ragione. Prima grayscale piu' opacita': il cerchio pieno diventava grigio
   scuro e la sagoma dentro restava scura - due scuri uno sull'altro. Poi grayscale piu' brightness:
   leggibile sul tema scuro e ancora illeggibile su quello chiaro, dove non c'era niente da
   schiarire. Riferito cosi': "cambiamo approccio, perche' nel chiaro e' ancora illeggibile".

   IL DIFETTO ERA IL METODO. Un filtro prende una cosa disegnata per essere letta in un modo e la
   sposta; il risultato dipende da dove partiva, quindi funziona su un tema e non sull'altro, e per
   aggiustarlo servono due filtri diversi che si rincorrono. Qui invece il passato ha un disegno
   SUO: "rendili due cerchi vuoti con dentro l'icona, bordo e icona neri nel tema chiaro, bordo e
   icona bianchi nel tema scuro".

   Niente filtro, niente opacita', nessuna variante per tema: --ink E' gia' "nero sul chiaro, bianco
   sullo scuro", quindi una riga sola dice tutte e due le cose e non possono separarsi. E il contrasto
   e' il massimo disponibile, perche' il cerchio e' vuoto e la sagoma sta sul fondo della tessera. */
.week-panel[data-week-offset^="-"] .week-day .week-disc {
  background: transparent;
  border-color: var(--ink);
  color: var(--ink);
}
/* La spunta e le discipline in piu' prendono lo stesso inchiostro, cosi' la colonna passata e' di un
   colore solo - che e' la differenza vera con una colonna di questa settimana, dove il colore c'e'. */
.week-panel[data-week-offset^="-"] .week-day .week-done-tick,
.week-panel[data-week-offset^="-"] .week-day .week-sport-item,
.week-panel[data-week-offset^="-"] .week-day .week-event-sport {
  color: var(--ink);
}
/* E la tessera perde la sua tinta: un fondo nel colore dell'accento sotto un cerchio vuoto e'
   esattamente il segnale che questa regola serve a togliere. */
.week-panel[data-week-offset^="-"] .week-day.day-done {
  border-color: var(--line-soft);
  background: transparent;
}

/* La spunta di cio' che e' stato eseguito: un segno e basta, senza pastiglia.

   Era un pallino verde. Il verde era l'unico della striscia e proprio per questo tirava l'occhio
   piu' della disciplina che accompagnava - sette pastiglie verdi in fila si leggevano prima delle
   sette sagome, che sono la cosa per cui la striscia esiste. Chiesto di toglierla: "togli il pallino
   verde e mettici la spunta nera/bianca in base alla palette".

   --ink e' proprio "nera/bianca in base alla palette": e' il colore del testo, quindi nero sul tema
   chiaro e bianco su quello scuro, senza due regole da tenere in pari. Il contorno nel colore della
   tessera la stacca dal cerchio pieno su cui si appoggia. */
.week-done-tick {
  position: absolute;
  right: -3px;
  bottom: -4px;
  /* FUORI DALLA SAGOMA, non appoggiata sopra. Stava sul bordo del cerchio e ne copriva un pezzo -
     "si sovrappone al cerchio e alle icone" - e su una disciplina come le impronte, che sono due
     forme staccate, ne nascondeva una intera.

     Il cerchio e' inscritto nel suo riquadro, quindi l'angolo in basso a destra del riquadro e'
     vuoto: spostandola di poco piu' di un quarto del diametro esce dall'arco e resta comunque
     dentro la colonna. I due scostamenti sono frazioni del diametro e non pixel, cosi' ridurre o
     allargare il cerchio se la porta dietro invece di scollarla.

     Poco meno di meta' del cerchio: grossa abbastanza da leggersi a colpo d'occhio. */
  font-size: calc(var(--week-disc) * 0.46);
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
  /* Un bordo sottile e neutro, per staccarla da qualunque cosa ci sia sotto.

     Serve perche' la spunta cade sul bordo del cerchio: meta' sul rosa pieno e meta' sulla tessera,
     e senza contorno la meta' sul rosa si impastava. --bg e' il fondo della pagina, quindi e' scuro
     sul tema scuro e chiaro su quello chiaro: sempre l'opposto di --ink, che e' il colore della
     spunta. Un contorno che si rovescia insieme al segno che contorna.

     paint-order mette il bordo DIETRO il riempimento invece che sopra: senza, un contorno da un
     pixel su un segno da quindici se ne mangia i tratti sottili e la spunta diventa un blocchetto. */
  -webkit-text-stroke: 1px var(--bg);
  paint-order: stroke fill;
}
/* Lo STESSO scostamento orizzontale per tutte e due le spunte: e' quello che le tiene sulla stessa
   verticale, che e' come e' stato chiesto ("qua le spunte allineate"). Cambia solo la misura del
   segno, perche' cambia la sagoma che accompagna. */
.week-done-tick,
.week-done-tick-sm {
  right: calc(var(--week-disc) * -0.24);
  bottom: calc(var(--week-disc) * -0.18);
}
/* Quella sulle discipline disegnate sotto il cerchio: stesso segno, misura minore, perche' anche
   l'icona che accompagna e' minore. */
/* Stesso angolo, stesso scostamento: e' quello che le mette sulla stessa verticale. Cambia solo la
   misura del segno, perche' l'icona che accompagna e' piu' piccola del cerchio. */
/* Quella sotto prende la misura dall'icona, non dal cerchio: e' la sagoma che accompagna. Lo
   scostamento invece resta quello del cerchio - vedi sopra, e' cio' che le allinea. */
.week-done-tick-sm { font-size: calc(var(--week-icon) * 0.62); }

/* PROGRAMMATA: l'icona e basta. Niente cerchio e niente sfondo - non c'e' niente da riempire,
   perche' non ne e' ancora stato niente. Riempirlo sarebbe l'applicazione che si prende una seduta
   che non e' successa. */
.day-ahead .week-disc {
  background: transparent;
  border-color: transparent;
  color: var(--ink);
}

/* NON EFFETTUATA: grigia e barrata. Il rosso se n'e' andato: una seduta saltata e' una cosa che non
   c'e' stata, non un errore, e il rosso e' il colore con cui questa applicazione dice che qualcosa
   e' andato storto. La riga in diagonale e' la stessa che barra i nomi sotto il cerchio. */
.day-missed .week-disc {
  background: transparent;
  border-color: transparent;
  color: var(--mut2);
}
/* La sagoma piu' spenta della riga che la taglia, se no le due si fondono in un grigio solo e il
   barrato sparisce: con il manubrio - che e' largo e ha gia' una barra orizzontale in mezzo - la
   riga cadeva esattamente sopra quella e non si vedeva affatto. E' la stessa ricetta delle righe
   sotto il cerchio, dove la stessa cosa era gia' stata risolta cosi'. */
.day-missed .week-disc .ico { opacity: .5; }
.day-missed .week-disc::after {
  content: "";
  position: absolute;
  left: 1px;
  right: 1px;
  top: 50%;
  height: 2px;
  border-radius: 2px;
  background: var(--mut);
  transform: rotate(-18deg);
}

.day-rest .week-disc { border-color: var(--line-soft); }

/* "E c'e' dell'altro": un puntino in alto a destra, come nel campione. Non un numero - un cerchio
   non e' un posto dove contare, che e' la stessa ragione per cui il segno del giorno e' sempre
   stato uno solo. Quante siano lo dicono le righe sotto. */
/* ---------- il puntino "e c'e' dell'altro" non c'e' piu' ----------

   Era un pallino nell'angolo del cerchio, acceso quando il giorno portava piu' di una disciplina.
   Chiesto e tolto: "cosa sono quei pallini rossi sopra le icone palestra?" - ed era la domanda
   giusta, perche' non dicevano piu' niente.

   Non erano inutili quando sono stati scritti: allora sotto il cerchio passavano i CHILOMETRI di
   ogni disciplina e non le icone, quindi il puntino era l'unico modo di sapere che il giorno ne
   aveva una seconda. Da quando le sagome sono scese li' sotto, il puntino si accendeva esattamente
   quando la cosa che annunciava era gia' disegnata un centimetro piu' in basso.

   E' la forma di residuo piu' difficile da vedere: non e' codice morto - girava, si disegnava, aveva
   le sue regole per ogni stato - era codice VIVO che aveva smesso di dire qualcosa.

   ATTENZIONE, il nome .week-more esiste ancora e NON e' questo: e' il "e altre 4" della carta della
   condizione, un <details> che non ha niente a che vedere con la striscia. Due componenti con lo
   stesso nome di classe, ed e' il motivo per cui questa nota sta qui invece che in un commit e
   basta. */

/* The tile takes a tint of its own state, which is what makes the row readable without reading. */
.week-day.day-done { border-color: var(--accent-line); background: var(--accent-soft); }
/* Il bordo rosso della tessera saltata se n'e' andato insieme al rosso dell'icona: un contorno
   d'allarme attorno a un'icona grigia sono due frasi diverse sullo stesso giorno. */
.week-day.day-missed { border-color: var(--line-soft); }
.week-day.day-rest { background: transparent; }

/* Today, marked the way the agenda and the day chart mark it. */
.week-day-today { box-shadow: inset 0 0 0 1px var(--accent); }
.week-day-today .week-weekday { color: var(--accent-text); }
/* Days already gone stay legible - they are the week's record - and stop competing with the days
   that can still be acted on. */
.week-day-past { opacity: .78; }

.week-sport {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: .2px;
  color: var(--ink);
  text-align: center;
  /* Le discipline ora sono icone e non vanno a capo; l'overflow-wrap resta per il nome breve
     delle discipline senza icona propria. */
  overflow-wrap: anywhere;
}
.day-rest .week-sport { color: var(--mut2); }
/* Ogni disciplina e' una voce della colonna: l'icona sopra, i chilometri sotto - la cifra non va
   mai a capo dove la parola andava. */
/* La disciplina di una data segnata: nel colore della stella, non in quello degli allenamenti.

   E' tutta la differenza fra le due cose: una gara di domenica non e' una seduta programmata per
   domenica, e con lo stesso rosa si leggerebbe come un allenamento in piu' da fare - il contrario di
   cio' che dice. Stessa scatola delle altre voci, cosi' resta incolonnata con loro. */
.week-event-sport {
  position: relative;
  width: var(--week-disc);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1.5px solid transparent;
  color: var(--accent-2-text);
}
.week-event-sport .ico { display: block; width: var(--week-icon); height: var(--week-icon); }

/* Ogni disciplina e' una voce della colonna, LARGA QUANTO IL CERCHIO SOPRA.

   Non e' un dettaglio di riempimento: la spunta si appoggia all'angolo in basso a destra della
   scatola che la contiene, e finche' le scatole erano due di misure diverse - trenta pixel il
   cerchio, venti l'icona - le due spunte cadevano su due verticali diverse, a cinque pixel l'una
   dall'altra. Segnalato con una riga tirata accanto: "qua le spunte allineate". Con una misura sola
   si allineano da sole, e restano allineate se un domani il cerchio cambia. */
.week-sport > .week-sport-item {
  position: relative;
  width: var(--week-disc);
  /* Lo stesso bordo del cerchio, invisibile. Un elemento posizionato si ancora al RIQUADRO INTERNO
     del genitore, non al suo bordo esterno: con il cerchio bordato e questa voce no, le due scatole
     erano larghe uguali e i due riquadri interni no, e le spunte finivano a un pixel l'una
     dall'altra. Misurato, non visto - a occhio un pixel non si nota, e l'anno prossimo qualcuno lo
     correggerebbe spostando una spunta di mezzo pixel invece di pareggiare le scatole. */
  border: 1.5px solid transparent;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}
/* ---------- le altre discipline fatte, in cerchio e legate al pallino ----------

   "Pallino colorato su entrambe le icone delle attivita' completate" - e poi, guardandolo: "anzi, le
   altre attivita' completate mettile in un cerchio attorno, stesso colore del pallino, collegato da
   una linea al pallino, per far capire che sono collegate".

   Il giorno ha UN cerchio pieno - la disciplina principale - e le altre stavano sotto come sagome
   nude: due attivita' fatte lo stesso giorno si vedevano come una fatta e una no. Riempire anche le
   altre non andava bene e la seconda richiesta dice perche': due pieni identici sono due giorni, non
   un giorno con due cose dentro. Il contorno dice "stessa famiglia", la linea dice "stessa giornata".

   IL CONTORNO E NON IL PIENO anche per una ragione che si vede solo insieme: il pieno e' il segno
   del giorno, e ce n'e' uno per colonna. Se lo prendessero in tre, la colonna perderebbe il suo
   punto di lettura.

   La scatola era gia' larga quanto il cerchio e aveva gia' il suo bordo trasparente - c'era per
   pareggiare i riquadri interni e far cadere le spunte sulla stessa verticale. Qui quel bordo si
   accende: nessuna misura nuova, e le due spunte restano dove sono. */
/* Il selettore passa dal genitore, e non e' stile: il bordo trasparente e' scritto su
   ".week-sport > .week-sport-item", che vale due classi - una sola non lo accende. Visto rendendo:
   la linea c'era e il cerchio no. */
.week-sport > .week-sport-done {
  height: var(--week-disc);
  justify-content: center;
  border-radius: 50%;
  /*
    L'ANELLO E' DIPINTO DAL FONDO, e non e' un vezzo: e' l'unico modo di averlo dello stesso diametro
    del pallino sopra senza toccare la scatola.

    "Cerchio di sotto stesso diametro del pallino sopra." Non lo era, e per una ragione che non si
    sa nominare guardandola: l'anello era un'ombra interna, e un'ombra interna si dipinge dentro il
    RIQUADRO DI RIEMPIMENTO - quindi restava dentro il bordo trasparente da un pixel e mezzo e
    veniva venticinque dove il pallino sopra e' ventotto. Tre pixel di aria tutt'intorno, riportati
    come "stesso diametro" e non come "sposta l'anello".

    E il bordo non si puo' ingrossare per rimediare: e' largo un pixel e mezzo su TUTTE le voci,
    trasparente, ed e' cio' che pareggia i riquadri interni e fa cadere le due spunte sulla stessa
    verticale. Ingrossarlo sposterebbe l'ancoraggio della spunta di mezzo pixel, cioe' scioglierebbe
    proprio la cosa che quel bordo serve a tenere.

    Un fondo invece arriva al bordo ESTERNO (da qui "border-box", che qui non e' un dettaglio ma la
    misura chiesta), non occupa spazio, e la scatola resta identica. Un gradiente radiale che tiene
    trasparente il centro e accende gli ultimi tre pixel: l'anello.

    UN SOLO STRATO, e non bordo acceso piu' ombra interna, che pure darebbe tre pixel a filo: due
    anelli affiancati dello stesso colore lasciano fra loro la riga di antialias, e sullo schermo si
    legge come un cerchio doppio. Visto rendendo.

    Tre pixel, come la barra che lo lega al pallino: "spessore cerchio uguale a spessore linea che li
    collega". Un anello piu' sottile del filo che lo lega faceva sembrare due cose disegnate da due
    mani - e le due misure sono tenute in pari da un test, perche' sono scritte in due regole diverse.

    E l'anello a filo e' anche cio' che rende simmetrica la strozzatura, che e' la terza cosa chiesta:
    il raccordo entra tre pixel sopra e tre sotto, ma finche' l'anello era rientrato di un pixel e
    mezzo, sotto se ne vedeva un pixel e mezzo in piu' che sopra.
  */
  /*
    IL COLORE PASSA DA currentColor, e non e' un vezzo nemmeno questo.

    "Quando passano in settimana scorsa deve essere grigio come il pallino." Una settimana passata
    perde il colore - il cerchio si svuota e diventa inchiostro, e c'e' gia' una regola che lo fa per
    il pallino, la spunta e le discipline. La catena era l'unica cosa rimasta rosa in una colonna
    tutta grigia, e con l'anello acceso diceva "questa e' di adesso" di un giorno di otto giorni fa.

    Scritto var(--accent) qui dentro, quella regola non poteva arrivarci: cambia il COLORE della
    voce, non il suo fondo. Scritto currentColor, ci arriva senza sapere che esiste una catena - e
    ci arrivera' anche la prossima regola che spegne una colonna, che e' il punto.

    L'accento sta quindi sul color di questa voce. I figli dichiarano il loro (la sagoma prende
    --ink, la spunta pure), quindi tingere la voce tinge l'anello e il raccordo e nient'altro.
  */
  color: var(--accent);
  background: radial-gradient(circle closest-side,
      transparent calc(100% - 3px), currentColor calc(100% - 3px)) border-box;
}

/* La sagoma dentro l'anello: piu' piccola e un filo piu' in basso.

   "Abbassa ancora l'icona, non deve sovrapporsi al cerchio."

   QUINDICI, ED E' UN CONTO E NON UN GUSTO. L'anello a tre pixel lascia un vano di ventidue, e una
   sagoma e' un QUADRATO: un quadrato da diciassette inscritto in un cerchio da ventidue ha la
   diagonale di ventiquattro, quindi i suoi angoli escono comunque - per questo, rimpicciolita una
   volta, continuava a toccare. Il lato massimo che ci sta e' 22 diviso radice di due, cioe' poco
   piu' di quindici.

   NIENTE SCOSTAMENTO: "le icone devono essere belle centrate nel cerchio". Il pixel di discesa era
   un rimedio a un guaio diverso - la sagoma toccava l'anello e si era abbassata per staccarla -
   e una volta rimpicciolita la sagoma quel pixel restava a scentrarla, cioe' a fare il danno che
   doveva riparare. Il centraggio lo fa gia' il flex, e lo fa esatto. */
.week-sport > .week-sport-done .week-sport-icon .ico { width: 15px; height: 15px; }
/* La linea che lega la sagoma al pallino sopra. Parte dal bordo di sopra e sale per lo spazio che
   separa le due voci: sei pixel di gap piu' il bordo, quindi otto.

   Solo dentro un giorno con il cerchio pieno: senza, la linea salirebbe verso una sagoma vuota e
   direbbe che sono collegate a qualcosa che non e' successo. */
.week-day.day-done .week-sport-done::before {
  content: "";
  position: absolute;
  left: 50%;
  /*
    ---------- il raccordo: "zero spigolo, deve essere una curva unica" ----------

    Con un disegno accanto, ed e' quello che ha chiarito la richiesta: non due capi arrotondati, ma
    la linea che si APRE entrando nel cerchio, come una clessidra. Gli angoli da togliere non sono
    quelli della linea - sono i due angoli acuti che la linea forma CON la curva, uno per lato, e un
    capo tondo li lascia dove sono.

    Un angolo concavo si disegna con un gradiente radiale: il cerchio trasparente sta fuori, e il
    colore riempie il resto del quadratino - quindi il confine curva verso l'interno invece che
    verso l'esterno. Quattro quadratini, due in alto e due in basso, e in mezzo la barra. Tutto in un
    solo pseudo-elemento: e' un fondo a piu' strati, non quattro scatole.

    ---------- e i numeri, che qui non sono a occhio ----------

    "Una curva unica" vuol dire una cosa precisa: il cerchietto del raccordo deve essere TANGENTE
    alla barra da una parte e al cerchio grande dall'altra. Se e' piu' piccolo i due non si toccano e
    resta una tacca; se e' piu' grande entra nel cerchio e taglia, e nel punto in cui esce si vede lo
    spigolo - che e' esattamente cio' che e' stato chiesto di togliere. Tangente in tutti e due i
    punti: la sagoma passa dalla barra al cerchio senza un vertice, e il contorno e' una linea sola.

    Il raggio non si sceglie, si ricava. Vita a meta' del vuoto (tre pixel sopra e tre sotto, che e'
    "strozzatura simmetrica"), barra larga tre, cerchi da ventotto: il centro del raccordo sta a
    1,5+R dall'asse, e la tangenza al cerchio grande vuole che disti 14+R dal suo centro. Viene
    R = 3,81. E' anche il piu' largo possibile: sopra quel valore la bocca del raccordo si RESTRINGE
    invece di allargarsi, quindi 3,81 e' insieme "zero spigolo" e "piu' raccordo" - non c'e' da
    scegliere fra le due. 3,85 e non 3,81 perche' a filo esatto, fra due curve che si sfiorano, resta
    il capello di antialias: un centesimo di sovrapposizione lo chiude e lo spigolo che introduce e'
    sotto il pixel.

    Bocca del raccordo: 7,6 pixel dove tocca il cerchio, contro i tre della barra.

    LA BARRA VA OLTRE IL RACCORDO, ed entra nei due cerchi. Serve a non lasciare un capello di
    trasparenza lungo il punto di tangenza - dove due curve si sfiorano l'antialias non e' d'accordo
    con nessuna delle due.

    Sotto entra di tre, che e' lo spessore dell'anello: un mezzo pixel piu' in giu' e spunterebbe nel
    vuoto del cerchio come un trattino.

    Sopra entra di UNO E MEZZO, e i due numeri sono diversi perche' i due cerchi lo sono. Il pallino
    di sopra e' pieno solo finche' la settimana e' questa: in una settimana passata si svuota e resta
    il suo bordo, un pixel e mezzo. Con tre pixel di barra, gli altri uno e mezzo restavano dentro il
    cerchio vuoto - un dentino appeso all'arco, visibile in un colpo d'occhio la prima volta che si
    e' guardata una settimana scorsa. La barra si accorcia dall'alto (e' l'unico strato che si
    accorcia: la scatola e i quattro raccordi restano dove sono, se no si scioglie la tangenza).

    Lo scostamento e' -10,5 e non -9 perche' un elemento assoluto si ancora al riquadro INTERNO del
    genitore, e il genitore ha un bordo da un pixel e mezzo.
  */
  top: -10.5px;
  height: 12px;
  width: 10.7px;
  margin-left: -5.35px;
  background:
    /* la barra, in mezzo, per tutta l'altezza */
    linear-gradient(currentColor, currentColor) 50% 100% / 3px calc(100% - 1.5px) no-repeat,
    /*
      I due raccordi verso il cerchio di sopra, e il centro del cerchio trasparente sta nell'angolo
      del quadratino che guarda l'ASSE DEL RACCORDO - fuori dalla barra e all'altezza della vita. La
      prima stesura lo metteva nell'angolo opposto e il risultato non era un raccordo smussato: era
      una freccia rivolta in giu' - il colore restava nel cuneo lontano dal centro invece di
      circondarlo. Visto rendendo, e in un colpo d'occhio.
    */
    radial-gradient(circle at 0 100%, transparent 3.85px, currentColor 3.85px) 0 2.47px / 3.85px 3.53px no-repeat,
    radial-gradient(circle at 100% 100%, transparent 3.85px, currentColor 3.85px) 100% 2.47px / 3.85px 3.53px no-repeat,
    /* e i due verso l'anello di sotto, specchiati */
    radial-gradient(circle at 0 0, transparent 3.85px, currentColor 3.85px) 0 calc(100% - 2.47px) / 3.85px 3.53px no-repeat,
    radial-gradient(circle at 100% 0, transparent 3.85px, currentColor 3.85px) 100% calc(100% - 2.47px) / 3.85px 3.53px no-repeat;
}

.week-sport-icon { display: inline-flex; align-items: center; justify-content: center; color: var(--ink); }
.week-sport-icon .ico {
  width: var(--week-icon);
  height: var(--week-icon);
  vertical-align: 0;
  /*
    BLOCCO, E NON IN LINEA. "Le icone devono essere belle centrate nel cerchio": non lo erano, e la
    ragione non stava nel disegno - i quattro disegni hanno l'inchiostro centrato nel loro riquadro,
    misurato. Stava qui: una sagoma in linea si appoggia alla linea di base, e sotto la linea di base
    la riga tiene lo spazio per le pance delle lettere anche dove lettere non ce ne sono. Due pixel e
    mezzo di vuoto SOTTO la sagoma, dentro una scatola che poi viene centrata: la scatola e' centrata
    e la sagoma no, e si vede come un'icona che scappa in alto.

    Misurato, non visto: la voce andava da 163 a 191 e la sagoma da 167 a 182, cioe' quattro pixel
    sopra e nove sotto. Da blocco non c'e' linea di base e non c'e' riga, e la sagoma torna al centro
    del cerchio da sola - qui e in ogni altro punto in cui questa icona compare.
  */
  display: block;
}
/* Una disciplina senza icona propria tiene il nome breve, condensato come prima. */
.week-sport-name { display: block; font-family: var(--cond); font-size: 12px; }
/* "Riposo" e' una parola sola e non deve spezzarsi in "Ripos-o": la colonna eredita overflow-wrap
   dalle discipline, che ora sono icone e non ne hanno piu' bisogno. */
/*
  La disciplina programmata e non fatta, barrata di rosso.

  Il giorno ha un segno solo e resta cosi' - una colonna larga quaranta pixel non ne regge due. Ma
  con tre nomi sotto una spunta sola, la spunta finiva per dire "fatte tutte e tre": "mi spunta la
  corsa anche come fatta, quando non l'ho fatta". La riga risponde per ogni nome senza aggiungere un
  segno alla colonna.

  Riga rossa e parola grigia: il rosso e' sulla riga, non sulla parola. Una parola rossa E barrata
  dice due volte la stessa cosa, e questa e' una colonna che si guarda, non che si legge.
*/
/* Grigio e non rosso, come il cerchio sopra: "non effettuate in grigio barrate". Una seduta saltata
   e' una cosa che non c'e' stata, non un errore, e il rosso qui dentro e' il colore con cui si dice
   che qualcosa e' andato storto. */
.week-sport-missed {
  text-decoration: line-through;
  text-decoration-color: var(--mut2);
  text-decoration-thickness: 2px;
  color: var(--mut2);
}
/* Il barrato non attraversa un'icona SVG, quindi la seduta saltata si segna sull'icona a parte:
   spenta e con una riga in diagonale, la stessa cosa che dice il testo barrato accanto. */
.week-sport-missed .week-sport-icon { position: relative; color: var(--mut2); opacity: .6; }
.week-sport-missed .week-sport-icon::after {
  content: "";
  position: absolute;
  left: -2px;
  right: -2px;
  top: 50%;
  height: 2px;
  border-radius: 2px;
  background: var(--mut2);
  transform: rotate(-18deg);
}
.week-weekday {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut);
}

/* The sentence under the strip. It carries the verdict's own name as a class so an encouraging
   reading and a warning one are not the same colour - the card used to have one register, and one
   register is what made a good week produce a complaint. */
.week-verdict {
  margin: 14px 0 0;
  padding: 11px 13px;
  border-radius: 12px;
  border: 1px solid var(--line-soft);
  border-left: 3px solid var(--accent);
  background: var(--field);
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink);
}
.week-verdict.verdict-nothing_planned { border-left-color: var(--line); color: var(--mut); }

/* ---------- la riga di una data segnata (home e /programma) ----------

   Dal 26/09 (mock 01) e' una riga di elenco come le altre (.record-tile, piu' sotto): la casella
   del giorno a sinistra, il nome, sotto la riga piccola con in coda «Modifica» (o il risultato), a
   destra la X, sorella del collegamento. Era un riquadro nel colore del secondo accento, con un
   collegamento esteso da un velo (::after, inset: 0) e la X e i moduli sopra il velo con uno
   z-index: tre impilamenti da tenere in ordine, e uno sbagliato era un campo che non prendeva il
   dito ("se clicco qua non mi fa scrivere, non succede nulla"). Da riga non c'e' niente da impilare.

   Il secondo accento non c'e' piu' su testo e segni: con la tavolozza volt e' quasi bianco, e nel
   tema chiaro non si scurisce - "Modifica" e "+ altre N" erano bianco su bianco (visto il 26/09,
   c'era anche su main). Ogni colore qui e' --accent-text o un grigio del tema, che reggono le sette
   tavolozze nei due temi (TheHomeRowsFollowThePaletteTest). */

/* IL BERSAGLIO E' LA TESSERA INTERA, e qui lo e' davvero: il margine interno sta sul collegamento e
   non sulla tessera. Con i 12 punti sopra e sotto sulla tessera, il collegamento era alto 41 su una
   riga di 67 e un dito sul bordo non apriva niente (verifiche del 26/09). Vale per le righe di
   «Oggi», per quelle delle date e, dal taglio 3, per quelle dell'agenda; dal taglio 4a per le
   schede della libreria e la riga di «Me la scrive Hybrx» (la riga di una scheda ha il suo margine,
   con la presa accanto: la regola sta con le altre della libreria); dal taglio 5 per lo storico
   allenamenti e gli import; dal taglio 8 per gli storici di gare (che sono righe di data,
   .event-row.race-row), infortuni e record.

   E 12 E 8 invece di 14 e 10: a 360 punti «Check-up giornaliero» chiedeva 160,8 punti e ne aveva
   155 - misurato, non stimato.

   `.record-tile.event-row` e non `.event-row`: le regole di .record-tile stanno mille righe piu' giu',
   e a parita' di peso vince chi viene dopo - la riga delle date teneva il suo margine sulla tessera. */
.home-today .record-tile,
.record-tile.event-row,
.record-tile.agenda-row,
.record-tile.plan-row,
.record-tile.plan-way,
.record-tile.history-tile,
.record-tile.job-row,
.record-tile.body-row,
.record-tile.meal-row,
.record-tile.conversation-row,
.record-tile.memory-row,
.record-tile.injury-row,
.record-tile.pr-row { padding: 0; gap: 0; }
.home-today .record-tile > .record-open,
.record-tile.event-row > .record-open,
.record-tile.agenda-row > .record-open,
.record-tile.plan-way > .record-open,
.record-tile.history-tile > .record-open,
.record-tile.job-row > .record-open,
.record-tile.body-row > .record-open,
.record-tile.meal-row > .record-open,
.record-tile.conversation-row > .record-open,
.record-tile.memory-row > .record-open,
.record-tile.injury-row > .record-open,
.record-tile.pr-row > .record-open {
  align-self: stretch;
  gap: 8px;
  padding: 12px 10px 12px 12px;
}
/* Sulle date la X segue il collegamento. Dal 27/09 sera prima della X c'e' anche la tessera di «Modifica»
   (sotto, .event-row-edit), fuori dal flusso: il collegamento le lascia il posto - 44 del bersaglio e i
   quattordici fra lui e il bordo del collegamento - cosi' che il nome non ci passi sotto. I centri, misurati
   a 390 con getBoundingClientRect (che conta gia' il translate della X): penna 286 e X 330, 44 punti come
   condividi 242, grafici 286 e X 330 della carta sotto - «lo spazio che separa la x dal tasto modifica […]
   deve essere uguale allo spazio che separa i tre bottoni che vedi sotto» (Luca, 27/09). */
.record-tile.event-row > .record-open { position: relative; padding-right: 62px; }

/* La riga si apre sotto se stessa - la correzione, "com'e' andata" - a tutta larghezza: e' la riga
   che si apre, non una seconda tessera accanto. Il margine che la tessera non ha piu' lo portano
   loro. */
.event-row { flex-wrap: wrap; }
.event-row > .event-edit,
.event-row > .result-entry { flex: 1 0 calc(100% - 24px); margin: 0 12px 12px; }

/* Una data gia' passata resta, spenta: quello che e' successo non sparisce - una gara di domenica
   spiega le gambe di lunedi', ed e' anche l'unica riga da cui la si corregge - ma smette di essere
   una cosa verso cui puntare. Lo spegnimento sta sul COLLEGAMENTO e non sulla riga: l'opacita' si
   eredita e non si disfa, e sotto la riga aperta ci sono due moduli - "il box appare annebbiato,
   quasi non fosse interagibile". Spento e' cio' che RACCONTA la data; quello che serve a scriverci
   sopra resta acceso. Sui FIGLI del collegamento e non sul collegamento: un'opacita' fa della scatola
   un livello suo, dipinto sopra alla X che le sta accanto, e i sei punti del bersaglio della X che
   stanno sopra al collegamento aprivano la riga invece di toglierla (misurato il 26/09). */
.event-row-gone > .record-open > * { opacity: .62; }

/* LA RIGA PICCOLA IN TRE PEZZI, e nessuno cede con i puntini.

   Quanto manca e il tipo stanno in .event-row-bits, una riga sola alta quanto una riga: quanto
   manca non cede, e il tipo o ci sta intero o va a capo in una seconda riga che non si vede. Il
   punto che li separa lo scrive il foglio di stile sul tipo, quindi se ne va con lui: prima il tipo
   cedeva con i puntini fino a sparire, e restava «FRA 38 GIORNI ·», con il punto che pendeva
   (verifiche del 26/09).

   In coda, allineato a destra, .event-row-end: «Modifica» sulle date che arrivano, il tempo o
   «senza tempo» su quelle finite. Stava in una colonna sua accanto alla X, e a 360 punti al nome
   restavano 102 punti - «Hyrox Mila…», «Mezz…». Nella riga piccola non si prende niente dal nome,
   e la colonna di destra e' la sola X, larga uguale su ogni riga. */
.event-row .record-sub { display: flex; align-items: baseline; gap: .8em; }
.event-row-bits {
  flex: 0 1 auto;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  column-gap: .35em;
  height: 1.4em;
  overflow: hidden;
}
.event-row-away,
.event-row-kind { flex: none; }
.event-row-kind::before { content: "\00b7\00a0"; }
.event-row-end { flex: none; margin-left: auto; }
/* «Modifica» nell'accento del testo perche' e' un comando e non uno stato; «senza tempo» resta
   grigio, come nello storico; il tempo scritto nel colore del testo, perche' e' il dato.

   «MODIFICA» E' UNA TESSERA CON LA PENNA, accanto alla X (Luca, 27/09: «Ovunque c'è il modifica che vedi a
   fianco la X deve diventare una nuova tessera con sfondo come la x, icona modifica di colore accento […] lo
   spazio tra le tessere deve essere coerente uguale a quella che c'è nelle tessere sotto»). Solo CSS: la
   parola resta nel collegamento per chi legge con lo schermo, a corpo zero; la tessera e' quella delle icone
   (32 su un bersaglio da 44, ::before), la penna una maschera nell'accento da leggere (::after, 17 come le
   altre icone). Fuori dalla riga piccola, che e' alta una riga e taglia: sta nel collegamento, a destra,
   centrata sulla sua altezza, subito prima del bersaglio della X - come condividi, grafici e X della carta
   «Ultima sessione». Tutta la riga resta il collegamento che apre la correzione. */
.event-row-edit {
  color: var(--accent-text);
  position: absolute;
  top: 50%;
  right: 14px;
  width: 44px;
  height: 44px;
  margin: -22px 0 0;
  font-size: 0;
}
.event-row-edit::before,
.memory-row-edit::before {
  content: "";
  position: absolute;
  inset: 0;
  width: 32px;
  height: 32px;
  margin: auto;
  border-radius: 10px;
  --solid: var(--surface-2);
  background: var(--button-face);
  box-shadow: var(--button-bevel), var(--sign-edge), var(--shadow-tile);
}
.event-row-edit::after,
.memory-row-edit::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 17px;
  height: 17px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 13v5.6a2 2 0 0 1-2 2H5.4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2H11'/%3E%3Cpath d='M18.4 3.2 20.8 5.6 11.5 14.9 8.6 15.4 9.1 12.5Z'/%3E%3Cpath d='M9.1 12.5 11.5 14.9'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.9' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 13v5.6a2 2 0 0 1-2 2H5.4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2H11'/%3E%3Cpath d='M18.4 3.2 20.8 5.6 11.5 14.9 8.6 15.4 9.1 12.5Z'/%3E%3Cpath d='M9.1 12.5 11.5 14.9'/%3E%3C/svg%3E") center / contain no-repeat;
}
.event-row-time { color: var(--ink); font-weight: 700; }
/* SULLO STORICO DELLE GARE il tipo viene per primo e sempre (*"tag sopra gara o test in piccolo"*: li'
   si mescolano), e quanto e' passato dopo: il punto passa su quel pezzo, che e' quello che cede per
   primo - la casella dice gia' la data. Senza, la riga diceva «· GARA», con il punto davanti a niente
   (critica al piano, R6). */
.race-row .event-row-kind::before { content: none; }
.race-row .event-row-away::before { content: "\00b7\00a0"; }

/* Oggi: la casella del giorno nell'accento, il segno che la data e' arrivata. */
.event-row-today .record-ico-day {
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent-line);
  color: var(--accent-text);
}
.event-row-today .record-ico-day > span { color: inherit; }

/* LA X: il disegno e' quello di sempre, il segno da 20 punti; il bersaglio e' 44 per 44. Il margine
   negativo tiene l'ingombro nella riga a 32 per 30, e il bottone - che non ha fondo ne' bordo, e' un
   segno - prende il dito su un quadrato piu' largo. Era 34 per 30, sotto la misura di un dito
   (verifiche del 26/09). L'ingombro stretto e' quello che lascia «35 GIORNI FA» e «SENZA TEMPO» sulla
   stessa riga piccola a 360 punti: misurati, 184 punti su 186. */
/* Senza il margine a destra che aveva (4 punti): la X di una data sta nella stessa colonna di quella della
   carta «Ultima sessione» sotto - «Le x devono essere allineate verticalmente nella home» (Luca, 27/09). */
.event-row > .record-erase,
.agenda-row > .record-erase { align-self: stretch; padding-right: 0; }
.record-tile.event-row .orb-x,
.record-tile.agenda-row > .record-erase .orb-x {
  width: 44px;
  height: 44px;
  min-width: 44px;
  min-height: 44px;
  flex: 0 0 44px;
  margin: -7px -6px;
}
/* LA X DENTRO AL BORDO, IN LINEA CON QUELLA DELLA CARTA «ULTIMA SESSIONE» (Luca, 27/09: «la x che vedi
   sottolineata deve essere in linea con la x del blocco sotto»): lo stesso spostamento di otto punti
   verso l'interno, con translate, che non cambia l'impaginazione. */
.record-tile.event-row .orb-x,
.record-tile.agenda-row > .record-erase .orb-x { translate: -8px 0; }

/* A destra nelle righe di «Oggi»: lo stato, «Da fare» su tutte e due. Piu' piccolo dello stato delle
   altre righe e senza la sua larghezza minima da 62, perche' a 360 punti quella misura si prendeva
   il nome del check-up; UN MINIMO pero' ce l'ha, quanto la parola, cosi' i bordi destri cadono
   nello stesso punto, e non va a capo. */
.home-today .record-state {
  min-width: 44px;
  font-size: 10px;
  letter-spacing: .4px;
}

/* ---------- le date segnate dietro la prima ----------

   "+ altre X in caso ci siano piu' eventi o gare programmati; cliccando il + apre tutti gli eventi
   fissati uno sopra l'altro con lo stesso formato di quello in homepage."

   Sotto la striscia della settimana, dove stava il promemoria della prossima data ("elimina il
   commento sotto al calendario e sostituiscilo col reminder del prossimo evento salvato"). La
   tendina e' la stessa dei contatori della settimana - stesso elemento, stesse classi, stesso
   segno - quindi qui non si ridisegna niente: si dice solo dove sta. In un <li> suo nell'elenco,
   allineata al bordo delle righe, e nell'accento del testo. */
.week-dates > .record-list { margin-top: 14px; }
.week-dates-more { margin-top: 10px; }
.week-more-events > summary { color: var(--accent-text); }
.week-more-events > summary:hover { color: var(--accent-text); opacity: .8; }
.week-more-events > .record-list { margin-top: 8px; }

/* ---------- the sync line at the foot of the dashboard ----------

   What is left of a card that used to be a whole screen: last sync, "sync now", "disconnect",
   "configure in Strava". Connecting an account is a setup task done once and then forgotten, and it
   was taking a screen of the page an athlete opens to find out what to do today. It lives on
   /connections now; this is a line that says whether it is on and gets you there. */
.sync-line {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 0 14px;
  border-radius: 999px;
  border: 1px solid var(--line-soft);
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut);
  text-decoration: none;
}
.sync-line:hover { border-color: var(--accent-line); color: var(--accent-text); text-decoration: none; }
.sync-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.sync-on { background: var(--accent); box-shadow: 0 0 8px var(--accent); }
.sync-off { background: var(--line); }
.sync-go { margin-left: auto; font-size: 17px; color: var(--accent-text); }


/*
  ---------- gli spazi che nessuno aveva dichiarato ----------

  Segnalato: "alcuni elementi, per esempio gli espandi, sono troppo attaccati con gli altri".
  Misurato su dodici pagine, e non erano casi isolati: un titolo di pagina attaccato al suo
  sottotitolo, un'intestazione di carta attaccata alla riga che la spiega, un campo attaccato al
  suo suggerimento, due righe di modulo a due pixel l'una dall'altra.

  La causa e' in cima a questo file: il reset azzera il margine di tutto. E' una buona regola -
  toglie di mezzo i margini di serie del browser, che si accavallano fra loro in modi che nessuno
  ricorda - ma ha un prezzo: da li' in poi OGNI spazio va dichiarato, e quello che nessuno ha
  dichiarato non e' "quello di default", e' zero. Su cento accostamenti se ne dimenticano dieci, e
  quei dieci sono elementi che si toccano.

  Quindi si dichiarano le relazioni invece dei casi. Sono poche e si ripetono su tutte le pagine:
  un titolo e cio' che lo segue, un'intestazione e la sua spiegazione, un campo e il suo
  suggerimento, un controllo e cio' che ha intorno.

  Scritte con :where(), che vale zero di specificita'. Cosi' queste regole battono solo il reset e
  perdono contro qualunque decisione presa altrove nel file: dove qualcuno ha gia' scelto uno
  spazio, quello resta. Riempiono i buchi, non ridiscutono niente.

  Quello che NON toccano sono gli accostamenti stretti fatti apposta - un'etichetta sopra il suo
  valore, il giorno sopra la data, i due numeri di una metrica. Li' la vicinanza e' l'informazione:
  dice che quelle due cose sono una cosa sola. Il difetto non e' "poco spazio", e' poco spazio fra
  cose che non stanno insieme.
*/

/*
  Le sezioni di una pagina sono tutte alla stessa distanza fra loro.

  Segnalato con uno screenshot che cerchiava due stacchi diversi nella stessa schermata. Erano 18
  pixel dappertutto tranne tre eccezioni, ognuna nata da una regola sua: la riga "Strava collegato"
  stava a 4, la nota sotto il piano alimentare a 12. Nessuna delle tre era una decisione: erano tre
  posti in cui qualcuno ha scritto un margine senza guardare quello accanto.

  Adesso il passo e' un token, dichiarato qui e applicato a ogni figlio della colonna. Chi ha una
  ragione per staccarsi di piu' lo dichiara e vince, perche' questa regola vale zero di
  specificita'; chi non ne ha una segue il passo.
*/
:root { --passo-sezione: 18px; }
:where(.app-shell > * + *) { margin-top: var(--passo-sezione); }

/* Un titolo di pagina e la riga che lo spiega. */
:where(.page-title + *) { margin-top: 10px; }

/* Un'intestazione di carta, o il suo occhiello, e quello che viene sotto. */
:where(.card-top + *, .card-head + *) { margin-top: 12px; }
:where(.card-eyebrow + *) { margin-top: 8px; }

/* Un titolo di sezione e l'elenco che apre. */
:where(.card h3 + ul, .card h3 + ol, .card h3 + .goal-list) { margin-top: 10px; }

/* Un campo e il suggerimento che lo segue. */
:where(input + .muted, select + .muted, textarea + .muted, .pick-row + .muted,
       .muted + .empty, .muted + div) { margin-top: 10px; }

/* Due righe di modulo di seguito. */
/*
  Lo stacco fra un campo e il successivo, e il difetto che ci stava dentro.

  "Devono essere allineati, attualmente le input non lo sono": nel modulo per programmare a mano,
  ORA partiva dodici pixel piu' in basso di GIORNO, e CHILOMETRI piu' in basso di DISCIPLINA. Quel
  modulo dal 26/09 e' il foglio «Nuova seduta», con i campi uno sotto l'altro; le righe restano nel
  modulo che corregge una seduta (la piega «Modifica»).

  Erano questi dodici pixel. La regola serve ai campi IMPILATI - scheda, appunto - e diceva
  ".planned-field + .planned-field", che pero' e' vero anche per due campi AFFIANCATI dentro a una
  .planned-row: il secondo di ogni coppia prendeva un margine sopra e scendeva rispetto al primo.
  Misurato in pagina prima e dopo: 26 pixel di schermo, cioe' esattamente i dodici del margine.

  "form >" e' quello che li distingue: i campi impilati sono figli diretti del modulo, quelli
  affiancati stanno dentro alla riga, e dentro alla riga la spaziatura la da' il gap.
*/
:where(.planned-row + .planned-row, .planned-row + .planned-field,
       form > .planned-field + .planned-field) { margin-top: 12px; }

/*
  Un controllo e cio' che ha intorno, che e' il caso da cui e' partita la segnalazione.

  Dodici pixel sopra e sotto: sotto quella soglia un pulsante non legge piu' come una cosa a se' -
  sembra l'ultima riga del paragrafo - e su un telefono un tocco che manca il bersaglio di due
  millimetri finisce sul testo invece che sul controllo.
*/
:where(.btn + p, .btn + .muted, button + p, button + .muted) { margin-top: 12px; }
:where(p + .btn, .muted + .btn, div + .btn) { margin-top: 12px; }
/* Sei, non quattro: il controllo e' gia' alto 44 pixel di suo - l'area minima da toccare con un
   pollice - quindi lo stacco sopra puo' essere piccolo senza che si attacchi a niente. Dodici
   sommati ai suoi quarantaquattro lo allontanavano piu' del dovuto dalla cosa che apre. */
:where(details.card-fold, details.advice-more, details.session-bars) { margin-top: 6px; }

/*
  Il binario dell'accento su tutto cio' che si apre.

  "Questo bordo mettilo in tutte le sezioni che si possono espandere." Era nato sulle pieghe degli
  obiettivi: la lista rientrata di 14 pixel con una riga verticale del colore del tema accanto. Dice
  una cosa sola e la dice bene - quello che stai leggendo appartiene alla sezione che hai appena
  aperto, non alla pagina. Su una pagina dove si aprono quattro sezioni una sotto l'altra e' la
  differenza tra un elenco e un elenco dentro qualcosa.

  Una regola sola per tutte le famiglie, non una per famiglia: sono venti punti dell'app e venti
  regole sono venti occasioni di divergere.

  Il rientro sta sul <details>, non sul contenuto, perche' il contenuto non ha una forma sola - la
  zona pericolosa del profilo ha cinque figli, la piega della scheda tre, l'accordion del cibo
  undici. Un bordo per figlio sarebbe un binario spezzato in cinque tronconi con i buchi dei margini
  in mezzo. Sul contenitore e' continuo qualunque cosa ci sia dentro.

  Il riepilogo torna dov'era con un margine negativo di 16 (14 di rientro piu' i 2 del bordo): chi
  apre e chiude non deve vedere il titolo che salta a destra. Cosi' l'unica cosa che si muove
  aprendo e' il contenuto, che e' l'unica cosa che c'e' da vedere.

  Fuori restano tre cose. Due per lo stesso motivo - non sono sezioni della pagina: il selettore del
  tema nella barra in alto e' una pastiglia che apre un pannello sospeso, e "espandi" del commento
  della dashboard non ha contenuto proprio, il testo lungo e' gia' in pagina e lei lo scopre.

  Le altre due sono le pieghe che SONO la carta, e la ragione e' la stessa: il contenitore c'e' gia'
  ed e' il bordo della carta. .card-fold che porta anche .card - "cosa alleni?" negli obiettivi,
  "aggiungi un esercizio" nel tracker - avrebbe il binario sul filo sinistro della carta e il titolo,
  tirato indietro di 16, fuori dalla carta. Il monitor nutrizionale e' il corpo intero della sua
  carta ed e' aperto di suo: il binario gli correrebbe accanto per tutta l'altezza, sempre, con
  dentro altre tre pieghe che il binario ce l'hanno per davvero. Viste in pagina prima di toglierle.
*/
details.card-fold:not(.card)[open],
details.session-bars[open],
details.explain[open],
details.planned-edit[open],
details.propose-card[open],
details.diet-alt[open],
details.session-when[open],
details.goal-fold[open],
details.meal-log[open],
details.proposal-move-by-hand[open] {
  padding-left: 14px;
  border-left: 2px solid var(--accent-line);
}
details.card-fold:not(.card)[open] > summary,
details.session-bars[open] > summary,
details.explain[open] > summary,
details.planned-edit[open] > summary,
details.propose-card[open] > summary,
details.diet-alt[open] > summary,
details.session-when[open] > summary,
details.goal-fold[open] > summary,
details.meal-log[open] > summary,
details.proposal-move-by-hand[open] > summary {
  /*
    Il titolo torna dov'era e il suo testo si incolonna con il contenuto.

    Il margine negativo riporta la scatola del titolo sul filo del binario - aprendo, una piega non
    deve far saltare a destra la riga che si e' appena toccata. I sedici di rientro dentro sono la
    seconda meta': senza, il testo finiva appoggiato al binario ("modifica troppo attaccato al bordo
    arancione"), e con questi cade esattamente nella colonna di cio' che ha aperto. Quindi il binario
    abbraccia titolo e contenuto, e i due si leggono incolonnati.

    Sui titoli allineati a destra - la maggior parte, che spingono l'etichetta verso il margine
    destro - non cambia niente: e' un rientro a sinistra su una riga che a sinistra non ha niente.
  */
  margin-left: -16px;
  padding-left: 16px;
}


/*
  La spunta che conferma di aggiungere in fondo a una scheda che ha gia' degli esercizi.

  Riga sola, casella e frase sulla stessa linea in cima al testo e non centrate: la frase va a capo
  due volte su un telefono, e una casella centrata su due righe di testo non si capisce a cosa
  appartenga. Un po' d'aria sopra la separa dalla domanda dei giorni, che e' un'altra domanda.
*/

/* Il collegamento all'informativa. Nella pagina dei propri dati parte dal filo del titolo; nel
   modulo di registrazione, quando segue la spunta, rientra quanto il testo della casella e si legge
   come parte di quella riga invece che come un capoverso nuovo. */
.consent-link { margin: -4px 0 14px; font-size: 14px; }
.checkbox-row + .consent-link { margin-left: 30px; }



/* ---------- weekly weight reminder ---------- */
.weight-reminder-intro { margin: 0 0 14px; line-height: 1.5; }
.weight-reminder-form fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }
.weight-reminder-days {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
}
.weight-reminder-day { position: relative; min-width: 0; cursor: pointer; }
.weight-reminder-day input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}
.weight-reminder-day span {
  display: grid;
  min-height: 44px;
  place-items: center;
  padding: 7px 5px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-2);
  color: var(--mut);
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: .7px;
  text-transform: uppercase;
  transition: transform 120ms ease, color 140ms ease, border-color 140ms ease,
              background-color 140ms ease, box-shadow 140ms ease;
}
.weight-reminder-day:active span { transform: scale(.94); }
.weight-reminder-day input:checked + span {
  border-color: var(--accent);
  color: var(--accent-text);
  background: var(--accent-soft);
  box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 16%, transparent);
}
.weight-reminder-day input:focus-visible + span {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.weight-reminder-hint { margin: 10px 0 12px; font-size: 12px; line-height: 1.45; }
.weight-reminder-form .btn { width: 100%; }
/* Gli avvisi della home non stanno dentro .setup-banners: la home li rende uno per uno in
   cima allo shell, quindi il gap del contenitore non li tocca. Uscivano attaccati fra loro e
   incollati all'anello sotto. Il margine sotto ciascuno fa le due cose in una volta - separa
   il secondo dal primo e stacca l'ultimo dal saluto - e vale per tutti e tre gli avvisi della
   home, non solo per quello del peso. */
.app-shell > .setup-banner { margin-bottom: 10px; }
/* A scanned weekly diet is seven closed visual blocks, never one uninterrupted meal stream. */
.diet-plan-day + .diet-plan-day { margin-top: 18px; }
.diet-plan-day-label {
  margin: 4px 0 2px;
  font-family: var(--cond);
  font-size: 14px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--accent-text);
}


/* ---------- editable imported eating plan ---------- */
.diet-replace-warning {
  margin: 14px 0;
  padding: 12px 14px;
  border: 1px solid color-mix(in srgb, var(--danger) 55%, var(--line));
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--danger) 9%, transparent);
  color: var(--ink-2);
  font-size: 13px;
  line-height: 1.5;
}
.diet-scan-privacy { margin-top: 6px; }
.diet-edit { margin-top: 4px; border-top: 1px dashed var(--line-soft); }
.diet-edit > summary {
  display: flex;
  align-items: center;
  gap: 7px;
  min-height: 44px;
  cursor: pointer;
  list-style: none;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--accent-text);
}
.diet-edit > summary::-webkit-details-marker { display: none; }
.diet-edit[open] > summary .session-detail-mark {
  transform: rotate(-135deg) translateY(3px);
}
.diet-edit-form {
  margin: 0 0 10px;
  padding: 12px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--surface-2) 78%, transparent);
}
.diet-edit-form label {
  margin: 0;
  font-family: var(--cond);
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut);
}
.diet-edit-form input[type="text"],
.diet-edit-form textarea {
  margin-top: 6px;
  padding: 11px 13px;
  font-family: var(--sans);
  /* Sedici come tutti gli altri campi: sotto, iOS ingrandisce la pagina appena lo si tocca, e qui
     era 14. Trovato dal test che cerca la stessa cosa in tutto il foglio, non a occhio. */
  font-size: 16px;
  letter-spacing: 0;
  text-transform: none;
}
.diet-edit-meal-name { display: block; margin-bottom: 12px !important; }
.diet-edit-dish {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(92px, 0.34fr);
  gap: 8px;
  padding: 10px 0;
  border-top: 1px solid var(--line-soft);
}
.diet-edit-save { width: 100%; margin-top: 12px; }


.diet-edit-alternative {
  display: block;
  margin-top: 12px !important;
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
}
.diet-edit-alternative textarea {
  min-height: 82px;
  resize: vertical;
}


/* ---------- Coach raised the load (progression) ----------
   La freccia accanto a un esercizio su cui il coach ha alzato il carico, and the confirm/keep prompt shown during the
   workout. The badge is inline with the exercise name; the plus rides small and high on the arm. */
/* Il nome dell'esercizio: "i titoli degli esercizi leggermente piu' grandi". E' la riga che si
   cerca scorrendo una seduta da sei carte - le altre righe sono numeri - quindi vale due punti in
   piu' degli altri titoli di carta.

   h3.session-exercise-name e non .session-exercise-name: `.card h3` e' classe+elemento, quindi
   batte una classe secca e i suoi 17px restavano. Stessa trappola gia' pagata due volte oggi. */
h3.session-exercise-name {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 20px;
  line-height: 1.2;
}

/*
  ---------- la carta di un esercizio si chiude ----------

  "Poi le varie card devono essere chiudibili." Una seduta da sei esercizi e' sei tabelle aperte:
  quella che si sta facendo e cinque da scorrere. Chiusa, la carta dice ancora il nome e i suoi
  segni, che e' quello che serve per ritrovarla.

  Il segno della piega e' .session-detail-mark, lo stesso di ogni altra piega di questa interfaccia:
  la freccina in accento che gira aprendosi. Qui pero' la regola che la fa girare e' scritta per
  .card-fold, che questa carta non e' - e' una carta intera, non un corpo ripiegato - quindi la
  rotazione va detta anche per lei.
*/
.session-exercise > summary {
  /* Griglia e non la fila di .card-top: il titolo e il segno della piega stanno sulla prima riga -
     il segno in fondo a destra - e i segni dell'esercizio vanno sotto, a tutta larghezza. In fila,
     "MODIFICATO RISPETTO AL PIANO" mandava a capo tutto quello che aveva dopo, segno compreso. */
  display: grid;
  /* Tre colonne: il disco con il numero (40, come la scheda in lettura), il nome, e il segno della
     piega. Il nome e' l'unico che si stringe - minmax(0, 1fr) e non 1fr, perche' 1fr non scende
     sotto la parola piu' lunga e "Distensioni sopra la testa con manubri" spingerebbe fuori carta
     tutto il resto: va a capo, e la carta non ha un foglio che lo mostri intero. */
  grid-template-columns: 40px minmax(0, 1fr) auto;
  align-items: center;
  gap: 6px 10px;
  list-style: none;
  cursor: pointer;
}
/* Due righe, e ognuno al suo posto:

     riga 1   il disco   il nome                          il segno della piega
     riga 2              i segni dell'esercizio

   Il segno della piega e' parallelo al nome - "i simboli espandi devono essere paralleli al nome
   esercizio" - e la riga del titolo non ha altro: il comando che toglie un esercizio aggiunto sta
   in fondo alla carta, sotto le sue serie, dove non divide un angolo con la piega.

   I segni dell'esercizio vanno sotto e a sinistra - "modificato rispetto al piano deve stare
   allineato a sinistra", "sotto il nome esercizio" - e .card-head-end li spingerebbe a destra con
   un margine automatico, che qui li lascerebbe appesi al bordo opposto del titolo.

   Posizionati a mano e non lasciati al riempimento automatico: il segno "modificato" c'e' solo
   quando serve, e con una cella che compare e sparisce l'automatico mette quello che resta dove
   capita. */
.session-exercise > summary > .session-exercise-n { grid-column: 1; grid-row: 1; align-self: center; }
.session-exercise > summary > h3 { grid-column: 2; grid-row: 1; }
.session-exercise > summary > .session-detail-mark {
  grid-column: 3;
  grid-row: 1;
  justify-self: end;
}
.session-exercise > summary > .session-source {
  grid-column: 2 / -1;
  grid-row: 2;
  justify-self: start;
  margin-left: 0;
}

/* ----------------------------------------------------------------------------
   IL COLORE DI UNA DISCIPLINA

   "Anche qui devi usare icone in base alla disciplina e devono essere colorate."

   Sei tinte fisse, una per disciplina, uguali su tutte le schermate: la corsa e' rosa dovunque
   compaia. Fisse per DISCIPLINA e non per posizione in un elenco - la legenda del volume assegna i
   suoi colori in ordine di comparsa, ed e' giusto li' dove servono a distinguere due barre fra
   loro, ma un colore che cambia a seconda di quante discipline hai allenato questa settimana non
   puo' essere l'identita' di una disciplina.

   IL COLORE E' IL TERZO STRATO. La sagoma dice quale disciplina e', la parola accanto la dice per
   esteso, e il colore viene dopo: nessuno deve riconoscere una corsa dal fatto che e' rosa. E'
   anche la condizione che rende accettabili sei tinte - a occhio distinguerle tutte e sei sotto
   daltonismo non si puo', e infatti sotto deuteranopia la bici e la camminata si avvicinano
   parecchio: misurato, non stimato.

   Due passi per tema: sul fondo scuro le tinte neon si leggono, sul chiaro no - e' lo stesso
   motivo per cui l'accento ha --accent-text.
   ---------------------------------------------------------------------------- */
:root {
  --sport-running: #ff5c8a;
  --sport-strength: #8b5cf6;
  --sport-cycling: #38bdf8;
  --sport-swimming: #10b981;
  --sport-hiking: #f59e0b;
  --sport-walking: #e879f9;
}
:root[data-theme="light"] {
  --sport-running: #d6336c;
  --sport-strength: #6d28d9;
  --sport-cycling: #0369a1;
  --sport-swimming: #047857;
  --sport-hiking: #b45309;
  --sport-walking: #a21caf;
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --sport-running: #d6336c;
    --sport-strength: #6d28d9;
    --sport-cycling: #0369a1;
    --sport-swimming: #047857;
    --sport-hiking: #b45309;
    --sport-walking: #a21caf;
  }
}
.sport-ink { display: inline-flex; align-items: center; color: var(--accent-text); }
.sport-ink .ico { display: block; }
/* ---------- la sagoma della disciplina, nel colore dell'accento ----------

   "Le icone delle discipline devono avere il colore dell'accento ovunque, TRANNE nel calendario
   mensile dove mantengono i loro colori distintivi per migliorare la lettura."

   E' la stessa regola che questa applicazione ha gia' scritto altrove, vista da vicino: il colore
   marca cio' su cui si puo' agire, e sei colori diversi in un elenco di allenamenti sono sei
   categorie che nessuno ha chiesto di distinguere - li' la disciplina e' gia' scritta accanto.

   Nel mese no: li' la sagoma e' sola dentro a una casella da quaranta pixel, senza una parola
   accanto, e sei caselle di seguito dello stesso colore non si leggono. Il colore e' l'unica cosa
   che le distingue, quindi li' resta. */
.agenda-month-sport[data-sport="running"] { color: var(--sport-running); }
.agenda-month-sport[data-sport="strength"] { color: var(--sport-strength); }
.agenda-month-sport[data-sport="cycling"] { color: var(--sport-cycling); }
.agenda-month-sport[data-sport="swimming"] { color: var(--sport-swimming); }
.agenda-month-sport[data-sport="hiking"] { color: var(--sport-hiking); }
.agenda-month-sport[data-sport="walking"] { color: var(--sport-walking); }

/* ----------------------------------------------------------------------------
   TREND CARICHI

   La miniatura nella riga del nome, la scritta che apre il foglio, e il foglio.

   Un colore solo - l'accento dell'atleta - perche' la serie e' una sola: una legenda serve a
   distinguere due linee, e qui il titolo dice gia' cosa si sta guardando. Il verde e il rosso
   dello scarto sono gli stessi che l'applicazione usa per "bene" e "attenzione" dappertutto.
   ---------------------------------------------------------------------------- */
/* NIENTE TREND SULLA RIGA DEL NOME. C'e' stata una miniatura, poi il solo scarto in cifre, e
   tutti e due mandavano a capo i titoli lunghi: "togli il numero di fianco ai titoli e lascia solo
   trend, apribile e chiudibile". Una riga di titolo dice il nome dell'esercizio e nient'altro;
   l'andamento sta dietro alla voce in fondo alla carta, in tutte e tre le schermate. */
/* La curva: due pixel, estremi e giunti arrotondati. La stessa su miniatura e grafico grande, cosi'
   il disegno piccolo e quello grande si riconoscono come la stessa cosa. */
.trend-line { stroke: var(--accent); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.trend-dot { fill: var(--panel); stroke: var(--accent); stroke-width: 2; }
.trend-dot.is-last { fill: var(--accent); }
.trend-delta {
  font-family: var(--cond);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--ok);
  white-space: nowrap;
}
.trend-delta.is-down { color: var(--warn); }

/* La voce che apre il foglio: parola a sinistra, freccia a destra, una riga sopra a staccarla
   dalle serie. Si legge come una voce di menu, che e' quello che fa.

   IL SELETTORE E' LUNGO DI PROPOSITO. Nel foglio c'e' una regola button[class] che da' a ogni
   bottone la faccia metallica, e vale 0-1-1: tanto quanto button.session-trend-entry. A parita'
   vince chi viene dopo, e quella viene mille righe dopo - quindi la riga usciva disegnata come una
   scatola invece che come una voce di menu. Un antenato in piu' porta il conto a 0-2-1 e chiude la
   questione. E' la trappola della specificita' gia' scritta in CLAUDE.md, vista dai bottoni.

   E sotto a ogni esercizio di «Cosa hai fatto», a seduta finita: la stessa voce (25/09). */
.session-exercise > button.session-trend-entry,
.recap-body > button.session-trend-entry {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 44px;
  margin: 16px 0 0;
  padding: 13px 2px 0;
  border: 0;
  border-top: 1px solid var(--line-soft);
  border-radius: 0;
  background: none;
  box-shadow: none;
  text-align: left;
}
.session-exercise > button.session-trend-entry .microlbl,
.recap-body > button.session-trend-entry .microlbl { margin: 0; }
/*
  Il segno dell'andamento accanto alla voce: verde se e' salito, rosso se e' sceso. Se e' fermo non
  c'e' segno - la riga parla solo quando ha qualcosa da dire.

  `display: block` sull'svg: un <svg> in linea si appoggia alla linea di base e il riquadro di riga
  tiene lo spazio per le pancine delle lettere che non ci sono, quindi un'icona da 15 vive in una
  scatola da 20 e il flex centra la scatola. E' la trappola gia' scritta in CLAUDE.md, e qui la
  riga e' alta 44: sbagliata si vede.

  Il colore sta sul contenitore e non sull'icona, perche' nessuna icona di questo progetto porta un
  colore addosso: ereditano `currentColor` e chi le ospita decide.
*/
.trend-badge { display: inline-flex; align-items: center; flex: 0 0 auto; }
.trend-badge .ico { display: block; width: 15px; height: 15px; }
.trend-badge.is-up { color: var(--ok); }
.trend-badge.is-down { color: var(--danger); }
.session-trend-go { margin-left: auto; font-size: 17px; line-height: 1; color: var(--accent-text); }
/* La stessa voce dentro alla carta del costruttore: li' la riga di separazione sopra c'e' gia',
   e il selettore e' lungo per lo stesso motivo dell'altra - button[class] pesa quanto una classe
   secca e viene dopo nel foglio. Un antenato e non un figlio diretto: il bottone sta dentro al
   corpo della carta, non appeso al <details>, e con ">" la regola non lo prendeva - la riga usciva
   larga quanto la parola invece che quanto la carta. */
.plan-builder-exercise button.plan-trend-entry {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 44px;
  margin: 14px 0 0;
  padding: 13px 2px 0;
  border: 0;
  border-top: 1px solid var(--line-soft);
  border-radius: 0;
  background: none;
  box-shadow: none;
  text-align: left;
}
.plan-builder-exercise button.plan-trend-entry .microlbl { margin: 0; }
/* La voce in fondo all'esercizio della scheda in lettura. Il selettore porta l'antenato e non solo
   la classe: button[class] da' a ogni bottone con una classe la faccia metallica e vale 0-1-1,
   tanto quanto button.plan-read-trend, e a parita' vince la regola che viene dopo - che e' quella,
   mille righe piu' in giu'. */
.plan-read-item button.plan-read-trend {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  /* 44 come la stessa voce nell'allenamento: era alta quanto la sua riga di testo. */
  min-height: 44px;
  margin: 12px 0 0;
  padding: 11px 0 0;
  border: 0;
  border-top: 1px solid var(--line-soft);
  border-radius: 0;
  background: none;
  box-shadow: none;
  text-align: left;
  cursor: pointer;
}
.plan-read-item button.plan-read-trend .microlbl { margin: 0; }

/* Il corpo del foglio prende i sedici pixel di lato che nel check-up ogni pezzo si mette da se':
   li' l'intestazione e la barra di avanzamento hanno la loro regola, e cio' che non ce l'ha resta
   appoggiato al bordo dello schermo - che e' come questo foglio e' uscito la prima volta. */
.trend-dialog .trend-head,
.trend-dialog .trend-chart,
.trend-dialog .trend-span,
.trend-dialog .trend-what,
.trend-dialog .trend-empty,
.trend-dialog .trend-rows { margin-left: 16px; margin-right: 16px; }
.trend-dialog .trend-chart { width: calc(100% - 32px); }
/* IL FOGLIO SENZA DATI HA COMUNQUE UN CORPO. Con dentro una riga sola, il <dialog> si stringeva
   all'altezza di quella riga: un nastro appoggiato al bordo del telefono, con la frase schiacciata
   contro il fondo e il titolo a filo - "quando non ci sono carichi si vede male". L'aria sotto non
   e' decorazione: e' cio' che lo fa leggere come un foglio invece che come un avviso di sistema. */
.trend-dialog .trend-empty {
  margin-top: 18px;
  margin-bottom: 28px;
  font-size: 14px;
  line-height: 1.55;
}

.trend-chart { display: block; width: 100%; height: auto; overflow: visible; margin-top: 6px; }
.trend-grid { stroke: var(--line-soft); stroke-width: 1; }
.trend-grid-label { font-family: var(--cond); font-size: 10px; letter-spacing: 1px; fill: var(--mut2); }
.trend-head { display: flex; align-items: baseline; gap: 10px; margin: 2px 0 10px; flex-wrap: wrap; }
.trend-now { font-size: 26px; font-weight: 800; letter-spacing: -.3px; }
.trend-since { font-size: 13px; color: var(--mut); }
.trend-span {
  display: flex;
  justify-content: space-between;
  margin: 8px 2px 0;
  font-family: var(--cond);
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut2);
}
.trend-what { margin: 16px 0 0; font-size: 13px; }
.trend-rows { list-style: none; margin: 10px 0 0; padding: 0; }
.trend-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 2px;
  border-top: 1px solid var(--line-soft);
  font-size: 14px;
}
.trend-row-when {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut);
}
.trend-row-kg { font-weight: 700; }
.trend-row-reps { color: var(--mut); font-size: 13px; }

/* Il comando che toglie un esercizio aggiunto: in fondo, sotto le sue serie, e discreto. E' il
   comando che si usa meno di tutti in questa schermata e l'unico che cancella qualcosa. */
.session-exercise-remove { margin-top: 14px; }
.session-exercise-remove form { margin: 0; }
.session-exercise-remove .btn { width: 100%; margin: 0; }

.session-exercise > summary::-webkit-details-marker { display: none; }
.session-exercise > summary::marker { content: ""; }
.session-exercise > summary:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 4px; }
.session-exercise[open] > summary .session-detail-mark {
  transform: rotate(-135deg) translateY(3px);
}
/* Chiusa, la carta non lascia l'aria che tiene sotto al titolo quando e' aperta. */
.session-exercise:not([open]) > summary { margin-bottom: 0; }
/* Il segno "sali di carico": una freccia disegnata, nell'accento dell'atleta. Era l'emoji del
   bicipite, che cambia faccia da un telefono all'altro e il colore se lo porta addosso. */
.coach-raise-badge {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  line-height: 1;
  color: var(--accent-text);
}
/* display: block sull'svg: in linea si siede sulla linea di base e la riga tiene sotto lo spazio
   per le pance delle lettere che non ci sono, quindi il segno risulta alto nella sua cella - e'
   la trappola scritta in CLAUDE.md. */
.coach-raise-badge .ico { display: block; width: 19px; height: 19px; }
.coach-raise-plus {
  font-size: 12px;
  font-weight: 800;
  color: var(--accent-text);
}
.coach-raise-ask {
  margin-top: 12px;
  padding: 12px 14px;
  border: 1px solid var(--accent-line);
  border-radius: var(--r-sm);
  background: var(--accent-soft);
}
.coach-raise-ask-text {
  margin: 0 0 10px;
  font-size: 14px;
  color: var(--ink);
}
.coach-raise-ask-buttons { display: flex; flex-wrap: wrap; gap: 8px; }
.coach-raise-ask-buttons form { flex: 1 1 auto; display: flex; }
.coach-raise-ask-buttons .btn { width: 100%; }
/* L'avviso sotto ai due bottoni: piccolo, perche' e' una condizione e non una seconda domanda -
   un secondo blocco di testo grande quanto il primo farebbe leggere meno tutti e due. Resta dentro
   al riquadro giallo, dove si decide se caricare: "ci deve essere un disclaimer che non ci
   prendiamo la responsabilita' se ti fai male aumentando di peso", e un avviso fuori dal momento
   della scelta e' un avviso che si legge dopo. */
.coach-raise-disclaimer {
  margin: 10px 0 0;
  color: var(--mut);
  font-size: 12px;
  line-height: 1.45;
}
/* Disegnato a 40, bersaglio a 44: uno pseudo-elemento trasparente prende tre punti sopra e sotto,
   senza cambiare il disegno (src/main/resources/CLAUDE.md, «ogni comando piccolo prende 44 punti»).
   Tre e non due: lo pseudo-elemento si misura dal bordo INTERNO, e il filo da 1 di un bottone
   secondario gliene toglieva uno per lato - «Togli per oggi», «Non carica le gambe», «Tieni il
   precedente» prendevano 42, il pieno accanto 44 (26/09, verifica browser D5). Il pieno, senza filo,
   ne prende 46. Solo il tracker lo usa: le gambe pesanti e il carico alzato dal coach. */
.btn-sm { padding: 9px 14px; font-size: 13px; min-height: 40px; position: relative; }
.btn-sm::after { content: ''; position: absolute; inset: -3px 0; }

/* ---------- inserimento manuale di un'attività ----------
   Un <details> sotto la striscia della settimana: chiuso è un comando discreto con un "+", aperto
   è il modulo. Nessun JavaScript per aprirlo, così funziona anche se lo script non arriva. */
/* ---------- i due comandi manuali, dentro la carta della settimana ----------

   "Questi due comandi inglobali dentro al box programma settimanale, in due mini box da una riga."

   Gli stessi due <details> di sempre, rimpiccioliti perche' adesso stanno DENTRO una sezione invece
   che accanto alle sezioni: a piena misura, in fondo a una carta, due riquadri come questi si
   leggono ancora come due carte annidate. Meno alti, testo piu' piccolo e il "+" piu' piccolo -
   quanto basta perche' si leggano come i comandi della carta che li contiene.

   Il corpo che si apre resta quello di prima: il modulo dentro non e' piu' stretto di un pixel, e
   non deve esserlo - quello che si rimpicciolisce e' la riga chiusa, non il modulo aperto. */
.next-commands { margin-top: 14px; display: flex; flex-direction: column; gap: 6px; }
.next-commands .manual-entry { margin-top: 0; }
/* E in minuscolo, dal 26/09 (mock 01): «Inserisci attività manualmente» e «Fissa una gara o un
   evento» sono frasi, e il maiuscolo condensato in questa applicazione e' per le etichette corte.
   Qui dentro e, dal taglio 5, sotto la testata dello storico allenamenti (.history-commands); dal
   taglio 8 anche sotto quella degli storici di gare, infortuni e record. */
.next-commands .manual-entry-open,
.history-commands .manual-entry-open {
  padding: 8px 12px;
  font-family: inherit;
  font-size: 14.5px;
  letter-spacing: 0;
  text-transform: none;
}
.next-commands .manual-entry-plus,
.history-commands .manual-entry-plus { width: 20px; height: 20px; font-size: 14px; }

.manual-entry {
  margin-top: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--field-soft);
}
.manual-entry-open {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  cursor: pointer;
  font-family: var(--cond);
  font-size: 14px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--accent-text);
  list-style: none;
}
/* Il triangolino nativo se ne va: il "+" dice già che cosa fa il comando. */
.manual-entry-open::-webkit-details-marker { display: none; }
.manual-entry-open::marker { content: ""; }
/* Il segno e basta, nel colore dell'accento: "sostituisci tutte le icone + e x di questo tipo con
   le icone pulite e color accento". Era un cerchio pieno di accento con dentro il glifo scuro - un
   bollo, che accanto a una parola pesa quanto la parola. Il disegno non cambia: le due barre sono
   gia' quelle, con i capi tondi. Cambia che non c'e' piu' niente dietro.

   Aperto ruota di 45 gradi ed e' una X - lo stesso segno che toglie, che e' anche quello che fa:
   chiude il riquadro che il + ha aperto. */
.manual-entry-plus {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  color: var(--accent-text);
  line-height: 1;
}
.manual-entry[open] .manual-entry-plus { transform: rotate(45deg); }
.manual-entry-body { padding: 0 14px 14px; }

.manual-entry-hint { margin: 0 0 12px; font-size: 13px; color: var(--mut); }
.manual-entry-form label,
.manual-field-label {
  display: block;
  margin-top: 12px;
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut);
}
.manual-entry-form select,
.manual-entry-form textarea,
.manual-entry-form input[type="text"],
.manual-entry-form input[type="date"],
.manual-entry-form input[type="number"] { width: 100%; margin-top: 4px; }
.manual-field[hidden] { display: none; }
/* Il promemoria che conta: una disciplina per volta. Riga laterale, come i messaggi del coach. */
.manual-entry-note {
  margin: 14px 0 0;
  padding: 10px 12px;
  border-left: 2px solid var(--accent);
  background: var(--field);
  border-radius: var(--r-sm);
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2);
}

/* ---------- le date segnate: una gara, un test, un rientro, un intervento ----------
   Stesso riquadro dell'inserimento manuale, subito sotto: i due fanno la stessa cosa - scrivere a
   mano qualcosa che nessun dispositivo ha registrato - e due comandi vicini che si comportano in
   modo diverso sono due comandi da imparare invece di uno. */
/* Dentro al foglio di una gara e' il secondo modulo, sotto al primo, a tutta larghezza e con un
   filo sopra che dice dove finisce il risultato e comincia la gara. Nella riga di una gara la piega
   va a capo sotto la riga, a tutta larghezza (.event-row, piu' su). */
.record-sheet-body > .event-edit,
.event-step > .event-more {
  justify-self: stretch;
  margin-top: 18px;
  border-top: 1px solid var(--line);
}
/* L'etichetta a sinistra e il segno a destra: `.card-fold` spinge tutto a destra, che e' giusto per
   una voce in un angolo di carta e sbagliato per il titolo di una sezione. Vale anche per «Altri
   dettagli» nel foglio delle date, che e' la stessa cosa: una sezione del foglio che si apre. */
.record-sheet-body > .event-edit > summary,
.event-step > .event-more > summary {
  justify-content: space-between;
  text-align: left;
}
.event-edit[open] { margin-top: 6px; }
.event-drop { margin-top: 6px; }
.event-drop .link-button { font-size: 12px; }

/* ---------- il programma di preparazione ----------

   "Deve generare un programma di 12 settimane, visionabili una ad una."

   Tutto quello che segue disegna una cosa sola: una settimana che si legge in tre secondi e si
   sfoglia con un dito. Le dodici righe di una settimana sono sette giorni piu' tre numeri, e l'unica
   decisione di disegno che conta e' quale dei tre sguardi arriva per primo - il pallino, che dice
   quanto costa la giornata. */

/* ---------- il foglio «Fissa una gara o un evento» ----------

   Un modulo a passi (fragments/athlete-events :: eventSheet): ogni passo e' un fieldset che si
   dispone come il modulo, in colonna. Senza script si vedono tutti, uno sotto l'altro, e la legenda
   di ogni passo e' il suo titolo; con lo script se ne vede uno, e la legenda la legge solo lo
   screen reader - il titolo del passo lo scrive la testata del foglio. */
.programme-setup,
.event-step { display: flex; flex-direction: column; gap: 6px; }
.programme-setup label { margin-top: 10px; }
.event-step { min-width: 0; margin: 0; padding: 0; border: 0; }
/* Lo stacco fra un passo e l'altro serve solo senza script, dove i passi stanno uno sotto l'altro.
   Con lo script se ne vede uno, ma il passo nascosto resta il fratello di quello che si vede: il
   margine valeva lo stesso, e i passi 2 e 3 cominciavano 22 punti piu' giu' del passo 1. */
@media (scripting: none) {
  .event-step + .event-step { margin-top: 22px; }
}
.programme-goals { border: 0; padding: 0; margin: 0; }

/* Il tipo, a pastiglie larghe un terzo di riga: cinque fanno tre piu' due, e le due arrivando da una
   gara (solo Gara e Test) fanno meta' riga ciascuna. Il margine a zero batte `.programme-setup
   label`, che e' piu' specifico di `.programme-pill` e le spingeva giu' di dieci punti. Il flex lo
   prende dal gruppo delle pastiglie, piu' sotto. */
.programme-kinds { border: 0; padding: 0; margin: 0; }
.programme-kinds .programme-pill { flex: 1 1 calc((100% - 16px) / 3); min-width: 0; margin: 0; padding: 9px 6px; }

/* ---------- la gara, in cima e in una scatola sua ----------

   "Giorno della gara deve essere prima informazione da inserire, ed evidenziala un po' di piu'
   altrimenti rischiamo che uno non la inserisca."

   Il campo aveva l'aspetto di tutti gli altri - un rettangolo in mezzo a una colonna di rettangoli -
   con dentro un valore gia' scritto, che e' proprio il caso in cui un campo non si tocca: si legge
   "13 dic 2026", sembra una risposta e si va avanti. Ed e' l'unico valore da cui esce tutto il
   resto: quante settimane ci sono, dove cade il taper, quanto si allunga la base.

   UN BORDO E UNA FACCIA, non un colore addosso al testo. Il rosa qui dentro vuol dire "scelto" - e'
   la pastiglia accesa, il bordo del giorno di oggi - e tingere l'etichetta di un campo vuoto direbbe
   che la risposta c'e' gia'. La scatola dice "questa parte conta", il campo resta un campo.

   Le etichette dentro tornano della misura delle legende degli altri riquadri: quello che cambia e'
   la cornice, non la voce. */
/* La scatola dell'accento, una volta sola: la data al passo 1 e il riepilogo al passo 3 sono la
   stessa cosa vista all'inizio e alla fine - quello da cui esce il programma. */
.programme-when,
.programme-recap {
  border: 1px solid var(--accent-line);
  border-radius: var(--r-sm);
  --solid: var(--accent-soft);
  background: var(--metal-face);
}
.programme-when {
  margin: 2px 0 6px;
  padding: 12px 14px 14px;
}
.programme-when > legend {
  /* La legenda di questo riquadro e' un titolo e non un'etichetta: e' la sola che nomini la scatola
     invece del campo sotto di se'.
     DENTRO LA SCATOLA, non sul bordo. Una <legend> il browser la disegna a cavallo del bordo del
     fieldset, e qui «LA DATA CHE FISSI» usciva mezza fuori, schiacciata contro l'aiuto di sopra: la
     prima cosa segnalata sulla schermata del 25/09. `float` la toglie da quel posto speciale e la
     mette nel flusso, come un titolo dentro la carta; le etichette sotto ripartono a capo. */
  float: left;
  width: 100%;
  margin: 0 0 10px;
}
/* Il colore del titolo, con un antenato in più: `.programme-setup legend`, più in basso nel foglio,
   dà a ogni legenda del modulo il grigio delle etichette, e con lo stesso peso vinceva lui - il titolo
   della scatola era grigio come «IL GIORNO» sotto, e si leggeva come un'etichetta in più. */
.programme-setup .programme-when > legend { color: var(--accent-text); }
.programme-when > legend + * { clear: left; }
.programme-when label { margin-top: 12px; }
.programme-when > label:first-of-type { margin-top: 6px; }
.programme-when input { width: 100%; }
.programme-when .programme-help { margin-top: 8px; }
/* La riga di aiuto sotto un campo.

   MINUSCOLA, e non e' una svista: le etichette di questo foglio sono maiuscole condensate e su una
   frase intera diventano un'insegna - "I CHILOMETRI DELLA TUA SETTIMANA PIU' ALTA, DI RECENTE" andava
   a capo due volte e si leggeva una lettera per volta. L'etichetta dice COSA, corta e maiuscola; la
   riga qui sotto dice PERCHE', in una frase normale che si legge come una frase. */
.programme-help {
  margin: -2px 0 2px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--mut);
}

/* I due campi del passo, con i due punti disegnati in mezzo: il tastierino del telefono non li ha,
   ed e' il motivo per cui il campo unico non si poteva compilare. */
.programme-pace {
  display: flex;
  align-items: center;
  gap: 8px;
}
.programme-pace input { width: 82px; text-align: center; }
.programme-pace-sep {
  font-size: 19px;
  font-weight: 700;
  color: var(--mut);
}

/* Le quattro pastiglie dei giorni. Un tocco invece di una tastiera che copre meta' schermo per
   scegliere fra quattro valori. */
.programme-days-choice { border: 0; padding: 0; margin: 0; }

.programme-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  margin: 8px 8px 0 0;
  min-width: 56px;
  min-height: 44px;
  padding: 9px 14px;
  box-sizing: border-box;
  --solid: var(--field);
  background: var(--plain-face);
  border: 1px solid var(--line-soft);
  border-radius: 999px;
  /* Il fianco da due (27/09, Luca: "pastiglie con bordo 2px"): piatte dal 25/09, adesso tessere basse,
     con il filo di luce in alto a sinistra e l'ombra corta in basso a destra. Il fianco dei riquadri e
     non quello dei segni (--sign-edge): la faccia e' piatta, e il fianco parte sotto al suo punto piu'
     scuro. Due punti sotto e a destra, dentro al gap di otto delle file: il bersaglio non cambia. */
  box-shadow: var(--edge-lit), var(--lift-edge), var(--shadow-tile);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
/* I numeri stanno più stretti delle parole: sei pastiglie da 56 andavano a capo e lasciavano il 7
   da solo sulla riga sotto, che su una scala da 2 a 7 fa sembrare il 7 un'altra domanda. Un numero
   non ha bisogno della larghezza di "mezza maratona". */
.programme-days-choice .programme-pill {
  min-width: 44px;
  padding: 9px 7px;
}

/* I TRE GRUPPI DI PASTIGLIE SONO CONTENITORI FLEX, e il margine destro sparisce.

   Erano inline-flex con un margine: a capo fra un'etichetta e l'altra il browser ci mette uno
   spazio bianco vero, largo quattro pixel, e sei pastiglie ne accumulano venti - quanto basta a far
   traboccare il 7 sulla riga sotto pur avendo lo spazio per stare in fila. Con gap lo spazio lo
   decide il foglio e non l'indentazione del template.

   La legenda tiene la riga tutta per se': in un fieldset flex Chromium la tira fuori dal flusso, ma
   dichiararlo e' cio' che la tiene sopra anche dove non lo fa. */
.programme-goals,
.programme-kinds,
.programme-days-choice,
.programme-start {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
/* Le tre legende erano tre blocchi identici copiati. Quando la domanda dei giorni e' cambiata ne ho
   riscritta una e le altre due sono rimaste indietro - visibilmente, in uno screenshot. Una regola
   sola, che e' la ragione per cui qui un duplicato e' un difetto e non una ripetizione.

   IL SELETTORE E' `.programme-setup legend` e non l'elenco dei tre fieldset, che era la prima
   stesura: ne ho aggiunto un quarto - i giorni in cui non si puo' - e si e' disegnato in minuscolo
   in mezzo agli altri tre, visibilmente, in uno screenshot. Un elenco di selettori e' un elenco da
   aggiornare; "le legende di questo modulo" e' una regola.

   Dal 25/09 ci sono anche le legende dei tre passi del foglio e quella del tipo: sono legende di
   questo modulo, e prendono la stessa voce senza un selettore in piu'.

   MAIUSCOLE, e la domanda ci sta perche' e' corta: "quanti allenamenti a settimana?" al posto di
   "quanti giorni alla settimana vuoi allenarti?", che andava a capo. La versione lunga aveva fatto
   pensare di cambiare la voce di tutto il modulo; accorciare la domanda risolve la stessa cosa senza
   toccare niente, ed e' l'atleta ad averlo visto. Quando una riga non ci sta, la prima cosa da
   provare e' scriverla piu' corta. */
.programme-setup legend {
  width: 100%;
  padding: 0;
  font-family: var(--cond);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut);
}
.programme-goal,
.programme-pill { margin: 0; }
.programme-pill:has(input:checked) {
  border-color: var(--accent-line);
  color: var(--accent-text);
}
/* Il pallino del radio sparisce: la pastiglia accesa E' la risposta, e un pallino accanto a una
   pastiglia gia' evidenziata dice la stessa cosa due volte. Resta raggiungibile da tastiera. */
.programme-pill input,
.programme-goal input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.programme-pill:focus-within,
.programme-goal:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }

.programme-goals legend {
  padding: 0;
  font-family: var(--cond);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut);
}
/* Le tre gare in fila, a pastiglia. Si toccano con il pollice e si leggono senza aprire niente: sono
   tre, e un menu a tendina per tre voci nasconde due terzi della domanda. */
.programme-goal {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin: 8px 8px 0 0;
  padding: 9px 14px;
  min-height: 44px;
  box-sizing: border-box;
  --solid: var(--field);
  background: var(--plain-face);
  border: 1px solid var(--line-soft);
  border-radius: 999px;
  /* Il fianco da due delle pastiglie di scelta (27/09), come .programme-pill. */
  box-shadow: var(--edge-lit), var(--lift-edge), var(--shadow-tile);
  cursor: pointer;
}
.programme-goal:has(input:checked) {
  border-color: var(--accent-line);
  color: var(--accent-text);
}

/* ---------- la testa, e la striscia delle dodici ---------- */
.programme-race {
  margin: 0 0 12px;
  font-family: var(--cond);
  font-size: 13px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--mut);
}
/* Dodici numeri, ognuno un indirizzo. Scorre in orizzontale invece di andare a capo: dodici
   pastiglie su due righe sembrano un calendario e non una barra di avanzamento, e quello che deve
   dire e' "sei qui, dentro una cosa lunga". */
.programme-strip {
  display: flex;
  gap: 6px;
  list-style: none;
  margin: 0;
  padding: 2px 0 6px;
  overflow-x: auto;
  scrollbar-width: none;
}
.programme-strip::-webkit-scrollbar { display: none; }
.programme-chip {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: 0 0 auto;
  --solid: var(--field);
  background: var(--plain-face);
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  /* Il fianco da due delle pastiglie di scelta (27/09, "pastiglie con bordo 2px"): era il filo e
     un'ombra sotto, senza spessore. La striscia ha sei punti sotto e sei fra una e l'altra, quindi il
     fianco non tocca la vicina e non lo taglia lo scorrimento. */
  box-shadow: var(--edge-lit), var(--lift-edge), var(--shadow-tile);
  font-family: var(--cond);
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
  text-decoration: none;
}
.programme-chip:hover { text-decoration: none; border-color: var(--accent-line); }
/* Quella che si sta guardando, accesa. Come la pastiglia della settimana corrente sulla striscia in
   home: una forma piena si riconosce prima di leggerla. */
.programme-chip-on {
  --solid: var(--accent);
  /* Senza la luce del metallo (27/09, --plain-face): su una pastiglia di 34 la luce e lo spegnimento
     coprono tutta la faccia, e con l'inchiostro scuro sull'accento la cifra scendeva da 4,9 a 4,1 a 1
     (rosa); nel chiaro con mono la luce bianca sul pieno nero la portava da 11,7 a 3,2. */
  background: var(--plain-face);
  color: var(--on-accent);
  border-color: transparent;
}
/* Lo scarico si riconosce senza aprirlo: e' l'unica settimana che si guarda per sapere se si puo'
   respirare. Contorno e non riempimento, che e' la stessa grammatica dei giorni qui sotto. */
.programme-chip[data-phase="deload"] { border-color: var(--accent-2); color: var(--accent-2); }
.programme-chip-on[data-phase="deload"] { color: var(--on-accent); }

/* ---------- i numeri della settimana ---------- */
.programme-numbers {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin: 0 0 14px;
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--mut);
  font-variant-numeric: tabular-nums;
}
/* I chilometri sono il numero che il maratoneta guarda per primo - "l'ansia numero uno e'
   infortunarsi per sovraccarico" - quindi sono l'unico dei tre a essere piu' grande e piu' acceso. */
.programme-total { font-size: 15px; font-weight: 700; color: var(--ink); }

/* ---------- i sette giorni ---------- */
.programme-days { list-style: none; margin: 0; padding: 0; }
/* Quattro colonne su una riga sola: pallino, giorno, cosa, numeri. I numeri a destra e in cifre
   tabulari, cosi' sette righe di seguito si leggono come una colonna invece che come sette frasi. */
.programme-day {
  display: grid;
  grid-template-columns: 10px 62px 1fr;
  align-items: baseline;
  gap: 4px 10px;
  padding: 11px 0;
  border-bottom: 1px solid var(--line-soft);
}
.programme-day:last-child { border-bottom: 0; }
.programme-day::before {
  content: "";
  width: 9px;
  height: 9px;
  border-radius: 999px;
  align-self: center;
}
.programme-weekday {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--mut);
}
.programme-what { font-size: 14.5px; font-weight: 600; }
/* I numeri vanno sotto il nome della seduta e non accanto: "6x1000 m @ 4:15 - rec 90" su un telefono
   da 390 non ci sta accanto a "Ripetute", e mandarlo a capo a meta' spezza un dato in due. */
.programme-detail {
  grid-column: 3;
  font-size: 13px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

/* I DUE COLORI DEL SISTEMA, E NIENTE ALTRO.

   "Usa il magenta e l'azzurro del vostro design system per taggare i giorni: un pallino magenta
   pieno per i lavori di intensita', un contorno azzurro per lo scarico o la Zona 2."

   Pieno vuol dire che costa, vuoto che non costa. E' una grammatica di due segni, e si impara
   guardandola una volta - sette colori sarebbero una legenda, e nessuno impara una legenda per
   guardare una settimana. */
.programme-hard::before { background: var(--accent); }
.programme-moderate::before {
  background: color-mix(in srgb, var(--accent) 45%, transparent);
}
.programme-easy::before {
  background: transparent;
  box-shadow: inset 0 0 0 2px var(--accent-2);
}
.programme-rest::before { background: var(--line); }
.programme-rest .programme-what { font-weight: 500; color: var(--mut); }

/* ---------- sfogliare ----------

   "Precedente e successiva sempre attaccate e in colore accento. Questa settimana sotto, centrato,
   in colore neutro."

   DUE COLONNE UGUALI E MAI UNA SOLA. Erano tre bottoni in un flex che andava a capo: alla settimana
   1 sparivano "precedente" e "questa settimana", gli altri risalivano, e il bersaglio da premere
   cambiava posto sotto il dito a ogni tocco. Su un carosello che si sfoglia venti volte di fila e'
   il difetto peggiore disponibile. Con una griglia da due colonne i due passi stanno dove stanno,
   e quello che non porta da nessuna parte resta li' spento.

   ACCESI TUTTI E DUE, perche' sono il gesto principale della pagina: si arriva qui per guardare le
   dodici settimane una a una, e guardarle vuol dire premere queste due. "Questa settimana" e'
   un'altra cosa - non avanza di uno, salta - e sta sotto in grigio per non contendere il colpo
   d'occhio a un comando che si preme di continuo. */
.programme-nav {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 18px;
}
.programme-steps {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.programme-step {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 10px 12px;
  box-sizing: border-box;
  --solid: var(--field);
  /* Piatti, e senza la luce del metallo (27/09, --plain-face): "presente e successiva piatti" (Luca),
     e su una pastiglia alta 44 la fascia di luce cade sotto la scritta - «Successiva ›» nel rosa
     scendeva da 4,2 a 4,0 a 1. */
  background: var(--plain-face);
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  box-shadow: var(--edge-lit), 0 4px 10px -7px rgba(0, 0, 0, .45);
  font-family: var(--cond);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--accent-text);
  text-decoration: none;
}
.programme-step:hover { text-decoration: none; }
/* Il capo della corsa. Spento e senza href: non si preme, non si raggiunge con la tastiera, e resta
   al suo posto - toglierlo farebbe saltare l'altro da una parte all'altra. */
.programme-step.is-off {
  border-color: var(--line-soft);
  color: var(--mut2);
  box-shadow: none;
  cursor: default;
}
.programme-today {
  align-self: center;
  padding: 8px 14px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  font-family: var(--cond);
  font-size: 12.5px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--mut);
}
.programme-today:hover { color: var(--ink-2); text-decoration: none; }

/* ---------- il feedback ---------- */
.programme-feedback-form { display: flex; flex-direction: column; gap: 8px; }
/* Le quattro correzioni in fila, e vanno a capo da sole su uno schermo stretto. Sono bottoni veri e
   non caselle: ognuno spedisce, e il programma e' riscritto prima che il dito si sia alzato. */
.programme-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 6px;
}
/* I giorni in cui non si puo': sette pastiglie dentro al modulo, non piu' un <details> dopo il
   programma. Strette come i numeri - "LUN" non ha bisogno della larghezza di "mezza maratona" - cosi'
   ci stanno in due righe invece di tre. */
/* Quattro e tre invece di sei e uno. Sette pastiglie non ci stanno su una riga da 390 in nessun modo,
   quindi vanno a capo comunque: sei piu' una sembra un difetto, quattro piu' tre sembra una scelta.
   Una griglia invece del ritorno a capo automatico e' cio' che rende la seconda riga deliberata.

   Un blocco solo: erano due - il bordo e i margini in uno, la griglia nell'altro - e
   StylesheetClashTest li ha presi, perche' due regole per la stessa classe vogliono dire che la
   seconda vince in silenzio e la prima si legge come se contasse. */
.programme-days-off {
  border: 0;
  padding: 0;
  margin: 4px 0 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}
.programme-days-off .programme-pill { min-width: 0; padding: 9px 4px; }

.programme-close { margin-top: 4px; }

/* Le stazioni della corsa compromessa: una pastiglia per frazione, nell'ordine di gara.

   IN FILA E NON IN UNA FRASE. "6×1000 m @ 4:40 · rec 60″ — ski erg, sled push, sled pull, burpees"
   e' una riga che su un telefono va a capo tre volte e che nessuno legge fino in fondo. In pastiglie
   si contano a colpo d'occhio, ed e' il numero che conta: quante frazioni, quindi quanto e' lunga la
   seduta e a che punto della gara arriva. */
.programme-stations {
  grid-column: 3;
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
}
.programme-stations li {
  padding: 3px 9px;
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  font-family: var(--cond);
  font-size: 11px;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--accent-text);
}

/* La scelta fra riscrivere la settimana in corso e cominciare lunedi'. Le stesse pastiglie delle
   altre due domande del modulo: erano due righe impilate con dentro due frasi intere, e la seconda
   andava a capo su un telefono. "Riscrivila o parti da lunedi'" - la domanda sta nella legenda, le
   risposte dicono solo cio' che le distingue.

   La legenda e' dell'accento e le altre due no: e' l'unica delle tre che compare a sorpresa, solo
   quando c'e' davvero qualcosa in calendario da perdere, e va letta invece che saltata. */
.programme-start { border: 0; padding: 0; margin: 4px 0 0; }
/* L'unica accesa delle tre: e' la sola domanda che compare a sorpresa, solo quando c'e' davvero
   qualcosa in calendario da perdere, e va letta invece che saltata. */
.programme-start legend { color: var(--accent-text); }

/* Il promemoria sotto i sette giorni: si spostano, ma altrove.

   Piu' stretto del margine di un .alert normale - sta fra una lista e i comandi per sfogliare, non
   fra due sezioni - e in condensato come tutto cio' che in questa pagina non e' una frase da
   leggere due volte. Il colore lo porta gia' .alert-notice, che e' il motivo per cui questa regola
   non lo nomina: un secondo posto in cui scrivere l'accento e' un secondo posto da cambiare. */
.programme-movable {
  margin: 14px 0 0;
  padding: 10px 14px;
  font-size: 13.5px;
  line-height: 1.5;
}

/* ---------- il cassetto, in gruppi ----------

   "Voci singole in colore accento con triangolino a punta in basso per far capire che si estendono."

   LE VOCI DI PRIMO LIVELLO SONO TUTTE DELL'ACCENTO, quelle che si aprono e quelle che portano
   dritte da qualche parte: sono lo stesso livello di lettura, e distinguerle col colore direbbe che
   una delle due conta di piu'. A dire quali si aprono ci pensa il triangolino, che e' l'unica
   differenza vera fra le due.

   Il triangolino e' disegnato e non quello del sistema: il marcatore predefinito di <summary> cambia
   forma da un browser all'altro, e in un cassetto scuro su iOS e' un triangolino nero su nero. */
/* Scritte tutte con .menu-panel davanti, e non e' zelo: la regola condivisa delle voci -
   ".menu-panel a, .menu-logout, .menu-panel .menu-group > summary" - vale tre classi, e senza il
   prefisso queste perdevano il confronto. Il triangolino usciva come una barretta verticale, perche'
   il display: flex non arrivava, e le intestazioni dei gruppi restavano grigie. */
.menu-panel .menu-top { color: var(--accent-text); }

.menu-panel .menu-group > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  cursor: pointer;
  list-style: none;
}
.menu-panel .menu-group > summary.menu-top { color: var(--accent-text); }
.menu-group > summary::-webkit-details-marker { display: none; }
.menu-group > summary::after {
  content: "";
  width: 7px;
  height: 7px;
  flex: 0 0 auto;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  margin-bottom: 3px;
  opacity: .7;
}
.menu-group[open] > summary::after { transform: rotate(-135deg); margin-bottom: -3px; }

/* <details> non distanzia i figli con gap - stanno in una scatola anonima - quindi il rientro e lo
   spazio stanno sui figli. E' costato una volta, sul modulo dei giorni. */
.menu-group > a,
.menu-group > .menu-group > summary { padding-left: 18px; }

/*
  ---------- l'albero: il filo che lega una sottovoce alla voce che la apre ----------

  FILO E PALLINI DELLO STESSO COLORE, e discreto. La prima stesura accendeva i pallini di un grigio
  piu' chiaro della barra, con la logica che un cerchio da tre pixel al nove per cento di bianco si
  vede meno di una barra da due - vero in astratto, e sbagliato qui: "i puntini stesso colore delle
  righe, cosi' sono troppo ingombranti visivamente, distraggono e sporcano la UI". Una fila di
  pallini piu' accesi del filo diventa un secondo elenco accanto all'elenco.

  L'albero e' una cosa che si vede senza guardarla: deve dire "queste voci stanno sotto quella" a chi
  scorre, non chiedere attenzione a chi legge. --line fa da se' i due temi - un bianco tenue sul
  fondo scuro, un grigio chiaro su quello chiaro - che e' esattamente come e' stato chiesto.

  "Crea qualcosa del genere che colleghi chiaramente le varie sottovoci con le voci che le aprono",
  con il disegno accanto: un filo che scende dall'intestazione e un pallino su ogni voce.

  IL RIENTRO DA SOLO NON BASTA. Diciotto pixel dicono "piu' dentro" a chi sa gia' che c'e' un dentro;
  aperti due gruppi di fila, una voce rientrata e la successiva intestazione stanno a sei pixel l'una
  dall'altra e l'occhio le legge come una lista sola. Il filo e' la stessa informazione detta da una
  cosa che si vede senza leggere.

  UN SOLO PSEUDO-ELEMENTO, DUE GRADIENTI. Il triangolino dei gruppi occupa gia' ::after, quindi filo
  e pallino stanno insieme nel ::before: una barra verticale al centro della colonna e un cerchio a
  meta' altezza. E' lo stesso modo in cui e' disegnata la catena delle attivita' fatte nella striscia
  della home - un fondo a piu' strati, non due scatole.

  L'ULTIMA VOCE CHIUDE IL RAMO: la sua barra e' alta la meta' e finisce nel suo pallino, invece di
  proseguire nel vuoto sotto. Si ottiene accorciando lo strato della barra, non l'elemento, cosi' il
  pallino resta dov'e'.
*/
.menu-group[open] > a,
.menu-group[open] > .menu-group > summary { position: relative; }
.menu-group[open] > a::before,
.menu-group[open] > .menu-group > summary::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 0;
  bottom: 0;
  width: 12px;
  background:
    radial-gradient(circle at 50% 50%, var(--line) 3px, transparent 3.5px) no-repeat,
    linear-gradient(var(--line), var(--line)) 50% 0 / 2px 100% no-repeat;
}
.menu-group[open] > a:last-child::before {
  background:
    radial-gradient(circle at 50% 50%, var(--line) 3px, transparent 3.5px) no-repeat,
    linear-gradient(var(--line), var(--line)) 50% 0 / 2px 50% no-repeat;
}
/* Il ramo dentro il ramo: stesso filo, spostato quanto il suo rientro. */
.menu-group-inner[open] > a::before { left: 19px; }
/* E il pallino della pagina in cui si e': acceso, e da solo. E' il terzo dei tre segni che dicono
   "sei qui" - fondo, filo sul fianco, pallino - e l'unico che sta sull'albero, quindi e' anche
   quello che dice DOVE si e' dentro l'albero. */
.menu-panel .menu-group[open] > a[aria-current="page"]::before {
  background:
    radial-gradient(circle at 50% 50%, var(--accent) 3.5px, transparent 4px) no-repeat,
    linear-gradient(var(--line), var(--line)) 50% 0 / 2px 100% no-repeat;
}
.menu-panel .menu-group[open] > a[aria-current="page"]:last-child::before {
  background:
    radial-gradient(circle at 50% 50%, var(--accent) 3.5px, transparent 4px) no-repeat,
    linear-gradient(var(--line), var(--line)) 50% 0 / 2px 50% no-repeat;
}
/* Il gruppo dentro il gruppo: rientrato di suo, e non dell'accento - dentro un ramo gia' aperto un
   secondo colore acceso farebbe sembrare le sue due voci piu' importanti delle quattro accanto. */
.menu-group-inner > a { padding-left: 34px; }

/* Il comando che porta il programma sul calendario. In fondo alla carta della settimana, largo
   quanto lei: e' l'unica cosa in questa pagina che cambia qualcosa fuori da questa pagina, e un
   bottone che scrive sessanta righe in agenda non puo' avere lo stesso peso di una freccia che
   sfoglia. La riga sotto dice che si puo' ripremere, perche' un bottone che sembra aggiungere si
   preme una volta sola. */
/* ---------- il comando in cima, e la fine del foglio ----------

   Il comando principale di una pagina, nel flusso (/programma sotto il titolo, «Programma una
   seduta» su /programmazione sotto la proposta): solo il margine, perche' larghezza e centratura le
   da' gia' `.btn`. */
.programme-add,
.agenda-new { margin: 0 0 18px; }

/* I bottoni in fondo al foglio delle date: due per riga, «Indietro» stretto quanto la sua parola.
   `.btn` e' a tutta riga con il margine sopra, e «Costruisci il programma» a 360 punti non sta in
   mezza riga: con flex 1 1 auto prende quello che gli serve e l'altro si stringe. */
.event-sheet-foot { display: flex; flex-wrap: wrap; gap: 10px; }
.event-sheet-foot > .btn { flex: 1 1 auto; width: auto; min-width: 0; min-height: 52px; margin: 0; }
.event-sheet-foot > [data-event-back] { flex: 0 0 auto; }

/* Il riepilogo sopra a «Costruisci il programma»: la scatola dell'accento e' quella della data al
   passo 1 (con `.programme-when`, piu' su). Il nome va a capo invece di finire nei puntini: qui si
   controlla. */
.programme-recap {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 14px;
  padding: 10px 14px;
}
.programme-recap-mark { flex: 0 0 auto; font-size: 18px; font-weight: 700; color: var(--accent-text); }
.programme-recap-text { min-width: 0; }
.programme-recap-name { margin: 0; font-weight: 600; font-size: 15.5px; }
.programme-recap-line { margin: 2px 0 0; font-size: 13px; color: var(--mut); }

/* «In corso» a destra nella riga di un piano: la parola dello stato nell'accento, non una pastiglia
   piena. Dei piani in elenco uno solo e' quello che l'atleta sta seguendo, ed e' l'unico che
   eliminando si perde qualcosa di voluto; una pastiglia piena pesava piu' del nome del piano. */
.record-state.programme-plan-now { color: var(--accent-text); }

.programme-save { margin-top: 18px; }
.programme-save > .btn { width: 100%; }
.programme-save > .programme-help { margin-top: 8px; text-align: center; }


/*
  ---------- ogni bottone e' metallo bombato, con il bordo tagliato e quattro pixel di spessore ----------

  "Tutti i bottoni cliccabili devono avere effetto metallico, superficie lievemente bombata,
  tridimensionalita' e bordo tagliato con spessore di 6px con ombreggiatura e illuminazione
  coerente." (Luca, 27/09) E lo stesso giorno: "Bottoni principali 4px spessore, schede ecc 2px".

  Dal 25/09 al 27/09 i bottoni avevano la tessera dei riquadri - la stessa faccia, il fianco da 4px -
  e un bottone e un riquadro si distinguevano solo dalla forma. Adesso sono due materie: il riquadro
  e' una lastra di metallo piatta con due pixel, il bottone un cuscino di metallo con quattro. In
  quest'ordine: il taglio (--button-bevel, una faccetta alla luce in alto a sinistra e una in ombra in
  basso a destra, due pixel dentro al bordo), il fianco da quattro (--button-edge, dal --solid di
  ciascuno: scuro sotto uno metallico, accento scurito sotto uno pieno, rosso spento sotto uno
  distruttivo), l'ombra di una cosa alta quattro (--shadow-button) e l'eventuale bagliore
  dell'accento. Il filo di luce dei riquadri qui non c'e': la faccetta alla luce del taglio e' lui,
  piu' largo.

  Nessun movimento alla pressione: il bottone resta dov'e', con il suo spessore. I quattro pixel
  sono un'ombra e non occupano posto: non spostano niente, e dove un bottone sta a meno di quattro
  punti da una cosa sotto o a destra il fianco la tocca (misurato col banco il 27/09).

  button[class] ha intenzionalmente piu' specificita' delle singole classi dei controlli speciali:
  anche i bottoni tondi, le frecce della chat e i comandi piccoli ricevono la stessa materia. .btn
  copre inoltre link e label che nel markup fanno il mestiere di un bottone, a.plan-new il
  collegamento pieno «Crea una nuova scheda» (26/09: era rimasto piatto, sopra a righe con «Esegui»
  che la tessera ce l'hanno). «Vedi dettagli attivita'» (a.last-session-open), che stava qui, e' uscito
  con la carta dell'ultima sessione del mock A (27/09): la sua porta e' l'icona dei grafici sulla riga.
  label.meal-photo e' la macchina fotografica del pasto, un <label> su un campo nascosto che fa il
  mestiere di un bottone (27/09, con «Registra un pasto» tornato nel monitor della home: era rimasta un
  quadrato con il filo). a.running-workout (l'allenamento in corso, in home) e
  details.plan-create-exercise-card (la carta dell'esercizio nel costruttore) si premono, e dal 27/09
  sono bottoni: «Anche allenamento e carta esercizio 4px» (Luca); erano riquadri con il fianco da tre.

  Non prendono questa materia, di proposito: le voci di menu, le pastiglie di scelta e i passi dei
  programmi, le righe di elenco (.record-tile, collegamenti ma righe, con un filo e non una faccia).
  Sono scelte e righe: dargli un cuscino di metallo li farebbe leggere come il comando della pagina.
  Dal 27/09 le pastiglie hanno pero' il fianco da due dei riquadri, sotto una faccia senza luce, e i
  passi restano piatti ("pastiglie con bordo 2px, presente e successiva piatti", Luca). I segni (+, x, condividi, grafici: .orb-x e .page-top-sign) non sono piu'
  piatti dal 27/09: hanno una tessera loro, piu' sottile, sotto (la materia dei segni).
*/
button[class],
button:not([class]),
.btn,
a.plan-new,
a.running-workout,
details.plan-create-exercise-card,
label.meal-photo,
.mic-fab {
  --solid: var(--surface-2);
  --button-glow: 0 0 0 transparent;
  background: var(--button-face);
  box-shadow:
    var(--button-bevel),
    var(--button-edge),
    var(--shadow-button),
    var(--button-glow);
}

/* Pieni nel colore dell'atleta: stessa faccia metallica, e il fianco nell'accento scurito. */
button.btn-primary,
.btn.btn-primary,
button.plan-new,
a.plan-new,
button.plan-set-plus,
button.chat-send,
button.meal-send {
  --solid: var(--accent);
  --button-glow: var(--glow-accent-strong);
}

/* Il salto alla risposta resta illuminato, ma con il bagliore piccolo che aveva gia'. */
button.chat-jump {
  --solid: var(--accent);
  --button-glow: var(--glow-accent-soft);
}

/* Distruttivi: non diventano lastre rosse. Il rosso resta nel bordo e nel testo, la faccia prende
   solo una tinta della stessa famiglia, cosi' il rilievo si vede senza invitare alla pressione. */
button.btn-danger,
.btn.btn-danger,
button.badge-delete {
  --solid: color-mix(in srgb, var(--danger) 12%, var(--surface-2));
}

/* L'allenamento in corso tiene il suo colore, la velatura dell'accento, come faccia e fianco del
   bottone; rimasto aperto e non in corso torna al metallo di tutti, perche' non e' l'allenamento di
   adesso e smette di essere la cosa piu' luminosa dello schermo. */
a.running-workout {
  --solid: color-mix(in srgb, var(--accent) 8%, var(--surface-2));
}
a.running-workout.running-workout-stale {
  --solid: var(--surface-2);
}

/* Il microfono centrale resta una tessera scura dentro la barra, con il fianco di tutti.

   a.mic-fab E NON .mic-fab, e il nome dell'elemento non e' decorazione: la regola che disegna il
   tasto sta millecinquecento righe piu' su, e due regole a classe secca con lo stesso nome sono
   esattamente cio' che StylesheetClashTest vieta - la seconda vince in silenzio, e chi legge la
   prima non lo sa. Il microfono e' un <a> che fa il mestiere di un bottone, quindi scriverlo qui
   dice anche quale delle due e' la sovrascrittura voluta. */
a.mic-fab {
  --solid: var(--bar);
  --button-glow: 0 8px 18px -8px rgba(0, 0, 0, .55);
}

/* Alla pressione il bottone resta com'e', taglio e spessore compresi. */
button[class]:active,
button:not([class]):active,
.btn:active {
  box-shadow:
    var(--button-bevel),
    var(--button-edge),
    var(--shadow-button),
    var(--button-glow);
}


/* ---------- tutti i segni sono una X, un + o un'icona su una tessera piccola ----------
   Il bersaglio resta 44x44 per essere comodo da toccare, e l'elemento stesso non disegna niente: ne'
   fondo, ne' bordo, ne' la materia metallica globale dei button, nemmeno premuto. Il disegno e' la
   tessera sotto (la materia dei segni, dopo queste regole), e il glifo. Fino al 27/09 c'era solo il
   glifo: "Chiudere o cancellare non deve sembrare un altro bottone". */
/* E anche un <summary>, dove la X o la matita sono il comando che apre una piega: e' un comando
   come gli altri, e disegnarlo in un secondo modo vorrebbe dire due X diverse nella stessa riga. */
button.orb-x,
label.orb-x,
summary.orb-x,
a.orb-x {
  display: inline-grid;
  place-items: center;
  width: 44px;
  height: 44px;
  min-width: 44px;
  min-height: 44px;
  flex: 0 0 44px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  color: var(--ink);
  background: transparent;
  box-shadow: none;
  /* GRIGIA, una volta per tutte (Luca, 27/09: «la x deve avere il colore della terza X che ti ho mandato
     nelle immagini perché continui a fare la x con il colore accentato» - la X grigia della carta «Ultima
     sessione»). Tutte le `.orb-x` sono X (icon('remove')), tranne condividi e grafici, che portano da
     qualche parte e hanno la loro regola nell'accento. Era l'accento («icone modifica e cancella […]
     sempre del colore dell'accento scelto»): superato per la X; la penna di «Modifica» resta nell'accento. */
  color: var(--mut);
  line-height: 1;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: none;
}
/* Il segno e' un disegno, non piu' il carattere "×".
   Era il glifo della tipografia: cambiava forma con il carattere e a diciotto pixel veniva una
   crocetta sottile. Adesso e' `icon('remove')`, due segmenti a capo tondo - la sagoma della
   fotografia con cui e' stato chiesto. `transform: none` resta: dice che questo segno non gira. */
.orb-x .ico {
  display: block;
  width: 17px;
  height: 17px;
  transform: none;
}
.orb-x:hover {
  color: var(--mut);
}
button.orb-x:active {
  background: transparent;
  box-shadow: none;
}

/*
  ---------- la materia dei segni: una tessera bombata da due pixel ----------

  "Queste tre icone includile in riquadri e rendili bombati con spessore ma da 2px anziche' 4 (tutte
  le icone cliccabili devono avere spessore 2px e bombatura, ombre luci e bordi)" (Luca, 27/09, con
  condividi, grafici e X cerchiati sulla carta dell'ultima sessione). Quindi ogni icona che si preme -
  .orb-x (le X, condividi, i grafici, le X dei fogli e delle righe) e .page-top-sign (il + e la
  macchina fotografica in testata) - poggia su una tessera: la faccia bombata dei bottoni
  (--button-face), il loro taglio (--button-bevel), un fianco da due (--sign-edge) e l'ombra corta di
  una casella (--shadow-tile). La luce e' la stessa, in alto a sinistra.

  LA TESSERA E' UNO PSEUDO-ELEMENTO, E NON L'ELEMENTO: il bersaglio resta com'era, 44 per 44 (34 per
  30 nelle righe di prima), e dentro si disegna una tessera di 36 al massimo, centrata, con quattro
  punti d'aria per lato dove il fianco e l'ombra cadono senza uscire dal bersaglio. Cosi' nessuna riga
  cambia misura: il nome della carta dell'ultima sessione resta dove stava («Altro allenamento» ha
  127,7 punti su 130 a 360), e niente si sposta sotto al dito. Dove il bersaglio e' piu' piccolo di
  40 la tessera lo segue con due punti d'aria, quanto il fianco.

  Il glifo tiene il suo colore: condividi e grafici nell'accento, la X dove le regole della sua riga
  la vogliono. isolation fa della X un contesto suo, cosi' la tessera a z-index -1 sta sotto al glifo
  e sopra alla carta, e non dietro alla carta.
*/
button.orb-x,
label.orb-x,
summary.orb-x,
a.orb-x,
.page-top-sign {
  --solid: var(--surface-2);
  position: relative;
  isolation: isolate;
}
button.orb-x::before,
label.orb-x::before,
summary.orb-x::before,
a.orb-x::before,
.page-top-sign::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  /* 32 dal 27/09 sera, per tutte le icone: «Tutti i bottoni x si devono allineare alla nuova grandezza» (Luca). */
  /* Fissa, e non piu' «al massimo 32»: dove il bersaglio era stretto (le righe vecchie da 34 per 30) la
     tessera usciva piu' piccola, e Luca: «stessa grandezza dello sfondo di tutti i bottoni a icona singola e
     di tutte le x» (27/09). Centrata sul bersaglio, anche se lo supera di qualche punto. */
  width: 32px;
  height: 32px;
  margin: auto;
  border-radius: 10px;
  background: var(--button-face);
  box-shadow: var(--button-bevel), var(--sign-edge), var(--shadow-tile);
  pointer-events: none;
}
/*
  ---------- l'icona condividi e' sempre colorata ----------

  «L'icona condividi deve essere sempre colorata.» Non lo era: nello storico usciva
  nell'inchiostro della pagina e sulla carta dell'ultima seduta nell'accento, cioe' lo stesso
  comando di due colori diversi a due schermate di distanza.

  MISURATO, non dedotto: `getComputedStyle` dava rgb(242,243,247) sulla prima e rgb(255,0,159)
  sulla seconda. La causa e' la trappola gia' scritta in CLAUDE.md, vista dai bottoni:
  `button.history-share` pesa 0-1-1 e `button.orb-x` pesa 0-1-1, e a parita' vince chi viene dopo -
  l'orb-x sta seimila righe piu' in giu'. `button.session-share` sopravviveva solo perche' sta
  ancora piu' sotto. Una regola giusta e una sbagliata per caso, decise dalla riga in cui sono
  scritte.

  E `.orb-x:hover` pesa 0-2-0, cioe' piu' di tutte e due: sotto al dito perdevano il colore anche
  quando ce l'avevano - e su un telefono lo stato hover resta appiccicato dopo il tocco.

  Quindi una regola sola, dopo l'orb-x, con un antenato nel selettore e non un nome di classe piu'
  lungo: 0-2-1 batte `button.orb-x`, e 0-3-1 batte `.orb-x:hover`. E' un comando che offre
  qualcosa, non uno che toglie, e accanto a una X che resta nell'inchiostro il colore e' l'unica
  cosa che lo dice - chiesto cosi' la prima volta: «falla dello stesso colore dell'accento scelto
  per il tema».

  COLORATA E LEGGIBILE: --accent-text, non --accent (26/09, taglio 5, D3). Nel tema chiaro l'icona
  non si vedeva con cinque tavolozze su sette: misurato, volt rgb(215,255,46) e tiffany
  rgb(46,230,223) su rgb(246,246,248). --accent e' il colore di un riempimento; un segno su fondo
  chiaro e' --accent-text, che nel chiaro si scurisce e nel buio e' lo stesso colore. Vale per i due
  bottoni, quindi anche per la carta dell'ultima seduta sulla home, e solo nel chiaro.
*/
button.orb-x.history-share,
button.orb-x.session-share,
button.orb-x.history-share:hover,
button.orb-x.session-share:hover {
  color: var(--accent-text);
}

/* L'anello del fuoco segue il segno: sul foglio che il server manda aperto il fuoco arriva sulla X
   da solo (showModal), e un anello di un'altra forma attorno al segno sembrava un'altra scatola
   (verifiche del 26/09). Dal 27/09 il segno e' una tessera arrotondata, e l'anello la contorna. */
.orb-x:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 0;
  border-radius: 12px;
}


/*
  ---------- aggiungi esercizio ----------

  Del modulo che questo comando apriva non resta niente: adesso crea la carta e basta. La
  progressione a tre pallini qui sotto e' rimasta perche' la usa ancora il percorso "crea una nuova
  scheda" (.plan-create-progress se la aggancia): le classi si chiamano plan-add-* per come sono
  nate.
*/

.plan-add-title {
  margin: 0;
  font-size: 20px;
  line-height: 1.2;
}

.plan-add-progress {
  --plan-add-progress: 33.333%;
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  width: 100%;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 22px 0 0;
  list-style: none;
}

.plan-add-progress::before,
.plan-add-progress::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 0;
  height: 4px;
  border-radius: 999px;
  pointer-events: none;
}

.plan-add-progress::before {
  right: 0;
  background: color-mix(in srgb, var(--line) 78%, transparent);
}

.plan-add-progress::after {
  width: var(--plan-add-progress);
  background: var(--accent);
  box-shadow: var(--glow-accent);
  transition: width .2s ease;
}

.plan-add-progress li {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  color: var(--mut);
  font-size: 12.5px;
  white-space: nowrap;
}

.plan-add-progress li:nth-child(2) { justify-content: center; }
.plan-add-progress li:nth-child(3) { justify-content: flex-end; }

.plan-add-progress-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  flex: 0 0 30px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--field);
  color: var(--mut2);
  font-size: 13px;
  font-weight: 750;
  font-variant-numeric: tabular-nums;
}

.plan-add-progress li[aria-current="step"] {
  color: var(--ink);
  font-weight: 650;
}

.plan-add-progress li[aria-current="step"] .plan-add-progress-dot {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--glow-accent-strong);
}

.plan-add-progress li.is-done .plan-add-progress-dot {
  border-color: var(--accent-line);
  color: var(--accent-ink);
}

@media (max-width: 360px) {
  .plan-add-progress { gap: 4px; }
  .plan-add-progress li { gap: 5px; font-size: 11.5px; }
  .plan-add-progress-dot {
    width: 27px;
    height: 27px;
    flex-basis: 27px;
    font-size: 12px;
  }
}


/*
  ---------- prima creazione scheda: wizard ----------

  La seconda schermata e' l'accordion del mock approvato: intestazione sempre leggibile, contenuto
  espandibile, serie come due pillole affiancate e X identica a quella che chiude il menu laterale.
  La progressione riusa volutamente .plan-add-progress, cioe' lo stesso componente di "Aggiungi
  esercizio" dentro una scheda gia' esistente.
*/

/* Stessa barra di .plan-add-progress; cambiano soltanto numero di colonne e percentuale. */
/* Tre tappe e non piu' due: davanti al nome c'e' la scelta fra scriverla da se' e farsela
   proporre. La barra sotto arriva a un terzo, a due terzi e in fondo - i valori dicono "a che punto
   sono", quindi sono tre e non due anche qui. */
/* DUE TAPPE, non piu' tre: il nome e gli esercizi stanno nella stessa schermata. Le percentuali
   sono una per tappa e sono quello che la barra colora, quindi il loro numero e quello dei passi
   sono la stessa cosa - PlanCreateWizardTest li tiene in pari, che e' come si e' scoperto di
   doverle cambiare tutte e tre. */
.plan-create-progress.plan-add-progress {
  --plan-add-progress: 50%;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: 0 0 28px;
}
.plan-create-wizard[data-step="1"] .plan-create-progress { --plan-add-progress: 50%; }
.plan-create-wizard[data-step="2"] .plan-create-progress { --plan-add-progress: 100%; }
/* La prima a sinistra, l'ultima a destra: con colonne uguali una tappa allineata a sinistra dentro
   la sua colonna non sta sotto al suo pallino. */
.plan-create-progress.plan-add-progress li:nth-child(2) { justify-content: flex-end; }

.plan-create-step {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* ---------- come la vuoi fare: tre carte (mock 07, dal 26/09) ----------

   La grammatica e' quella delle pastiglie del programma - una <label> che avvolge il radio, la
   faccia metallica, il bordo dell'accento quando e' scelta - e cambia una cosa sola: qui dentro ci
   sta anche una riga di spiegazione. Serve: "Hybrx te la scrive" senza dire che poi si corregge e'
   la promessa che fa premere indietro, e una pastiglia larga quanto due parole non ha dove dirlo.

   Il margine delle <label> del modulo va azzerato, come per le pastiglie: la regola globale
   `label { margin: 16px 0 8px }` e' scritta per le etichette dei campi, e qui dentro diventerebbe
   aria fra una carta e l'altra che il gap ha gia' deciso. */
/* Le tre carte alte uguali, quanto la piu' alta: la riga di Hybrx va su tre righe a 360 e a 390, e
   le carte leggevano 90 / 109 / 90 (verifiche del taglio 4a, 26/09). */
.plan-create-choice {
  display: grid;
  grid-auto-rows: minmax(0, 1fr);
  gap: 10px;
  margin: 0 0 4px;
}
.plan-create-choice-card {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 76px;
  margin: 0;
  padding: 12px 14px;
  box-sizing: border-box;
  /*
    LA REGOLA GLOBALE DELLE ETICHETTE VA AZZERATA QUI, tutta: ogni <label> della pagina e' condensata,
    maiuscola, 11,5px e spaziata 1,2 - e' il mestiere delle micro-etichette sopra i campi. Queste due
    carte sono <label> perche' avvolgono un radio, ma quello che ci sta dentro e' un titolo e una
    frase, e con quella regola addosso si leggevano "ME LA SCRIVE HYBRX / TE NE PROPONE UNA DAI TUOI
    OBIETTIVI...": tre righe di maiuscolo spaziato al posto di una spiegazione.

    Niente andava rosso, perche' si disegnava benissimo. E' la trappola gia' scritta in CLAUDE.md -
    un elemento preso dal vocabolario dei moduli per un lavoro che non e' quello di un modulo deve
    rimettere a posto la regola globale - e l'ha presa il render, non il diff.
  */
  font-family: inherit;
  font-size: inherit;
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  line-height: 1.5;
  --solid: var(--field);
  background: var(--metal-face);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  cursor: pointer;
}
.plan-create-choice-card:has(input:checked) {
  border-color: var(--accent-line);
}
/* Il pallino resta, al contrario delle pastiglie: li' la pastiglia accesa E' la risposta, qui la
   carta e' alta tre righe e il solo bordo acceso si legge come decorazione. A DESTRA, come nel mock
   07: nel markup viene per primo (la <label> lo avvolge), quindi l'order lo porta in fondo. E
   nell'accento da leggere: accent-color disegna il pallino scelto, e --accent con volt nel chiaro
   era un giallo chiaro su bianco. */
.plan-create-choice-card input {
  order: 2;
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin: 0 0 0 auto;
  accent-color: var(--accent-text);
}
/* Il segno della strada, a sinistra: 44 punti come nel mock, sul fondo dei campi e nell'accento del
   testo come il segno di una riga di elenco (.record-ico). */
.plan-create-choice-ico {
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 14px;
  background: var(--field);
  color: var(--accent-text);
}
.plan-create-choice-ico .ico { display: block; width: 22px; height: 22px; }
.plan-create-choice-body {
  display: flex;
  flex: 1 1 0;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.plan-create-choice-title {
  color: var(--ink);
  font-size: 15.5px;
  font-weight: 700;
}
.plan-create-choice-card:has(input:checked) .plan-create-choice-title {
  color: var(--accent-text);
}
.plan-create-choice-copy {
  color: var(--mut);
  font-size: 13px;
  line-height: 1.45;
}

/* Le tre domande e il comando che chiede la proposta: con lo script compaiono solo scegliendo
   Hybrx, quindi stanno staccate dalle carte quanto basta a leggersi come la conseguenza della
   scelta. Senza script si vedono sempre (non nascono piu' hidden: 26/09). */
.plan-create-hybrx { margin-top: 18px; }
/* La terza strada: il pannello della foto, sotto al modulo della creazione. */
.plan-create-photo-title { margin: 0 0 10px; }
/*
  CON LO SCRIPT, NIENTE SFARFALLIO. Il pannello di Hybrx e quello della foto nascono visibili - e'
  quello che li fa vedere a chi non ha lo script - e li nasconde app.js secondo la carta scelta. Fra
  il primo disegno e quel momento si vedrebbero tutti e due per un istante: finche' il modulo non e'
  pronto (.plan-create-wizard-ready, messa da app.js) non si disegnano. Senza :has() il pannello
  della foto lampeggia e basta.
*/
@media (scripting: enabled) {
  .plan-create-wizard:not(.plan-create-wizard-ready) .plan-create-hybrx,
  .plan-create:has(> .plan-create-wizard:not(.plan-create-wizard-ready)) ~ .plan-create-photo { display: none; }
}
/*
  SENZA SCRIPT, NESSUN COMANDO MORTO. «Avanti» e «Indietro», i «+» e le «×» del passo 2 sono
  bottoni che vivono di script (type="button"): senza, non fanno niente. Non si disegnano, con le
  loro righe; la scheda si crea con l'esercizio e la serie che ci sono, e il resto si aggiunge dal
  foglio della scheda, che dal 26/09 si apre anche senza script. E «Trend carichi» (la scheda e
  l'allenamento): un hx-get senza indirizzo, che senza script non apre niente. Con i suoi antenati
  nel selettore, perche' le regole che la disegnano come voce di menu li hanno (0-2-1). In DA-FARE
  §23 la pagina del trend senza script.
*/
@media (scripting: none) {
  [data-plan-create-next],
  [data-plan-create-back],
  [data-plan-create-add-exercise],
  [data-plan-create-add-set],
  [data-plan-create-remove-exercise],
  [data-plan-create-remove-set],
  .plan-create-wizard .plan-set-more,
  .plan-create-remove-exercise-wrap,
  .session-trend-entry,
  :is(.plan-read-item, .plan-builder-exercise, .session-exercise, .recap-exercise) button.session-trend-entry { display: none; }
}
.plan-create-hybrx .intake { margin-top: 0; }
.plan-create-write { width: 100%; margin-top: 4px; }
/* L'attesa e' lunga - e' una chiamata al modello - e l'indicatore lo accende HTMX. Centrata sotto
   il bottone, come la lettura di una foto. */
.plan-create-wait { justify-content: center; margin-top: 12px; }
.plan-create-step-title {
  margin-bottom: 8px;
  color: var(--ink);
  font-size: 20px;
  font-weight: 700;
}
.plan-create-step-copy {
  margin: 0 0 18px;
  color: var(--mut);
  font-size: 13.5px;
  line-height: 1.5;
}
.plan-create-field {
  display: block;
  margin: 0;
}
.plan-create-field > input,
.plan-create-field > textarea {
  display: block;
  width: 100%;
  min-width: 0;
  margin: 7px 0 0;
}
.plan-create-field > textarea {
  min-height: 82px;
  resize: vertical;
}

/* Il suggerimento sotto al campo del nome: e' un suggerimento, non l'argomento della schermata.
   Era la riga di spiegazione di un passo tutto suo - "step due e tre li unirei insieme, inutile
   avere una schermata intera solo per il titolo" - e sotto al campo deve pesare quanto una
   didascalia, altrimenti si porta dietro l'importanza che aveva quando era un titolo. */
.plan-create-field-hint {
  margin: 6px 0 0;
  color: var(--mut);
  font-size: 12.5px;
  line-height: 1.45;
}

/* "Esercizi" non e' piu' un passo, e' una sezione dentro al passo: piu' piccolo del titolo della
   schermata, con l'aria sopra che dice che qui comincia un'altra cosa. */
.plan-create-step-subtitle {
  margin: 22px 0 12px;
  color: var(--ink);
  font-size: 16px;
  font-weight: 700;
}

/* "Puoi inserire il carico ora oppure la prima volta che la esegui": la riga che spiega una
   scatola vuota. Sta dentro la carta dell'esercizio, sotto le tre scatole, e si legge come una
   nota - se pesasse quanto un avviso, dodici esercizi ne farebbero dodici. */
.plan-create-load-later {
  margin: 10px 0 0;
  color: var(--mut);
  font-size: 12.5px;
  line-height: 1.45;
}

.plan-create-exercise-list {
  display: grid;
  gap: 12px;
}
/* La carta dell'esercizio si preme (si apre e si chiude), quindi dal 27/09 e' un bottone della casa:
   «Anche allenamento e carta esercizio 4px» (Luca). La materia la da' la regola di tutti i bottoni
   (details.plan-create-exercise-card, in fondo al foglio); fino ad allora aveva il fianco da tre.
   APERTA TIENE IL FIANCO E IL TAGLIO, E LA FACCIA DIVENTA QUELLA DEI RIQUADRI: il bordo in alto resta
   quello che la richiude, ma sotto c'e' un modulo alto cinquecento punti, e la bombatura e' in
   percentuale - su quell'altezza non e' piu' "lievemente bombata", e' una vignetta sotto ai campi, lo
   "scolorito e slavato" per cui il riflesso dei riquadri e' in pixel. L'anello dell'accento passa dal
   bagliore del bottone, che e' il suo posto nella pila delle ombre. */
.plan-create-exercise-card {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 18px;
}
.plan-create-exercise-card[open] {
  border-color: var(--accent);
  --button-glow: 0 0 0 1px var(--accent-line);
  background: var(--metal-face);
}

.plan-create-exercise-summary {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 18px;
  align-items: center;
  gap: 12px;
  min-height: 72px;
  padding: 13px 16px;
  list-style: none;
  cursor: pointer;
  user-select: none;
}
.plan-create-exercise-summary::-webkit-details-marker { display: none; }
.plan-create-exercise-summary::marker { content: ""; }
.plan-create-exercise-summary::after {
  content: "";
  width: 10px;
  height: 10px;
  justify-self: center;
  border-right: 2px solid var(--ink-2);
  border-bottom: 2px solid var(--ink-2);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .16s ease;
}
.plan-create-exercise-card[open] > .plan-create-exercise-summary::after {
  transform: rotate(225deg) translate(-1px, -1px);
}
.plan-create-exercise-summary-copy {
  display: grid;
  gap: 3px;
  min-width: 0;
}
.plan-create-exercise-summary-name {
  overflow: hidden;
  color: var(--ink);
  font-size: 17px;
  font-weight: 750;
  line-height: 1.2;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.plan-create-exercise-summary-meta {
  color: var(--mut);
  font-size: 12.5px;
  line-height: 1.2;
}

.plan-create-exercise-body {
  display: grid;
  gap: 16px;
  padding: 15px 16px 16px;
  border-top: 1px solid var(--line-soft);
}
.plan-create-exercise-name,
.plan-create-exercise-notes {
  min-width: 0;
}

.plan-create-set-block {
  display: grid;
  gap: 10px;
}
/* Il "+" porta gia' il suo respiro dalla scheda salvata; sommato al gap del blocco farebbe
   ventidue pixel fra l'ultima serie e il comando. */
.plan-create-set-block > .plan-set-more { margin-top: 0; }
.plan-create-set-list { display: block; }
/* ---------- la serie: la stessa di una scheda gia' creata ----------

   Le tre etichette stavano DENTRO alle pastiglie, come suffisso, e per questo tre campi in fila
   non ci stavano: su una colonna da 390 restavano ottantotto pixel a pastiglia e quaranta se li
   prendeva l'etichetta. Da lì venivano le due righe - ripetizioni sopra, carico e recupero sotto -
   e il recupero che si prendeva anche la colonna della X per lasciare abbastanza testo leggibile.

   Spostare l'etichetta SOPRA toglie il problema invece di aggirarlo: il campo si tiene tutta la
   sua larghezza per il valore, e i tre stanno in fila. Chiesto così, con una schermata: "quando
   sto inserendo gli esercizi le input devono essere allineate in questo modo".

   E la riga ha la testa di una serie in una scheda salvata - "1 serie" e la crocetta a destra -
   perché è la stessa cosa vista nello stesso momento: "quando aggiungo una scheda la
   visualizzazione degli esercizi deve essere come quando sto visualizzando degli esercizi di una
   scheda già inserita". Stessa misura (.plan-set), stesse colonne (.plan-set-edit), e la crocetta
   sale nella testa: sotto, a destra, era l'unico posto dove le due schermate si somigliavano solo
   per modo di dire.

   align-items: end perché le tre etichette non sono lunghe uguali: "Recupero (s)" va a capo dove
   "Kg" non ci va, e allineando in alto le pastiglie finirebbero su tre quote diverse. */
.plan-create-set-row {
  display: block;
  padding: 16px 0;
  border-bottom: 1px solid var(--line-soft);
}
.plan-create-set-row:last-child { border-bottom: none; }
.plan-create-set-row:first-child { padding-top: 4px; }
.plan-create-set-fields {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 8px;
  min-width: 0;
}

/* La stessa X del menu: .orb-x fornisce target 44x44 senza disegnare un bottone. */
button.plan-create-remove-set.orb-x {
  align-self: center;
  color: var(--ink);
}


.plan-create-remove-exercise-wrap {
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
}
/* Stessi colori/materiale del piccolo "Elimina" nell'ultima sessione, ma largo come nel mock. */
button.plan-create-remove-exercise.badge-delete {
  width: 100%;
  min-height: 48px;
  margin: 0;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 700;
}

.plan-create-add-exercise {
  width: 100%;
  min-height: 48px;
  margin: 12px 0 0;
}

.plan-create-nav {
  display: flex;
  gap: 10px;
  margin-top: 22px;
}
.plan-create-nav .btn {
  flex: 1 1 0;
  margin: 0;
}
.plan-create-wizard [data-plan-create-next],
.plan-create-wizard [data-plan-create-back] {
  display: none;
}
.plan-create-wizard-ready [data-plan-create-next],
.plan-create-wizard-ready [data-plan-create-back] {
  display: inline-flex;
}
.plan-create-wizard-ready .plan-create-step[hidden] { display: none; }
.plan-create-wizard [data-plan-create-next]::after {
  content: "›";
  margin-left: 8px;
  font-size: 21px;
  font-weight: 500;
  line-height: .8;
}

@media (max-width: 390px) {
  .plan-create-exercise-summary {
    min-height: 68px;
    padding-inline: 14px;
  }
  .plan-create-exercise-body { padding-inline: 14px; }
  .plan-create-set-fields { gap: 6px; }
  .set-field input { font-size: 16px; }
}


/* ---------- la cartolina da condividere ----------

   Una foto dell'atleta con sopra i suoi numeri, da mettere in una storia. Il foglio arriva su
   richiesta dentro #story-slot (session/list.html) e se ne va quando si chiude: story.js svuota il
   contenitore, perche' due fogli nel documento vorrebbero dire comandi agganciati a quello vecchio.

   La tela e' 1080x1920 nei suoi attributi - quella e' la dimensione dell'immagine che l'atleta si
   salva - e qui viene solo rimpicciolita per starci dentro. Le due misure sono cose diverse: la
   prima decide la qualita' del file, la seconda quanto spazio occupa sullo schermo. */

.story-dialog {
  /* Centrata a mano, per la stessa ragione della finestra di conferma: un <dialog> modale viene
     disposto dal browser come inset:0 con margin:auto, a meno che qualcosa nel foglio non gli abbia
     gia' dato una posizione - e allora finisce in un angolo. */
  position: fixed;
  inset: 0;
  margin: auto;
  height: fit-content;
  max-height: calc(100dvh - 32px);
  width: min(420px, calc(100vw - 32px));
  overflow: auto;
  padding: 18px;
  border: 1px solid var(--accent-line);
  border-radius: 18px;
  background: var(--panel);
  color: var(--ink);
  box-shadow: 0 18px 48px rgba(0, 0, 0, .45);
}
.story-dialog::backdrop { background: rgba(0, 0, 0, .6); }

.story-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.story-title { margin: 0; font-size: 18px; }

/* I numeri anche in testo, non solo dentro i pixel: un lettore di schermo non puo' leggere una
   tela, e una figura con le cifre disegnate dentro e nient'altro attorno non dice niente a chi non
   la vede. Serve anche a story.js, che li legge da qui invece di conoscerli. */
.story-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
}
.story-facts li { display: flex; align-items: baseline; gap: 6px; }
.story-fact-label {
  font-family: var(--cond);
  font-size: 11.5px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut2);
}
.story-fact-value { font-weight: 700; }

.story-frame { position: relative; margin: 12px 0; }
.story-canvas {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 14px;
  background: var(--surface-2);
}

/* ---------- il riquadro che dice cosa manca ----------

   Sopra la tela e non dentro: quello che sta sulla tela finisce nell'immagine che l'atleta salva.
   Sta DOVE andra' la foto, perche' il vuoto era una tela scura con le scritte sospese e da fuori
   non si capiva ne' che mancasse una foto ne' da dove metterla.

   pointer-events: none sul riquadro e auto sul piu': il riquadro copre tutta la tela, e senza
   questo sarebbe una lastra che intercetta ogni tocco per un solo bottone al centro. */
.story-empty {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin: 16px;
  border: 1.5px dashed rgba(255, 255, 255, .5);
  border-radius: 12px;
  pointer-events: none;
}
.story-empty[hidden] { display: none; }
.story-empty-text {
  font-family: var(--cond);
  font-size: 13px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: #fff;
  text-shadow: 0 2px 10px rgba(0, 0, 0, .8);
}
/* Una <label> che fa il mestiere di un bottone: azzera il margine e il maiuscoletto della regola
   globale delle etichette, che altrimenti la fa alta e tutta in maiuscolo. */
.story-plus {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin: 0;
  border: 1.5px solid rgba(255, 255, 255, .6);
  border-radius: 50%;
  font-family: var(--sans);
  font-size: 27px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  line-height: 1;
  color: #fff;
  background: rgba(0, 0, 0, .35);
  cursor: pointer;
  pointer-events: auto;
}
.story-plus:hover { background: rgba(0, 0, 0, .55); }

.story-masks {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
  padding: 0;
  border: 0;
}
.story-legend {
  padding: 0;
  font-family: var(--cond);
  font-size: 11.5px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut2);
}
/* Una <label> che non e' l'etichetta di un campo di testo: azzera il margine e il maiuscoletto
   della regola globale delle etichette, che altrimenti la fa alta e tutta in maiuscolo. */
.story-mask {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 6px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  cursor: pointer;
}
.story-mask:has(input:checked) {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  color: var(--accent-ink);
}
.story-mask input { position: absolute; opacity: 0; pointer-events: none; }
.story-mask-glyph { display: block; width: 24px; height: 14px; }
/* Tre gruppi di scelte, uno sotto l'altro: lo stesso spazio fra i gruppi che c'e' fra un gruppo e i
   bottoni sotto. */
.story-masks + .story-masks { margin-top: 12px; }
/* Il nome del carattere scritto nel carattere: il campione e' la risposta. */
.story-font-pulito { font-family: 'Poppins', var(--sans); font-weight: 600; }
.story-font-pennello { font-family: 'Knewave', var(--sans); font-size: 15px; letter-spacing: .3px; }
/* Il campione di colore: un pallino pieno, e il bianco con il suo filo, o su fondo chiaro sparisce. */
.story-ink-swatch {
  display: block;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 1px solid var(--line);
}
.story-ink-bianco { background: #fff; }
.story-ink-nero { background: #0b0c14; }
.story-ink-gradiente { background: linear-gradient(90deg, rgb(245, 59, 240), rgb(43, 217, 240)); }

.story-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.story-actions .btn { flex: 1 1 auto; }
/* Il selettore di file e' una <label> travestita da bottone: il campo vero e' nascosto, perche'
   "Scegli file / Nessun file selezionato" non e' ne' tradotto ne' della stessa famiglia del resto. */
.story-pick { display: inline-flex; align-items: center; justify-content: center; text-align: center; }
.story-note { margin: 10px 0 0; font-size: 12px; }


/* ---------- perché questa scheda ----------

   Due o tre frasi del coach sulla scheda che ha appena scritto, nel modulo di creazione e poi sulla
   pagina della scheda. Chiesto così: "quando Hybrx crea la scheda sarebbe bello avere anche una
   breve spiegazione della scheda che ti ha creato".

   Una carta dentro la carta, con la linea d'accento a sinistra: è una voce diversa da quelle
   attorno - lì si compila, qui si legge - e senza un segno che lo dica il paragrafo si legge come
   un'istruzione del modulo. Lo stesso blocco serve i due posti, perché sono la stessa cosa detta
   nello stesso momento. */
.plan-create-why,
.plan-why {
  margin: 14px 0 16px;
  padding: 10px 14px;
  border-left: 2px solid var(--accent-line);
  border-radius: 0 12px 12px 0;
  background: var(--accent-soft);
}
.plan-create-why-label,
.plan-why-label {
  display: block;
  margin-bottom: 4px;
  font-family: var(--cond);
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--accent-ink);
}
/* Sulla pagina della scheda il perche' si apre e si chiude, e nasce chiuso: sono cinque righe che
   si leggono una volta e poi stanno fra il nome e "Esegui scheda" ogni volta che si apre questa
   pagina per andare ad allenarsi. Nel modulo di creazione resta aperto - li' e' il momento in cui
   si legge, ed e' la stessa ragione al contrario. */
.plan-why > summary.plan-why-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0;
  padding: 2px 0;
  list-style: none;
  cursor: pointer;
}
.plan-why-what { display: flex; align-items: center; gap: 7px; min-width: 0; }
.plan-why > summary::-webkit-details-marker { display: none; }
.plan-why > summary::marker { content: ""; }
.plan-why > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* Il segno che dice "si apre": una punta disegnata con due bordi, che ruota. Niente icona da
   caricare e niente carattere: e' decorazione, e sta accanto alla parola che la spiega. */
.plan-why-chevron {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .18s ease;
}
.plan-why[open] > summary .plan-why-chevron {
  transform: rotate(-135deg) translate(-3px, -3px);
}
.plan-why > p { margin-top: 8px; }
/* Sulla pagina della scheda il perche' e' una riga-piega nella sua carta, come nel mock 08: il segno
   del modello a sinistra, la frase «Perche' questa scheda», la freccia in fondo. Non piu' la fascia
   dell'accento, che resta al modulo di creazione: li' e' il testo da leggere adesso. */
.plan-why-card { padding: 10px 14px; }
.plan-why-card > .plan-why {
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
}
.plan-why-card > .plan-why > summary.plan-why-label {
  gap: 12px;
  min-height: 44px;
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
  color: var(--ink);
}
.plan-why-card .plan-why-what { flex: 1 1 0; }
.plan-why-card .plan-why-chevron { margin-right: 6px; color: var(--accent-text); }
.plan-why-card > .plan-why > p { margin: 8px 0 4px; }
.plan-create-why p,
.plan-why p {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
}

/* ---------- aggiungi esercizio: una riga in fondo alla lista ----------

   Era una carta a se', sotto a quella degli esercizi e grande quanto lei, per un comando. Poi e'
   diventata una piega che apriva un modulo - nome, note, le serie da comporre - e adesso e' quello
   che era gia' un livello piu' giu': un comando che CREA e basta, "Nuovo esercizio" con dentro una
   serie vuota, da aprire e correggere come tutti gli altri.

   Quindi qui non resta quasi niente da dire: il disegno e' quello di .plan-new, il bottone pieno
   che in libreria crea una scheda, e questa regola dice solo dove sta e che il titolo dentro al
   bottone prende la misura del bottone. Portava ancora i 20px di quando era l'<h2> di una carta a
   se', ed e' cosi' che "Aggiungi esercizio" finiva scritto piu' grande di "Esegui scheda" dieci
   centimetri piu' su - "ha un font troppo grande rispetto agli altri due bottoni". */
.plan-add-new { margin-top: 14px; }
.plan-add-new .plan-add-title {
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
}

/* ---------- il livello dichiarato, come sezione della disciplina ----------
   Va a capo da solo: su un telefono stretto "anni", i due passi e i due massimali non ci stanno
   affiancati, e un `wrap` costa meno di una media query che qualcuno dovra' mantenere. Piu' spento
   dei bersagli perche' e' facoltativo, e si deve leggere come un'aggiunta.

   E con un titolo sopra e uno stacco sotto alla riga della disciplina: appesi in coda ai bersagli
   questi campi si leggevano come "altri due numeri", cioe' non si leggevano - riferito come "non
   vedo dove chiedere". Una domanda che non si vede e' una domanda che non e' stata fatta.

   UN BLOCCO SOLO, e non due: erano due, ed e' esattamente la regola che vince solo per le
   dichiarazioni che ripete - la seconda avrebbe tolto il flex senza dirlo. L'ha presa
   StylesheetClashTest. */
.discipline-level {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
  opacity: .82;
}
.discipline-level .discipline-target { margin: 0; }

/* Il livello si mostra solo per la disciplina spuntata, e lo decide il foglio di stile con :has()
   invece di uno script: cinque discipline per quattro campi sono venti scatole in colonna, e una
   schermata che chiede venti numeri e' una schermata che si chiude. I campi restano nel modulo
   anche da nascosti - display:none si invia lo stesso - e proprio per questo nessuno di loro porta
   un vincolo del browser: un controllo rifiutato mentre non si vede non si puo' mettere a fuoco
   per segnalarlo. */
.discipline:not(:has(.discipline-pick input:checked)) .discipline-level { display: none; }

/* Quanti giorni e come divisa, sopra al bottone che scrive la scheda: due controlli affiancati che
   vanno a capo da soli sul telefono stretto, con la stessa aria dei bersagli di una disciplina. */
.onboarding-gym-shape {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 14px;
  margin-bottom: 14px;
}
.onboarding-gym-shape .discipline-target { margin: 0; }
.onboarding-gym-shape select { min-width: 190px; }

/* ---------- "tue considerazioni", chiuso di default ----------
   Una tessera dentro a un'altra, quindi prende il gradino di chiaro che ogni tessera annidata
   prende. Il segno della piega e' quello di tutte le altre, e gira all'apertura: e' la stessa
   regola scritta per il monitor nutrizionale, e una piega con un segno suo e' una piega che
   qualcuno deve imparare due volte. */
.your-take > summary {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  font-family: var(--cond);
  font-size: 13px;
  font-weight: 650;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--mut);
}
.your-take > summary .session-detail-mark { margin-left: auto; }
/* <details> non distanzia i figli con gap - il contenuto sta in una scatola anonima - quindi
   l'aria la mette il margine del primo elemento dentro. */
.your-take-text { margin-top: 12px; }

/* Il titolo prende la riga per se': e' un figlio del flex, quindi senza `flex: 1 0 100%` si
   metterebbe in fila con i campi invece che sopra. */
.discipline-level-head {
  flex: 1 0 100%;
  margin: 0 0 8px;
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut);
}

/* ---------- i record ----------

   UNA TESSERA PER RECORD, e la tessera veniva dalla riga della scheda palestra: il nome sopra, da
   dove viene il numero sotto in condensato, il numero a destra. Dal 26/09 e' la riga delle schede a
   essere questa (.record-tile.plan-row). *"Invece di avere una lista fai una
   piccola card che occupa tutto lo spazio orizzontale... prendi spunto da questa."*

   IL FONDO E' QUELLO DELLA CARTA CHE LA CONTIENE: *"lo sfondo delle card non deve essere chiaro"*.
   Una tessera sopra a un'altra prende un gradino di chiaro - e' la regola del domino - ma li' si
   parla di UNA tessera dentro a un'altra, e qui dentro ce ne stanno trenta di fila: trenta gradini
   sono una carta che si schiarisce tutta, cioe' un blocco piu' chiaro con dentro dei nomi. Il
   rilievo qui lo fa il filo del bordo, come faceva la riga della scheda palestra, che e' il disegno
   da cui questa viene.

   I NUMERI IN COLONNA. Il nome cede (`flex: 1 1 0`), il numero tiene una larghezza minima sua ed e'
   allineato a destra, la X dopo di lui e' larga uguale su ogni tessera: i tre bordi destri cadono
   nello stesso punto qualunque cosa ci sia scritto. Con la base `auto` sul nome la misura di
   partenza sarebbe la larghezza del CONTENUTO - un nome lungo si prende la tessera e manda a capo
   il resto, che e' il difetto riferito come *"si sputtana tutto e disallinea i numeri"*.

   TUTTE ALTE UGUALE, e per questo il nome si taglia con i puntini: *"le card devono avere tutte la
   stessa altezza, se titolo troppo lungo ... il nome lo vedi in visualizza"*. Finche' andava a capo
   una tessera su tre era alta il doppio delle altre e l'elenco si leggeva a scalini. Tagliare non
   perde niente PERCHE' IL FOGLIO C'E': il nome intero si legge toccando, ed e' la stessa scelta
   della riga di una scheda palestra, che si taglia per la stessa ragione. Senza il foglio
   sarebbe una perdita - un nome tagliato fa sparire proprio la parte che distingue due esercizi
   che cominciano uguale - e infatti prima andava a capo. */
.record-list { list-style: none; margin: 0; padding: 0; }
.record-tile {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  padding: 12px 14px;
  border: 1px solid var(--line-soft);
  border-radius: 12px;
  /* Un fianco da un pixel e un'ombra corta su ogni riga (Luca, 27/09: la prova sulle date della home, poi
     «Bordi 1px e metallo sui box date in home estendilo a tutto»). */
  --solid: var(--surface);
  box-shadow: var(--lift-edge-1), 0 1px 2px rgba(0, 0, 0, .18);
}
.record-tile:first-child { margin-top: 0; }
/* Il bersaglio e' la tessera intera: su un telefono un'icona da venti pixel e' il modo di mancare
   il comando.

   UN ANTENATO NEL SELETTORE, e non un nome di classe piu' lungo: `button[class]` da' la faccia
   metallica a ogni bottone che abbia una classe e pesa 0-1-1, esattamente quanto
   `button.record-open` - e a parita' vince chi viene dopo, che e' la regola dei bottoni, mille
   righe piu' in giu'. E' la trappola di CLAUDE.md vista dal lato dei bottoni. */
.record-tile > .record-open {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.record-head {
  display: flex;
  flex: 1 1 0;
  min-width: 0;
  flex-direction: column;
  gap: 3px;
}
/* `min-width: 0`: il minimo implicito di un elemento flex e' la sua parola piu' lunga, quindi un
   nome con dentro una parola lunghissima terrebbe la riga larga quanto quella e spingerebbe il
   numero fuori colonna - la stessa trappola di `1fr` scritta in CLAUDE.md, dall'altro lato. */
.record-what {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
  line-height: 1.3;
  color: var(--ink);
  font-weight: 700;
}
.record-tile .record-what {
  font-size: 17px;
  font-weight: 600;
  /* Una riga sola: il taglio e' quello che tiene le tessere alte uguale. `nowrap` va detto qui
     perche' `.record-what` nasce per la riga di un infortunio, dove il nome a capo ci sta. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* La riga sotto al nome: la data, piccola e a sinistra. In condensato maiuscolo e in grigio, come
   il conteggio sotto al nome di una scheda - e' la stessa riga, nello stesso posto. */
.record-sub {
  font-family: var(--cond);
  font-size: 11.5px;
  letter-spacing: 1.2px;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--mut2);
  /* Una riga anche qui, e non perche' il testo di oggi ci stia: perche' due righe su una tessera
     sola la fanno piu' alta delle altre, che e' proprio cio' che si sta tenendo fermo. Le parole
     sono corte apposta - la garanzia non puo' dipendere da quanto sono corte. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* La colonna che deve incolonnarsi: larga almeno quanto "140 kg", e allineata a destra perche' e'
   il bordo destro che deve cadere sempre nello stesso punto - non il sinistro. */
.record-time {
  flex: 0 0 auto;
  min-width: 62px;
  text-align: right;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -.2px;
}
/* Dove sta il numero, quando la riga non ha un numero: lo stato di un infortunio. Stessa colonna,
   stesso bordo destro, stessa riga sola - in condensato maiuscolo perche' e' un'etichetta e non una
   misura, e nel colore che le spetta (l'avviso finche' e' aperto). */
.record-state {
  flex: 0 0 auto;
  min-width: 62px;
  text-align: right;
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 1px;
  line-height: 1.3;
  text-transform: uppercase;
  color: var(--mut);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* La X sta accanto al numero e non dentro al bottone che apre: un bottone dentro a un bottone non
   e' markup valido, e un <form> dentro a un elemento interattivo e' la trappola gia' pagata con il
   "rimuovi esercizio" che salvava l'esercizio. */
.record-erase { flex: 0 0 auto; display: flex; align-items: center; }
/* Il segno a sinistra di una riga, quando la riga ne ha uno: l'icona di quello che e' («Oggi»: il
   check-up, la gara da raccontare) o la casella del giorno (.record-ico-day, una data segnata). UNA
   MISURA PER ELENCO, 40 punti: con segni di misure diverse i nomi non si incolonnano, e l'elenco si
   legge a scalini di lato invece che in altezza. Nasce con la home del mock 01 (26/09); dal taglio 5
   anche lo storico allenamenti e gli import lo portano (era un segno da 22 dentro al nome).

   Nell'accento del testo, sul fondo dei campi: segue le sette tavolozze e i due temi. `display:
   block` sull'<svg> per la trappola del suo spazio per le discendenti, che lo terrebbe mezzo
   punto sopra al centro. */
.record-ico {
  flex: 0 0 40px;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 12px;
  background: var(--field);
  color: var(--accent-text);
}
.record-ico .ico { display: block; width: 21px; height: 21px; }
/* La casella del giorno: il numero grande, il mese sotto in condensato, come il calendario del
   telefono. */
.record-ico-day {
  align-content: center;
  gap: 0;
  color: var(--ink);
  line-height: 1;
  /* Una tessera di metallo piatto con il fianco da due, ovunque ci sia una data (27/09: «estendilo a tutto»).
     Il giorno di oggi tiene la sua velatura (.event-row-today .record-ico-day, piu' specifica). */
  --solid: var(--field);
  background: var(--metal-face);
  box-shadow: var(--edge-lit), var(--lift-edge), var(--shadow-tile);
}
.record-ico-day > b { font-size: 16px; font-weight: 700; }
/* Con l'anno sotto (una data che non e' di quest'anno) le tre righe devono stare nei 40 punti: il
   giorno scende di un punto. */
.record-ico-day:has(> span + span) > b { font-size: 14px; }
.record-ico-day > span {
  font-family: var(--cond);
  font-size: 9.5px;
  font-weight: 650;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--mut);
}
/* Quello che si legge aprendo il foglio: quando, e cosa c'era scritto prima. */
.record-note {
  margin: 14px 0 0;
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--mut);
}
.record-declared {
  margin-left: 5px;
  font-family: var(--cond);
  font-size: 10.5px;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--accent-text);
}

/* Un bersaglio comodo ma non alto quanto un comando isolato: qui i due stanno in fila dentro a una
   riga di elenco, e 44 pixel per due farebbero righe alte il doppio del loro contenuto. A quindici
   pixel l'icona era un segno che si indovinava; a venti si vede. */
.record-tile .orb-x {
  width: 34px;
  height: 30px;
  min-width: 34px;
  min-height: 30px;
  flex: 0 0 34px;
}
.record-tile .orb-x .ico { width: 20px; height: 20px; }

/* ---------- le righe dell'agenda (taglio 3, mock 03, 26/09) ----------

   Le stesse righe della home: il segno da 40 punti, il nome su una riga, la riga piccola, il numero a
   destra, la X fuori dal collegamento. Qui sotto solo quello che l'agenda ha in piu'.

   La riga piccola in pezzi, come quella di una gara (.event-row-bits): una riga sola alta quanto una
   riga, dove ogni pezzo o ci sta intero o va a capo in una seconda riga che non si vede. Il primo -
   il giorno - ci sta sempre; lo stato viene subito dopo, perche' e' quello che conta; "scritto a
   mano", i minuti e l'ora cedono per primi. Il punto che separa lo scrive il foglio di stile sul pezzo
   che separa, cosi' se ne va con lui invece di pendere. Misurato a 360 punti. */
.agenda-row-sub {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  height: 1.4em;
  overflow: hidden;
}
.agenda-row-sub > * { flex: none; }
.agenda-row-sub > * + *:not(.sr-only)::before { content: "\00b7\00a0"; margin-left: .35em; }
/* Una riga che si apre toccandola e' un'etichetta (le sedute fuori settimana: la riga sceglie il
   radio del suo pannello), e le etichette dei moduli sono maiuscole e spaziate: qui no. */
.agenda-row > label.record-open { text-transform: none; letter-spacing: normal; }
/* Le righe che portano altrove (i piani, le abitudini, chiedere una settimana): nessuna freccia a
   destra, come il mock la disegna, e il nome un punto piu' piccolo. Misurato a 360 punti: dentro la
   carta al nome restavano 186 punti con la freccia, e «Chiedi una settimana a Hybrx» ne chiede 220 a
   17 - una richiesta scritta ("il bottone deve rimanere cosi'") tagliata con i puntini. Senza la
   freccia e a 16 ne chiede 207 su 218. La riga e' la tessera intera, e si tocca tutta. */
.agenda-links .record-what { font-size: 16px; }
/* La sagoma di una riga nell'accento del testo, come la home: anche quella di un allenamento
   generico, che per conto suo prende la tinta del secondo accento (.ico-training) - con volt nel
   chiaro, quasi bianco su bianco. Una regola per l'agenda, lo storico (un'attivita' «Altro» ha il
   segno generico), gli import (taglio 5) e le righe dell'account (`.body-row`: «Che atleta sei» e
   «Allenamenti dal telefono» erano una casella vuota su chiaro con volt, verifiche del taglio 9). */
.agenda-list .record-ico .ico,
.history-tile .record-ico .ico,
.job-row .record-ico .ico,
.record-tile.body-row .record-ico .ico { --ico-tint: var(--accent-text); color: var(--ico-tint); }
/* Come e' finita una seduta, nel colore che le spetta: fatta e' una rassicurazione, saltata un
   fatto, "non registrata" l'unica su cui l'atleta deve fare qualcosa - --danger-ink e non --danger,
   una spinta e non un errore. «Proposta in attesa» nell'accento: e' quello che aspetta. */
.agenda-state-done { color: var(--ok); }
.agenda-state-missed { color: var(--danger-ink); }
.agenda-state-skipped { color: var(--mut2); }
.agenda-state-on { color: var(--accent-text); }
/* LO STATO IN CODA ALLA RIGA PICCOLA, come «Modifica» nella riga di una gara (.event-row-end): fatta,
   saltata, non registrata. Stava in una colonna sua a destra del nome, e a 360 punti la colonna si
   prendeva il nome - «Forza…» su «Forza A — spinta» (verifiche del 26/09). A destra resta il numero
   dove c'e', e la X. Il resto della riga piccola cede prima di lui: lo stato non si taglia. */
.agenda-row-line { display: flex; align-items: baseline; gap: .8em; }
.agenda-row-line > .agenda-row-sub { flex: 0 1 auto; min-width: 0; }
.agenda-row-end { flex: none; margin-left: auto; }
/* Il pannello di una seduta fuori settimana si apre dentro la sua riga, sotto, a tutta larghezza:
   e' la riga che si apre, non una seconda tessera (come la correzione di una gara, .event-row). */
.agenda-row { flex-wrap: wrap; }
/* Col pannello aperto la X della riga se ne va: due X una sopra l'altra, una che elimina e una che
   chiude, sono due segni uguali con due significati (verifiche del 26/09). Resta quella che chiude, e
   «Elimina» e' nella fila dei comandi del pannello. Senza :has() restano tutte e due, come prima. */
.agenda-row:has(> .agenda-manage-toggle:checked) > .record-erase { display: none; }
.agenda-row > .agenda-manage-toggle:checked + .agenda-manage-body { flex: 1 0 calc(100% - 24px); margin: 0 12px 12px; }
/* La X del pannello e' un segno da 44 anche dentro a una riga: la regola delle X delle righe
   (.record-tile .orb-x, 34 per 30) la raggiungerebbe. */
.agenda-sheet-head > .orb-x { width: 44px; height: 44px; min-width: 44px; min-height: 44px; flex: 0 0 44px; margin: 0; }

.agenda-empty { margin: 0 0 12px; }
/* Le tre frasi su da dove viene la regola, in cima al foglio delle abitudini: sopra ai campi che la
   cambiano. */
.agenda-habits-now { margin: 0 0 8px; font-size: 14px; line-height: 1.5; color: var(--ink-2); }

/* ---------- lo storico, l'attivita' e l'importazione (taglio 5, mock 09, 12, 13 e 26, 26/09) ----------

   Le righe dello storico allenamenti e degli import sono le righe della casa: il margine sul
   collegamento (la regola del gruppo, piu' su), il segno da 40, il nome, la riga piccola, la cifra a
   destra. Qui solo quello che hanno in piu'. */

/* I COMANDI DELLO STORICO IN UNA COLONNA SORELLA DEL COLLEGAMENTO, come la X di una data e di una
   seduta dell'agenda. Condividi resta sulla riga («rimetti l'icona anche nello storico allenamenti»),
   la X anche, contro il mock che li porta nel dettaglio. Ognuno prende 44 punti di larghezza e TUTTA
   L'ALTEZZA DELLA RIGA: alti 44 su una riga di 67, le fasce di undici punti sopra e sotto non
   prendevano il dito (verifica nel browser del 26/09, D1). Era 34 per 30 l'uno.

   NESSUN POSTO MORTO, E LA CIFRA NELLO STESSO PUNTO SU OGNI RIGA. Una seduta di palestra ha due
   comandi, un'attivita' importata uno solo, e senza script condividi non si disegna. La colonna era
   larga 88 su ogni riga, e dove un comando mancava il suo quadrato non rispondeva al dito; senza script
   era vuota e morta, e il nome si tagliava per lei. Ora il posto di un comando che manca lo prende un
   altro:
   - con lo script la colonna e' di 88, tenuta a 72 dai margini negativi (a sinistra il bersaglio di
     condividi copre il margine del collegamento e finisce dove finisce la cifra; a destra quello della
     X esce di sei punti oltre il bordo della tessera, come la X di una data). Senza la X condividi e'
     largo tutta la colonna, con il segno dov'e' sulle altre righe; senza condividi (una seduta ancora
     aperta) la colonna e' la X, e il collegamento prende il resto con il suo margine;
   - senza script la colonna e' la X o niente, e il collegamento prende il posto che manca: il nome ha
     44 punti in piu'.
   Stringere la colonna solo dove un comando manca darebbe al nome 44 punti su quelle righe e porterebbe
   la loro cifra 44 punti piu' in la' delle altre: provato, le cifre a zig-zag, contro «i bordi destri
   devono stampare lo stesso numero su ogni riga». TheHistoryTakesAFingerTest fa il conto per i quattro
   tipi di riga, con e senza script. NIENTE VELO: il collegamento non passa sotto ai comandi. Il nome
   cede con i puntini, e aprendo la riga il nome e' intero nel titolo della pagina. */
.history-tools {
  flex: 0 0 88px;
  align-self: stretch;
  display: flex;
  align-items: stretch;
  justify-content: flex-end;
  margin: 0 -6px 0 -10px;
}
/* LA CIFRA, CONDIVIDI E LA X PIU' A SINISTRA, lontani dal bordo della riga (Luca, 27/09: «Sposta km icona
   condividi x piu a sinistra!!! Non devono toccare il bordo esterno»): otto punti verso l'interno, come
   sulla carta «Ultima sessione», con translate - l'impaginazione e il nome non cambiano. */
.history-tile > .record-open > .record-time,
.history-tile > .record-open > .history-open,
.history-tile > .history-tools { translate: -8px 0; }
/* E il collegamento stringe i suoi spazi, per la riga piccola: sei punti fra il segno, il nome e la
   cifra invece di otto, dieci a sinistra invece di dodici. */
.record-tile.history-tile > .record-open { gap: 6px; padding-left: 10px; }
.record-tile.history-tile .history-tools .orb-x {
  width: 44px;
  height: auto;
  min-width: 44px;
  min-height: 44px;
  flex: 0 0 44px;
  margin: 0;
}
/* Senza la X, condividi prende anche il suo posto, con il segno dove sta sulle altre righe. */
.record-tile.history-tile.history-no-x .history-tools .history-share { flex-basis: 88px; width: 88px; padding-right: 44px; }
/* E la sua tessera (la materia dei segni) sta sotto al segno, nei primi 44: centrata negli 88 era una
   tessera vuota accanto al segno (27/09). */
.record-tile.history-tile.history-no-x .history-tools .history-share::before { right: 44px; }
/* Senza condividi la colonna e' la X, e il collegamento prende il resto; senza niente, tutto. */
.history-tile.history-no-share > .history-tools { flex-basis: 44px; }
.record-tile.history-tile.history-no-share > .record-open { padding-right: 54px; }
.history-tile.history-no-share.history-no-x > .history-tools { display: none; }
.record-tile.history-tile.history-no-share.history-no-x > .record-open { padding-right: 82px; }
/* La cartolina e' uno script: senza, «condividi» e' un bottone che non fa niente, e non si disegna; la
   colonna e' la X o niente. Un antenato nel selettore: `button.orb-x` pesa 0-1-1 e rimetterebbe il suo
   display. */
@media (scripting: none) {
  .history-tools .history-share { display: none; }
  .history-tile .history-tools { flex-basis: 44px; }
  .history-tile.history-no-x > .history-tools { display: none; }
  .record-tile.history-tile.history-no-share > .record-open { padding-right: 10px; }
  .record-tile.history-tile.history-no-x > .record-open,
  .record-tile.history-tile.history-no-share.history-no-x > .record-open { padding-right: 38px; }
}

/* ---------- la carta dell'ultima sessione (27/09, mock A) ----------

   «A con aggiunta dell'icona in foto come collegamento ai grafici e dettagli. Ordine: condividi,
   grafici, x» (Luca, 27/09). In cima a ogni allenamento una riga della casa, come quelle dello
   storico: la sagoma, il nome, la riga piccola con l'ora e l'origine, e i tre comandi in una colonna
   SORELLA del collegamento. Al posto di titolo, badge, «Vedi dettagli attivita'», «Elimina» e della
   riga della data: le loro regole (.last-session-open, .last-session-actions, .last-session-when,
   a.session-title-link, il condividi da 34) sono andate con loro.

   IL MARGINE SUL COLLEGAMENTO, non sulla tessera: la sagoma, il nome e la riga piccola sono un
   bersaglio solo, alto quanto la riga. OGNI COMANDO E' LARGO 44 E ALTO QUANTO LA RIGA, come nello
   storico: alti 44 su una riga di 67 lasciavano due fasce morte. Qui non c'e' una cifra da tenere in
   colonna, quindi la colonna e' larga quanto quello che ha: tre comandi, o due dove condividi non si
   disegna (un allenamento senza durata ne' distanza, e senza script), e il nome prende il resto.
   TheLastSessionTakesAFingerTest fa il conto dalla cascata, in cima e nella piega, con e senza script.

   IL NOME NON SI TAGLIA A 360, per nessuna disciplina: misurato il 27/09, la riga e' larga 290 e al
   nome restano 130 punti con tre comandi, 174 senza script (due). Nel corpo 16, «Altro allenamento»
   ne chiede 127,7, «Trail and hiking» 111,4, «Trail e trekking» 108,3; nel 17 delle righe dello storico
   «Altro allenamento» ne chiedeva 135,7, e con la casella da 40 attorno alla sagoma ne restavano 108.
   Quindi: il corpo 16 (come le righe dell'agenda che portano altrove), niente casella, sei punti fra
   la sagoma e il nome e dieci davanti (come lo storico), e la colonna dei comandi che rientra di sei
   punti per lato - a sinistra copre il margine del collegamento, a destra la X esce di sei oltre il
   bordo della tessera, come la X di una data e quella dello storico. Il segno di condividi resta a
   dodici punti dalla fine del nome. */
.record-tile.last-session-row {
  padding: 0;
  gap: 0;
  margin-top: 12px;
}
.record-tile.last-session-row > .record-open {
  align-self: stretch;
  gap: 6px;
  padding: 12px 0 12px 10px;
}
.record-tile.last-session-row .record-what { font-size: 16px; }
/* UN ALLENAMENTO DALL'ALTRO: lo stacco, e niente filo. Era «un filo e un po' d'aria» fra due blocchi
   e sopra al primo dentro alla piega («Sistema la spaziatura, non deve sovrapporsi alla scheda sopra»:
   due allenamenti nello stesso pomeriggio sono il caso normale). Dal 27/09 ogni blocco comincia con la
   sua riga incorniciata, che dice gia' dove comincia: un filo sopra a una cornice erano due righe, e
   sotto alla piega un filo, trentatre punti vuoti e la riga. Il primo blocco nella piega sta sotto
   alla riga-piega con il solo margine della sua riga. */
.last-session-block + .last-session-block { margin-top: 18px; }
.last-session-ico .ico { width: 22px; height: 22px; }
/* La riga piccola in pezzi che non cedono, come quella di una gara o dell'agenda: una riga alta una
   riga, e quello che non ci sta va a capo dove non si vede. Il punto lo scrive il foglio sul pezzo che
   separa. L'origine e' GRIGIA, come la X: «Sulla carta X è origine grigie» (Luca, 27/09). Nel mock era
   nell'accento, e la carta l'aveva presa cosi'. */
.last-session-sub {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  height: 1.4em;
}
.last-session-sub > * { flex: none; }
.last-session-source { color: var(--mut); }
.last-session-source::before { content: "\00b7\00a0"; margin-left: .35em; color: var(--mut2); }

.last-session-tools {
  flex: 0 0 auto;
  align-self: stretch;
  display: flex;
  align-items: stretch;
  margin: 0 -6px;
}
/* LE TESSERE DENTRO AL BORDO (Luca, 27/09, su una foto: «Sposta i bottoni leggermente a destra, escono dal
   bordo»). La colonna rientra di sei punti per lato, come nello storico, cosi' che il nome abbia i suoi
   130 punti a 360: a destra la X esce di sei oltre il bordo della riga, e con le icone su tessera (27/09)
   quella della X ci cadeva sopra. Si sposta il bottone intero - tessera e icona insieme, «ovviamente sposta
   anche le icone dei bottoni» - di sei punti verso l'interno, tutti e tre, con `translate`, che non cambia
   l'impaginazione: restano alla stessa distanza fra loro e il nome non perde niente. */
/* E un po' piu' piccole, e un po' piu' dentro: «Rendi i bottoni leggermente di poco più piccoli, sono ancora
   troppo attaccati al bordo destro» - tessera da 32 invece di 36 (dal 27/09 sera per tutte le icone, nella
   regola comune), otto punti invece di sei. */
.last-session-tools .orb-x { translate: -8px 0; }
.last-session-tools > .session-delete {
  display: flex;
  align-items: stretch;
  margin: 0;
}
.record-tile.last-session-row .last-session-tools .orb-x {
  width: 44px;
  height: auto;
  min-width: 44px;
  min-height: 44px;
  flex: 0 0 44px;
  margin: 0;
}
/* I grafici sono una porta, come condividi: nell'accento da leggere, anche sotto al dito (.orb-x:hover
   lo porterebbe al riempimento, che sul chiaro con volt non si vede). */
.last-session-tools .last-session-charts,
.last-session-tools .last-session-charts:hover { color: var(--accent-text); }
/* La cartolina e' uno script: senza, condividi non si disegna, e il nome prende il suo posto. */
@media (scripting: none) {
  .last-session-tools .session-share { display: none; }
}

/* LA PIEGA DEL GIORNO PRIMA E' UNA RIGA: sopra, piccolo, «Il giorno prima»; sotto il giorno e quanti
   allenamenti; una freccia sola in fondo, quella delle pieghe (la disegna ::after nel gruppo delle
   pieghe di testo), che gira aperta. Era «› ALTRI 1 gio 24 set ⌄», due frecce: «non mi piace "altri"
   perche' di fianco c'e' la data con un altro simbolo espandi».

   NIENTE BINARIO: dentro ci sono righe della stessa carta, e i sedici punti del rientro erano i punti
   del nome a 360 (come «e altri N» dei pasti). */
.last-session-more { margin-top: 14px; padding-top: 2px; border-top: 1px solid var(--line-soft); }
.last-session-more > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 56px;
  padding: 6px 0;
  color: var(--ink);
  cursor: pointer;
  list-style: none;
}
.last-session-fold {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  overflow: hidden;
}
.last-session-fold-label {
  font-family: var(--cond);
  font-size: 11.5px;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut2);
}
/* Il giorno e il conteggio: due pezzi che non cedono, e a 360 il conteggio va a capo intero
   («Mercoledì 23 settembre · 2 allenamenti» chiede circa 280 punti e ne ha 255). IL PUNTO LO SCRIVE IL
   FOGLIO, nello spazio prima del conteggio: la riga sta 1,2em a sinistra della colonna, ogni pezzo ha
   1,2em di margine, e il punto sta in quel margine - accanto al giorno sulla stessa riga, fuori dalla
   colonna (che taglia) quando il conteggio comincia la riga sua. Non pende e non apre una riga. */
.last-session-fold-day {
  display: flex;
  flex-wrap: wrap;
  margin-left: -1.2em;
  font-size: 15px;
  font-weight: 700;
  line-height: 1.3;
}
.last-session-fold-day > * { flex: none; margin-left: 1.2em; }
.last-session-fold-count::before {
  content: "\00b7";
  display: inline-block;
  width: 1.2em;
  margin-left: -1.2em;
  text-align: center;
}
.last-session-more > summary::after { color: var(--accent-text); margin-right: 14px; }

/* Il «+» sotto la testata dello storico: la stessa scatola della home, alta 44 (sulla home e' 37, in
   una carta: in DA-FARE §23). E' un collegamento, quindi niente sottolineatura. */
.history-commands { margin: 0 0 16px; }
.history-commands .manual-entry { margin-top: 0; }
.history-commands .manual-entry-open { min-height: 44px; box-sizing: border-box; }
.manual-entry > a.manual-entry-open,
.manual-entry > a.manual-entry-open:hover { text-decoration: none; }

/* La frase di una pagina vuota o oltre la fine, con la sua porta sotto. */
.history-empty,
.history-page-empty { margin: 0; }
.history-empty a,
.history-page-empty a { display: flex; align-items: center; min-height: 44px; color: var(--accent-text); }

/* «Più recenti» e «Più vecchi» erano 56 per 20: un bersaglio trasparente li porta a 44 d'altezza,
   senza cambiare niente del disegno (e vale anche per gli storici di gare, record e infortuni, che
   usano lo stesso pager). */
.history-pager a { position: relative; }
.history-pager a::after { content: ""; position: absolute; inset: -12px -8px; }

/* «Elimina attività» in fondo alla pagina di un'attivita', fuori da una carta. */
.activity-delete { margin: 4px 0 8px; }

/* Il record sotto il titolo di un'attivita': la corona con la parola e la frase intera, nell'accento
   da leggere (dopo le verifiche del 26/09: «si legge aprendo l'allenamento» era scritto in tre posti,
   e la pagina non lo mostrava). Il punto che separa la frase lo scrive il foglio di stile. */
.page-top .activity-record {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px 6px;
  margin: 8px 0 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--accent-text);
}
.activity-record .ico { display: block; width: 16px; height: 16px; }
.activity-record-word { font-family: var(--cond); letter-spacing: 1.1px; text-transform: uppercase; }
.activity-record-what::before { content: "\00b7\00a0"; }

/* L'AREA DA TOCCARE DI /import: l'etichetta del campo dei file (.magic-fill-drop, la carta della foto
   di /plans/new, che non cambia), in colonna, con il segno, la frase e la riga sotto. Il tratteggio
   e il segno in --accent-text: con volt nel chiaro l'accento pieno e' un filo giallo su bianco. */
.import-form { margin: 0 0 20px; }
/* Un <label>, e le etichette dei moduli sono maiuscole, condensate e con un margine loro: l'area non e'
   un'etichetta di campo, e lo annulla (la trappola di `label { margin }` scritta in CLAUDE.md). */
.magic-fill-drop.import-drop {
  flex-direction: column;
  gap: 6px;
  margin: 0;
  font-family: inherit;
  letter-spacing: normal;
  text-transform: none;
  padding: 22px 18px 20px;
  border: 1.5px dashed var(--accent-text);
  border-radius: 18px;
  background: var(--accent-soft);
  color: var(--ink);
}
.import-drop-ico {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  margin-bottom: 4px;
  border-radius: 14px;
  background: var(--field);
  color: var(--accent-text);
}
.import-drop-ico .ico { display: block; width: 24px; height: 24px; }
.import-drop-title { font-size: 17px; font-weight: 600; }
.import-drop-hint { font-size: 13px; font-weight: 400; line-height: 1.45; color: var(--mut); }
/* Senza script il campo nativo si vede dentro all'area: e' l'unico modo di sapere quali file si sono
   scelti (lo dice lo script, sotto). Solo qui: la carta della foto di /plans/new resta com'e'. */
@media (scripting: none) {
  .import-drop input[type="file"] {
    position: static;
    width: auto;
    max-width: 100%;
    height: auto;
    margin-top: 8px;
    overflow: visible;
    clip: auto;
  }
}
.import-kept {
  display: flex;
  gap: 8px;
  margin: 12px 2px 16px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--mut);
}
.import-kept .ico { flex: 0 0 16px; width: 16px; height: 16px; margin-top: 2px; color: var(--accent-text); }

/* GLI ESITI DI UN CARICAMENTO, in cima: il nome del file e, in coda, quello che e' successo al
   caricamento, nella forma e nei colori della riga dello stato degli import - «Caricato», «Già
   importato» quieto, «Non caricato» con il perche' sotto. Erano pastiglie, e «IN CODA» restava li'
   mentre sotto lo stato cambiava (verifica nel browser del 26/09, D4). Il nome va a capo: non c'e' un
   foglio che lo mostri intero. */
.upload-results { list-style: none; padding: 0; margin: 0 0 16px; font-size: 14px; }
.upload-results li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 10px;
  padding: 7px 0;
}
.upload-name { flex: 1 1 0; min-width: 0; overflow-wrap: anywhere; }
.upload-outcome {
  flex: none;
  font-family: var(--cond);
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: 1.2px;
  text-transform: uppercase;
}
/* «Caricato» nell'inchiostro e non nel verde di «Importata»: e' una ricevuta, e un file caricato puo' ancora
   non riuscire - lo dice lo stato vero, sotto. */
.upload-outcome-queued { color: var(--ink-2); }
.upload-outcome-duplicate { color: var(--mut); }
.upload-outcome-rejected { color: var(--danger-ink); }
.upload-reason { flex: 1 0 100%; margin: 2px 0 0; font-size: 13px; line-height: 1.45; color: var(--mut); }

/* LE RIGHE DEGLI IMPORT. Il nome del file VA A CAPO, e anche la riga piccola se non ci sta: qui non c'e'
   un foglio che li mostri interi, e la regola della casa e' che senza il foglio si manda a capo. Lo
   stato in coda alla riga piccola, nel colore che gli spetta; l'errore sotto, a tutta larghezza. Una
   riga senza attivita' non si tocca, e non lo fa credere. */
.job-row { flex-wrap: wrap; }
.record-tile.job-row .record-what {
  font-size: 15.5px;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}
.job-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: .8em;
  white-space: normal;
}
.job-line > .job-state { flex: none; margin-left: auto; }
.job-state-pending { color: var(--mut); }
.job-state-running,
.job-state-open { color: var(--accent-text); }
.job-state-completed { color: var(--ok); }
.job-state-failed { color: var(--danger-ink); }
/* Nessun job nasce piu' DUPLICATE (un doppione e' un esito del caricamento), ma una riga di prima puo'
   esserci finche' il conteggio di S-162 J12 non e' fatto: quieta, come un'attesa. */
.job-state-duplicate { color: var(--mut2); }
.job-row > div.record-open { cursor: default; }
.job-row > .job-error {
  flex: 1 0 calc(100% - 24px);
  margin: -6px 12px 12px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--mut);
}

/* ---------- il foglio «Nuova seduta» (mock 04) ----------

   Le tre discipline con la sagoma sopra la parola, come nel mock: tasti grandi per una scelta da un
   tocco. `margin: 0` con due classi, perche' `.programme-setup label` (una classe e un elemento)
   spingerebbe giu' le pastiglie di dieci punti; `display: block` sull'<svg> per lo spazio delle
   discendenti che lo terrebbe sopra al centro. */
.agenda-new-sports .programme-pill {
  flex-direction: column;
  gap: 6px;
  min-height: 72px;
  margin: 0;
  padding: 10px 6px 8px;
  border-radius: 18px;
}
.agenda-new-sports .programme-pill .ico { display: block; width: 24px; height: 24px; }
/* I giorni, quattro e tre come .programme-days-off, in due righe: il giorno corto e il numero.
   minmax(0, 1fr) e non 1fr: con due righe per pastiglia la parola piu' larga terrebbe larghe tutte
   le colonne. */
.agenda-new-days { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.agenda-new-days .programme-pill {
  flex-direction: column;
  gap: 4px;
  min-height: 56px;
  margin: 0;
  padding: 8px 4px;
  border-radius: 16px;
}
.agenda-new-days i {
  font-style: normal;
  font-family: var(--cond);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--mut);
}
.agenda-new-days .programme-pill:has(input:checked) i { color: inherit; }
.agenda-new-days b { font-size: 18px; line-height: 1; }
/* Senza script le pastiglie non ci sono - nessuno le legherebbe al campo data, e il campo basta - e
   l'etichetta del campo dice «Giorno» invece di «Un altro giorno». */
.agenda-new-plain { display: none; }
@media (scripting: none) {
  .agenda-new-days,
  .agenda-new-other { display: none; }
  .agenda-new-plain { display: inline; }
}

/* ---------- la carta di un'area, chiusa ----------

   "Tutte le card dei record devono essere compresse di default con icona per espanderle e vedere i
   dettagli." Con diciotto esercizi in elenco la pagina era un muro di numeri, e quello che si cerca
   aprendola e' una cosa sola: quale area guardare.

   Il riassunto e' la testata della carta piu' il segno delle pieghe - lo stesso di ogni altra piega
   dell'applicazione - quindi qui non si disegna un comando nuovo, si dice solo come si impagina. */
.record-card > summary {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 38px;
  list-style: none;
  cursor: pointer;
  /* Il riassunto di una piega e' scritto in condensato maiuscolo nell'accento, e va bene per una
     riga che dice "leggi tutto". Qui il riassunto e' la TESTATA della carta, e una testata in
     maiuscolo accentato e' un muro di titoli colorati - il colore in questa applicazione sta sulla
     sagoma e non sulle parole, che e' scritto nella regola di .card-title-row. Quindi si rimette
     quello che la piega aveva tolto, e lo si rimette per NOME: una regola che vince e non ridichiara
     cio' che si riprende lascia in piedi tutto il resto, ed e' la trappola gia' pagata con la
     stella del calendario. */
  font-family: inherit;
  font-size: inherit;
  letter-spacing: normal;
  text-transform: none;
  text-align: left;
  color: inherit;
}
.record-card > summary::-webkit-details-marker { display: none; }
.record-card > summary > .card-title-row { flex: 1 1 auto; min-width: 0; }
/* Quanti ce ne sono dentro: e' l'unica cosa che una carta chiusa puo' dire di se' oltre al nome, ed
   e' anche quella che dice se vale la pena aprirla. */
.record-card-count {
  flex: 0 0 auto;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1px;
  color: var(--mut);
}
/* E NEANCHE AL TOCCO. "Toccando la disciplina cambia colore e prende accento, NO: nome disciplina
   sempre nero o bianco, icona va bene colorata." La riga sopra rimette il colore che la piega aveva
   tolto, ma `.card-fold > summary:hover` lo ritoglieva - e su un telefono `:hover` non e' un
   passaggio del mouse: resta addosso dopo il tocco, quindi il titolo restava acceso finche' non si
   toccava qualcos'altro. Il colore qui sta sulla sagoma e non sulle parole, aperta o chiusa, toccata
   o no. */
.record-card > summary:hover { color: inherit; }
.record-card[open] > summary { margin-bottom: 6px; }

/* ---------- il foglio di un record ----------

   E' il foglio del check-up, con le sue classi: testata ferma in alto, salva fermo in basso, e in
   mezzo l'unica cosa che scorre. Qui si dice soltanto quanto respira dentro - tutto il resto
   (l'animazione dal basso, il raggio in cima, lo sfondo inerte) lo porta .checkin-dialog. */
.record-sheet-body {
  min-height: 0;
  padding: 14px 20px 18px;
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* Il comando che apre il foglio vuoto: la stessa scatola di prima, che pero' adesso e' un bottone e
   non un <summary>. UN ANTENATO NEL SELETTORE, per la ragione scritta sopra la tessera. */
.manual-entry > button.manual-entry-open {
  width: 100%;
  margin: 0;
  border: 0;
  background: none;
  box-shadow: none;
}

/* ---------- un tempo si batte in tre caselle ----------
   "Con discipline di velocita' deve chiedere il tuo tempo e tre sezioni apposite h:m:s." Tre
   caselle non hanno un formato da indovinare: in una sola, "42:07" e "1:42" sono due cose diverse
   a seconda di come le si legge, e chi le scrive non sa quale delle due il server capira'.
   L'unita' di ogni casella e' il suo segnaposto (fragments/time-box): "h, min, sec non a destra
   ma dentro", e la cifra scritta la sostituisce. L'etichetta vera e' l'aria-label, perche' una
   "h" letta ad alta voce non dice "ore". */
.record-hms {
  display: flex;
  align-items: center;
  gap: 6px;
}
.record-hms input { flex: 1 1 0; min-width: 0; text-align: center; }
/* Le frecce del campo numerico, su un desktop, coprono la meta' destra di un segnaposto centrato:
   "min" diventa "m". Come per input.session-box. */
.time-box::-webkit-outer-spin-button,
.time-box::-webkit-inner-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}
.time-box { appearance: textfield; }

/* ---------- lo storico degli infortuni ----------

   E' la tessera dei record con dentro un'altra cosa: stessa lista, stessa tessera, stessa X, stesso
   foglio che si apre dal basso. Quello che cambia sono tre dettagli. */

/* "Ancora aperto" nel colore dell'avviso e non dell'accento: e' lo stato che il coach guarda, non
   una decorazione. Guarito torna al grigio di tutto il resto, perche' un infortunio passato non ha
   piu' niente da dire. */
.injury-open { color: var(--warn); }
.injury-healed .injury-name { color: var(--mut); }
/* La nota: una frase, e nel foglio c'e' lo spazio per leggerla intera. In elenco stava su due
   righe e faceva una tessera piu' alta delle altre. */
.injury-note { margin: 12px 0 0; font-size: 12.5px; line-height: 1.4; }
/* I due gesti nella barra del salva: "segna risolto" pieno, e sotto di lui - quando c'e' qualcosa
   da disfare - il collegamento che lo riapre. */
.injury-resolve .checkin-save-row { display: grid; gap: 6px; justify-items: center; }

/* ---------- le righe di infortuni e record (taglio 8, mock 20 e 21, 27/09) ----------

   Righe della casa, come i pasti di /diet: la X alta quanto la riga e larga 44, sorella del
   collegamento, e il collegamento senza margine a destra - fra la cifra e il segno della X c'e' gia'
   il vuoto del suo bersaglio. Ogni punto della riga risponde, e la colonna della X e' larga uguale su
   ogni riga: i bordi destri delle cifre cadono nello stesso punto (Luca, 26/09: *«Cifre allineate»*). */
.record-tile.injury-row > .record-open,
.record-tile.pr-row > .record-open { padding-right: 0; }
.record-tile.injury-row > .record-erase,
.record-tile.pr-row > .record-erase { align-self: stretch; }
.record-tile.injury-row > .record-erase .orb-x,
.record-tile.pr-row > .record-erase .orb-x {
  width: 44px;
  height: auto;
  min-width: 44px;
  min-height: 44px;
  flex: 0 0 44px;
  margin: 0;
}
/* La X nella testa del foglio di un infortunio e di un record: il foglio sta dentro alla sua riga, e
   `.record-tile .orb-x` - la X di una riga di prima, 34 per 30 - prendeva anche lei. Senza script e' un
   collegamento, e l'unico modo di chiudere il foglio: 44 per 44, come la X del foglio di una gara (verifica
   col dito del taglio 8, 27/09: misurata 34×31 su tutte le righe). */
.record-tile.injury-row .checkin-dialog-head > .orb-x,
.record-tile.pr-row .checkin-dialog-head > .orb-x {
  width: 44px;
  height: 44px;
  min-width: 44px;
  min-height: 44px;
  flex: 0 0 44px;
  margin: 0;
}
/* La carta delle gare e degli infortuni tiene le righe a 6 punti dal bordo (il raggio della carta meno
   quello della riga, come i pasti di /diet): a 360 la riga piccola di un infortunio guarito - «28 MAG →
   17 LUG» e «guarito» - chiede 181 punti, e con il rientro di 18 la testa della riga ne aveva 162: le
   date finivano coi puntini. Il pager ritrova il suo rientro. */
.card.history-rows { padding: 6px; }
.history-rows > .history-pager { margin: 10px 12px 6px; }

/* La riga piccola di un infortunio in due pezzi: le date, che cedono, e in coda lo stato, che non cede
   - «ancora aperto» e' quello che il coach guarda. */
.injury-sub { display: flex; align-items: baseline; gap: .8em; }
.injury-when { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.injury-state { flex: none; margin-left: auto; }
.injury-healed .injury-state { color: var(--mut2); }
/* La cifra: i giorni di un aperto nel colore dell'avviso, quelli di un guarito quieti. */
.injury-open-row .injury-days { color: var(--warn); }
.injury-healed .injury-days { color: var(--mut); }

/* SENZA SCRIPT un foglio che il server manda aperto e' un pannello nel flusso (checkin.css), e qui sta
   dentro alla sua riga: la riga va a capo e il pannello la prende intera, sotto il collegamento e la X.
   La riga di una gara va gia' a capo (.event-row). */
@media (scripting: none) {
  .record-tile.injury-row,
  .record-tile.pr-row { flex-wrap: wrap; }
  .record-tile.race-row > dialog,
  .record-tile.injury-row > dialog,
  .record-tile.pr-row > dialog { flex: 1 0 100%; }
}

/*
  ---------- gambe pesanti prima di una corsa dura (HeavyLegs) ----------

  Il riquadro in cima alla seduta. Le righe sono righe di elenco dentro a una carta, quindi un filo
  e non una faccia (la regola in CLAUDE.md): nome su una riga tagliato con i puntini, sotto la riga
  piccola in condensato che dice com'e' adesso, e sotto i comandi. I comandi vanno a capo fra loro,
  il nome no.
*/
.heavy-legs-title {
  margin: 2px 0 6px;
  font-size: 20px;
}
.heavy-legs-lead {
  margin: 0 0 12px;
  font-size: 14px;
}
.heavy-legs-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.heavy-legs-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px;
  border: 1px solid var(--line-soft);
  border-radius: 12px;
}
.heavy-legs-what {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.heavy-legs-name {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-weight: 700;
}
.heavy-legs-state {
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--mut2);
}
.heavy-legs-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.heavy-legs-form {
  display: flex;
  margin: 0;
}
/* Tolto per oggi: la carta resta, spenta come un esercizio finito, e senza serie da spuntare. */
.session-exercise.is-left-out > .session-exercise-head { opacity: .6; }

/* ---------- corpo e cibo (taglio 6, mock 14, 14b, 15, 15b e 18, 26/09) ----------

   /weight, /diet con il monitor del cibo, la porta del cibo sulla home. Le righe sono quelle della casa
   (il gruppo `.record-tile.body-row` e `.meal-row` sta nelle regole comuni, piu' su); qui solo quello che
   hanno in piu'. Colori solo con i gettoni, e su fondo chiaro l'accento da leggere. */

/* Il titolo di una sezione della pagina, fuori dalle carte: «I pasti di oggi», «Il piano del
   nutrizionista», «Impostazioni». La misura di un titolo di carta, perche' e' lo stesso grado. */
.page-section-h {
  margin: 26px 0 10px;
  font-size: 19px;
  line-height: 1.25;
  font-weight: 700;
}

/* Il comando della pagina sotto il titolo, a tutta larghezza e alto quanto un pollice: «Registra il
   peso», «Aggiungi un pasto». Un antenato nel selettore: `.btn` da sola perde contro le regole dei
   bottoni che vengono dopo. */
.app-shell > .weight-new,
.app-shell > .meal-new {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 48px;
  margin: 0 0 16px;
}
.app-shell > .nutrition-unavailable { margin: 0 0 16px; }

/* ---------- /weight: la carta di oggi ---------- */
.weight-eyebrow {
  margin: 0 0 6px;
  font-family: var(--cond);
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--mut2);
}
.weight-today .weight-now-value { font-size: 44px; }
/* I due cambi come pastiglie, che vanno a capo se non ci stanno. Il bordo e il fondo nel gemello da
   leggere dell'accento: --accent-line e --accent-soft con volt nel chiaro sono un bordo giallo pallido
   su bianco, e la pastiglia non si vedeva (critica della pagina, E5). */
.weight-changes {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}
.weight-change {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 32px;
  padding: 0 12px 0 9px;
  border: 1px solid color-mix(in srgb, var(--accent-text) 45%, transparent);
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent-text) 8%, transparent);
  font-size: 13.5px;
  color: var(--ink-2);
  white-space: nowrap;
}
.weight-change > .ico { display: block; width: 17px; height: 17px; color: var(--accent-text); }
.weight-change > b { font-weight: 600; color: var(--accent-text); }
.weight-change-steady { padding-left: 12px; }
.weight-change-steady > b { color: var(--ink-2); }
.weight-too-soon { margin: 10px 0 0; }
.weight-target {
  margin: 16px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--line-soft);
  font-size: 15px;
  color: var(--ink-2);
}

/* ---------- /weight: il foglio «Pesati oggi» ---------- */
.weight-sheet-row {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 8px;
  margin: 6px 0 4px;
}
/* Il numero grande, al centro: e' l'unica cosa del foglio. input + classe, per battere la regola
   globale dei campi (la trappola di casa). Almeno 16 punti, o iOS ingrandisce la pagina. */
input.weight-sheet-field {
  width: 7ch;
  min-height: 56px;
  padding: 6px 10px;
  font-size: 34px;
  font-weight: 700;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.weight-sheet-unit { font-family: var(--cond); font-size: 18px; color: var(--mut); }
.weight-last { margin: 10px 0 0; text-align: center; font-size: 13px; }

/* ---------- le righe del corpo e del cibo ---------- */
/* A destra lo stato o il numero di una riga di impostazioni: «60,0 kg», «Ogni giorno», «Spento». */
.record-tile.body-row .record-state { min-width: 44px; max-width: 42%; }

/* Il segno del cibo nelle righe nell'accento del testo: .ico-intake da' il terzo colore, e con volt nel
   chiaro e' quasi bianco su bianco (critica della pagina, E8). La regola della casa per una sagoma
   generica. */
.nutrition-door .record-ico .ico,
.meal-row .record-ico .ico { --ico-tint: var(--accent-text); color: var(--ico-tint); }

/* ---------- /diet: la pagina del cibo ---------- */
.nutrition-page > .card + .card { margin-top: 14px; }
/* La carta del coach e' una carta sua, e il commento perde quello che porta come piede di una carta:
   il filo e lo spazio sopra (critica della pagina, E12). Il contenitore nel selettore, non un fratello. */
.nutrition-coach > .box-comment {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
.nutrition-meals .meal-advice { margin: 0 0 12px; }
/* Le carte con le righe di /diet tengono le tessere a 6 punti dal bordo, non a 18: il doppio rientro
   (18 della carta, poi il filo e i 12 del collegamento) era lo spazio che mancava al nome di un pasto,
   «Pane e mar…» a 360 punti con le cifre in una colonna sola (verifica del browser, D2, 26/09). Sei e non
   zero: il raggio della carta (18) meno sei e' quello della tessera (12), e gli angoli restano paralleli. */
.card.meal-card,
.card.nutrition-more { padding: 6px; }
.meal-card .meal-more > summary { padding: 0 12px; }
.nutrition-meals-empty { margin: 0; }
.nutrition-more { margin-top: 16px; }

/* La riga di un pasto: la riga piccola in pezzi - l'ora non cede, la fonte e «riusato» ci stanno
   intere o non ci stanno - con il punto che li separa scritto sul pezzo che separa. */
.meal-row .record-sub {
  display: flex;
  flex-wrap: wrap;
  column-gap: .35em;
  height: 1.4em;
  overflow: hidden;
}
.meal-row .record-sub > * { flex: none; }
.meal-row .meal-source::before { content: "\00b7\00a0"; }
.meal-row .record-time > small,
.injury-row .record-time > small {
  margin-left: 2px;
  font-family: var(--cond);
  font-size: 11px;
  font-weight: 600;
  color: var(--mut);
}
/* La X alta quanto la riga e larga 44: ogni punto della riga risponde - la regola dello storico
   (taglio 5). Il collegamento non tiene margine a destra: fra la cifra e il segno della X c'e' gia' il
   vuoto del suo bersaglio, e i 4 punti erano del nome (D2). */
.record-tile.meal-row > .record-open { padding-right: 0; }
.record-tile.meal-row > .meal-erase { align-self: stretch; }
.record-tile.meal-row > .meal-erase .orb-x {
  width: 44px;
  height: auto;
  min-width: 44px;
  min-height: 44px;
  flex: 0 0 44px;
  margin: 0;
}
/* «e altri N», sotto il pasto piu' nuovo. Senza il binario delle pieghe (26/09): dentro ci sono righe della
   stessa lista, e il binario le spostava di 16 punti a destra - i segni e i nomi fuori colonna rispetto al
   pasto sopra, misurato a 360 (35 contro 51). Una misura per elenco. */
.meal-card .meal-more { margin-top: 6px; }
.meal-card .meal-more .meal-list { margin-top: 10px; }

.meal-help { margin: 10px 0 0; font-size: 13px; }
.meal-form .nutrition-cost { margin-top: 8px; }

/* Il piano del nutrizionista: il comando della scansione a tutta larghezza sotto il messaggio. */
.diet-professional .diet-scan-open {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 48px;
  margin-top: 14px;
}
.diet-scan-unavailable { margin: 12px 0 0; }
.diet-plan-section .diet-empty { margin: 12px 0 0; }

/* ---------- «+ Registra un pasto», in fondo al monitor sulla home (27/09) ----------

   Com'era prima del taglio 6 - una piega in fondo alla carta delle cifre, che si apre sul posto con la
   riga macchina fotografica, casella, invio - con i segni della casa di oggi (Luca, 27/09: «al massimo
   migliora un po la grafica basandoti sulle nuove grafiche»): la riga alta 44 e tutta bersaglio, sotto un
   filo come le righe delle barre sopra; il + disegnato con le due barre del gruppo di casa, nell'accento,
   pulito e senza il bollo pieno che aveva (i segni «mai un bollo pieno»), che aprendo diventa un −; la
   macchina fotografica e l'invio con la regola comune dei bottoni (metallo bombato, sei pixel), l'invio pieno
   nell'accento. Sulla home il + della riga «Alimentazione» non c'e' piu': era il secondo modo della stessa
   cosa. */
.meal-log {
  margin-top: 6px;
  border-top: 1px solid var(--line-soft);
}
.meal-log > summary {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  cursor: pointer;
  list-style: none;
  font-family: var(--cond);
  font-size: 13px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink);
}
.meal-log > summary::-webkit-details-marker { display: none; }
.meal-log > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Venti di scatola, come i segni; le barre sono quelle del gruppo «Il "+" dentro a un cerchio: disegnato,
   non scritto». Aperta, la barra verticale se ne va: il segno dice cosa fa toccarlo di nuovo. */
.meal-log-plus { display: block; flex: 0 0 20px; width: 20px; height: 20px; color: var(--accent-text); }
.meal-log[open] .meal-log-plus::after { display: none; }
/* Il corpo: la riga, poi «Analizza foto» quando c'e' una foto, il come e il costo. Sotto, lo spazio per il
   fianco da quattro dei bottoni della riga. */
.meal-log-body { padding: 2px 0 8px; }
.meal-log .meal-analyse { margin: 12px 0 0; }
.meal-log .meal-advice { margin: 4px 0 10px; }
/* L'invio: tondo, 44, come quello della chat. La materia - la faccia bombata, il taglio, il fianco - e il
   pieno nell'accento vengono dalla regola comune dei bottoni (button[class], button.meal-send). */
.meal-send {
  flex: 0 0 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  color: var(--on-accent);
  cursor: pointer;
}
.meal-send svg { display: block; }
.meal-send:hover { filter: brightness(1.08); }

/* ---------- l'account: profilo, sincronizzazioni, i tuoi dati, le pagine d'errore (taglio 9, 27/09) ----------

   Le righe sono quelle di /weight (`.record-tile.body-row`), i fogli quelli del check-up: qui c'e' solo
   quello che le pagine dell'account hanno di loro. Nessun colore scritto a mano: l'accento, il pericolo e
   l'avviso vengono dai gettoni, e seguono le sette tavolozze nei due temi. */

/* La testata del profilo: la foto (o l'iniziale) a sinistra del nome, come nel mock 27. Da 56, in una
   colonna sua: il titolo e l'email le stanno accanto, e il segno della foto nell'angolo. */
.page-top.profile-top { min-height: 56px; padding-left: 70px; }
.page-top.profile-top > .profile-avatar {
  position: absolute;
  top: 0;
  left: 0;
  width: 56px;
  height: 56px;
  font-size: 24px;
}
.page-top.profile-top > .page-title { font-size: 26px; overflow-wrap: anywhere; }

/* La colonna di destra di una riga del profilo: il valore, o dove manca, «Manca» nell'avviso - una colonna
   vuota accanto a una di numeri si legge come un difetto di allineamento. La freccia di una riga che porta
   su un'altra pagina e' nella stessa colonna, larga uguale. */
/* Le carte di righe dell'account tengono le tessere a sei punti, come /diet e lo storico: con i dodici della
   carta e i dodici del collegamento, a 360 «Peso e altezza» e «Frequenza massima» finivano nei puntini. */
.card.profile-rows { padding: 6px; }
/* Tutte le righe alte uguale: una con la riga piccola era alta 67,2, una con il solo nome 66 (il segno da 40
   e i margini). Il collegamento tiene l'altezza della piu' alta, e il nome solo sta nel mezzo. */
.card.profile-rows .record-tile.body-row > .record-open { min-height: 66px; }
.record-tile.body-row .record-state.is-missing { color: var(--warn); }
.record-tile.body-row .record-state.record-go { min-width: 20px; font-size: 20px; line-height: 1; color: var(--mut2); }
.record-tile.body-row .record-state.record-name { text-transform: none; letter-spacing: 0; font-family: inherit; font-size: 14px; }
.record-tile .record-what .field-req { margin-left: 3px; }

/* La riga rossa, «Ricomincia da zero» ed «Elimina l'account»: il nome e il segno nel colore del pericolo,
   e nient'altro - una riga come le altre, che dice che cosa fa. */
.record-tile.is-danger .record-what,
.record-tile.is-danger .record-ico { color: var(--danger-ink); }
/* E la sua sagoma, che la regola delle righe dell'account porterebbe nell'accento. */
.record-tile.body-row.is-danger .record-ico .ico { --ico-tint: var(--danger-ink); }

/* «Esci»: un modulo vero con il bottone a forma di riga. Il collegamento delle altre righe e' figlio
   diretto della tessera; qui c'e' il modulo in mezzo, e il bottone perde la faccia metallica che
   `button[class]` da' a ogni bottone (la trappola di CLAUDE.md dal lato dei bottoni: un antenato nel
   selettore). */
.record-tile > .record-open-form { flex: 1 1 0; min-width: 0; display: flex; margin: 0; }
.record-tile > .record-open-form > button.record-open {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 12px 10px 12px 12px;
  min-height: 66px;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

/* Le scelte di un foglio del profilo sono le pastiglie della casa (`.programme-pill`, quelle dei toni del
   coach); in colonna dove sono poche e con i nomi lunghi («Non l'ho deciso»), in fila per il sesso. */
.programme-kinds.profile-picks { flex-direction: column; align-items: stretch; }
.programme-kinds.profile-picks > .programme-pill { justify-content: flex-start; padding-left: 16px; }
.programme-kinds.profile-sex > .programme-pill { flex: 1 1 0; }
.profile-sheet-note { margin: 8px 0 14px; font-size: 13px; line-height: 1.45; }

/* /connections (mock 25): quello che il telefono ha letto - due caselle della casa (`.tiles`), sotto le sue
   righe - poi la via a mano e la riga rossa, ognuna nella sua carta, e la riga su di chi sono i dati, con il
   segno nell'accento come nel mock. Staccate di quanto si staccano le sezioni della pagina. */
.health-read-rows,
.connections-erase { margin-top: 14px; }
.health-privacy-line {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  margin: 14px 4px 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--mut);
}
.health-privacy-line > .ico { flex: 0 0 18px; width: 18px; height: 18px; margin-top: 1px; color: var(--accent-text); }
/* «Come li usiamo»: in coda alla frase, alto una riga di testo, e a 360 andava a capo in due pezzi da 19 punti -
   il dito al centro della scatola cadeva fra i due. Una parola sola, e uno pseudo-elemento trasparente da 44
   che non cambia la frase (verifiche del taglio 9, 27/09). */
.health-privacy-line a { position: relative; white-space: nowrap; color: var(--accent-text); }
.health-privacy-line a::after {
  content: "";
  position: absolute;
  left: -6px;
  right: -6px;
  top: 50%;
  height: 44px;
  margin-top: -22px;
}

/* /privacy (mock 28): l'abbonamento e' un segnaposto, e la carta lo dice con il disegno oltre che con le
   parole - un bordo tratteggiato e nessuna faccia metallica: non e' una tessera da premere, e dentro non
   c'e' niente da premere (T9-D10, TheSubscriptionDoesNotLookLikeItWorksTest). La riga rossa si stacca come
   quella di /connections. */
.card.soon-card { border: 1px dashed var(--line); background: var(--field); box-shadow: none; }
.soon-card-top { display: flex; align-items: center; justify-content: space-between; margin: 0; }
.soon-card-ico { display: inline-flex; color: var(--accent-text); }
.soon-card-chip {
  padding: 3px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--cond);
  font-size: 12px;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--mut);
}
.soon-card h3 { margin: 12px 0 0; font-size: 19px; }
.soon-card p.muted { margin: 6px 0 0; font-size: 14px; line-height: 1.45; }
/* Le caselle «Passi» e «Notti» di quello che il telefono ha letto: la sagoma nell'accento da leggere, come le
   righe. Nell'accento pieno, su chiaro con volt era circa 1,2 a 1 (verifiche del taglio 9, 27/09). */
.health-tiles .tile-label > .ico { --ico-tint: var(--accent-text); }
/* Il piano di chi guarda (T9-D10): una riga sotto il filo, il nome a sinistra e il valore a destra. */
.soon-card-plan {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin: 14px 0 0;
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
  font-size: 14px;
  color: var(--mut);
}
.soon-card-plan b { color: var(--ink); font-weight: 700; }
.privacy-erase { margin-top: 22px; }

/* Le pagine d'errore (mock 30): il numero sbiadito nell'accento, il segno a cavallo del numero, la frase, e i
   due modi di ripartire. Il numero e' disegno (aria-hidden): quello che si legge e' il titolo. Il 500 non ha
   il numero, e il segno non ha niente da scavalcare (`is-alone`). */
.error-page { position: relative; margin: 72px 0 0; text-align: center; }
.error-page-number {
  margin: 0;
  font-size: 116px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -1px;
  color: color-mix(in srgb, var(--accent-text) 16%, transparent);
}
.error-page-sign {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  margin: -34px auto 0;
  border-radius: 20px;
  background: var(--bg);
  box-shadow: inset 0 0 0 1px var(--accent-line), 0 0 0 8px var(--bg);
  color: var(--accent-text);
}
.error-page-sign.is-alone { margin-top: 0; }
.error-page-sign::before { content: ""; position: absolute; inset: 0; border-radius: inherit; background: var(--accent-soft); }
.error-page-sign .ico { position: relative; display: block; width: 30px; height: 30px; }
.error-page h1,
.error-page h2 { margin: 22px 0 0; font-size: 26px; font-weight: 700; }
.error-page-line { margin: 8px auto 0; max-width: 330px; font-size: 15px; line-height: 1.45; color: var(--mut); }
.error-page .btn.error-page-home {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 26px;
  min-height: 54px;
  font-size: 16px;
}
.error-page .btn.error-page-home .ico { width: 20px; height: 20px; }
/* Una label e non un collegamento: apre il cassetto con la sua casella, anche senza script. Il modulo
   globale darebbe a una label il maiuscolo spaziato e il margine di un campo: qui e' una riga di testo nel
   colore dei comandi, alta 44. */
label.error-page-menu {
  display: flex;
  align-items: center;
  justify-content: center;
  width: max-content;
  min-height: 44px;
  margin: 10px auto 0;
  padding: 0 12px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--accent-text);
  cursor: pointer;
}
