/* ============================================
   Visor 3D reutilizable (src/components/Viewer3D.astro)
   ============================================
   Se carga con pageCss="root:viewer3d".

   Estados, todos en el MISMO nodo .viewer3d (data-state):
     idle     → portada (imagen estática del plano + botón). Es lo que ve todo
                el mundo al llegar; Three.js (~2,3 MB) no baja hasta pulsar.
     loading  → descargando librería + modelo.
     ready    → el canvas manda; la portada se va; aparecen etiquetas y barra.
     error    → la portada SE QUEDA (la imagen es el respaldo) + reintentar.

   Modo pantalla completa: .viewer3d.is-fullscreen (lo pone viewer3d.js tanto
   con la API nativa como con el respaldo por CSS para iPhone, que no tiene
   Fullscreen API en elementos). Ahí el canvas captura todos los gestos —
   incluido el pellizco para el zoom— porque ya no hay página que scrollear.

   PROGRESSIVE ENHANCEMENT: los botones salen del build con [hidden] y los
   revela el JS (igual que la barra de filtros de la Biblioteca). Sin JS queda
   la portada, la leyenda y ningún control muerto.
   OJO: NO se usa la clase .js de animations.js para revelarlos — esa clase NO
   se pone con prefers-reduced-motion, y dejaría sin visor a esas personas.
   ============================================ */

.viewer3d {
  position: relative;
  display: grid;
  gap: var(--space-3);
  /* Acento por grupo de zona. Se hereda a etiquetas y leyenda. */
  --z-recorrido: var(--c-cyan);
  --z-destacada: var(--c-pink);
  --z-servicio: #ffffff;
  --z-liberada: var(--c-muted-2);
}

/* El marco: vidrio oscuro con los glows de la marca y una rejilla técnica. */
.viewer3d__frame {
  position: relative;
  border-radius: var(--radius-xl);
  border: 1px solid var(--c-line-strong);
  background:
    radial-gradient(ellipse 55% 60% at 20% 100%, rgba(0, 229, 255, 0.10), transparent 70%),
    radial-gradient(ellipse 50% 55% at 85% 0%, rgba(234, 64, 118, 0.10), transparent 70%),
    rgba(18, 18, 18, 0.55);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  overflow: hidden;
  height: var(--viewer3d-alto, clamp(320px, 52vh, 560px));
}
.viewer3d__frame::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,0.035) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.035) 1px, transparent 1px);
  background-size: 48px 48px;
  mask-image: radial-gradient(ellipse at center, black 40%, transparent 85%);
  -webkit-mask-image: radial-gradient(ellipse at center, black 40%, transparent 85%);
  pointer-events: none;
}

/* --- 1. El lienzo --- */
.viewer3d__stage {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.5s var(--ease-out);
}
.viewer3d[data-state="ready"] .viewer3d__stage { opacity: 1; }
.viewer3d__stage canvas {
  display: block;
  width: 100%;
  height: 100%;
  outline: none;
  /* touch-action lo fija el MOTOR con estilo inline (OrbitControls también lo
     escribe inline, así que una regla CSS acá no ganaría): pan-y en la página
     —el scroll vertical sigue siendo de la página— y none en pantalla completa. */
}
.viewer3d__stage canvas:focus-visible {
  outline: 2px solid var(--c-cyan);
  outline-offset: -2px;
}

/* --- 2. Etiquetas ancladas al 3D --- */
.viewer3d__labels {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s var(--ease-out) 0.2s;
}
.viewer3d[data-state="ready"] .viewer3d__labels { opacity: 1; }

/* Cada etiqueta se posiciona con transform desde el motor (translate al punto
   proyectado). El pin marca el punto exacto; la ficha cuelga encima. */
.viewer3d__label {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* el punto anclado queda en la base del pin */
  transform: translate(-50%, -100%);
  will-change: transform;
  pointer-events: auto;
  /* La ficha se puede tocar (fija la zona), así que el cursor lo anuncia. */
  cursor: pointer;
  transition: opacity 0.25s var(--ease-out);
}
.viewer3d__label[hidden] { display: none; }
.viewer3d__label-pin {
  order: 2;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--z, var(--c-cyan));
  box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.35), 0 0 12px var(--z, var(--c-cyan));
  position: relative;
}
/* El "hilo" entre el pin y la ficha. */
.viewer3d__label-pin::before {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 100%;
  width: 1px;
  height: 14px;
  background: linear-gradient(to top, var(--z, var(--c-cyan)), transparent);
}
.viewer3d__label-card {
  order: 1;
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 14px;
  padding: 5px 10px 5px 5px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(14, 14, 14, 0.82);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: 0 10px 28px -12px rgba(0, 0, 0, 0.8);
  white-space: nowrap;
  transition: border-color 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out), transform 0.25s var(--ease-out);
}
.viewer3d__label-num {
  flex: none;
  display: grid;
  place-items: center;
  min-width: 24px;
  height: 24px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--z, var(--c-cyan));
  color: var(--c-dark);
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.02em;
}
.viewer3d__label-text { display: flex; flex-direction: column; line-height: 1.15; }
.viewer3d__label-name {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 12.5px;
  color: var(--c-white);
}
.viewer3d__label-sub { font-size: 10.5px; color: var(--c-muted); }

/* Acento por grupo */
.viewer3d__label--recorrido { --z: var(--z-recorrido); }
.viewer3d__label--destacada { --z: var(--z-destacada); }
.viewer3d__label--destacada .viewer3d__label-num { color: var(--c-white); }
.viewer3d__label--servicio  { --z: var(--z-servicio); }
.viewer3d__label--liberada  { --z: var(--z-liberada); opacity: 0.72; }
.viewer3d__label--liberada .viewer3d__label-card {
  border-style: dashed;
  background: rgba(14, 14, 14, 0.6);
}
.viewer3d__label--liberada .viewer3d__label-num {
  background: transparent;
  border: 1px dashed var(--z);
  color: var(--z);
}
.viewer3d__label--liberada .viewer3d__label-pin { box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.35); }

/* NIVEL DE DETALLE por zoom (data-zoom lo escribe el motor): en la vista
   general —todo el plano en el marco— diez fichas con nombre se pisan, así que
   queda solo el número y la leyenda de abajo lo explica. Al acercarse, al pasar
   el mouse o al activar una zona, vuelve el nombre. */
.viewer3d[data-zoom="lejos"] .viewer3d__label:not(.is-active):not(:hover) .viewer3d__label-card { padding: 3px; gap: 0; }
.viewer3d[data-zoom="lejos"] .viewer3d__label:not(.is-active):not(:hover) .viewer3d__label-text { display: none; }

/* Zona activa (leyenda, etiqueta o toque en el propio plano): ella sube y
   brilla, el resto se atenúa. 0,55 y no menos: por debajo, el texto de las
   fichas atenuadas deja de cumplir AA sobre el canvas. */
.viewer3d[data-active] .viewer3d__label { opacity: 0.55; }
.viewer3d[data-active] .viewer3d__label.is-active {
  opacity: 1;
  z-index: 2;
}
.viewer3d__label.is-active .viewer3d__label-card {
  border-color: var(--z);
  box-shadow: 0 16px 34px -14px var(--z), 0 0 0 1px rgba(255, 255, 255, 0.06);
  transform: translateY(-3px);
}

/* Pie: qué es este plano. Va discreto, pero SIEMPRE visible — también sin JS,
   que es cuando más falta hace porque solo se ve la portada. */
.viewer3d__pie {
  margin: 0;
  font-size: 12px;
  color: var(--c-muted-2);
}

/* --- 3. Portada (idle / loading / error) --- */
.viewer3d__poster {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: end center;
  justify-items: center;
  gap: var(--space-4);
  padding: var(--space-5);
  text-align: center;
  transition: opacity 0.4s var(--ease-out), visibility 0.4s;
}
.viewer3d[data-state="ready"] .viewer3d__poster {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
/* La imagen del plano: es el respaldo, así que se ve entera y nítida. Un velo
   oscuro abajo da contraste al texto y al botón sin tapar el plano. */
/* El RESPALDO: la cenital en SVG que genera el build. Ocupa el mismo sitio que
   ocupaba la imagen y se comporta igual (no captura el puntero, deja el texto
   de la portada encima). Al ser SVG inline hereda los tokens de color. */
/* El hueco de abajo se reserva con `inset`, no con `padding`: un padding en
   PORCENTAJE se resuelve contra el ANCHO en los cuatro lados, así que en un
   marco apaisado se comía casi toda la altura y el plano quedaba diminuto. */
.viewer3d__poster-mapa {
  position: absolute;
  inset: 4% 4% 27%;
  pointer-events: none;
}
/* Bloque, no grid: con place-items:center el height:100% del SVG se resolvía
   contra la caja de PADDING y el plano salía 2,5x más grande y recortado. */
.viewer3d__mapa {
  display: block;
  width: 100%;
  height: 100%;
}
.viewer3d__poster::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(10, 10, 10, 0.88) 0%, rgba(10, 10, 10, 0.55) 30%, transparent 62%);
  pointer-events: none;
}
.viewer3d__poster-body {
  position: relative;
  display: grid;
  gap: var(--space-3);
  justify-items: center;
  max-width: 52ch;
}
.viewer3d__eyebrow {
  font-family: var(--f-display);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--c-cyan);
}
.viewer3d__title {
  font-family: var(--f-display);
  font-size: clamp(1.15rem, 2.4vw, 1.5rem);
  line-height: 1.25;
  font-weight: 700;
}
.viewer3d__note {
  font-size: 0.92rem;
  color: var(--c-muted);
  text-wrap: balance;
}

.viewer3d__loading {
  display: none;
  align-items: center;
  gap: var(--space-3);
  font-size: 0.92rem;
  color: var(--c-muted);
}
.viewer3d[data-state="loading"] .viewer3d__loading { display: flex; }
.viewer3d[data-state="loading"] .viewer3d__activate,
.viewer3d[data-state="loading"] .viewer3d__note { display: none; }
.viewer3d__spinner {
  width: 18px;
  height: 18px;
  flex: none;
  border: 2px solid rgba(255, 255, 255, 0.18);
  border-top-color: var(--c-cyan);
  border-radius: 50%;
  animation: viewer3d-spin 0.9s linear infinite;
}
@keyframes viewer3d-spin { to { transform: rotate(360deg); } }

.viewer3d__error {
  display: none;
  gap: var(--space-3);
  justify-items: center;
  color: var(--c-muted);
  font-size: 0.92rem;
}
.viewer3d[data-state="error"] .viewer3d__error { display: grid; }
.viewer3d[data-state="error"] .viewer3d__activate,
.viewer3d[data-state="error"] .viewer3d__note { display: none; }

/* --- Botones dentro del marco (pantalla completa / cerrar) --- */
.viewer3d__chrome {
  position: absolute;
  top: 12px;
  right: 12px;
  display: flex;
  gap: 6px;
  z-index: 3;
}
.viewer3d__icon-btn {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(14, 14, 14, 0.7);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: var(--c-white);
  cursor: pointer;
  transition: border-color 0.2s var(--ease-out), background 0.2s var(--ease-out), opacity 0.3s var(--ease-out);
}
.viewer3d__icon-btn:hover { border-color: var(--c-cyan); background: rgba(0, 229, 255, 0.14); }
.viewer3d__icon-btn:focus-visible { outline: 2px solid var(--c-cyan); outline-offset: 2px; }
.viewer3d__icon-btn[hidden] { display: none; }
/* Cerrar solo existe en pantalla completa (lo enciende la regla de .is-fullscreen). */
.viewer3d__icon-btn--close { display: none; }
/* Solo tiene sentido con el visor activo. */
.viewer3d:not([data-state="ready"]) .viewer3d__chrome { display: none; }

/* --- Barra inferior: pista + controles --- */
.viewer3d__bar {
  display: none;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
  min-width: 0;
}
.viewer3d[data-state="ready"] .viewer3d__bar { display: flex; }
.viewer3d__hint { font-size: 0.85rem; color: var(--c-muted-2); min-width: 0; }
.viewer3d__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); min-width: 0; }

.viewer3d__btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 9px 16px;
  max-width: 100%;
  border: 1px solid var(--c-line-strong);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.05);
  color: var(--c-white);
  font-family: var(--f-body);
  font-size: 0.86rem;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.2s var(--ease-out), background 0.2s var(--ease-out), transform 0.2s var(--ease-out);
}
.viewer3d__btn:hover { border-color: var(--c-cyan); background: var(--c-cyan-soft); transform: translateY(-1px); }
.viewer3d__btn:focus-visible { outline: 2px solid var(--c-cyan); outline-offset: 2px; }
.viewer3d__btn[aria-pressed="true"] { border-color: var(--c-cyan); background: var(--c-cyan-soft); }
.viewer3d__btn svg { flex: none; }
.viewer3d__activate {
  padding: 12px 22px;
  font-size: 0.95rem;
  border-color: var(--c-cyan);
  background: var(--c-cyan-soft);
}

/* --- Leyenda (el control accesible; también la versión sin JS) --- */
.viewer3d__legend {
  display: grid;
  gap: var(--space-5);
  margin-top: var(--space-2);
}
.viewer3d__legend-group { display: grid; gap: var(--space-3); }
.viewer3d__legend-title {
  font-family: var(--f-display);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--c-muted-2);
}
.viewer3d__steps {
  list-style: none;
  display: grid;
  gap: 12px;
}
.viewer3d__steps--recorrido { grid-template-columns: repeat(5, minmax(0, 1fr)); counter-reset: none; }
.viewer3d__steps--otras     { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.viewer3d__step { position: relative; display: flex; min-width: 0; }
/* Flecha entre pasos del recorrido. */
.viewer3d__steps--recorrido .viewer3d__step + .viewer3d__step::before {
  content: "";
  position: absolute;
  left: -10px;
  top: 22px;
  width: 8px;
  height: 8px;
  border-top: 1.5px solid var(--c-muted-2);
  border-right: 1.5px solid var(--c-muted-2);
  transform: rotate(45deg);
  opacity: 0.7;
}
.viewer3d__step-btn {
  --z: var(--c-cyan);
  flex: 1;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  min-width: 0;
  padding: 14px;
  text-align: left;
  border: 1px solid var(--c-line);
  border-radius: var(--radius-md);
  background: rgba(18, 18, 18, 0.55);
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition: border-color 0.25s var(--ease-out), background 0.25s var(--ease-out), transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.viewer3d__step-btn--destacada { --z: var(--c-pink); }
.viewer3d__step-btn--servicio  { --z: var(--c-white); }
.viewer3d__step-btn--liberada  { --z: var(--c-muted-2); }
.viewer3d__step-btn:hover { border-color: var(--z); background: rgba(18, 18, 18, 0.8); transform: translateY(-3px); }
.viewer3d__step-btn:focus-visible { outline: none; border-color: var(--c-cyan); box-shadow: 0 0 0 3px var(--c-cyan-soft); }
.viewer3d__step-btn[aria-pressed="true"] {
  border-color: var(--z);
  background: rgba(18, 18, 18, 0.86);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06), 0 22px 44px -26px rgba(0, 229, 255, 0.35);
}
.viewer3d__step-num {
  flex: none;
  display: grid;
  place-items: center;
  min-width: 30px;
  height: 30px;
  padding: 0 7px;
  border-radius: 999px;
  background: var(--z);
  color: var(--c-dark);
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 13px;
}
.viewer3d__step-btn--destacada .viewer3d__step-num { color: var(--c-white); }
.viewer3d__step-btn--liberada .viewer3d__step-num { background: transparent; border: 1px dashed var(--z); color: var(--z); }
.viewer3d__step-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.viewer3d__step-name { font-family: var(--f-display); font-weight: 700; font-size: 15px; color: var(--c-white); line-height: 1.2; }
.viewer3d__step-sub  { font-size: 12px; font-weight: 600; letter-spacing: 0.04em; color: var(--z); }
.viewer3d__step-btn--servicio .viewer3d__step-sub { color: var(--c-muted); }
.viewer3d__step-detail { font-size: 13px; line-height: 1.5; color: var(--c-muted); margin-top: 4px; }
.viewer3d__legend-note { font-size: 0.85rem; color: var(--c-muted-2); }

/* Estado del visor para lectores de pantalla: se anuncia, no se ve. */
.viewer3d__status {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ============================================
   PANTALLA COMPLETA
   ============================================
   Misma clase para las dos vías (Fullscreen API y respaldo por CSS): el
   visor ocupa toda la ventana, por encima del nav fijo y de los botones
   flotantes del sitio; la barra queda flotando abajo y la leyenda se esconde. */
.viewer3d.is-fullscreen {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: block;
  padding: 0;
  /* La página puede haberle puesto un ancho de lectura (ej. .where .viewer3d
     con max-width 1180px): en pantalla completa no cuenta. */
  max-width: none;
  width: auto;
  margin: 0;
  background: var(--c-dark);
}
.viewer3d.is-fullscreen .viewer3d__frame {
  height: 100%;
  height: 100dvh;
  border-radius: 0;
  border: 0;
}
.viewer3d.is-fullscreen .viewer3d__legend,
.viewer3d.is-fullscreen .viewer3d__hint { display: none; }
.viewer3d.is-fullscreen .viewer3d__bar {
  position: absolute;
  left: 50%;
  bottom: max(16px, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  justify-content: center;
  z-index: 3;
}
.viewer3d.is-fullscreen .viewer3d__chrome {
  top: max(12px, env(safe-area-inset-top));
  right: max(12px, env(safe-area-inset-right));
}
/* Cerrar reemplaza a "pantalla completa" en el mismo sitio. */
.viewer3d.is-fullscreen .viewer3d__icon-btn--close { display: grid; }
.viewer3d.is-fullscreen [data-viewer3d-fullscreen] { display: none; }
/* Sin scroll de fondo mientras el visor ocupa la pantalla. */
body.viewer3d-fullscreen { overflow: hidden; }
/* La API nativa pinta un fondo negro detrás del elemento; se iguala al sitio. */
.viewer3d:fullscreen { background: var(--c-dark); }

/* ============================================
   Responsive
   ============================================ */
@media (max-width: 1100px) {
  .viewer3d__steps--recorrido,
  .viewer3d__steps--otras { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .viewer3d__steps--recorrido .viewer3d__step + .viewer3d__step::before { display: none; }
}
@media (max-width: 640px) {
  /* En el plano queda solo la ficha con el número; el nombre vive en la leyenda. */
  .viewer3d__label-card { padding: 3px; gap: 0; margin-bottom: 10px; }
  .viewer3d__label-text { display: none; }
  .viewer3d__label-num { min-width: 22px; height: 22px; font-size: 11px; }
  .viewer3d__label-pin::before { height: 10px; }
  .viewer3d__steps--recorrido,
  .viewer3d__steps--otras { grid-template-columns: 1fr; gap: 10px; }
  .viewer3d__step-btn { padding: 12px; }
  .viewer3d__poster-mapa { inset: 3% 2% 34%; }
}
/* En pantalla completa hay sitio: vuelven los nombres a las etiquetas. */
@media (max-width: 640px) {
  .viewer3d.is-fullscreen .viewer3d__label-card { padding: 5px 10px 5px 5px; gap: 8px; margin-bottom: 14px; }
  .viewer3d.is-fullscreen .viewer3d__label-text { display: flex; }
  .viewer3d.is-fullscreen .viewer3d__label-sub { display: none; }
}
/* En táctil la ficha se encoge a solo el número (22 px): demasiado poco para
   un dedo. Se le cuelga un área de toque de 44 px CENTRADA, sin tocar lo que
   se ve. */
@media (pointer: coarse) {
  .viewer3d__label-card::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
  }
}

@media (max-width: 560px) {
  .viewer3d__bar { justify-content: center; }
  .viewer3d__hint { text-align: center; width: 100%; }
  .viewer3d__actions { justify-content: center; width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .viewer3d__spinner { animation: none; border-top-color: var(--c-cyan); }
  .viewer3d__label,
  .viewer3d__label-card,
  .viewer3d__step-btn,
  .viewer3d__btn,
  .viewer3d__stage,
  .viewer3d__labels,
  .viewer3d__poster { transition: none; }
  .viewer3d__step-btn:hover,
  .viewer3d__label.is-active .viewer3d__label-card { transform: none; }
}
