/* ======================================================
   Sayonara_Alice.exe — v71.css
   Scalable visual architecture (Blocco 01)
   ------------------------------------------------------
   Namespace: all classes are prefixed .v71- to guarantee
   zero collisions with the historical stylesheets
   (style.css, navbar.css, game.css, audio.css, scrollbar.css).

   This file does not redefine or override any existing
   selector. It only reads the state already exposed by the
   v70 systems (html.visual-soft / .visual-normal / .visual-full,
   prefers-reduced-motion) to scale its own components.

   Nothing in this file is final content: every media slot is
   a reusable container, populated with a temporary dignified
   fallback until real assets are imported in a later block.
====================================================== */

:root {
  --v71-radius: 18px;
  --v71-gap: 1.1rem;
  --v71-focal: 50% 50%;
  --v71-reveal-duration: .55s;
  --v71-reveal-distance: 18px;
}

/* ------------------------------------------------------
   1. Media container — reusable aspect-ratio component
------------------------------------------------------ */

.v71-media {
  position: relative;
  width: 100%;
  border-radius: var(--v71-radius);
  overflow: hidden;
  background:
    radial-gradient(circle at 30% 20%, rgba(0, 220, 255, .10), transparent 55%),
    linear-gradient(160deg, rgba(0, 24, 34, .55), rgba(0, 0, 0, .35));
  border: 1px solid rgba(0, 220, 255, .14);
}

/* Aspect-ratio variants. `aspect-ratio` reserves the box
   before any image loads, which is the primary layout-shift
   prevention mechanism here. */
.v71-media--vertical   { aspect-ratio: 3 / 4; }
.v71-media--horizontal { aspect-ratio: 16 / 9; }
.v71-media--square     { aspect-ratio: 1 / 1; }
.v71-media--cinematic  { aspect-ratio: 21 / 9; }

/* Free variant: used where the future image's ratio is not
   known yet. No fixed aspect-ratio, only a sane minimum
   height so the section never collapses to zero height. */
.v71-media--free {
  aspect-ratio: auto;
  min-height: 220px;
}

.v71-media-inner {
  position: absolute;
  inset: 0;
}

/* Future <img>/<picture> content. Not used yet in this block,
   defined so later blocks can drop real images into an
   already-correct container without touching this file again. */
.v71-media-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--v71-focal);
}

/* ------------------------------------------------------
   2. Temporary fallback — dignified placeholder
   Clearly a *visual* placeholder (no image yet), but never
   an ugly "under construction" box. Marked in the HTML with
   an explicit comment as temporary; replaced during asset
   import (Fase 2/3), this rule can then simply go unused.
------------------------------------------------------ */

.v71-fallback {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.v71-fallback-symbol {
  font-size: clamp(1.1rem, 2.6vw, 1.7rem);
  color: #9ef4ff;
  opacity: .38;
  line-height: 1;
}

html.visual-normal .v71-fallback-symbol,
html.visual-full .v71-fallback-symbol {
  animation: v71FallbackGlow 3.4s ease-in-out infinite;
}

@keyframes v71FallbackGlow {
  0%, 100% { opacity: .3; }
  50%      { opacity: .62; }
}

/* ------------------------------------------------------
   3. Caption area
------------------------------------------------------ */

.v71-caption {
  margin: .55rem .1rem 0;
  color: rgba(220, 250, 255, .68);
  font: 700 .72rem/1.35 "Courier New", Consolas, monospace;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* ------------------------------------------------------
   4. Media + text layout (e.g. Story fragments)
------------------------------------------------------ */

.v71-media-text {
  display: grid;
  grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr);
  gap: clamp(1.2rem, 3vw, 2.4rem);
  align-items: center;
  width: 100%;
}

.v71-media-text .v71-media {
  max-width: 420px;
}

@media (max-width: 760px) {
  .v71-media-text {
    grid-template-columns: 1fr;
  }
  .v71-media-text .v71-media {
    max-width: 320px;
    margin: 0 auto;
  }
}

/* ------------------------------------------------------
   5. Cinematic frame (Gallery opening sequence, future)
------------------------------------------------------ */

.v71-frame {
  width: min(980px, 100%);
  margin: 0 auto;
}

/* ------------------------------------------------------
   6. Future visual grid (Gallery body, future)
------------------------------------------------------ */

.v71-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--v71-gap);
  width: 100%;
}

@media (max-width: 520px) {
  .v71-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* ------------------------------------------------------
   7. Continuity element — small connector between sections
------------------------------------------------------ */

.v71-continuity {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  width: min(760px, 100%);
  margin: 1.4rem auto;
  padding: .3rem 0;
  color: rgba(158, 244, 255, .5);
  font: 700 .66rem/1.3 "Courier New", Consolas, monospace;
  letter-spacing: .16em;
  text-transform: uppercase;
  text-align: center;
}

.v71-continuity-symbol {
  color: rgba(158, 244, 255, .65);
}

/* ------------------------------------------------------
   8. Reveal system
   Default state is fully visible: if v71_reveal.js never
   runs (JS disabled, script blocked, load-order issue),
   every .v71-reveal element stays visible and the page
   remains dignified. JS only ADDS the pending (hidden)
   state right before observing, then removes it on
   intersection.
------------------------------------------------------ */

.v71-reveal {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--v71-reveal-duration) ease,
    transform var(--v71-reveal-duration) ease;
}

.v71-reveal.v71-reveal-pending {
  opacity: 0;
  transform: translateY(var(--v71-reveal-distance));
}

/* Visual Intensity reacts here only in duration/distance,
   never touching the v70 custom properties or classes. */
html.visual-soft .v71-reveal {
  --v71-reveal-duration: .3s;
  --v71-reveal-distance: 8px;
}

html.visual-full .v71-reveal {
  --v71-reveal-duration: .68s;
  --v71-reveal-distance: 22px;
}

/* -----------------------------------------------------------
   v96 — Timing di reveal per pagina.
   Il modulo v71_reveal.js non contiene tempi: aggiunge e toglie
   solo .v71-reveal-pending. Durata e distanza vivono in queste
   due custom property, quindi le pagine si differenziano qui,
   senza toccare una riga di JavaScript.

   Story respira lentamente: la materia affiora.
   I selettori ripetono la classe di intensita' cosi' che Visual
   Intensity continui a comandare, come fa oggi, invece di essere
   scavalcata dallo scope di pagina.
   ----------------------------------------------------------- */
body[data-page="story"] .v71-reveal {
  --v71-reveal-duration: .72s;
  --v71-reveal-distance: 18px;
}

html.visual-soft body[data-page="story"] .v71-reveal {
  --v71-reveal-duration: .38s;
  --v71-reveal-distance: 8px;
}

html.visual-full body[data-page="story"] .v71-reveal {
  --v71-reveal-duration: .86s;
  --v71-reveal-distance: 22px;
}

@media (prefers-reduced-motion: reduce) {
  .v71-reveal,
  .v71-reveal.v71-reveal-pending {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
    filter: none !important;
    clip-path: none !important;
  }

  .v71-reveal .v71-chapter-title,
  .v71-reveal.v71-chapter-title,
  .v71-reveal .v71-archivepage-closing-title {
    letter-spacing: normal !important;
    transition: none !important;
  }

  .v71-fallback-symbol {
    animation: none !important;
  }
}

/* ------------------------------------------------------
   8b. Reveal variants — bloom / scan / drift (Blocco 02a)
   Pure CSS extensions of the existing .v71-reveal-pending
   mechanism above: v71_reveal.js is unchanged and has no idea
   these variants exist. Each variant replaces the default
   translateY with its own one-shot effect; the reduce-motion
   block above already neutralizes filter/clip-path/transform
   for every .v71-reveal element regardless of variant.
------------------------------------------------------ */

/* Bloom: soft blur + brightness settling in, no slide. */
.v71-reveal.v71-bloom {
  filter: blur(0) brightness(1);
  transition:
    opacity var(--v71-reveal-duration) ease,
    filter var(--v71-reveal-duration) ease;
}

.v71-reveal.v71-bloom.v71-reveal-pending {
  transform: none;
  filter: blur(var(--v71-bloom-blur)) brightness(1.3);
}

html.visual-full .v71-reveal.v71-bloom {
  box-shadow: 0 0 24px rgba(0, 220, 255, .12);
}

/* Scan: a soft settle — brightness dip + tiny lift/scale, never
   a full clip. clip-path: inset(0 0 100% 0) previously collapsed
   the element's visible/paintable surface to zero while pending,
   which left the IntersectionObserver with nothing to confirm as
   intersecting — the card stayed stuck in .v71-reveal-pending
   forever (confirmed: this affected both Fragments 01/03/05 and
   all four Sayonara Core secondary cards, which share this same
   class). The fix keeps the element's real box intact at all
   times; only opacity/transform/filter animate. */
.v71-reveal.v71-scan {
  transition:
    opacity var(--v71-reveal-duration) ease,
    transform var(--v71-reveal-duration) ease,
    filter var(--v71-reveal-duration) ease;
}

.v71-reveal.v71-scan.v71-reveal-pending {
  transform: translateY(calc(var(--v71-reveal-distance) * .55)) scale(.985);
  filter: brightness(.82);
}

/* Reconstruct: opacity + filter + scale settling in together — a
   quieter cousin of bloom, used for Core's non-featured cards so
   the featured ones (bloom) read as more "maestoso" by contrast.
   No canvas, no fragmentation, just three properties easing in. */
.v71-reveal.v71-reconstruct {
  filter: blur(0) saturate(1);
  transition:
    opacity var(--v71-reveal-duration) ease,
    transform var(--v71-reveal-duration) ease,
    filter var(--v71-reveal-duration) ease;
}

.v71-reveal.v71-reconstruct.v71-reveal-pending {
  transform: scale(.97);
  filter: blur(3px) saturate(.7);
}

/* Echo's soft bloom: a deliberately gentler version of bloom,
   independent of Visual Intensity, for "drift/bloom molto dolce". */
.v71-reveal.v71-bloom.v71-echo-soft-bloom.v71-reveal-pending {
  filter: blur(calc(var(--v71-bloom-blur) * .5)) brightness(1.12);
}

/* Materialize (Blocco 03b): a stronger, deliberately rare one-shot
   effect — text/scene "resolves" out of blur and drifting letter-
   spacing into focus. Reserved for the handful of big scenographic
   moments (chapter thresholds, chapter transitions, the closing
   scene) — never applied to the 63 archive cards themselves, so
   its heavier filter cost stays cheap regardless of archive size. */
.v71-reveal.v71-materialize {
  filter: blur(0);
  transition:
    opacity calc(var(--v71-reveal-duration) * 1.3) ease,
    transform calc(var(--v71-reveal-duration) * 1.3) ease,
    filter calc(var(--v71-reveal-duration) * 1.3) ease,
    letter-spacing calc(var(--v71-reveal-duration) * 1.3) ease;
}

.v71-reveal.v71-materialize.v71-reveal-pending {
  transform: translateY(calc(var(--v71-reveal-distance) * .7)) scale(1.015);
  filter: blur(10px);
}

.v71-reveal.v71-materialize .v71-chapter-title,
.v71-reveal.v71-materialize.v71-chapter-title,
.v71-reveal.v71-materialize .v71-archivepage-closing-title {
  transition: letter-spacing calc(var(--v71-reveal-duration) * 1.3) ease;
  letter-spacing: normal;
}

.v71-reveal.v71-materialize.v71-reveal-pending .v71-chapter-title,
.v71-reveal.v71-materialize.v71-reveal-pending.v71-chapter-title,
.v71-reveal.v71-materialize.v71-reveal-pending .v71-archivepage-closing-title {
  letter-spacing: .12em;
}

/* Drift: small controlled lateral shift, no vertical slide. */
.v71-reveal.v71-drift.v71-reveal-pending {
  transform: translateX(var(--v71-drift-distance));
}

/* Echo: very light drift. The reveal is carried by the whole rail
   rather than by each card, so a horizontal swipe never re-triggers
   a per-card fade on the neighbours entering view. */
.v71-act--echo .v71-echo-track.v71-drift,
.v71-act--echo .v71-echo-card.v71-drift {
  --v71-drift-distance: 8px;
}
.v71-act--echo .v71-echo-card:nth-child(1) { transition-delay: 0ms; }
.v71-act--echo .v71-echo-card:nth-child(2) { transition-delay: 55ms; }
.v71-act--echo .v71-echo-card:nth-child(3) { transition-delay: 110ms; }
.v71-act--echo .v71-echo-card:nth-child(4) { transition-delay: 165ms; }
.v71-act--echo .v71-echo-card:nth-child(5) { transition-delay: 220ms; }


/* ------------------------------------------------------
   10. Screen-reader-only utility (Blocco 02)
------------------------------------------------------ */

.v71-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;
}

/* ------------------------------------------------------
   11. Gallery — three-act Visual Archive (Blocco 02a polish)
------------------------------------------------------ */

:root {
  --v71-gallery-max: 1120px;
  --v71-gallery-gutter: clamp(1rem, 4vw, 2.5rem);
  --v71-rail-safe: 40px;
  --v71-bloom-blur: 6px;
  --v71-drift-distance: 10px;
}

@media (hover: none) and (pointer: coarse) {
  :root {
    /* The custom scrollbar rail is already hidden entirely on
       touch devices (see scrollbar.css), so a smaller safety
       margin here is purely a fluid-layout courtesy, not a
       collision fix. */
    --v71-rail-safe: 14px;
  }
}

html.visual-soft {
  --v71-bloom-blur: 3px;
  --v71-drift-distance: 6px;
}

html.visual-full {
  --v71-bloom-blur: 8px;
  --v71-drift-distance: 12px;
}

#gallery.v71-gallery {
  scroll-margin-top: clamp(110px, 12vw, 150px);
  position: relative;
}

/* Every direct block of the Gallery (heading, each act, the
   transition connectors) shares one controlled safe area:
   centered, capped width, fluid gutters, extra clearance on
   the right so nothing ever sits under the custom scrollbar. */
#gallery.v71-gallery > .section-heading,
#gallery.v71-gallery > .v71-act,
#gallery.v71-gallery > .v71-transition,
#gallery.v71-gallery > .v71-archive-cta {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--v71-gallery-max);
  margin-inline: auto;
  box-sizing: border-box;
  padding-inline: var(--v71-gallery-gutter);
  padding-right: calc(var(--v71-gallery-gutter) + var(--v71-rail-safe));
}

/* ------------------------------------------------------
   15. Home → complete archive CTA (Blocco 03)
------------------------------------------------------ */

.v71-archive-cta {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .4rem;
  text-align: center;
  text-decoration: none;
  margin-top: clamp(2.2rem, 5vw, 3.4rem);
  padding-top: 1.7rem;
  padding-bottom: 1.6rem;
  border: 1px solid rgba(0, 220, 255, .28);
  border-radius: 20px;
  background:
    radial-gradient(ellipse 70% 90% at 50% 0%, rgba(0, 220, 255, .08), transparent 70%),
    linear-gradient(135deg, rgba(0, 32, 44, .5), rgba(0, 0, 0, .32));
  transition: border-color .25s ease, box-shadow .25s ease, transform .25s ease;
}

.v71-archive-cta-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-size: cover;
  background-position: center 20%;
  filter: blur(3px) brightness(.32) saturate(1.1);
  transform: scale(1.08);
  opacity: .8;
}

.v71-archive-cta > *:not(.v71-archive-cta-bg) {
  position: relative;
  z-index: 1;
}

@media (hover: hover) and (pointer: fine) {
  .v71-archive-cta:hover .v71-archive-cta-bg {
    filter: blur(2px) brightness(.4) saturate(1.15);
  }
}

@media (prefers-reduced-motion: reduce) {
  .v71-archive-cta:hover .v71-archive-cta-bg {
    transition: none;
  }
}

.v71-archive-cta::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: min(160px, 40%);
  height: 1px;
  transform: translate(-50%, -1px);
  background: linear-gradient(to right, transparent, rgba(0, 220, 255, .55), transparent);
}

.v71-archive-cta-index {
  padding: .2rem .6rem;
  border-radius: 999px;
  border: 1px solid rgba(0, 220, 255, .3);
  color: rgba(158, 244, 255, .85);
  font: 700 .64rem/1 "Courier New", Consolas, monospace;
  letter-spacing: .1em;
}

.v71-archive-cta-title {
  color: #eaffff;
  font: 800 1.05rem/1.4 "Courier New", Consolas, monospace;
  letter-spacing: .04em;
}

.v71-archive-cta-note {
  max-width: 380px;
  color: rgba(220, 250, 255, .58);
  font: 400 .82rem/1.5 "Courier New", Consolas, monospace;
  font-style: italic;
}

.v71-archive-cta-subtitle {
  color: rgba(158, 244, 255, .65);
  font: 700 .7rem/1.4 "Courier New", Consolas, monospace;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.v71-archive-cta:focus-visible {
  outline: none;
  border-color: rgba(120, 235, 255, .9);
  box-shadow: 0 0 0 3px rgba(0, 220, 255, .26), 0 0 32px rgba(0, 220, 255, .2);
}

@media (hover: hover) and (pointer: fine) {
  .v71-archive-cta:hover {
    border-color: rgba(120, 235, 255, .8);
    box-shadow: 0 0 36px rgba(0, 220, 255, .2);
    transform: translateY(-3px);
  }

  .v71-archive-cta:hover .v71-archive-cta-index {
    border-color: rgba(120, 235, 255, .8);
  }
}

@media (prefers-reduced-motion: reduce) {
  .v71-archive-cta:hover {
    transform: none;
  }
}

/* ------------------------------------------------------
   15b. Home -> community page CTA
   A variant of the archive CTA above: same geometry, same
   reveal, same hover. It carries no .v71-archive-cta-bg
   because the section has no hero image, and the two source
   logos (150px and 92px) are far too small to become one.
------------------------------------------------------ */

.v71-community-cta {
  width: min(760px, 100%);
  margin-inline: auto;
  box-sizing: border-box;
  padding-inline: clamp(1.1rem, 5vw, 2rem);
}

/* The badge carries a full identifier rather than a count, so it
   is set a little smaller and allowed to wrap: at 320px
   "NETWORK 4072 // 02 SIGNALS" does not fit the pill on one line. */
.v71-community-cta .v71-archive-cta-index {
  max-width: 100%;
  font-size: .58rem;
  line-height: 1.5;
  letter-spacing: .08em;
  text-align: center;
  white-space: normal;
}

.v71-act {
  margin-top: clamp(2.4rem, 5vw, 4rem);
}

.v71-act-heading {
  margin-bottom: 1.1rem;
  max-width: 640px;
}

.v71-act-kicker {
  margin: 0 0 .4rem;
  color: rgba(158, 244, 255, .75);
  font: 800 .72rem/1.3 "Courier New", Consolas, monospace;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.v71-act-heading h3 {
  margin: 0 0 .5rem;
  color: #eaffff;
}

.v71-act-text {
  margin: 0;
  color: rgba(220, 250, 255, .68);
  font-size: .95rem;
  line-height: 1.6;
}

/* Shared trigger/card base: every gallery card is a <button>,
   reset to behave like a plain image block. */
.v71-archive-trigger {
  position: relative;
  appearance: none;
  -webkit-appearance: none;
  display: block;
  width: 100%;
  padding: 0;
  margin: 0;
  border: 1px solid rgba(0, 220, 255, .14);
  border-radius: var(--v71-radius);
  overflow: hidden;
  background: rgba(0, 10, 16, .3);
  cursor: pointer;
  text-align: inherit;
  font: inherit;
  color: inherit;
  transition: border-color .3s ease, box-shadow .3s ease;
}

/* Family accent tint — read by hover glow, scan-line and the
   featured-card seal below. Same three tones used for the
   per-section environment washes in v71_archive_page.css. */
.v71-archive-trigger[data-v71-act="core"] { --v71-card-accent: 0, 220, 255; }
.v71-archive-trigger[data-v71-act="fragments"] { --v71-card-accent: 90, 140, 255; }
.v71-archive-trigger[data-v71-act="echo"] { --v71-card-accent: 205, 235, 255; }

.v71-archive-trigger img {
  display: block;
  width: 100%;
  height: auto;
  transition: transform .35s ease, filter .35s ease;
}

.v71-archive-trigger:focus-visible {
  outline: none;
  border-color: rgba(120, 235, 255, .85);
  box-shadow: 0 0 0 3px rgba(0, 220, 255, .24);
}

/* One-shot scan-line sweep, per hover — a CSS transition (not a
   looping animation), so it plays once on hover-in and settles;
   it does not replay while the pointer stays still. */
.v71-archive-trigger::after {
  content: "";
  position: absolute;
  top: 0;
  left: -35%;
  width: 30%;
  height: 100%;
  background: linear-gradient(
    100deg, transparent, rgba(var(--v71-card-accent, 0, 220, 255), .32), transparent
  );
  opacity: 0;
  pointer-events: none;
  transform: translateX(0);
  transition: transform .6s ease, opacity .6s ease;
  z-index: 1;
}

@media (hover: hover) and (pointer: fine) {
  .v71-archive-trigger:hover,
  .v71-archive-trigger:focus-visible {
    border-color: rgba(var(--v71-card-accent, 0, 220, 255), .5);
  }

  .v71-archive-trigger:hover img {
    transform: scale(1.018);
    filter: brightness(1.04);
  }

  .v71-archive-trigger:hover::after {
    opacity: 1;
    transform: translateX(430%);
  }

  html.visual-full .v71-archive-trigger:hover {
    box-shadow: 0 0 0 1px rgba(var(--v71-card-accent, 0, 220, 255), .32), 0 18px 40px rgba(var(--v71-card-accent, 0, 220, 255), .16);
  }
}

@media (prefers-reduced-motion: reduce) {
  .v71-archive-trigger img,
  .v71-archive-trigger::after {
    transition: none !important;
  }
  .v71-archive-trigger:hover::after {
    opacity: 0 !important;
  }
}

/* Featured cards: a quiet inset seal frame, never a size change —
   4:5 and layout stay exactly as already approved. */
.v71-fullarchive-card.is-featured {
  border-color: rgba(var(--v71-card-accent, 0, 220, 255), .32);
}

.v71-fullarchive-card.is-featured::before {
  content: "";
  position: absolute;
  inset: 7px;
  border: 1px solid rgba(var(--v71-card-accent, 0, 220, 255), .22);
  border-radius: calc(var(--v71-radius) - 7px);
  pointer-events: none;
  z-index: 1;
}

/* ---- Act 1: Sayonara Core — balanced editorial grid ----
   Two roughly equal columns (not the old 1.4fr/1fr) inside a
   960px cap: primary ≈ 470px, secondary 2×2 cells ≈ 227px each,
   which makes the secondary column's total height land within
   a few pixels of the primary's — no leftover vertical gap. */

.v71-core-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  max-width: 960px;
  margin-inline: auto;
  align-items: start;
}

.v71-core-primary {
  max-width: 500px;
  margin-inline: auto;
}

.v71-core-secondary-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

@media (max-width: 980px) {
  .v71-core-grid {
    grid-template-columns: 1fr;
    max-width: 420px;
    gap: 18px;
  }
  .v71-core-primary {
    max-width: 380px;
  }
  .v71-core-secondary-grid {
    grid-template-columns: repeat(2, 1fr);
    width: 100%;
    max-width: 380px;
    margin-inline: auto;
  }
}

@media (max-width: 640px) {
  .v71-core-grid {
    max-width: 300px;
    gap: 14px;
  }
  .v71-core-primary {
    max-width: 300px;
  }
  .v71-core-secondary-grid {
    max-width: 300px;
    gap: 10px;
  }
}

/* ---- Act 2: Visual Archive — clean, more compact fragments grid ---- */

.v71-fragments-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  max-width: 920px;
  margin-inline: auto;
}

@media (max-width: 980px) {
  .v71-fragments-grid {
    grid-template-columns: repeat(2, 1fr);
    max-width: 600px;
  }
}

@media (max-width: 640px) {
  .v71-fragments-grid {
    max-width: 340px;
    gap: 10px;
  }
}

@media (max-width: 359px) {
  .v71-fragments-grid {
    grid-template-columns: 1fr;
    max-width: 280px;
  }
}

.v71-fragment-card {
  position: relative;
}

.v71-fragment-index {
  position: absolute;
  left: .55rem;
  bottom: .55rem;
  padding: .2rem .5rem;
  border-radius: 999px;
  background: rgba(2, 10, 14, .58);
  color: rgba(234, 255, 255, .68);
  font: 700 .62rem/1 "Courier New", Consolas, monospace;
  letter-spacing: .08em;
  pointer-events: none;
}

/* ---- Act 3: Echo within glitch of time ----
   Tablet/mobile: horizontal scroll-snap capsule, with real
   trailing safe space so the last card can reach full view
   without sitting under the custom scrollbar rail.
   Wide desktop (≥1180px): all five fit elegantly, so it becomes
   a plain 5-column grid instead — no horizontal scroll needed. */

.v71-echo-track {
  display: flex;
  gap: 18px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: 20px 28px;
  padding-inline: 20px 28px;
  padding-bottom: .6rem;
}

.v71-echo-card {
  flex: 0 0 auto;
  width: min(70vw, 260px);
  max-width: calc(100% - 4px);
  scroll-snap-align: center;
}

@media (min-width: 641px) and (max-width: 1179px) {
  .v71-echo-card {
    width: 220px;
  }
}

@media (min-width: 1180px) {
  .v71-echo-track {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    overflow-x: visible;
    max-width: 1100px;
    margin-inline: auto;
    padding-inline: 0;
    padding-bottom: 0;
    gap: 18px;
  }
  .v71-echo-card {
    width: auto;
    max-width: 205px;
    margin-inline: auto;
  }
}


/* ------------------------------------------------------
   12. Archive lightbox (Blocco 02)
------------------------------------------------------ */

body.v71-lightbox-locked {
  overflow: hidden;
}

.v71-lightbox {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
  opacity: 0;
  transition: opacity .25s ease;
}

@keyframes v71LightboxFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* Opening uses a keyframe animation rather than relying on the
   transition above: a transition needs the browser to register
   the "before" computed style as an already-painted frame before
   the "after" style change counts as something to animate from.
   When both changes happen synchronously inside a click handler,
   that registration is not guaranteed to happen promptly — in
   testing this occasionally left the lightbox fully transparent
   for a long, unpredictable stretch after the click. A keyframe
   animation has no such dependency: naming it via .is-open makes
   it start immediately and reliably. Closing (removing .is-open)
   falls back to the plain transition above, which is acceptable
   even if occasionally instant rather than animated. */
.v71-lightbox.is-open {
  opacity: 1;
  animation: v71LightboxFadeIn .28s ease;
}

.v71-lightbox[hidden] {
  display: none;
}

/* The same image the user opened, reused as a soft ambient
   backdrop — no duplicate asset, no video, just a blurred CSS
   background layer sitting behind the dark scrim. */
.v71-lightbox-backdrop-image {
  position: absolute;
  inset: -8%;
  background-size: cover;
  background-position: center;
  filter: blur(58px) saturate(1.25) brightness(.5);
  transform: scale(1.1);
  opacity: .85;
}

.v71-lightbox-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(2, 8, 12, .78);
}

.v71-lightbox.is-core .v71-lightbox-backdrop {
  background: radial-gradient(ellipse 70% 60% at 50% 40%, rgba(0, 40, 55, .35), rgba(2, 8, 12, .82));
}
.v71-lightbox.is-fragments .v71-lightbox-backdrop {
  background: radial-gradient(ellipse 70% 60% at 50% 40%, rgba(20, 30, 60, .35), rgba(2, 8, 12, .82));
}
.v71-lightbox.is-echo .v71-lightbox-backdrop {
  background: radial-gradient(ellipse 70% 60% at 50% 40%, rgba(40, 55, 65, .3), rgba(2, 8, 12, .82));
}

.v71-lightbox-panel {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 1rem;
  width: 100%;
  max-width: min(94vw, 1100px);
  transform: scale(.975);
  transition: transform .25s ease;
}

@keyframes v71LightboxPanelIn {
  from { transform: scale(.975); }
  to { transform: scale(1); }
}

.v71-lightbox.is-open .v71-lightbox-panel {
  transform: scale(1);
  animation: v71LightboxPanelIn .28s ease;
}

.v71-lightbox-figure {
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.v71-lightbox-img {
  display: block;
  max-width: 100%;
  max-height: 72vh;
  width: auto;
  height: auto;
  border-radius: 14px;
  border: 1px solid rgba(0, 220, 255, .18);
  box-shadow: 0 24px 70px rgba(0, 0, 0, .55);
  transition: border-color .3s ease;
}

@keyframes v71LightboxAuraPulse {
  0%   { box-shadow: 0 24px 70px rgba(0, 0, 0, .55), 0 0 0 rgba(0, 220, 255, 0); }
  40%  { box-shadow: 0 24px 70px rgba(0, 0, 0, .55), 0 0 46px rgba(0, 220, 255, .28); }
  100% { box-shadow: 0 24px 70px rgba(0, 0, 0, .55), 0 0 0 rgba(0, 220, 255, 0); }
}

.v71-lightbox.is-open .v71-lightbox-img {
  animation: v71LightboxAuraPulse 1.1s ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .v71-lightbox.is-open .v71-lightbox-img {
    animation: none !important;
  }
}

.v71-lightbox.is-core .v71-lightbox-img { border-color: rgba(0, 220, 255, .32); }
.v71-lightbox.is-fragments .v71-lightbox-img { border-color: rgba(90, 140, 255, .32); }
.v71-lightbox.is-echo .v71-lightbox-img { border-color: rgba(205, 235, 255, .32); }

html.visual-full .v71-lightbox-img {
  box-shadow: 0 24px 70px rgba(0, 0, 0, .55), 0 0 60px rgba(0, 220, 255, .12);
}

.v71-lightbox-caption {
  margin: 1rem 0 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .35rem;
  max-width: 480px;
  text-align: center;
}

.v71-lightbox-caption-main {
  color: #eaffff;
  font: 700 .78rem/1.4 "Courier New", Consolas, monospace;
  letter-spacing: .05em;
}

.v71-lightbox-caption-state {
  padding: .18rem .6rem;
  border-radius: 999px;
  border: 1px solid rgba(0, 220, 255, .3);
  color: rgba(158, 244, 255, .85);
  font: 700 .62rem/1 "Courier New", Consolas, monospace;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.v71-lightbox-caption-copy {
  color: rgba(220, 250, 255, .6);
  font: 400 .78rem/1.5 "Courier New", Consolas, monospace;
  font-style: italic;
}

.v71-lightbox-btn {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  border: 1px solid rgba(0, 220, 255, .3);
  background: linear-gradient(135deg, rgba(0, 32, 44, .78), rgba(0, 0, 0, .58));
  color: #eaffff;
  font-size: 1.35rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color .18s ease, box-shadow .18s ease;
}

.v71-lightbox-btn:hover,
.v71-lightbox-btn:focus-visible {
  border-color: rgba(120, 235, 255, .85);
  box-shadow: 0 0 0 3px rgba(0, 220, 255, .24);
}

.v71-lightbox-btn:focus-visible {
  outline: none;
}

.v71-lightbox-close {
  position: fixed;
  top: 1rem;
  right: calc(.75rem + var(--v71-rail-safe, 14px));
  z-index: 2;
}

@media (prefers-reduced-motion: reduce) {
  .v71-lightbox,
  .v71-lightbox-panel {
    transition: none !important;
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}

@media (max-width: 620px) {
  .v71-lightbox-panel {
    gap: .5rem;
  }
  .v71-lightbox-btn {
    width: 40px;
    height: 40px;
    font-size: 1.15rem;
  }
}

/* ------------------------------------------------------
   13. Gallery background depth + signal spine (Blocco 02a)
   Purely decorative, behind all content (z-index:0, content
   sits at z-index:1 — see section 11). No effect on layout,
   no impact on legibility, no animation.
------------------------------------------------------ */

.v71-gallery::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 55% 32% at 18% 6%, rgba(0, 220, 255, .05), transparent 62%),
    radial-gradient(ellipse 48% 30% at 85% 42%, rgba(70, 130, 255, .045), transparent 65%),
    radial-gradient(ellipse 50% 30% at 22% 92%, rgba(0, 220, 255, .04), transparent 65%);
}

.v71-gallery::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 4%;
  bottom: 4%;
  width: 1px;
  z-index: 0;
  pointer-events: none;
  transform: translateX(-50%);
  background: linear-gradient(
    to bottom,
    transparent,
    rgba(0, 220, 255, .12) 15%,
    rgba(0, 220, 255, .12) 85%,
    transparent
  );
}

@media (max-width: 640px) {
  .v71-gallery::after {
    display: none;
  }
}

/* Subtle per-act tint differences — Core stays coolest/blue,
   Fragments neutral, Echo slightly warmer and quieter, matching
   the "silenzioso, intimo e luminoso" tone already intended for
   that act. Contained to a soft glow behind each act's heading,
   never full-bleed, never reducing text contrast. */

.v71-act--core .v71-act-heading {
  position: relative;
}
.v71-act--core .v71-act-heading::before {
  content: "";
  position: absolute;
  left: -12%;
  top: -30%;
  width: 55%;
  height: 160%;
  background: radial-gradient(ellipse, rgba(0, 220, 255, .06), transparent 70%);
  z-index: -1;
  pointer-events: none;
}

.v71-act--echo .v71-act-heading {
  position: relative;
}
.v71-act--echo .v71-act-heading::before {
  content: "";
  position: absolute;
  left: -12%;
  top: -30%;
  width: 55%;
  height: 160%;
  background: radial-gradient(ellipse, rgba(255, 220, 200, .05), transparent 70%);
  z-index: -1;
  pointer-events: none;
}

/* ------------------------------------------------------
   14. Act transition connectors (Blocco 02a)
   System-style passages between acts — a thin signal line and
   a short uppercase line, never a normal heading, never a
   button, never a reveal of the secret portal.
------------------------------------------------------ */

.v71-transition {
  text-align: center;
  color: rgba(158, 244, 255, .58);
  font: 700 .66rem/1.5 "Courier New", Consolas, monospace;
  letter-spacing: .16em;
  text-transform: uppercase;
  margin-top: clamp(2rem, 4.5vw, 3.2rem);
  margin-bottom: 0;
}

.v71-transition::before {
  content: "";
  display: block;
  width: min(220px, 55%);
  height: 1px;
  margin: 0 auto .8rem;
  background: linear-gradient(to right, transparent, rgba(0, 220, 255, .4), transparent);
}
