/* ============================================================
   reattore.css — la plancia.

   Una cosa sola da tenere a mente leggendo questo file: la scena e'
   in prospettiva vera. `.volume` e i suoi figli vivono in
   `transform-style: preserve-3d`, quindi gli anelli hanno una
   posizione nello spazio e il browser li dispone davanti o dietro al
   nucleo da solo. Per questo qui dentro non si trovano `z-index`
   sugli anelli: non servirebbero a niente, li ordina la profondita'.

   Corollario importante: **niente `filter`, `opacity` sotto 1 o
   `overflow` diverso da visible** su `.plancia` e `.volume`. Ognuna
   di quelle proprieta' appiattisce la scena 3D e il reattore torna
   a essere un disegno.

   La variabile `--voce` (0..1) la scrive `assistente.js` a ogni
   fotogramma mentre l'assistente parla. Qui viene solo letta.
   ============================================================ */

.hud { width: 100%; height: 100%; display: grid; place-items: center; }

.hud-scena {
  position: relative;
  width: 100%;
  max-width: min(520px, 78vh);
  aspect-ratio: 1;
  display: grid; place-items: center;
  transition: max-width .32s cubic-bezier(.2,.8,.3,1);
}

/*
  Qui nasce la profondita': "perspective" sul contenitore piu'
  "preserve-3d" su .volume. E' la coppia che trasforma le rotazioni in
  movimento nello spazio invece che in ellissi disegnate. Se una delle
  due manca, il reattore torna piatto.
*/
.plancia {
  position: absolute;
  inset: 0;
  perspective: 1400px;
  perspective-origin: 50% 46%;
  animation: sfarfallio 7.3s linear infinite;
}

/*
  Lo sfarfallio di una proiezione. Deve essere irregolare e appena
  percettibile: se lo si vede lampeggiare e' troppo, e dopo dieci
  secondi da' fastidio. Sono scarti di pochi centesimi in punti
  dispari della battuta, cosi' l'occhio non ne trova il ritmo.
*/
@keyframes sfarfallio {
  0%, 100% { opacity: 1; }
  17%      { opacity: .965; }
  18.4%    { opacity: 1; }
  43%      { opacity: .98; }
  44%      { opacity: 1; }
  61.2%    { opacity: .955; }
  62%      { opacity: 1; }
  88%      { opacity: .975; }
  89%      { opacity: 1; }
}

/* ============================================================
   1. Bagliori — la luce che il nucleo sparge attorno a se'
   ============================================================ */

.bagliore {
  position: absolute;
  left: 50%; top: 50%;
  width: 116%; height: 116%;
  transform: translate(-50%, -50%) scale(calc(1 + var(--voce, 0) * .12));
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle at 50% 50%,
    color-mix(in srgb, var(--accent) 26%, transparent) 0%,
    color-mix(in srgb, var(--accent) 9%, transparent) 26%,
    color-mix(in srgb, var(--accent) 2%, transparent) 52%,
    transparent 72%);
  opacity: calc(.55 + var(--voce, 0) * .45);
}

.bagliore.stretto {
  width: 52%; height: 52%;
  background: radial-gradient(circle at 50% 50%,
    color-mix(in srgb, #fff 22%, var(--accent)) 0%,
    color-mix(in srgb, var(--accent) 45%, transparent) 22%,
    transparent 66%);
  opacity: calc(.4 + var(--voce, 0) * .6);
  transform: translate(-50%, -50%) scale(calc(.9 + var(--voce, 0) * .35));
  animation: alito 6.8s ease-in-out infinite;
}

@keyframes alito {
  0%, 100% { filter: brightness(.85); }
  50%      { filter: brightness(1.15); }
}

/* ============================================================
   2. Polvere — granelli sospesi a profondita' diverse
   ============================================================ */

.campo {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  pointer-events: none;
}

.granello {
  position: absolute;
  width: var(--dm); height: var(--dm);
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 6px 1px color-mix(in srgb, var(--accent) 70%, transparent);
  transform: translateZ(var(--z));
  animation: deriva var(--dur) ease-in-out infinite;
  animation-delay: var(--rit);
  opacity: .5;
}

/* Salgono piano e svaniscono. Il movimento e' minuscolo di
   proposito: e' polvere in un raggio di luce, non neve. */
@keyframes deriva {
  0%   { transform: translateZ(var(--z)) translateY(6px);  opacity: 0; }
  22%  { opacity: .65; }
  78%  { opacity: .5; }
  100% { transform: translateZ(var(--z)) translateY(-10px); opacity: 0; }
}

/* ============================================================
   3. Il volume
   ============================================================ */

.volume {
  position: absolute; inset: 0;
  transform-style: preserve-3d;

  /* Una deriva lentissima attorno a due assi. Da sola non si nota,
     ma e' quello che fa capire all'occhio che l'oggetto ha un dentro
     e un fuori: gli anelli si scoprono e si nascondono a vicenda. */
  animation: deriva-volume 33s ease-in-out infinite;
}

@keyframes deriva-volume {
  0%, 100% { transform: rotateX(5deg)  rotateY(-7deg); }
  33%      { transform: rotateX(-4deg) rotateY(6deg); }
  66%      { transform: rotateX(6deg)  rotateY(4deg); }
}

/* ---------- Anelli giroscopici ---------- */

.anello3 {
  position: absolute;
  inset: calc((100% - var(--dim)) / 2);
  transform-style: preserve-3d;
  animation: giro-y var(--dur) linear infinite;
  pointer-events: none;
}
.anello3.asse-x { animation-name: giro-x; }
.anello3.contro { animation-direction: reverse; }

@keyframes giro-y { to { transform: rotateY(360deg); } }
@keyframes giro-x { to { transform: rotateX(360deg); } }

.anello3 .cerchio {
  position: absolute; inset: 0;
  border-radius: 50%;
  border: 1.6px solid color-mix(in srgb, var(--accent) 66%, transparent);
  transform: rotateX(var(--incl));
  transform-style: preserve-3d;
  box-shadow:
    0 0 14px -3px color-mix(in srgb, var(--accent) 75%, transparent),
    inset 0 0 18px -6px color-mix(in srgb, var(--accent) 60%, transparent);
}
.anello3.asse-x .cerchio { transform: rotateY(var(--incl)); }

.anello3.sottile .cerchio {
  border-width: 1px;
  border-color: color-mix(in srgb, var(--accent) 42%, transparent);
}
.anello3.caldo .cerchio {
  border-color: color-mix(in srgb, var(--caldo, #ff9d2e) 62%, transparent);
  box-shadow:
    0 0 16px -3px color-mix(in srgb, var(--caldo, #ff9d2e) 75%, transparent),
    inset 0 0 18px -6px color-mix(in srgb, var(--caldo, #ff9d2e) 55%, transparent);
}

/*
  Il punto luminoso appeso all'anello. Sembra un dettaglio, ma e' la
  prova visiva della profondita': essendo un elemento suo, il browser
  lo colloca davanti o dietro al nucleo a seconda di dove si trova nel
  giro. E' quello che convince l'occhio che la cosa e' solida.
*/
.anello3 .perla {
  position: absolute;
  top: 50%; left: 100%;
  width: 7px; height: 7px;
  margin: -3.5px 0 0 -3.5px;
  border-radius: 50%;
  background: color-mix(in srgb, #fff 45%, var(--accent));
  box-shadow: 0 0 12px 2px var(--accent), 0 0 26px 6px color-mix(in srgb, var(--accent) 40%, transparent);
}
.anello3.caldo .perla {
  background: color-mix(in srgb, #fff 40%, var(--caldo, #ff9d2e));
  box-shadow: 0 0 12px 2px var(--caldo, #ff9d2e), 0 0 26px 6px color-mix(in srgb, var(--caldo, #ff9d2e) 40%, transparent);
}

/* ---------- La gabbia: una sfera di filo ---------- */

.gabbia {
  position: absolute;
  inset: calc((100% - var(--dim)) / 2);
  transform-style: preserve-3d;
  animation: giro-y var(--dur) linear infinite;
  pointer-events: none;
}

.gabbia .meridiano,
.gabbia .parallelo {
  position: absolute; inset: 0;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
}
.gabbia .meridiano { transform: rotateY(var(--a)); }

/* I paralleli chiudono la sfera: senza, i soli meridiani leggono
   come un ventaglio invece che come un volume. */
.gabbia .parallelo {
  inset: 26% 0;
  transform: rotateX(90deg) translateZ(var(--q));
  border-color: color-mix(in srgb, var(--accent) 22%, transparent);
}

/* ---------- La corazza piatta ---------- */

.lamiera {
  position: absolute; inset: 0;
  transform: translateZ(0);
  transform-style: preserve-3d;
}

.corazza { width: 100%; height: 100%; overflow: visible; }

/* Anelli sottili tratteggiati */
.corazza .filo {
  fill: none;
  stroke: var(--accent);
  stroke-width: .8;
  opacity: .2;
  stroke-dasharray: var(--d);
  transform-origin: 250px 250px;
  animation: hud-gira 104s linear infinite;
}
.corazza .filo.lento { animation-duration: 168s; animation-direction: reverse; opacity: .14; }

/* Piastre: archi spessi e spezzati, come le lamiere di una corazza */
.corazza .piastra { fill: none; stroke-linecap: round; }

.corazza .piastra.grossa { stroke: var(--accent); stroke-width: 15; opacity: .24; }
.corazza .piastra.grossa.scura {
  stroke: color-mix(in srgb, var(--accent) 62%, #000);
  stroke-width: 19; opacity: .5;
}
.corazza .piastra.media {
  stroke: var(--accent); stroke-width: 7; opacity: .4;
  filter: drop-shadow(0 0 4px var(--accent));
}
.corazza .piastra.calda {
  stroke: var(--caldo, #ff9d2e); stroke-width: 4; opacity: .78;
  filter: drop-shadow(0 0 6px var(--caldo, #ff9d2e));
}
.corazza .piastra.calda.sottile { stroke-width: 2.2; opacity: .58; }

.corazza .strato { transform-origin: 250px 250px; }
.corazza .s1 { animation: hud-gira 148s linear infinite; }
.corazza .s2 { animation: hud-gira 98s linear infinite reverse; }
.corazza .s3 { animation: hud-gira 72s linear infinite; }
.corazza .s4 { animation: hud-gira 116s linear infinite reverse; }
.corazza .s5 { animation: hud-gira 54s linear infinite; }

/* Nodi luminosi sugli anelli */
.corazza .nodo { fill: var(--accent); filter: drop-shadow(0 0 6px var(--accent)); }
.corazza .nodo.alone-nodo { opacity: .16; filter: blur(4px); }
.corazza .nodo.caldo {
  fill: var(--caldo, #ff9d2e);
  filter: drop-shadow(0 0 7px var(--caldo, #ff9d2e));
}
.corazza .nodo.caldo.alone-nodo { opacity: .2; filter: blur(4px); }

/* Filamenti dal nucleo */
.corazza .filamento {
  stroke: var(--accent);
  stroke-width: 1;
  stroke-linecap: round;
  opacity: .28;
  animation: filo-vibra 5.6s ease-in-out infinite;
  animation-delay: calc(var(--i) * -.19s);
}
.corazza .filamento.lungo {
  stroke: color-mix(in srgb, #fff 55%, var(--accent));
  stroke-width: 1.4;
  opacity: .55;
}
@keyframes filo-vibra { 0%, 100% { opacity: .16; } 50% { opacity: .68; } }

/* Corone di trattini */
.corazza .trattino {
  stroke: var(--accent);
  stroke-width: .9;
  stroke-linecap: round;
  opacity: .18;
}
.corazza .trattino.lungo { stroke-width: 1.3; opacity: .4; }

.corazza .corona {
  transform-origin: 250px 250px;
  animation: hud-gira 260s linear infinite;
}

/* Anello delle ore */
.corazza .ora-tacca {
  stroke: var(--accent);
  stroke-width: 1.4;
  stroke-linecap: round;
  opacity: .16;
  transition: stroke .3s, opacity .3s, stroke-width .3s;
  cursor: pointer;
  pointer-events: auto;
}
.corazza .ora-tacca:hover { opacity: .8; stroke-width: 2.4; }
.corazza .ora-tacca.pieno  { opacity: .9; stroke-width: 2.6; }
.corazza .ora-tacca.chiuso { stroke: var(--ok); opacity: .48; stroke-width: 2.2; }
.corazza .ora-tacca.adesso {
  stroke: var(--caldo, #ff9d2e); opacity: 1; stroke-width: 3;
  filter: drop-shadow(0 0 6px var(--caldo, #ff9d2e));
  animation: hud-respira 3.4s ease-in-out infinite;
}

/* Avanzamento della giornata: un dato, quindi non ruota */
.corazza .giro-base { fill: none; stroke: var(--line); stroke-width: 3; opacity: .5; }
.corazza .giro-vivo {
  fill: none; stroke: var(--caldo, #ff9d2e);
  stroke-width: 3.4; stroke-linecap: round;
  transform: rotate(-90deg); transform-origin: 250px 250px;
  filter: drop-shadow(0 0 8px var(--caldo, #ff9d2e));
  transition: stroke-dashoffset 1s cubic-bezier(.4,0,.2,1);
}

/* ---------- Il nucleo ---------- */

.nucleo {
  position: absolute;
  inset: 37%;
  transform: translateZ(1px);
  transform-style: preserve-3d;
  display: grid; place-items: center;

  /* Trasparente ai clic: quello che si tocca sono la sfera e i suoi
     anelli, non il riquadro vuoto attorno. Cosi' le tacche delle ore
     sotto restano raggiungibili. */
  pointer-events: none;
}

.nucleo span { position: absolute; border-radius: 50%; }
.alone, .anello-sfera, .sfera { pointer-events: auto; }

.alone {
  width: 300%; height: 300%;
  background: radial-gradient(circle at 50% 50%,
    color-mix(in srgb, #fff 30%, var(--accent)) 0%,
    color-mix(in srgb, var(--accent) 55%, transparent) 16%,
    color-mix(in srgb, var(--accent) 14%, transparent) 42%,
    transparent 68%);
  opacity: calc(.5 + var(--voce, 0) * .5);
  transform: scale(calc(.94 + var(--voce, 0) * .22));
  animation: alone-respira 6.8s ease-in-out infinite;
  cursor: pointer;
}
@keyframes alone-respira {
  0%, 100% { filter: brightness(.88); }
  50%      { filter: brightness(1.12); }
}

/*
  L'onda: un cerchio che si allarga quando la voce sale. Non e' un
  anello in piu' per riempire — e' il modo in cui una sillaba forte
  si vede propagare verso l'esterno.
*/
.onda {
  width: 150%; height: 150%;
  border: 1.5px solid color-mix(in srgb, var(--accent) 70%, transparent);
  opacity: calc(var(--voce, 0) * .7);
  transform: scale(calc(.7 + var(--voce, 0) * 1.15));
}

.anello-sfera {
  width: 190%; height: 190%;
  border: 1.4px dashed color-mix(in srgb, var(--accent) 55%, transparent);
  opacity: calc(.4 + var(--voce, 0) * .5);
  animation: hud-gira 32s linear infinite reverse;
  cursor: pointer;
}

.sfera {
  width: 62%; height: 62%;
  background: radial-gradient(circle at 46% 40%,
    #ffffff 0%,
    color-mix(in srgb, #fff 55%, var(--accent)) 24%,
    var(--accent) 58%,
    color-mix(in srgb, var(--accent) 60%, #000) 100%);
  box-shadow:
    0 0 calc(14px + var(--voce, 0) * 34px) color-mix(in srgb, var(--accent) 85%, transparent),
    0 0 calc(40px + var(--voce, 0) * 70px) color-mix(in srgb, var(--accent) 40%, transparent);
  transform: scale(calc(1 + var(--voce, 0) * .3));
  animation: sfera-pulsa 6.8s ease-in-out infinite;
  cursor: pointer;
}
@keyframes sfera-pulsa {
  0%, 100% { filter: brightness(.92); }
  50%      { filter: brightness(1.1); }
}

/* ============================================================
   4. Il velo olografico
   ============================================================ */

/*
  Righe di scansione. Sono il segno piu' riconoscibile di una
  proiezione, ma vanno tenute quasi invisibili: sopra il due per
  cento di opacita' diventano un effetto, e si vede il trucco.
*/
.righe {
  position: absolute; inset: -4%;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    transparent 0 2px,
    color-mix(in srgb, var(--accent) 9%, transparent) 2px 3px);
  opacity: .32;
  animation: righe-scorrono 9s linear infinite;
  border-radius: 50%;
  -webkit-mask-image: radial-gradient(circle at 50% 50%, #000 42%, transparent 74%);
  mask-image: radial-gradient(circle at 50% 50%, #000 42%, transparent 74%);
}
@keyframes righe-scorrono {
  to { background-position: 0 60px; }
}

/* Una passata di luce, ogni tanto. Rara di proposito: se torna
   spesso diventa un tergicristallo. */
.passata {
  position: absolute;
  left: -10%; right: -10%;
  height: 26%;
  top: -30%;
  pointer-events: none;
  background: linear-gradient(to bottom,
    transparent,
    color-mix(in srgb, var(--accent) 13%, transparent) 45%,
    color-mix(in srgb, #fff 10%, transparent) 50%,
    color-mix(in srgb, var(--accent) 13%, transparent) 55%,
    transparent);
  animation: passata-scende 11s cubic-bezier(.6,0,.4,1) infinite;
  -webkit-mask-image: radial-gradient(ellipse 60% 100% at 50% 50%, #000 30%, transparent 80%);
  mask-image: radial-gradient(ellipse 60% 100% at 50% 50%, #000 30%, transparent 80%);
}
@keyframes passata-scende {
  0%       { transform: translateY(0); opacity: 0; }
  8%       { opacity: 1; }
  46%      { opacity: 1; }
  58%      { transform: translateY(520%); opacity: 0; }
  100%     { transform: translateY(520%); opacity: 0; }
}

/* ============================================================
   Reazioni: ascolto, voce, pensiero
   ============================================================ */

/* Mentre ascolta il reattore si stringe e si raffredda: e' fermo,
   in attesa. La differenza col parlare deve essere leggibile senza
   guardare il pulsante. */
body.sta-ascoltando .anello3 { animation-duration: calc(var(--dur) * 2.2); }
body.sta-ascoltando .sfera {
  box-shadow:
    0 0 16px color-mix(in srgb, var(--ok, #35d6a4) 80%, transparent),
    0 0 44px color-mix(in srgb, var(--ok, #35d6a4) 35%, transparent);
}
body.sta-ascoltando .anello-sfera { animation-duration: 9s; }

/* Mentre parla, tutto segue le sillabe. Le regole che leggono
   --voce sono gia' scritte sopra, negli elementi: qui restano solo
   le cose che cambiano proprio perche' sta parlando. */
body.sta-parlando .corazza .filamento {
  animation: none;
  opacity: calc(.16 + var(--voce, 0) * .78);
}
body.sta-parlando .corazza .filamento.lungo {
  opacity: calc(.3 + var(--voce, 0) * .7);
}
body.sta-parlando .corazza .piastra.calda { opacity: calc(.7 + var(--voce, 0) * .3); }
body.sta-parlando .anello3 .cerchio {
  border-color: color-mix(in srgb, var(--accent) calc(60% + var(--voce, 0) * 40%), transparent);
}
body.sta-parlando .gabbia .meridiano {
  border-color: color-mix(in srgb, var(--accent) calc(28% + var(--voce, 0) * 45%), transparent);
}

/* Mentre pensa gira piu' in fretta e il nucleo si abbassa: e' la
   differenza fra "sto lavorando" e "sto parlando". */
body.sta-pensando .anello3 { animation-duration: calc(var(--dur) * .38); }
body.sta-pensando .gabbia  { animation-duration: 9s; }
body.sta-pensando .sfera   { animation: sfera-pensa 1.9s ease-in-out infinite; }
@keyframes sfera-pensa {
  0%, 100% { transform: scale(.82); filter: brightness(.7); }
  50%      { transform: scale(1);   filter: brightness(1.15); }
}

/* ============================================================
   Rotazione condivisa
   ============================================================ */

@keyframes hud-gira   { to { transform: rotate(360deg); } }
@keyframes hud-respira { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }

/* ============================================================
   Chi preferisce che le cose stiano ferme
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  .plancia, .volume, .anello3, .gabbia, .granello, .righe, .passata,
  .bagliore, .alone, .sfera, .anello-sfera,
  .corazza .strato, .corazza .filo, .corazza .corona,
  .corazza .filamento, .corazza .ora-tacca.adesso { animation: none; }

  .passata { display: none; }
}

/* ============================================================
   Schermi piccoli

   Sul telefono la plancia e' larga un terzo, e con una sezione
   aperta scende a 26vh: meta' del pulviscolo e le righe di
   scansione non si distinguerebbero piu', costerebbero solo
   batteria. Si tolgono quelle, non gli anelli — quelli sono il
   motivo per cui la cosa sembra tridimensionale.
   ============================================================ */

@media (max-width: 860px) {
  .granello:nth-child(2n) { display: none; }
  .righe { display: none; }
  .anello3 .perla { width: 5px; height: 5px; margin: -2.5px 0 0 -2.5px; }
}

/* Con una sezione aperta la plancia e' un francobollo: resta il
   nucleo e gli anelli grossi, il resto sparisce. */
body.pannello-aperto .campo,
body.pannello-aperto .passata,
body.pannello-aperto .righe { display: none; }
body.pannello-aperto .corazza .corona,
body.pannello-aperto .corazza .filo { display: none; }
