/* ===== OptionWheel (React Bits, vanilla port) ===== */
.option-wheel {
  --ow-text-color: #a6a6a6;
  --ow-active-color: #ffffff;
  --ow-font-size: 3rem;
  --ow-inset: 80px;

  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  /* La mano, che e' quel che Luca preferisce vedere. C'era stato un
     passaggio ad all-scroll — il simbolo dello scorrimento — quando il
     trascinamento non funzionava bene; ora che funziona (si sfoglia mentre si
     tiene, si sceglie al rilascio: vedi onCommit in js/option-wheel.js) la
     mano dice la cosa giusta, perche' afferrare e' proprio quel che si fa. */
  cursor: grab;
  user-select: none;
  touch-action: none;
  outline: none;
}

.option-wheel--dragging {
  cursor: grabbing;
}

.option-wheel__item {
  position: absolute;
  top: 50%;
  left: var(--ow-inset);
  white-space: nowrap;
  font-size: var(--ow-font-size);
  line-height: 1;
  font-weight: 200;
  transform-origin: left center;
  cursor: pointer;
  will-change: transform, opacity, filter;
  color: color-mix(in srgb, var(--ow-active-color) calc(var(--ow-p, 0) * 100%), var(--ow-text-color));
}

.option-wheel--right .option-wheel__item {
  left: auto;
  right: var(--ow-inset);
  transform-origin: right center;
}

.option-wheel__item--selected {
  font-weight: 500;
}

/* ===== nav-rail: the wheel, vertically centred =====
   Fixed against the left edge so it stays put while the page scrolls. Hidden
   until JS confirms the wheel mounted (body.nav-wheel-ready), so the plain
   link row and the mobile hamburger stay as the no-JS fallback.

   Only the wheel is in the rail's flow, so `top:50%` centres the WHEEL. The
   audio chip used to be a flex child with a 36px gap, which added 80px to the
   top of the column and pushed the wheel ~40px below the viewport centre —
   that offset (plus the distance to the button) is what made the menu read as
   off-centre. It is now absolutely positioned inside the rail instead, so it
   costs the menu no vertical space at all. */
.nav-rail {
  display: none;
  position: fixed;
  left: 0;
  top: 50%;
  translate: 0 -50%;
  z-index: 90;
  flex-direction: column;
  align-items: flex-start;
}

/* ===== Audio chip: 3D HUD control =====
   Three stacked planes inside a shared perspective — a glow "socket" behind, a
   bevelled hex rim, and the raised face carrying the icon. js/hud-3d.js feeds
   --hud-rx / --hud-ry / --hud-z so the chip banks toward the pointer and sinks
   when pressed; with that file absent (or reduced-motion) the defaults below
   still render a static 3D chip. Sits inside the wheel's box but above it, in
   the empty margin column to the left of the labels. */
.audio-toggle {
  position: absolute;
  top: 2px;
  left: 22px;
  z-index: 2;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  color: var(--accent);
  perspective: 420px;
  -webkit-tap-highlight-color: transparent;
}

.hud-plate {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transform:
    rotateX(var(--hud-rx, 8deg))
    rotateY(var(--hud-ry, -14deg))
    translateZ(var(--hud-z, 0px));
}

.hud-plate__glow,
.hud-plate__edge,
.hud-plate__face {
  position: absolute;
  inset: 0;
  /* Hexagon: the HUD-panel silhouette, shared by all three planes so the
     bevel reads as one solid chip rather than three stacked shapes. */
  clip-path: polygon(50% 0%, 96% 26%, 96% 74%, 50% 100%, 4% 74%, 4% 26%);
}

/* Socket: the powered-up halo the chip floats above. */
.hud-plate__glow {
  transform: translateZ(-14px) scale(1.22);
  background: radial-gradient(circle at 50% 45%, rgba(219, 107, 43, 0.75), rgba(219, 107, 43, 0) 68%);
  opacity: 0.85;
  transition: opacity 0.45s var(--ease);
}

/* Bevelled rim: lit from the top-left, catching the accent along the bottom. */
.hud-plate__edge {
  transform: translateZ(0);
  background: linear-gradient(155deg,
    rgba(255, 255, 255, 0.55) 0%,
    rgba(255, 255, 255, 0.10) 38%,
    rgba(219, 107, 43, 0.65) 100%);
  transition: opacity 0.45s var(--ease);
}

/* Raised face: dark glass, inset just enough to leave the rim visible. */
.hud-plate__face {
  transform: translateZ(8px) scale(0.86);
  background:
    linear-gradient(155deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.01) 46%, rgba(0, 0, 0, 0.5)),
    rgba(10, 10, 10, 0.94);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Sound ON reads as a live equaliser rather than a speaker glyph — the bars
   only move while audio is actually unmuted, so the control states itself. */
.hud-eq {
  display: flex;
  align-items: center;
  gap: 2px;
  height: 15px;
}
.hud-eq i {
  display: block;
  width: 2px;
  height: 26%;
  border-radius: 2px;
  background: currentColor;
  box-shadow: 0 0 7px currentColor;
  animation: hud-eq 1.15s ease-in-out infinite;
}
.hud-eq i:nth-child(1) { animation-delay: -0.95s; }
.hud-eq i:nth-child(2) { animation-delay: -0.40s; }
.hud-eq i:nth-child(3) { animation-delay: -0.72s; }
.hud-eq i:nth-child(4) { animation-delay: -0.15s; }
.hud-eq i:nth-child(5) { animation-delay: -0.58s; }

@keyframes hud-eq {
  0%, 100% { height: 22%; }
  50%      { height: 96%; }
}

.hud-mute {
  display: none;
  width: 19px;
  height: 19px;
}

/* Muted: bars off, crossed speaker on, the whole chip powered down. */
.audio-toggle.is-muted { color: var(--text-40); }
.audio-toggle.is-muted .hud-eq { display: none; }
.audio-toggle.is-muted .hud-mute { display: block; }
.audio-toggle.is-muted .hud-plate__glow { opacity: 0; }
.audio-toggle.is-muted .hud-plate__edge { opacity: 0.45; }

.audio-toggle:hover { color: #ffb27a; }
.audio-toggle.is-muted:hover { color: var(--text); }

.audio-toggle:focus-visible { outline: none; }
.audio-toggle:focus-visible .hud-plate__edge {
  background: var(--accent);
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .hud-eq i { animation: none; height: 60%; }
}

.nav-wheel {
  /* Width follows the lane, and that is not cosmetic: the rail is fixed at
     z-index 90, so every pixel of this box is a pointer target sitting ON TOP
     of the page. At a flat 360px it swallowed clicks over ~120px of content on
     a 1280px laptop — an invisible drag surface across the left of every card.
     The lane is measured as "label ink + air", so the box is exactly wide
     enough to hold the labels it clips at.

     Height is generous on purpose: it only has to be tall enough for six rows
     at the largest configured font size. */
  width: var(--wheel-lane, 300px);
  height: 500px;
  /* No background: the dodge effect keeps content out of the labels' way, so the
     wheel can sit straight on the page with nothing boxing it in. */
  background: none;
}

.nav-wheel .option-wheel__item {
  letter-spacing: -0.01em;
}

.nav-wheel .option-wheel__item--selected {
  font-weight: 400;
}

@media (min-width: 981px) {
  body.nav-wheel-ready .nav-rail { display: flex; }
  body.nav-wheel-ready .nav-links { display: none; }

  /* The header is gone entirely on desktop, which frees the top of the page for
     the wheel. It stays in the markup as the no-JS fallback and as the mobile
     header, where the hamburger is still the navigation. */
  body.nav-wheel-ready .navbar { display: none; }

  /* ===== The wheel's lane =====
     One number, because two of them is how the layout ended up broken.

     --wheel-lane is how far from the LEFT EDGE OF THE VIEWPORT a block has to
     start in order to clear the wheel: the rail's 78px inset, plus the widest
     label's ink (~190px at the 2.4rem the wheel is configured with in
     js/main.js), plus a little air. js/nav-dodge.js reads the same value and
     will not push a block past it, so the static indent and the magnetic dodge
     now agree on where the wheel ends.

     They used not to. The indent reserved 170px while the dodge wanted 300, so
     on every laptop-width viewport the dodge shoved each block ~50-130px to the
     right and shrank it up to 6% to compensate — straight past the right edge
     of .scene-inner, which clips on overflow-x. That is what made the cards and
     the table look like they were walking off the page between 1280px and
     1512px. Reserve the real lane and there is nothing left to push.

     The subtraction is what keeps this from wasting space on a wide monitor:
     the container is centred and capped at 1280px, so once the free margin on
     its left is already wider than the lane, the indent collapses back to the
     normal 24px.

     The 300px here is only the value before js/main.js has measured anything;
     that file sizes the wheel for the viewport and then writes the real
     figure — label ink plus air — onto <body>, overriding this. */
  body.nav-wheel-ready {
    --wheel-lane: 300px;
  }

  /* The hero deliberately sits 40px INSIDE the lane: it is the one panel whose
     left column is meant to react to the wheel, so it starts just short of
     clear and lets js/nav-dodge.js cover the last stretch. Derived from the
     same lane as everything else, so the overlap stays 40px at every width
     instead of drifting as the wheel resizes. */
  body.nav-wheel-ready .hero {
    padding-left: max(24px, calc(var(--wheel-lane) - 40px - max(0px, (100vw - 1280px) / 2)));
    /* The 110px top padding existed to clear the fixed header; with the header
       gone the hero centres properly on its own. */
    padding-top: 60px;
  }

  body.nav-wheel-ready main section {
    padding-left: max(24px, calc(var(--wheel-lane) - max(0px, (100vw - 1280px) / 2)));
  }
}

/* ===== nav-wheel-bar: the wheel, at bar size =====
   The phone's navigation. Same component and same index as the fixed rail on
   desktop (js/main.js drives both from one call), shown three rows tall
   instead of six: the section you are on, and the step either side of it.

   Why this and not the hamburger it replaces: the page's whole movement is
   moving between six sections, so a menu listing those six sections was a
   second way to do what the swipe already does — and it could only say where
   the reader was once they had opened it. This says so at rest, and turns by
   itself as the scenes change, which is the part that makes it read as a
   position indicator rather than a control.

   Hidden above the breakpoint, where the rail is doing this job, and hidden
   until js/main.js confirms the wheel mounted, so the hamburger stays as the
   no-JS route. */
/* Il contenitore porta la misura; la ruota lo riempie e il bottone
   trasparente ci sta steso sopra. Prima la misura stava sulla ruota, ma un
   bottone in posizione assoluta ha bisogno di un genitore posizionato che
   sappia quanto e' grande — e dentro la ruota non poteva stare, perche'
   OptionWheel azzera il contenuto del suo contenitore quando si costruisce. */
.nav-wheel-trigger {
  display: none;
  position: relative;
  /* Wide enough for the longest label at this size (Benvenuto) without
     letting the box grow into the logo on a 360px screen.

     Scritta come variabile e non come valore, perche' la usa anche il chip
     dell'audio per sapere dove finisce la ruota. Un numero solo: due copie
     della stessa formula sono due cose da tenere allineate a mano, e prima o
     poi una resta indietro. */
  width: var(--nav-wheel-w);
  /* Three rows of --ow-font-size x spacing (0.95rem x 1.45 = ~22px), plus the
     cap height of the outer two, which the curve lifts slightly past the
     nominal row. Under this the rail clips the neighbours mid-letter. */
  height: 64px;
  flex-shrink: 0;
}

.nav-wheel-bar {
  position: relative;
  width: 100%;
  height: 100%;
}

/* Il bersaglio. Trasparente per scelta: l'indizio che si puo' premere non
   deve essere un disegno in piu' — la ruota e' gia' l'unica cosa in quella
   zona della barra, e gira da sola, che e' quanto di piu' evidente ci sia.

   Sborda dal riquadro della ruota: quei pochi pixel in piu' su ogni lato
   sono la differenza fra un tocco preso e un tocco mancato, e non costano
   niente perche' l'area e' invisibile. */
.nav-wheel-trigger__hit {
  position: absolute;
  inset: -6px -8px;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  /* iOS disegna un rettangolo grigio sopra tutto quel che si tocca: qui
     coprirebbe la ruota nell'istante esatto in cui il menu si apre. */
  -webkit-tap-highlight-color: transparent;
}

.nav-wheel-trigger__hit:focus-visible {
  outline: 1px solid var(--glass-border);
  outline-offset: 2px;
  border-radius: 8px;
}

@media (max-width: 980px) {
  body.nav-bar-wheel-ready .nav-wheel-trigger { display: block; }

  /* Nessun hamburger accanto alla ruota. E' stato provato e tolto: era il
     modo ovvio per dire "qui si apre un menu", ma aggiungeva un secondo
     simbolo di navigazione a fianco di una navigazione che c'e' gia' — e la
     ruota, che e' la cosa piu' riconoscibile del sito, finiva a fare da
     etichetta a un'icona generica.

     La ruota E' il comando: si preme lei. Il bersaglio e' il bottone
     trasparente steso sopra (.nav-wheel-trigger__hit), quindi la barra
     resta esattamente com'era a vedersi.

     Il pulsante a tre righe resta nel markup e resta nascosto: e' la
     navigazione di chi non ha JavaScript, o di chi non ha la ruota perche'
     lo script non e' arrivato. */
  body.nav-bar-wheel-ready .nav-toggle { display: none; }

  /* The bar is on screen permanently now rather than only at the top of a
     scroll, so it is worth what it costs and no more: the 18px band above and
     below the row was sized for a page you scrolled past, and here it is
     ~9% of a phone screen held open for good. */
  body.nav-bar-wheel-ready .nav-inner {
    padding: 8px 20px;
    gap: 12px;
  }

  /* La larghezza della ruota, dichiarata sul body: .nav-rail e
     .nav-wheel-trigger sono rami diversi dell'albero, e una variabile scritta
     sul secondo il primo non la eredita. Sul body la vedono entrambi. */
  body.nav-bar-wheel-ready {
    /* ===== Largo quanto la parola, non quanto lo schermo =====
       Era clamp(112px, 38vw, 168px): cresceva con lo schermo. Ma le voci
       hanno un corpo FISSO, e la piu' lunga ("Benvenuto") chiede 80px a
       qualunque larghezza — misurato a 320, 360, 375, 390 e 430. Quindi il
       riquadro avanzava da 42 a 83px di vuoto sul suo lato sinistro.

       Quel vuoto non si vedeva, ma si sentiva altrove: il chip dell'audio e'
       ancorato al BORDO del riquadro, non alle parole, e finiva percio' a
       mezzo schermo dalle scritte. Luca: "si vede al centro".

       Stringendo il riquadro alla parola, il chip lo segue da solo e si
       accosta alle voci. Le voci non si muovono di un pixel: sono allineate
       a DESTRA, e quello che cambia e' il bordo sinistro.

       Il margine e' abbondante di proposito: restano fra 16 e 32px oltre la
       parola piu' lunga, cioe' un quinto della sua larghezza. Serve per due
       cose che non si possono misurare da qui — il carattere reso da un
       iPhone vero, che differisce di frazioni di percento, e una sezione che
       un giorno prenda un nome piu' lungo. Se dovesse servirne di piu', il
       numero da alzare e' questo, e _verifica/test-barra-vicina.js dice
       subito quanto margine e' rimasto.

       Quel che NON si e' fatto, e la ragione: far entrare il chip dentro al
       riquadro, sovrapponendolo alla sua parte vuota. Sarebbe stato lo
       stesso risultato visivo, ma il riquadro e' il bersaglio che apre il
       menu, e sovrapporre un comando a un altro comando e' un rischio che
       qui non serviva correre. Stringendo, invece, il bersaglio resta tutto
       intero: solo piu' aderente a quel che mostra. */
    --nav-wheel-w: clamp(96px, 25vw, 112px);
  }

  /* Il nome resta a ogni larghezza, e vale la pena dire perche' per un po'
     non e' stato cosi': con l'hamburger accanto alla ruota i tre pezzi
     chiedevano 299px sui 280 disponibili a 320px, e a uscire dallo schermo
     era proprio il pulsante del menu. Il nome cedeva il posto per salvare la
     navigazione.

     Tolto l'hamburger, quel conto e' sparito: a 320px logo e ruota lasciano
     ancora 25px di aria in mezzo. Nascondere il nome sarebbe rimasto un
     rimedio senza piu' malattia — e a 320px apriva 122px di vuoto in mezzo
     alla barra. Verificato a 320, 360, 375, 390 e 430px. */

  /* Cintura di sicurezza per le misure che non ho previsto: se lo spazio
     manca lo stesso, a stringersi e' la ruota — che al peggio taglia una
     etichetta — mai a sparire dallo schermo, che vorrebbe dire restare senza
     modo di aprire il menu. */
  body.nav-bar-wheel-ready .nav-wheel-trigger {
    flex-shrink: 1;
    min-width: 92px;
  }

  /* Scene mode never scrolls the document, so .navbar.scrolled — which
     js/main.js sets from window.scrollY — can never fire. The bar sits over
     live panels the whole time and has to carry its own backdrop or the
     labels land on top of whatever the scene is showing. */
  body.scene-mode-ready.nav-bar-wheel-ready .navbar {
    background: rgba(0, 0, 0, 0.72);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-bottom-color: rgba(255, 255, 255, 0.08);
  }

  /* Labels are right-aligned against the bar's own padding, so the selected
     one lines up with the edge the eye is already following. */
  .nav-wheel-bar .option-wheel__item {
    font-size: var(--ow-font-size);
    letter-spacing: -0.01em;
  }

  /* ===== The audio chip, without the rail =====
     The chip lives inside .nav-rail in the markup because on desktop it sits
     in the empty margin beside the wheel. The rail itself has no place on a
     phone — but the control does, and moving it in the DOM would mean two
     buttons and two pieces of state for one mute.

     La colonna torna quindi come una scatola vuota, con la ruota dentro
     nascosta, spostata IN BARRA accanto al menu.

     Stava in fondo a sinistra, ed era una scelta ragionata: il pollice
     arriva prima in basso che in alto. Ma stava anche da solo, lontano da
     ogni altro comando, e i comandi di una pagina si cercano dove stanno gli
     altri comandi — cioe' in barra, dove c'e' gia' il menu.

     Ancorata a DESTRA e non a sinistra: `right` parte dal bordo, salta il
     margine della barra e la larghezza della ruota, e atterra nello spazio
     vuoto fra il logo e il menu. Cosi' segue la ruota quando questa si
     restringe, invece di inseguirla con un numero fisso.

     L'altezza e' quella della barra — che js/main.js misura e pubblica in
     --navbar-h — con il chip centrato dentro: nessuna coordinata verticale
     da riaggiustare quando la barra cambia misura, per esempio col telefono
     coricato. */
  body.nav-bar-wheel-ready .nav-rail {
    display: flex;
    align-items: center;
    justify-content: center;
    /* ===== Sopra la barra, non sotto =====
       Ecco perche' il chip "non si vedeva ancora" dopo essere stato
       ridisegnato: non era un problema di disegno. .nav-rail sta a z-index 90
       e .navbar a 100, e sono due elementi fixed fratelli — finche' la
       colonna stava a meta' schermo non si incontravano mai, ma qui la
       colonna viene portata DENTRO al rettangolo della barra, e quindi
       finisce sotto al suo fondo nero al 72% con 16px di sfocatura.

       Il chip era li', al pixel giusto, e infatti la prova che ne misurava la
       posizione passava: era solo coperto. E non solo invisibile —
       document.elementFromPoint sul suo centro rispondeva .nav-inner, cioe'
       il dito non lo raggiungeva nemmeno. Verificato su Chromium e WebKit.

       101 e non di piu': basta a scavalcare la barra e resta ben sotto al
       menu a tutto schermo, che sta a 210 (css/nav-sheet.css) e deve
       continuare a coprire tutto. La regola sta dentro alla media query, non
       fuori: su desktop la colonna deve restare a 90, dove non ruba i click
       destinati al logo se la finestra e' bassa. */
    z-index: 101;
    top: 0;
    bottom: auto;
    left: auto;
    right: calc(20px + var(--nav-wheel-w) + 10px);
    translate: none;
    width: 36px;
    height: var(--navbar-h, 80px);
  }

  /* Nella colonna il chip era in posizione assoluta contro l'angolo; qui e'
     l'unico contenuto di una scatola che lo centra da sola.

     36px invece dei 48 della colonna: in barra deve stare fra il logo e il
     menu, e ogni pixel in piu' e' un pixel tolto a uno dei due. Resta sopra
     la soglia di quel che si prende con un dito senza mirare, perche' la
     scatola che lo contiene e' alta quanto tutta la barra — l'area toccabile
     e' 36x80, non 36x36. */
  body.nav-bar-wheel-ready .audio-toggle {
    position: relative;
    top: auto;
    left: auto;
    width: 36px;
    height: 36px;
  }

  /* ===== In barra il chip resta quello di sempre =====
     Qui c'era stato un ridisegno: in barra il chip diventava piatto, un
     contorno ambra con l'equalizzatore dentro, perche' a 36px su fondo scuro
     il 3D sembrava illeggibile. La premessa era sbagliata. Il chip non era
     scuro perche' fosse troppo piccolo: era scuro perche' stava SOTTO alla
     barra (vedi lo z-index poco piu' su). Tolto quel velo, i tre piani in
     prospettiva si vedono benissimo anche a questa misura.

     Quindi niente scorciatoie di stile: il pulsante e' lo stesso oggetto
     dov'e' adesso e dov'era prima, in basso a sinistra. Un comando che cambia
     faccia a seconda di dove sta e' un comando che si deve imparare due
     volte. */

  /* ===== Sotto i 370px il nome cede il posto =====
     Non e' una preferenza, e' aritmetica: logo col nome (133) + chip (36) +
     ruota (38vw) + margini (40) + spazi (20) stanno dentro W solo se
     W >= 369. Sotto, qualcosa si sovrappone — e a sovrapporsi sarebbe il
     chip sul nome.

     Cede il NOME, non il marchio: il cubo resta e continua a portare a casa,
     e "Luca Curseri" e' gia' scritto grande nella hero che si apre subito
     sotto. Perdere una ripetizione costa meno che accavallare due comandi. */
  @media (max-width: 369px) {
    body.nav-bar-wheel-ready .logo-word { display: none; }
  }
  body.nav-bar-wheel-ready .nav-rail .nav-wheel { display: none; }
  body.nav-bar-wheel-ready .audio-toggle {
    top: 0;
    left: 0;
  }
}
