/* ==========================================================================
   Un ecommerce, un ecosistema — landing
   Vanilla CSS. Every value resolves through a token in tokens.css.
   Selectors are kept to a single class to avoid specificity collisions.
   ========================================================================== */

/* --- Reset ---------------------------------------------------------------- */

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

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--rail-h) + var(--space-lg));
}

body {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--c-bg);
  color: var(--c-fg);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img,
svg {
  display: block;
  max-width: 100%;
}

ul,
ol {
  list-style: none;
  padding: 0;
}

a {
  color: inherit;
}

main {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
}

/* On a viewport taller than the page, the slack has to be absorbed by the ink
   region — otherwise the paper background shows through between the last dark
   section and the dark footer. */
.zone-fill {
  flex: 1 1 auto;
}

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

.skip {
  position: absolute;
  left: var(--space-md);
  top: var(--space-md);
  z-index: 20;
  padding: var(--space-xs) var(--space-md);
  background: var(--c-ink);
  color: var(--c-paper);
  font-size: var(--text-label);
  text-decoration: none;
  transform: translateY(-200%);
  transition: transform var(--dur-fast) var(--ease-out);
}

.skip:focus-visible {
  transform: none;
}

/* --- The shell: one column of margin either side -------------------------
   The page margin is derived from the grid rather than declared: one column
   plus one gutter. `100%` here is the viewport, since every .shell is a
   block child of a full-width parent. No max-width — the grid is what
   scales, and it scales continuously instead of stepping at breakpoints. */

.shell {
  --col: calc((100% - (var(--grid-cols) - 1) * var(--gutter)) / var(--grid-cols));
  width: 100%;
  /* Su mobile il margine di griglia mangia troppa larghezza — a 560px sarebbe
     47px per lato — e lì la griglia a 12 colonne non ha comunque nulla da
     allineare, perché è tutto in colonna singola. Sotto il primo breakpoint è
     un valore piatto della scala; da lì in su torna a essere la colonna 1. */
  padding-inline: var(--space-lg);
}

.section {
  padding-block: var(--space-4xl);
}

/* The quietest voice on the page. Sentence case, no tracking: letterspaced
   capitals here are what read as classified ads. */
.label {
  display: block;
  font-size: var(--text-label);
  font-weight: 500;
  line-height: var(--leading-normal);
  color: var(--c-fg-3);
}

/* --- Azione ------------------------------------------------------------- */

/* L'unico elemento della pagina che è un oggetto e non del testo. In un
   impianto tutto tipografico l'azione principale deve poter essere riconosciuta
   di colpo, e il perimetro è il minimo che lo ottiene: filetto pieno, lo stesso
   peso e lo stesso colore della linea di terra. A riposo non ha riempimento —
   la pagina non ha superfici piene da nessuna parte.

   L'hover è il ribaltamento paper→ink, cioè il gesto più forte del sistema
   applicato a un componente invece che a una sezione: fondo di primo piano,
   testo di fondo. Passa dagli alias semantici, quindi dentro `.zone-ink` si
   inverte da sé senza una riga in più.

   Corpo `--text-h3`, peso 500: lo stesso registro di `.section-label`, della
   riga della data e dei titoli degli interventi. Sta sopra il testo dell'inciso
   che lo precede e sotto l'occhiello, che è esattamente il suo posto nella
   gerarchia. Il perimetro è il solo segnale: nessuna sottolineatura in più. */
.button {
  align-self: start;
  display: inline-flex;
  align-items: center;
  /* Un'azione prende un tempo in più della prosa: i 24px di gap dell'inciso
     più 8px qui fanno 32, che è `--space-xl` sulla scala. */
  margin-top: var(--space-xs);
  padding: var(--space-sm) var(--space-xl);
  border: var(--hairline) solid var(--c-line-strong);
  color: var(--c-bg);
  background-color: var(--c-fg);
  font-size: var(--text-h3);
  font-weight: 500;
  line-height: var(--leading-snug);
  letter-spacing: var(--track-title);
  text-decoration: none;
  transition: background-color var(--dur-base) var(--ease-out),
    color var(--dur-base) var(--ease-out);
}

.button:hover {
  background-color: transparent;
  color: var(--c-fg);
}

/* --- Rail (top bar) ----------------------------------------------------- */

.rail {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--c-paper);
  border-bottom: var(--hairline) solid var(--c-line);
}

.rail-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-lg);
  min-height: var(--rail-h);
}

.rail-title {
  min-width: 0;
  font-size: var(--text-label);
  font-weight: 500;
  color: var(--c-fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* La data non cede spazio — è `nowrap` — quindi in una barra stretta è il
   titolo a pagarla, in ellissi. Sotto il primo breakpoint passa alla forma
   numerica: da 130px a 58px, che è quanto basta perché il titolo entri intero
   già da ~360px. Il `datetime` sul `<time>` tiene la data leggibile a
   macchina in entrambe le forme. */
.rail-meta {
  font-size: var(--text-label);
  color: var(--c-fg-3);
  white-space: nowrap;
}

.rail-meta-long {
  display: none;
}

/* --- Hero ---------------------------------------------------------------- */

.hero {
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
  padding-top: var(--space-6xl);
  padding-bottom: var(--space-5xl);
}

.hero-title {
  font-size: var(--text-display);
  font-weight: 500;
  line-height: var(--leading-tight);
  letter-spacing: var(--track-display);
}

.hero-title-line {
  display: block;
  overflow: hidden;
}

.hero-title-inner {
  display: block;
}

/* The ground rule and what sits under it move together, 24px apart. */
.hero-close {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
}

/* The ground line: what follows is what the storefront does not show. It runs
   the whole content width. */
.hero-ground {
  height: var(--hairline);
  background: var(--c-line-strong);
  transform-origin: left center;
}

/* Lead left, date right, sitting on the same baseline. The date lives here
   rather than above the title: the full-bleed line opens the room for it,
   and one statement of the date in the hero is enough. */
.hero-lead-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-lg);
}

.hero-lead {
  max-width: var(--measure-prose);
  font-size: var(--text-lead-hero);
  font-weight: 400;
  line-height: var(--leading-snug);
  letter-spacing: var(--track-title);
  color: var(--c-fg);
  text-wrap: balance;
}

/* No `nowrap` here: the string is ~350px and would push a narrow viewport into
   horizontal scroll. The slashes are the only places it may break — the date
   and the time range are held together with non-breaking spaces instead. */
.hero-date {
  font-size: var(--text-h3);
  font-weight: 700;
  line-height: var(--leading-snug);
  letter-spacing: var(--track-title);
  color: var(--c-fg);
}

/* --- Split: presentation beside the programme ---------------------------
   Below the desktop breakpoint the two stack; from there up they take their
   column spans and the whole thing snaps onto the page grid. */

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3xl);
  border-top: var(--hairline) solid var(--c-line);
  padding-top: var(--space-2xl);
}

.split-aside {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
  min-width: 0;
}

.split-main {
  display: flex;
  flex-direction: column;
  gap: var(--space-xl);
  min-width: 0;
}

.intro-lead {
  max-width: var(--measure-prose);
  font-size: var(--text-lead-hero);
  line-height: var(--leading-snug);
  letter-spacing: var(--track-title);
  color: var(--c-fg);
  text-wrap: pretty;
}

.intro-text {
  max-width: var(--measure-prose);
  font-size: var(--text-small);
  line-height: var(--leading-loose);
  color: var(--c-fg-2);
}

/* Testa di sezione, non didascalia: stesso corpo del titolo di un intervento.
   Una sola classe per il programma e per i tre gruppi del roster — sono la
   stessa cosa, e tenerli allineati è ciò che li distingue dai role. */
.section-label {
  font-size: var(--text-h3);
  font-weight: 500;
  line-height: var(--leading-snug);
  letter-spacing: var(--track-title);
  color: var(--c-fg-3);
}

/* --- Agenda -------------------------------------------------------------
   One column, always: the programme is a chronology and splitting it into
   halves forced a break the day does not have.

   The row is its own five-column grid. Because the programme column is five
   page columns wide and the gutter is the same, those five sub-columns land
   exactly on the page grid: the time is column 1, the entry is columns 2–5. */

.agenda {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
}

.agenda-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2xs) var(--gutter);
}

/* A short tick between two consecutive entries — one column wide, aligned to
   the time column, a mark rather than a table border. Painted as a background
   so no empty list item is needed, and the first entry gets none. Kept lighter
   than ink: a minor separator must not outweigh the section rule above it. */
.agenda-item + .agenda-item {
  padding-top: var(--space-lg);
  background-image: linear-gradient(var(--c-fg-3), var(--c-fg-3));
  background-repeat: no-repeat;
  background-size: 100% var(--hairline);
  background-position: left top;
}

.agenda-time {
  font-variant-numeric: lining-nums tabular-nums;
  font-size: var(--text-small);
  letter-spacing: 0.04em;
  color: var(--c-fg);
  white-space: nowrap;
}

.agenda-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  min-width: 0;
}

/* Track and credit share one line above the title: two short fields at the
   two ends of the entry, with the title running full width beneath them. */
.agenda-meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-xs) var(--space-md);
}

.agenda-track {
  font-size: var(--text-label);
  font-weight: 500;
  color: var(--c-fg-3);
}

.agenda-by {
  max-width: var(--measure-credit);
  font-size: var(--text-small);
  color: var(--c-fg-2);
  text-align: end;
}

.agenda-title {
  max-width: var(--measure-title);
  font-size: var(--text-h3);
  font-weight: 500;
  line-height: var(--leading-snug);
  letter-spacing: var(--track-title);
}

/* Breaks are not sessions: they stay subordinate typographically, and share the
   same rhythm as the entries — the ticks do the separating. */
.agenda-item-break .agenda-time,
.agenda-item-break .agenda-title {
  font-size: var(--text-small);
  font-weight: 400;
  letter-spacing: 0;
  color: var(--c-fg-3);
}

.agenda-tba {
  font-size: var(--text-label);
  color: var(--c-fg-3);
}

/* --- Ink zone ----------------------------------------------------------- */

.zone-ink {
  background: var(--c-bg);
  color: var(--c-fg);
}

/* --- Participants ------------------------------------------------------- */

/* Unbranded means no logos, so the names have to be the mark themselves —
   set large, they are the third and last beat after the display and the
   small dense programme. */
.roster {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xl);
}

.roster-group {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-sm) var(--space-xl);
}

/* In colonna sotto il primo breakpoint: a quel corpo due nomi non stanno mai
   davvero su una riga, e il separatore fra loro non ha più niente da separare
   — l'a capo lo fa già. Sparendo, la barra si porta via anche le due
   spaziature su cui sedeva, perché in flex un elemento nascosto non lascia
   gap dietro di sé. */
.roster-names {
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
}

.roster-sep {
  display: none;
  font-size: var(--text-roster);
  font-weight: 500;
  line-height: var(--leading-tight);
  color: var(--c-fg-3);
}

.roster-entry {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

.roster-name {
  font-size: var(--text-roster);
  font-weight: 500;
  line-height: var(--leading-tight);
  letter-spacing: var(--track-display);
}

/* A sinistra, sotto il nome. Sta nella stessa colonna dell'etichetta di
   sezione, quindi deve leggersi come un'altra cosa: quella è 21/500, questo è
   14/400 — un salto di corpo, non una sfumatura di peso. */
.roster-role {
  font-size: var(--text-label);
  font-weight: 400;
  color: var(--c-fg-3);
}

/* --- Footer ------------------------------------------------------------- */

.footer {
  margin-top: auto;
  padding-block: var(--space-xl);
  border-top: var(--hairline) solid var(--c-line);
}

.footer-inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-md);
}

/* The one thing in the footer that is not muted: full foreground against the
   two grey labels beside it, because it is how you answer the page without
   filling in a form. Underlined at rest — a link has to look like one — and
   hover moves colour only. Underline plus colour would be two signals for one
   intent; the underline follows via currentColor.

   Kept as plain type, no frame: `.button` in the aside is the loud action, this
   is the quiet one, and giving both a perimeter would set them competing. */
.footer-link {
  color: var(--c-fg);
  text-decoration: underline;
  text-decoration-thickness: var(--hairline);
  text-decoration-color: var(--c-fg-3);
  text-underline-offset: 0.3em;
  transition: color var(--dur-fast) var(--ease-out),
    text-decoration-color var(--dur-fast) var(--ease-out);
}

.footer-link:hover {
  text-decoration-color: currentColor;
}

/* --- Load + scroll reveal ----------------------------------------------- */

.reveal {
  opacity: 0;
  transform: translateY(1.25rem);
  transition: opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
}

.reveal-in {
  opacity: 1;
  transform: none;
}

.lift {
  transform: translateY(102%);
  transition: transform 900ms var(--ease-out);
}

.lift-in {
  transform: none;
}

.draw {
  transform: scaleX(0);
  transition: transform 900ms var(--ease-out);
}

.draw-in {
  transform: none;
}

/* --- Breakpoints -------------------------------------------------------- */

@media (min-width: 40rem) {
  /* Da qui il margine torna a essere la colonna 1 della griglia. */
  .shell {
    padding-inline: calc(var(--col) + var(--gutter));
  }

  /* Da qui la barra ha spazio per la data per esteso. */
  .rail-meta-long {
    display: inline;
  }

  .rail-meta-short {
    display: none;
  }

  /* Time and entry side by side.

     The time column is NOT a plain fraction of the grid. An orario is
     unbreakable, so a fraction narrower than the string does not shrink it —
     it lets it spill into the entry beside it. That is what happened from
     1024 up to about 1350, where the programme column divided into five gives
     sub-columns under 100px, and again in the 640–690 band.

     So the track is a column when a column is wide enough for the string, and
     the string's own width when it is not: `minmax(min-content, one column)`.
     Wherever it fits, the row is still exactly on the page grid. */
  .agenda-item {
    grid-template-columns:
      minmax(min-content, calc((100% - 4 * var(--gutter)) / 5))
      minmax(0, 1fr);
  }

  /* Raises the track's min-content floor, so the column never collapses onto
     the glyphs even while a fallback font is still swapping in. */
  .agenda-time {
    min-width: var(--time-col);
  }

  /* The same expression as the track, so the tick measures the time column
     exactly: on the grid where it fits, on the floor where it does not. */
  .agenda-item + .agenda-item {
    background-size: max(var(--time-col), calc((100% - 4 * var(--gutter)) / 5))
      var(--hairline);
  }

  /* Da qui i nomi tornano in riga e il separatore ha di nuovo un lavoro. */
  .roster-names {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-lg) var(--space-xl);
  }

  .roster-sep {
    display: block;
  }
}

@media (min-width: 64rem) {
  .hero {
    gap: var(--space-xl);
  }

  /* Ten content columns: the presentation takes four, the programme five,
     and the column between them is the gap. The section's own padding moves
     onto the two columns so their first lines can sit on a shared baseline. */
  .split {
    grid-template-columns: repeat(10, minmax(0, 1fr));
    column-gap: var(--gutter);
    align-items: baseline;
    padding-top: 0;
  }

  .split-aside {
    grid-column: 1 / span 4;
    /* Stays in view while the day scrolls past it. */
    position: sticky;
    top: calc(var(--rail-h) + var(--space-2xl));
    padding-block: var(--space-5xl);
  }

  .split-main {
    grid-column: 6 / span 5;
    padding-block: var(--space-5xl);
  }
}

/* --- Accessibility ------------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .reveal,
  .lift,
  .draw {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* --- Print: the programme should print as a clean one-pager ------------- */

@media print {
  .rail {
    display: none;
  }

  body {
    background: #fff;
    color: #000;
  }

  .zone-ink {
    --c-bg: #fff;
    --c-fg: #000;
    --c-fg-2: #333;
    --c-fg-3: #555;
    --c-line: #bbb;
    --c-line-strong: #000;
  }

  .section {
    padding-block: var(--space-lg);
  }

  /* Sticky positioning confuses paged media; the aside prints above the
     programme, in one column. */
  .split {
    display: block;
  }

  .split-aside {
    position: static;
    padding-block: 0;
    margin-bottom: var(--space-xl);
  }

  .split-main {
    padding-block: 0;
  }

  /* Su carta il perimetro non ha più niente da promettere: resta l'etichetta, e
     accanto l'indirizzo del form per esteso, che è il solo modo di raggiungerlo
     da una pagina stampata. */
  .button {
    margin-top: var(--space-md);
    padding: 0;
    border: 0;
  }

  .button::after {
    /* Spazio unificatore: quello normale in `content` viene collassato e
       l'etichetta finirebbe attaccata alla lineetta. */
    content: "\00a0— " attr(href);
    font-size: var(--text-small);
    font-weight: 400;
    color: #555;
  }

  .agenda-item {
    break-inside: avoid;
  }

  /* Browsers drop backgrounds when printing, which would take the ticks with
     them — on paper a plain rule does the same job. */
  .agenda-item + .agenda-item {
    padding-top: var(--space-sm);
    background-image: none;
    border-top: var(--hairline) solid #bbb;
  }
}
