/* ============================================================
   Vitium Designs — sistema de estilos
   Tokens y medidas tomados del archivo de Figma "Vitium Designs"
   ============================================================ */

:root {
  /* Color (Figma: bg/*, accent/*, text/*, border/*) */
  --bg-base: #000000;
  --bg-elevated: #161528;
  --bg-elevated-2: #1F1B33;
  --accent-purple: #5E00A3;
  --accent-violet: #8523DD;
  /* El violeta de marca sobre fondo oscuro da 2.6-3.3:1: alcanza para
     rellenos (con blanco encima da 6.4:1) pero no para texto chico, que
     pide 4.5:1. Esta variante clara conserva el tono y da 5.2-6.5:1. */
  --accent-violet-text: #B072F0;
  --text-primary: #FFFFFF;
  --text-secondary: #AFAABC;
  --text-muted: #918CA3;
  --border-subtle: #2B273D;
  /* El hairline decorativo no alcanza para marcar el limite de un campo. */
  --border-control: #565073;
  /* Estados del formulario. Medidos sobre #1F1B33, el fondo real de la
     tarjeta: error 7.33:1, exito 10.82:1 — los dos pasan AAA. El borde de
     error es mas saturado porque no lleva texto encima, solo marca el
     campo. */
  --color-error: #FF8A8A;
  --color-error-border: #E5484D;
  --color-success: #7EE787;
  /* Verde oficial de WhatsApp, solo para su ícono: identifica el canal. */
  --color-whatsapp: #25D366;

  /* Tipografía */
  --font-serif: "Fraunces", "Iowan Old Style", Georgia, serif;
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-mono: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace;

  /* Espaciado */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 32px;
  --space-8: 40px;
  --space-9: 64px;
  --space-10: 100px;

  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 10px;
  --radius-xl: 12px;

  --container: 1248px;
  --header-height: 79px;

  --duration-fast: 160ms;
  --duration-base: 260ms;
  --ease-standard: cubic-bezier(0.22, 0.61, 0.36, 1);
  /* Desaceleración fuerte: arranca rápido y se asienta. Es la curva que
     se lee como "fluido" en entradas largas. */
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  /* Leve sobrepaso, solo para elementos chicos que aparecen. */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ============ Reset ============ */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg-base);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
img, svg { max-width: 100%; display: block; }
/* Cualquier regla propia con display le gana al [hidden] del navegador, y
   entonces algo marcado como oculto se sigue viendo. Paso obligatorio:
   ya pasó con las fotos de la galería y con el botón de los videos. */
[hidden] { display: none !important; }
a { color: inherit; text-decoration: none; }
ul, ol { margin: 0; padding: 0; list-style: none; }
h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
input, textarea, select { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--accent-violet-text);
  outline-offset: 3px;
  border-radius: var(--radius-xs);
}

/* Texto solo para lectores de pantalla. Se usa en los encabezados que la
   jerarquia necesita pero el diseno no muestra: sin ellos el indice de
   encabezados salta de h1 a h3 y quien navega por headings pierde el hilo.
   No se usa display:none ni visibility:hidden porque eso tambien lo
   esconderia del lector, que es justo lo contrario de lo que se busca. */
.solo-lectores {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: -60px;
  z-index: 200;
  background: var(--accent-violet);
  color: #fff;
  padding: var(--space-2) var(--space-6);
  border-radius: var(--radius-xs);
  transition: top var(--duration-base) var(--ease-standard);
}
.skip-link:focus { top: var(--space-4); }

/* ============ Layout ============ */
.wrap {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--space-6);
}
@media (min-width: 48em) { .wrap { padding: 0 var(--space-8); } }

.section { padding: var(--space-9) 0; }
.section-elevated { background: var(--bg-elevated); }
@media (min-width: 64em) {
  .section { padding: var(--space-10) 0; }
}

/* ============ Tipografía compartida ============ */
.eyebrow {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.8125rem;
  letter-spacing: 1.04px;
  color: var(--accent-violet-text);
  text-transform: uppercase;
}

.section-heading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  text-align: center;
  margin-bottom: var(--space-8);
}
.section-heading h2 {
  font-weight: 700;
  font-size: clamp(1.5rem, 3vw, 2rem);
  line-height: 1.25;
  text-wrap: balance;
}

/* ============ Botones ============ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 14px 28px;
  border-radius: var(--radius-xs);
  border: 1px solid transparent;
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.2;
  white-space: nowrap;
  touch-action: manipulation;
  transition: transform var(--duration-fast) var(--ease-standard),
              box-shadow var(--duration-base) var(--ease-standard),
              background-color var(--duration-base) var(--ease-standard),
              border-color var(--duration-base) var(--ease-standard);
}
.btn-primary {
  background: var(--accent-violet);
  border-color: var(--accent-violet);
  color: var(--text-primary);
}
/* Anotación de diseño: micro-lift + resplandor al hover */
.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(133, 35, 221, 0.45);
}
.btn-secondary {
  background: transparent;
  border-color: var(--border-subtle);
  color: var(--text-primary);
}
.btn-secondary:hover {
  transform: translateY(-2px);
  border-color: var(--accent-violet);
}
.btn-invert {
  background: var(--text-primary);
  border-color: var(--text-primary);
  color: var(--accent-purple);
}
.btn-invert:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
.btn-block { width: 100%; }
.btn:active { transform: translateY(0); }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; transform: none; box-shadow: none; }

/* ============ Header ============ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border-subtle);
  transition: background-color var(--duration-base) var(--ease-standard);
}
/* Anotación de diseño: el header se vuelve sólido al hacer scroll */
.site-header.is-scrolled { background: var(--bg-base); }

.header-inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-4);
  min-height: var(--header-height);
  padding-top: 14px;
  padding-bottom: 14px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  grid-column: 1;
  justify-self: start;
}
.brand img { width: auto; height: 36px; }
/* El nombre va con la tipografía del logo oficial (Sofia Sans, ensanchada un
   7% como en el .ai), no con la del sitio: así isotipo y texto se leen como
   una sola pieza. El ensanche es visual, por eso el margen compensa el ancho
   extra que el transform no le suma a la caja. */
.wordmark {
  display: flex;
  align-items: center;
  gap: 0.24em;
  font-family: "Sofia Sans", var(--font-sans);
  font-weight: 800;
  font-size: 1.34375rem;
  line-height: 1;
  color: var(--accent-violet-text);
  transform: scaleX(1.074);
  transform-origin: left center;
  margin-right: 0.5em;
}

.main-nav {
  display: none;
  align-items: center;
  gap: 24px;
  grid-column: 2;
  justify-self: center;
  font-weight: 500;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--text-secondary);
}
/* Breakpoints del nav en em, no en px: si alguien agranda la fuente por
   defecto del navegador, el umbral crece en proporcion y el menu pasa a
   hamburguesa antes de desbordar el header. 75em = 1200px al tamano normal. */
@media (min-width: 75em) { .main-nav { gap: 40px; font-size: 0.8125rem; letter-spacing: 0.12em; } }
@media (min-width: 87.5em) { .main-nav { gap: 52px; } }
/* Subrayado del nav: entra desde la izquierda y, al salir, se va hacia la
   derecha en lugar de rebobinar. Se posiciona con bottom negativo para no
   cambiar la altura del enlace y descolocar el header. */
.main-nav a {
  position: relative;
  transition: color var(--duration-base) var(--ease-standard);
}
.main-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -7px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 420ms var(--ease-out-expo);
}
.main-nav a:hover { color: var(--text-primary); }
.main-nav a:hover::after {
  transform: scaleX(1);
  transform-origin: left center;
}

/* La página actual se marcaba solo con color. El subrayado permanente le
   suma un indicador que no depende de distinguir tonos. */
.main-nav a[aria-current="page"] { color: var(--text-primary); }
.main-nav a[aria-current="page"]::after {
  transform: scaleX(1);
  background: var(--accent-violet-text);
}

/* En el desplegable móvil cada ítem es una fila con borde propio: ahí el
   subrayado sobraría. */
.main-nav.is-open a::after { content: none; }

.header-cta { display: none; grid-column: 3; justify-self: end; }

.nav-toggle {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  grid-column: 3;
  justify-self: end;
  margin-right: -10px;
}
.nav-toggle span {
  width: 20px;
  height: 1.5px;
  background: var(--text-primary);
  transition: transform var(--duration-base) var(--ease-standard),
              opacity var(--duration-base) var(--ease-standard);
}
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

.main-nav.is-open {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  /* neutraliza la alineación del grid del header: si no, el panel
     se encoge al ancho de su columna en vez de ocupar todo el ancho */
  justify-self: stretch;
  align-self: start;
  background: var(--bg-elevated);
  border-bottom: 1px solid var(--border-subtle);
  padding: var(--space-2) var(--space-6) var(--space-6);
}
.main-nav.is-open a {
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--border-subtle);
  font-size: 0.875rem;
}

@media (min-width: 64em) {
  .main-nav { display: flex; }
  .header-cta { display: inline-flex; }
  .nav-toggle { display: none; }
}

/* ============ Hero (Inicio) ============ */
.hero {
  position: relative;
  padding: var(--space-9) 0;
}
@media (min-width: 64em) {
  .hero { padding: var(--space-10) 0; }
}
.hero-inner {
  display: grid;
  gap: var(--space-9);
  align-items: center;
}
@media (min-width: 64em) {
  .hero-inner { grid-template-columns: minmax(0, 1fr) 500px; }
}

.hero-copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-6);
  max-width: 560px;
}
.hero-title {
  font-family: var(--font-serif);
  font-weight: 300;
  font-variation-settings: "SOFT" 0, "WONK" 1;
  font-size: clamp(2.125rem, 5vw, 3.375rem);
  line-height: 1.12;
  text-wrap: balance;
}
.hero-desc {
  font-size: 1.125rem;
  color: var(--text-secondary);
  max-width: 480px;
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.hero-visual { display: flex; flex-direction: column; gap: var(--space-3); }
.visual-panel {
  position: relative;
  background: var(--bg-elevated-2);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-xl);
  overflow: hidden;
}
.hero-visual .visual-panel { width: 100%; aspect-ratio: 500 / 480; }

/* ============ Banner de página interior ============ */
.page-banner {
  position: relative;
  background: var(--bg-elevated-2);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  text-align: center;
  padding: var(--space-9) var(--space-6);
  min-height: 240px;
}
.page-banner h1 {
  font-family: var(--font-serif);
  font-weight: 300;
  font-variation-settings: "SOFT" 0, "WONK" 1;
  font-size: clamp(1.875rem, 4.4vw, 2.875rem);
  line-height: 1.12;
}
.page-intro {
  padding: var(--space-9) 0;
  text-align: center;
}
.page-intro p {
  max-width: 760px;
  margin: 0 auto;
  font-size: 1.125rem;
  color: var(--text-secondary);
}

/* ============ WhatsApp flotante ============
   Integrado al sitio, no pegado encima: mismo panel y borde que las
   tarjetas, y el verde de WhatsApp solo en el ícono. Siempre visible: una
   versión anterior aparecía y desaparecía según lo que hubiera en pantalla
   y en la práctica no estaba casi nunca. Para que al final de la página no
   tape nada, el pie reserva abajo el lugar que ocupa (ver .footer-bottom). */
.wa-flotante {
  position: fixed;
  right: max(20px, env(safe-area-inset-right));
  bottom: max(20px, env(safe-area-inset-bottom));
  z-index: 90; /* debajo del header (100) y de su menú */
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 56px;
  padding: 0 22px 0 18px;
  border-radius: 999px;
  background: rgba(31, 27, 51, 0.92); /* --bg-elevated-2 translúcido */
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border-control);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.55);
  color: var(--text-primary);
  font-size: 0.9375rem;
  font-weight: 600;
  transition: transform var(--duration-base) var(--ease-standard),
              border-color var(--duration-fast) var(--ease-standard);
}
.wa-flotante svg {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  color: var(--color-whatsapp);
}
.wa-flotante:hover { border-color: var(--color-whatsapp); transform: translateY(-2px); }
/* Con el menú móvil abierto no tiene que asomar por encima. */
body:has(.main-nav.is-open) .wa-flotante { visibility: hidden; opacity: 0; }
/* En teléfono queda solo el ícono: el texto ocuparía media pantalla. El
   nombre accesible viene del aria-label, que incluye "WhatsApp". */
@media (max-width: 47.99em) {
  .wa-flotante { width: 56px; padding: 0; justify-content: center; }
  .wa-flotante-texto { display: none; }
}

/* ============ Páginas legales ============
   Texto largo para leer, no para escanear: columna angosta, interlineado
   generoso y los avisos obligatorios de la ley diferenciados del resto. */
.legal {
  max-width: 72ch;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  color: var(--text-secondary);
  line-height: 1.7;
}
.legal h2 {
  margin-top: var(--space-6);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text-primary);
}
.legal ul { display: flex; flex-direction: column; gap: var(--space-2); padding-left: 1.2em; list-style: disc; }
.legal strong { color: var(--text-primary); font-weight: 600; }
.legal a { color: var(--accent-violet-text); text-decoration: underline; text-underline-offset: 2px; }
.legal-fecha { font-family: var(--font-mono); font-size: 0.8125rem; color: var(--text-muted); }
.legal-aviso {
  padding: var(--space-4) var(--space-5);
  border-left: 2px solid var(--accent-violet);
  background: var(--bg-elevated);
  font-size: 0.875rem;
}

/* ============ Feature Card ============ */
.card-grid {
  display: grid;
  gap: var(--space-6);
}
@media (min-width: 40em) { .card-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64em) { .card-grid { grid-template-columns: repeat(3, 1fr); } }

.feature-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
  background: var(--bg-elevated-2);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: 28px 24px;
  transition: border-color var(--duration-base) var(--ease-standard),
              transform var(--duration-base) var(--ease-standard);
}
.feature-card:hover { border-color: rgba(133, 35, 221, 0.5); transform: translateY(-2px); }
.feature-card .icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  background: var(--accent-purple);
  color: var(--text-primary);
  flex-shrink: 0;
}
.feature-card .icon svg { width: 20px; height: 20px; }
.feature-card h3 { font-weight: 600; font-size: 1.125rem; line-height: 1.3; }
.feature-card p { font-size: 0.875rem; color: var(--text-secondary); }


/* ---- Etiquetas de software (servicios) ----
   Nombres de programas y formatos dentro de una .feature-card. Van en mono,
   como el resto de los rótulos del sitio, con el borde sutil en vez de un
   relleno: son datos, no botones, y no tienen que competir con el texto. */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: auto;
  padding-top: var(--space-2);
  list-style: none;
}
.chips li {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.4px;
  color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
  border-radius: 999px;
  padding: 5px 11px;
  white-space: nowrap;
}

/* Los formatos no son una herramienta más: son la respuesta a "¿te sirve
   mi archivo?". Van juntos en una banda debajo de las tarjetas, centrados
   y sin caja, para que se lean de un vistazo sin competir con ellas. */
.formatos {
  margin-top: var(--space-8);
  padding-top: var(--space-7);
  border-top: 1px solid var(--border-subtle);
  text-align: center;
}
.formatos h3 {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.8125rem;
  letter-spacing: 1.04px;
  text-transform: uppercase;
  color: var(--text-muted);
}
.chips--centro {
  justify-content: center;
  max-width: 68ch;
  margin: var(--space-5) auto 0;
  padding-top: 0;
}
.software-nota {
  max-width: 62ch;
  margin: var(--space-7) auto 0;
  text-align: center;
  font-size: 0.9375rem;
  color: var(--text-secondary);
}
.software-nota a { color: var(--accent-violet-text); text-decoration: underline; text-underline-offset: 3px; }
/* ---- Tarjetas de servicio con foto ----
   Variante solo para la grilla de servicios. La de tecnologías (FDM, resina,
   post-procesado) usa la misma .feature-card y sigue sin foto. */
.feature-card--servicio {
  padding: 0;
  gap: 0;
  align-items: stretch;
  overflow: hidden;
}
.servicio-foto {
  position: relative;
  aspect-ratio: 3 / 2;
  background: var(--bg-elevated);
}
.servicio-foto img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* El ícono queda montado sobre el corte entre foto y texto: conserva el
   sistema de íconos del sitio sin taparle nada a la foto. El anillo del
   color de la tarjeta lo despega de la imagen. */
.servicio-foto .icon {
  position: absolute;
  left: 24px;
  bottom: -20px;
  box-shadow: 0 0 0 4px var(--bg-elevated-2);
}
.servicio-cuerpo {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
  flex: 1;
  padding: 36px 24px 24px;
}
/* margin-top: auto manda el botón al pie: quedan alineados entre tarjetas
   aunque los textos tengan largos distintos. Va en variante secundaria
   porque seis botones rellenos en una grilla gritan; el ícono verde alcanza
   para decir "WhatsApp" de un vistazo. */
.btn-consulta {
  margin-top: auto;
  width: 100%;
  gap: 10px;
  font-size: 0.9375rem;
  /* .btn no deja partir el texto; acá sí hace falta: en un teléfono
     "Pedir presupuesto por WhatsApp" no entra en una línea y, sin salto,
     ensanchaba el formulario entero y la página desbordaba. */
  white-space: normal;
  text-align: center;
}
.btn-icono { width: 18px; height: 18px; flex-shrink: 0; }
.btn-consulta .btn-icono { color: var(--color-whatsapp); }

/* ============ Process Step Card ============ */
.process-grid {
  display: grid;
  gap: var(--space-6);
}
@media (min-width: 40em) { .process-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64em) { .process-grid { grid-template-columns: repeat(4, 1fr); } }

.process-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
  background: var(--bg-elevated-2);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: 24px 24px 28px;
  transition: border-color var(--duration-base) var(--ease-standard),
              transform var(--duration-base) var(--ease-standard);
}
.process-card:hover { border-color: rgba(133, 35, 221, 0.5); transform: translateY(-2px); }
.process-card .thumb {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  background: var(--bg-elevated);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
/* La foto se pinta encima del dibujo técnico. Si el archivo todavía no
   existe, la capa queda transparente y se ve el dibujo como respaldo. */
.process-card .thumb::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--photo);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
/* El plano es tinta negra sobre papel blanco: invertido se lee como
   blueprint y deja de ser un bloque blanco en medio de la sección. */
.process-card .thumb--blueprint::after {
  filter: invert(1) brightness(0.92);
}
.process-card .step {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.8125rem;
  color: var(--accent-violet-text);
}
.process-card h3 { font-weight: 600; font-size: 1.25rem; line-height: 1.3; }
.process-card p { font-size: 0.875rem; color: var(--text-secondary); }

/* ============ Portfolio Card ============ */
.portfolio-grid {
  display: grid;
  gap: var(--space-7);
}
@media (min-width: 40em) { .portfolio-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64em) { .portfolio-grid { grid-template-columns: repeat(3, 1fr); } }

.portfolio-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  border-radius: var(--radius-lg);
}
.portfolio-card .thumb {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--bg-elevated-2);
  border-radius: var(--radius-md);
  overflow: hidden;
  transition: transform var(--duration-base) var(--ease-standard);
}
.portfolio-card:hover .thumb { transform: translateY(-4px); }
/* Galería: las tres tomas viven en el HTML como <img> con su alt y se
   cruzan por opacidad. Las secundarias arrancan con [hidden] — esa es la
   compuerta que evita que una grilla de 6 piezas baje 18 fotos de
   entrada — y el JS la levanta la primera vez que hacen falta. */
.galeria .toma {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* La foto ahora responde al click: el cursor tiene que decirlo. */
  cursor: pointer;
  opacity: 0;
  transition: opacity 420ms var(--ease-standard);
}
.galeria .toma.is-active { opacity: 1; }

/* Puntos indicadores. Ahora son <button> de verdad, así que necesitan área
   de toque: el punto sigue midiendo 6px pero el botón que lo rodea llega a
   24x32, por encima del mínimo de 24x24 de WCAG 2.5.8. En táctil, además,
   tocar la foto también avanza, así que hay un camino alternativo. */
/* Fondo propio: los puntos blancos al 40% desaparecian sobre una foto
   clara, y ademas le dan al anillo de foco algo con que contrastar. */
.galeria-puntos {
  position: absolute;
  left: 6px;
  bottom: 4px;
  display: flex;
  z-index: 2;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(4px);
}
/* .thumb recorta con overflow:hidden y el outline global sale 5px hacia
   afuera: sobre el borde quedaria cortado. Se dibuja hacia adentro, donde
   el boton tiene 24x32 de sobra para mostrarlo entero. */
.galeria-punto:focus-visible {
  outline-offset: -4px;
  border-radius: 999px;
}
.galeria-punto {
  width: 24px;
  height: 32px;
  padding: 0;
  display: grid;
  place-items: center;
}
.galeria-punto::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.4);
  transition: background-color var(--duration-base) var(--ease-standard),
              transform var(--duration-base) var(--ease-standard);
}
.galeria-punto:hover::before { background: rgba(255, 255, 255, 0.75); }
.galeria-punto.is-active::before {
  background: var(--text-primary);
  transform: scale(1.15);
}

/* Antes acá había un ::after con un ▶ decorativo: parecía un control pero
   no lo era, y con teclado el video no se podía ver. Ahora es un botón. */
.video-toggle {
  position: absolute;
  right: 10px;
  bottom: 10px;
  width: 44px;
  height: 44px;
  padding: 0;
  display: grid;
  place-items: center;
  color: var(--text-primary);
  background: rgba(0, 0, 0, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 50%;
  backdrop-filter: blur(4px);
  z-index: 2;
  transition: background-color var(--duration-fast) var(--ease-standard),
              opacity var(--duration-base) var(--ease-standard);
}
.video-toggle:hover { background: rgba(0, 0, 0, 0.75); }
/* Mismo motivo que en los puntos, y ademas el anillo cae sobre el fondo
   oscuro del propio boton en vez de sobre la foto. */
.video-toggle:focus-visible { outline-offset: -3px; }
/* Mientras corre se corre del camino, pero no desaparece: sigue siendo el
   modo de pausarlo. Vuelve entero con hover o con foco. */
.video-toggle.is-playing { opacity: 0.35; }
.portfolio-card:hover .video-toggle,
.video-toggle:focus-visible { opacity: 1; }

/* Triángulo de play y dos barras de pausa, dibujados en CSS */
.video-toggle-icono {
  width: 0;
  height: 0;
  margin-left: 3px;
  border-style: solid;
  border-width: 6px 0 6px 10px;
  border-color: transparent transparent transparent currentColor;
}
.video-toggle.is-playing .video-toggle-icono {
  box-sizing: border-box;
  width: 10px;
  height: 12px;
  margin-left: 0;
  border: 0;
  border-left: 3px solid currentColor;
  border-right: 3px solid currentColor;
}

.portfolio-card .tag {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.6875rem;
  letter-spacing: 0.66px;
  color: var(--accent-violet-text);
  text-transform: uppercase;
}
.portfolio-card h3 {
  margin-top: var(--space-1);
  font-weight: 600;
  font-size: 1.125rem;
  line-height: 1.35;
}

/* Al llegar desde un enlace (portafolio.html#baul-honda) la tarjeta no
   tiene que quedar tapada por el encabezado fijo. */
.portfolio-card[id],
h2[id] { scroll-margin-top: calc(var(--header-height) + var(--space-5)); }

/* Proyectos destacados en el inicio: las mismas tarjetas del portafolio,
   con una sola foto y enlazadas a su proyecto. Toda la tarjeta es el link. */
.destacados .portfolio-card { color: inherit; text-decoration: none; }
.destacados .portfolio-card:focus-visible { outline: 2px solid var(--accent-violet); outline-offset: 6px; }
.destacados .thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.destacados-pie { display: flex; justify-content: center; margin-top: var(--space-8); }

/* ---- Quiénes somos ----
   Las etapas del proceso viven solo en el inicio. Esta página cuenta quién
   está detrás, para qué tipo de proyecto sirve y responde las dudas previas. */
.about-datos { margin-top: var(--space-2); padding-top: 0; }

/* Ejemplos de cada perfil: links al proyecto en el portafolio. El rótulo
   lleva margin-top: auto para que las tres listas queden alineadas al pie. */
.perfil-ejemplos-titulo {
  margin-top: auto;
  padding-top: var(--space-2);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.6875rem;
  letter-spacing: 0.66px;
  text-transform: uppercase;
  color: var(--text-muted);
}
.perfil-ejemplos { list-style: none; display: flex; flex-direction: column; gap: 6px; }
.perfil-ejemplos a { color: var(--accent-violet-text); text-decoration: none; }
.perfil-ejemplos a::after { content: " →"; }
.perfil-ejemplos a:hover { text-decoration: underline; text-underline-offset: 3px; }

/* Preguntas frecuentes: <details> nativo, se abre con mouse, dedo o teclado
   sin JS. El "+" gira a "×" al abrir. */
.faq { max-width: 760px; margin: 0 auto; border-top: 1px solid var(--border-subtle); }
.faq details { border-bottom: 1px solid var(--border-subtle); }
.faq summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-5) 0;
  font-weight: 600;
  font-size: 1.0625rem;
  cursor: pointer;
  list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  flex: none;
  font-family: var(--font-mono);
  font-size: 1.375rem;
  line-height: 1;
  color: var(--accent-violet-text);
  transition: transform var(--duration-base) var(--ease-standard);
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq summary:hover { color: var(--accent-violet-text); }
.faq summary:focus-visible { outline: 2px solid var(--accent-violet); outline-offset: 4px; border-radius: 4px; }
.faq details p { max-width: 64ch; padding-bottom: var(--space-5); color: var(--text-secondary); }
.faq details p a { color: var(--accent-violet-text); text-decoration: underline; text-underline-offset: 3px; }

/* ============ CTA Band ============ */
.cta-band {
  background: var(--accent-purple);
  padding: var(--space-10) 0;
  text-align: center;
}
.cta-band-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
}
.cta-band h2 {
  font-weight: 700;
  font-size: clamp(1.625rem, 3.4vw, 2.25rem);
  line-height: 1.25;
  text-wrap: balance;
}
.cta-band p {
  font-size: 1rem;
  opacity: 0.85;
  max-width: 640px;
}
/* Dos caminos para pedir presupuesto: formulario o WhatsApp. En pantallas
   chicas se apilan solos gracias al wrap. */
.cta-band-acciones {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
}
/* Secundario sobre la banda violeta: contorno blanco, sin relleno. El ícono
   queda blanco — el verde de WhatsApp sobre violeta se pelearía. */
.btn-claro {
  gap: 10px;
  white-space: normal;
  text-align: center;
  background: transparent;
  border-color: rgba(255, 255, 255, 0.6);
  color: var(--text-primary);
}
.btn-claro:hover {
  transform: translateY(-2px);
  border-color: var(--text-primary);
  background: rgba(255, 255, 255, 0.08);
}

/* ============ Quiénes somos ============ */
.about-grid {
  display: grid;
  gap: var(--space-9);
  align-items: center;
}
@media (min-width: 64em) {
  .about-grid { grid-template-columns: 560px 1fr; }
}
.about-visual { display: flex; flex-direction: column; gap: var(--space-3); }
.about-visual .visual-panel { aspect-ratio: 560 / 420; border-radius: var(--radius-lg); }

/* ---- Render de la caja caliente sobre el plano tecnico ----
   El PNG tiene fondo transparente, asi que por primera vez el blueprint de
   atras se ve: la pieza queda apoyada sobre la grilla de dibujo en lugar de
   taparla. Va contenida y no recortada porque el render es cuadrado y el
   panel 4:3 — con cover se perderian la manija de arriba y las patas del
   bastidor, los dos extremos que hacen legible la explosion. */
.visual-panel--render .blueprint {
  position: absolute;
  inset: 0;
  z-index: 0;
  /* El plano pasa a segundo plano: con la pieza encima competia por atencion
     en vez de acompanarla. */
  opacity: 0.5;
}

/* Luz de estudio detras de la pieza. Las piezas del render promedian 92/255
   de luminancia contra un panel en 30: son 2.57:1, y sin ayuda los paneles
   mas oscuros se hunden en el fondo. El nucleo neutro los despega y el halo
   violeta lo ata al acento de la marca. */
.visual-panel--render::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(44% 42% at 50% 44%, rgba(255, 255, 255, 0.11) 0%, transparent 72%),
    radial-gradient(66% 60% at 50% 50%, rgba(133, 35, 221, 0.04) 0%, transparent 78%);
}

.render-pieza {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: var(--space-5);
  /* Medido: las piezas promedian 92/255 contra un panel en 30 — 2.57:1.
     Subirles el brillo las despega del fondo sin tocar el archivo, y la
     sombra les devuelve el borde que el fondo oscuro se comia. */
  filter: brightness(1.3) contrast(1.05) drop-shadow(0 14px 30px rgba(0, 0, 0, 0.6));
}
.about-copy { display: flex; flex-direction: column; gap: var(--space-4); }
.about-copy h2 {
  font-weight: 700;
  font-size: clamp(1.5rem, 3vw, 2rem);
  line-height: 1.25;
}
.about-copy p { color: var(--text-secondary); font-size: 1rem; }

/* ============ Cómo cotizamos ============ */
.steps-grid {
  display: grid;
  gap: var(--space-6);
}
@media (min-width: 48em) { .steps-grid { grid-template-columns: repeat(3, 1fr); } }
.quote-step { display: flex; flex-direction: column; gap: var(--space-3); }
.quote-step .num {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.8125rem;
  color: var(--accent-violet-text);
}
.quote-step h3 { font-weight: 600; font-size: 1.125rem; }
.quote-step p { font-size: 0.875rem; color: var(--text-secondary); }

/* ============ Contacto ============ */
.contact-grid {
  display: grid;
  gap: var(--space-9);
  align-items: start;
}
/* Sin esto, un nombre de archivo largo sin espacios fija el ancho mínimo de
   la columna y el formulario se sale de la pantalla en el celular. Con
   min-width: 0 la columna manda y el nombre se recorta con puntos
   suspensivos (ver .archivo-nombre). */
.contact-grid > * { min-width: 0; }
@media (min-width: 56.25em) {
  .contact-grid { grid-template-columns: 1fr 1fr; gap: 72px; }
}

/* Luz ambiental detrás de la sección, para que las tarjetas tengan
   sobre qué brillar en vez de flotar sobre negro plano */
.contact-section { position: relative; isolation: isolate; }
.contact-section::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(65% 55% at 50% 35%, rgba(133, 35, 221, 0.12), transparent 70%);
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  background: var(--bg-elevated-2);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-7);
}

.contact-form h2 { font-weight: 600; font-size: 1.375rem; }
.field-row { display: grid; gap: var(--space-4); }
@media (min-width: 35em) { .field-row { grid-template-columns: 1fr 1fr; } }

.field { display: flex; flex-direction: column; gap: var(--space-2); }
.field label {
  font-weight: 500;
  font-size: 0.8125rem;
  color: var(--text-secondary);
}
.field label span { color: var(--accent-violet-text); }
.field input,
.field textarea {
  width: 100%;
  min-height: 48px;
  padding: 14px 16px;
  /* más oscuro que la tarjeta (Figma los tiene del mismo color) para
     que el campo se lea hundido y no plano */
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid var(--border-control);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-size: 0.875rem;
  transition: border-color var(--duration-fast) var(--ease-standard);
}
.field textarea { min-height: 120px; resize: vertical; }
.field input::placeholder,
.field textarea::placeholder { color: var(--text-muted); }
.field input:focus, .field textarea:focus { border-color: var(--accent-violet); }
.field input[aria-invalid="true"],
.field textarea[aria-invalid="true"] { border-color: var(--color-error-border); }

.field-error { font-size: 0.7813rem; color: var(--color-error); min-height: 1em; }

/* ---- Adjuntos ----
   Mismo fondo hundido y borde que los demás campos; el borde punteado dice
   "soltá acá". El <input type=file> real cubre toda la zona, transparente:
   así el click, el teclado y el arrastrar-soltar son los nativos del
   navegador, y el lector de pantalla anuncia un campo de archivos común. */
.field label .label-opcional { color: var(--text-muted); font-weight: 400; }
.archivos-zona {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-6) var(--space-4);
  text-align: center;
  background: rgba(0, 0, 0, 0.45);
  border: 1px dashed var(--border-control);
  border-radius: var(--radius-sm);
  transition: border-color var(--duration-fast) var(--ease-standard),
              background-color var(--duration-fast) var(--ease-standard);
}
.archivos-zona input[type="file"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  min-height: 0;
  padding: 0;
  border: 0;
  opacity: 0;
  cursor: pointer;
}
.archivos-zona:hover,
.archivos-zona.is-arrastrando {
  border-color: var(--accent-violet);
  background: rgba(133, 35, 221, 0.08);
}
/* El input es invisible, así que el anillo de foco lo muestra la zona. Solo
   con teclado (:focus-visible), no al hacer click. */
.archivos-zona:has(input:focus-visible) {
  outline: 2px solid var(--accent-violet-text);
  outline-offset: 3px;
}
.archivos-zona.is-invalida { border-color: var(--color-error-border); }
.archivos-icono { width: 28px; height: 28px; color: var(--accent-violet-text); }
.archivos-texto { font-size: 0.875rem; color: var(--text-secondary); }
.archivos-texto strong { color: var(--text-primary); font-weight: 600; }
.archivos-ayuda { font-size: 0.75rem; color: var(--text-muted); }

.archivos-lista { display: flex; flex-direction: column; gap: var(--space-2); }
.archivos-lista:empty { display: none; }
.archivos-lista li {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 6px 6px 6px 12px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
  font-size: 0.8125rem;
}
.archivo-nombre {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-primary);
}
.archivo-peso { flex-shrink: 0; font-family: var(--font-mono); font-size: 0.75rem; color: var(--text-muted); }
.archivo-quitar {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-xs);
  color: var(--text-secondary);
}
.archivo-quitar:hover { color: var(--text-primary); background: rgba(255, 255, 255, 0.06); }
.archivo-quitar svg { width: 16px; height: 16px; }
.form-note { font-size: 0.75rem; color: var(--text-muted); }
.form-note a,
.footer-bottom a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Segundo canal para el mismo pedido: WhatsApp, debajo del envío por mail. */
.form-alternativa {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.form-alternativa-separador {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.form-alternativa-separador::before,
.form-alternativa-separador::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border-subtle);
}
.form-alternativa-nota {
  font-size: 0.75rem;
  color: var(--text-muted);
  text-align: center;
}
.form-status { font-size: 0.8438rem; color: var(--text-secondary); }
.form-status[data-state="success"] { color: var(--color-success); }
.form-status[data-state="error"] { color: var(--color-error); }

/* El estado del formulario puede ofrecer una salida (abrir el correo con
   la consulta ya escrita). Hereda el color del estado para no competir
   con el mensaje que la acompaña. */
.form-status-link {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.form-status-link:hover { text-decoration-thickness: 2px; }

/* Trampa anti-spam. Fuera de la vista y del recorrido de foco, pero no
   con display:none ni visibility:hidden: varios bots descartan los
   campos ocultos de esa forma y la trampa dejaria de funcionar. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.contact-info { display: flex; flex-direction: column; gap: var(--space-6); }

.info-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  background: var(--bg-elevated-2);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-7);
}
.info-card h2 { font-weight: 600; font-size: 1.375rem; }

.info-list { display: flex; flex-direction: column; gap: var(--space-5); }
.info-item { display: flex; align-items: flex-start; gap: var(--space-4); }
.info-item .icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: var(--accent-purple);
  color: var(--text-primary);
}
.info-item .label {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.75rem;
  letter-spacing: 0.72px;
  color: var(--accent-violet-text);
}
.info-item .value {
  display: block;
  margin-top: 2px;
  font-size: 1rem;
  color: var(--text-primary);
  overflow-wrap: anywhere;
  transition: color var(--duration-fast) var(--ease-standard);
}
a.value:hover { color: var(--accent-violet-text); }

.info-social {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-subtle);
}
.info-social .label {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.75rem;
  letter-spacing: 0.72px;
  color: var(--accent-violet-text);
}

.hours-list { display: flex; flex-direction: column; gap: var(--space-3); }
.hours-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: 0.9375rem;
  color: var(--text-secondary);
}
.hours-list .hours { color: var(--text-primary); }

/* Resplandor de las tarjetas de contacto.
   Va después de .contact-form y .info-card para ganarles el border/background. */
.contact-form,
.info-card {
  border-color: rgba(133, 35, 221, 0.22);
  background:
    radial-gradient(120% 90% at 0% 0%, rgba(133, 35, 221, 0.10), transparent 60%),
    var(--bg-elevated-2);
  box-shadow:
    0 24px 60px -24px rgba(0, 0, 0, 0.85),
    0 0 48px -18px rgba(133, 35, 221, 0.45);
}
.info-card {
  transition: box-shadow var(--duration-base) var(--ease-standard),
              border-color var(--duration-base) var(--ease-standard);
}
.info-card:hover {
  border-color: rgba(133, 35, 221, 0.42);
  box-shadow:
    0 24px 60px -24px rgba(0, 0, 0, 0.85),
    0 0 64px -14px rgba(133, 35, 221, 0.6);
}

.social-row { display: flex; gap: 10px; }
.social-row a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--border-subtle);
  border-radius: 50%;
  font-weight: 600;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  transition: border-color var(--duration-fast) var(--ease-standard),
              color var(--duration-fast) var(--ease-standard);
}
.social-row a:hover { border-color: var(--accent-violet); color: var(--text-primary); }
.social-row svg { width: 17px; height: 17px; }
.footer-col .social-row svg { width: 15px; height: 15px; }

/* ============ Footer ============ */
.site-footer {
  background: var(--bg-elevated);
  padding-top: var(--space-9);
}
.footer-top {
  display: grid;
  gap: var(--space-8);
  padding-bottom: var(--space-8);
}
@media (min-width: 48em) {
  .footer-top { grid-template-columns: 1.6fr 1fr 1.2fr 0.8fr; }
}
.footer-brand { display: flex; flex-direction: column; gap: 14px; }
.footer-brand .brand { margin-right: 0; }
.footer-brand img { width: auto; height: 28px; }
.footer-brand .wordmark { font-size: 1.0625rem; }
.footer-brand p {
  font-size: 0.8125rem;
  color: var(--text-muted);
  max-width: 240px;
}
.footer-col { display: flex; flex-direction: column; gap: 14px; }
.footer-col h2 {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.75rem;
  letter-spacing: 0.96px;
  color: var(--text-muted);
}
.footer-col ul { display: flex; flex-direction: column; gap: 10px; }
.footer-col a, .footer-col li {
  font-size: 0.875rem;
  color: var(--text-secondary);
}
.footer-col a:hover { color: var(--text-primary); }

/* Mismo subrayado que el nav. Va sobre 'ul a' para no alcanzar a los
   círculos de redes, que son botones con ícono y ya tienen su hover. */
.footer-col ul a {
  position: relative;
  display: inline-block;
  transition: color var(--duration-base) var(--ease-standard);
}
.footer-col ul a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -4px;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 420ms var(--ease-out-expo);
}
.footer-col ul a:hover::after {
  transform: scaleX(1);
  transform-origin: left center;
}

.footer-col .social-row a { width: 44px; height: 44px; font-size: 0.75rem; }

.footer-divider { height: 1px; background: var(--border-subtle); }
.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-top: var(--space-8);
  /* 56px del botón flotante + 20px de margen + aire: así el último renglón
     queda por encima del botón en vez de debajo. */
  padding-bottom: calc(76px + var(--space-5));
  font-size: 0.75rem;
  color: var(--text-muted);
}

/* ============ Ilustraciones técnicas (placeholders de imagen) ============ */
.blueprint { width: 100%; height: 100%; }
.blueprint .grid-line { stroke: var(--border-subtle); stroke-width: 1; }
.blueprint .draw { stroke: var(--accent-violet); fill: none; stroke-width: 1.3; }
.blueprint .draw-purple { stroke: var(--accent-purple); fill: none; stroke-width: 1.3; }
.blueprint .node { fill: var(--accent-violet); }

/* ============ Reveal (anotación: fade + stagger de 100ms) ============ */
.reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 500ms var(--ease-out-expo), transform 500ms var(--ease-out-expo);
  transition-delay: calc(var(--reveal-index, 0) * 100ms);
}
.reveal.is-visible { opacity: 1; transform: none; }

/* ============ Entrada del hero ============
   Secuencia escalonada al cargar. El isométrico se traza solo, siguiendo
   la anotación de Figma "las marcas de esquina se dibujan al cargar".
   Los trazos usan pathLength="1" para normalizar el largo de cada path,
   así el dashoffset va de 1 a 0 sin importar la geometría. */

@keyframes heroRise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}
@keyframes heroFade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes heroPanel {
  from { opacity: 0; transform: translateY(26px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
@keyframes heroRule {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
@keyframes heroDraw {
  from { stroke-dashoffset: 1; }
  to   { stroke-dashoffset: 0; }
}
@keyframes heroNode {
  from { opacity: 0; transform: scale(0.4); }
  to   { opacity: 1; transform: scale(1); }
}

.hero-copy > *,
.hero-visual .visual-panel {
  animation-duration: 620ms;
  animation-timing-function: var(--ease-out-expo);
  animation-fill-mode: both;
}


.hero-copy > *:nth-child(1) { animation-name: heroRise; animation-delay: 220ms; }
.hero-copy > *:nth-child(2) { animation-name: heroRise; animation-delay: 320ms; }
.hero-copy > *:nth-child(3) { animation-name: heroRise; animation-delay: 420ms; }
.hero-copy > *:nth-child(4) { animation-name: heroRise; animation-delay: 520ms; }

.hero-visual .visual-panel { animation-name: heroPanel; animation-delay: 300ms; }

/* La foto entra recién cuando el isométrico terminó de trazarse: el dibujo
   se convierte en la pieza real, que es literalmente el titular de la página.
   Si el archivo no existe, queda el dibujo y no se rompe nada. */
.hero-visual .visual-panel::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--photo);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  animation: heroFade 850ms var(--ease-standard) 1600ms both;
}

/* Banner de páginas interiores. Está sobre la línea de flote, así que
   entra al cargar igual que el hero. Lo de más abajo usa .reveal, que se
   dispara al scrollear: animar al cargar algo que no se ve es tirar la
   animación a la basura. La marca de esquina ya se anima globalmente. */
.page-banner .eyebrow,
.page-banner h1 {
  animation-duration: 620ms;
  animation-timing-function: var(--ease-out-expo);
  animation-fill-mode: both;
  animation-name: heroRise;
}
.page-banner .eyebrow { animation-delay: 200ms; }
.page-banner h1 { animation-delay: 300ms; }

/* Trazado del dibujo dentro del panel */
.hero-visual .blueprint .grid-line { animation: heroFade 700ms var(--ease-standard) 520ms both; }
.hero-visual .blueprint .draw:not(.draw-dashed) path,
.hero-visual .blueprint .draw:not(.draw-dashed) circle {
  stroke-dasharray: 1;
  animation: heroDraw 900ms var(--ease-out-expo) 640ms both;
}
/* Las guías punteadas ya usan dasharray para su estilo: se desvanecen */
.hero-visual .blueprint .draw-dashed {
  animation: heroFade 600ms var(--ease-standard) 1320ms both;
}
.hero-visual .blueprint .node circle {
  transform-box: fill-box;
  transform-origin: center;
  animation: heroNode 420ms var(--ease-spring) 1400ms both;
}

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

  /* Las animaciones declaradas se apagan enteras: la entrada del hero, los
     trazos que se dibujan solos, cualquier loop. Eso es movimiento que
     arranca sin que nadie lo pida, que es justo lo que se está pidiendo
     evitar. Con animation-fill-mode: both cada una queda en su estado
     final, no invisible. */
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
  }

  /* Las transiciones NO se apagan en bloque. Son la respuesta a algo que
     la persona acaba de hacer — abrir el menú, enfocar un campo, ver el
     resultado del formulario — y apagarlas no reduce movimiento: borra el
     aviso de que algo cambió. Se acortan y se limitan a propiedades que no
     desplazan nada. El movimiento se anula abajo, por separado. */
  *, *::before, *::after {
    transition-duration: 120ms !important;
    transition-property: color, background-color, border-color, outline-color,
                         opacity, box-shadow, fill, stroke !important;
  }

  /* Sin la transición, un translateY de hover saltaría de golpe: peor que
     no tenerlo. Se quedan quietos. */
  .btn:hover,
  .feature-card:hover,
  .process-card:hover,
  .portfolio-card:hover .thumb,
  .hero-actions .btn-secondary:hover::after,
  .wa-flotante:hover,
  .galeria-punto.is-active::before { transform: none; }

  .reveal { opacity: 1; transform: none; }
  /* sin animación el trazo debe quedar completo, no invisible */
  .hero-visual .blueprint .draw:not(.draw-dashed) path,
  .hero-visual .blueprint .draw:not(.draw-dashed) circle { stroke-dasharray: none; stroke-dashoffset: 0; }
}

/* ============================================================
   CAPA V3 — composición "void"
   Referencia: Dala (refero.design). Se toman TRES cosas y nada más:
   composición sin cajas, escala tipográfica grande y un segundo
   acento ámbar. NO se toma su prohibición de serifs ni de fotos:
   Fraunces y las fotos de piezas reales son justamente lo que
   separa a Vitium del uniforme negro+violeta de Linear/Vercel/
   Runway, que es a lo que se parece Dala.
   Tampoco se toma su botón tipo píldora: el radio chico (4px) lee
   técnico, la píldora lee consumer.
   Todo este bloque pisa a la hoja de arriba por cascada. Borrándolo
   entero, el sitio vuelve exactamente a como estaba en v2.
   ============================================================ */

:root {
  /* Segundo acento. Sobre negro da 12:1 — pasa AAA hasta en texto
     chico. Contra el violeta arma la tensión de dos colores que hace
     que una paleta se lea diseñada y no autogenerada. Para un taller
     además significa algo: metal caliente, nozzle a temperatura. */
  --accent-amber: #FFB829;
  --space-11: 104px;
}

/* --- Los labels mono pasan a ámbar --- */
.eyebrow { color: var(--accent-amber); }

/* --- Hero: más aire arriba, headline grande, columnas asimétricas --- */
.hero { padding: var(--space-9) 0 var(--space-9); }
@media (min-width: 64em) {
  .hero { padding: 128px 0 var(--space-11); }
  .hero-inner {
    grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
    gap: var(--space-9);
    align-items: center;
  }
}
.hero-copy { max-width: 660px; gap: var(--space-7); }
.hero-title {
  /* 44px → 96px. Antes topaba en 54px. La jerarquía la da la escala,
     no el peso: sigue en Fraunces 300. */
  font-size: clamp(2.75rem, 8.2vw, 6rem);
  line-height: 1.02;
  /* la serif a este tamaño abre demasiado; se cierra apenas */
  letter-spacing: -0.015em;
}
.hero-desc {
  /* Dala usa weight 200. Sobre negro el texto claro ya se ve más fino
     de lo que es (halación), así que 200 se rompe: 300 es el
     equivalente real en modo oscuro. */
  font-weight: 300;
  font-size: 1.25rem;
  line-height: 1.55;
  max-width: 520px;
}

/* Un solo botón lleno; el segundo pasa a link fantasma */
.hero-actions { gap: var(--space-6); align-items: center; }
.hero-actions .btn-secondary {
  background: none;
  border-color: transparent;
  padding-left: 0;
  padding-right: 0;
  gap: 10px;
  font-weight: 500;
  color: var(--text-secondary);
}
.hero-actions .btn-secondary::after {
  content: "→";
  transition: transform var(--duration-base) var(--ease-out-expo);
}
.hero-actions .btn-secondary:hover {
  transform: none;
  border-color: transparent;
  color: var(--text-primary);
}
.hero-actions .btn-secondary:hover::after { transform: translateX(5px); }

/* El panel deja de ser panel: sin caja, sin borde, sin radio */
.hero-visual .visual-panel {
  background: transparent;
  border: 0;
  border-radius: 0;
  /* la proporción del render: sin aire de sobra arriba y abajo */
  aspect-ratio: 1020 / 974;
}

/* --- Títulos de sección: serif liviana y grande --- */
.section-heading h2 {
  font-family: var(--font-serif);
  font-weight: 300;
  font-variation-settings: "SOFT" 0, "WONK" 1;
  /* 32px → 52px, y sale de Inter 700, que era el reflejo de plantilla */
  font-size: clamp(2rem, 4.6vw, 3.25rem);
  line-height: 1.1;
  letter-spacing: -0.015em;
}

/* --- Sección sin cajas --- */
.void-section { padding-bottom: var(--space-10); }
.void-section .section-heading {
  align-items: flex-start;
  text-align: left;
  margin-bottom: var(--space-9);
}
.void-section .section-heading h2 { max-width: 15ch; }

.void-grid {
  display: grid;
  gap: var(--space-9) var(--space-8);
}
@media (min-width: 48em) {
  .void-grid { grid-template-columns: repeat(3, 1fr); gap: var(--space-8); }
}

/* Sin fondo, sin borde, sin radio, sin hover-lift: separa el aire */
.void-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-4);
}
/* El ícono conserva el dibujo pero pierde el cuadradito violeta */
.void-item .icon {
  display: block;
  width: 32px;
  height: 32px;
  background: none;
  border-radius: 0;
  color: var(--accent-amber);
}
.void-item .icon svg { width: 32px; height: 32px; }
.void-item h3 {
  font-family: var(--font-serif);
  font-weight: 300;
  font-variation-settings: "SOFT" 0, "WONK" 1;
  font-size: 1.625rem;
  line-height: 1.2;
}
.void-item p {
  font-weight: 300;
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--text-secondary);
  max-width: 36ch;
}


/* La grilla del blueprint también termina en un rectángulo duro. Se le
   funde el borde para que el bloque entero se disuelva en el negro en
   vez de quedar recortado. */
.hero-visual .visual-panel {
  -webkit-mask-image: radial-gradient(128% 116% at 50% 45%, #000 58%, transparent 100%);
  mask-image: radial-gradient(128% 116% at 50% 45%, #000 58%, transparent 100%);
}

/* ============================================================
   HERO: RENDER RECORTADO SOBRE NEGRO
   El motor viene en dos archivos: el color en JPEG (95 KB) y la silueta
   en una máscara PNG (36 KB). Como un solo PNG transparente pesaba
   865 KB, y es de lo primero que descarga la página.
   ============================================================ */

/* La foto vieja iba en el ::after del panel; ahora la pieza es un
   elemento propio, porque el contorno necesita un contenedor (ver abajo). */
.hero-visual .visual-panel::after { content: none; }

/* Luz neutra detrás. La mitad del motor es casi negra: sin esto el
   soplador y el bloque se funden con el fondo y no se ve dónde termina. */
.hero-visual .visual-panel::before {
  content: "";
  position: absolute;
  inset: 6% 2% 4%;
  background: radial-gradient(50% 50% at 50% 54%, rgba(255, 255, 255, 0.13), transparent 72%);
  pointer-events: none;
  animation: heroFade 1100ms var(--ease-standard) 1650ms both;
}

.hero-pieza {
  position: absolute;
  inset: 4% 3%;
  /* El contorno va en el contenedor y no en la imagen: el filtro se
     calcula antes que la máscara, así que en la misma capa rodearía el
     rectángulo entero del JPEG y la máscara lo borraría junto con él. */
  filter: drop-shadow(0 0 1px rgba(255, 255, 255, 0.35))
          drop-shadow(0 0 22px rgba(176, 114, 240, 0.22));
  animation: heroPieza 900ms var(--ease-out-expo) 1750ms both;
}
.hero-pieza::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--photo) center / contain no-repeat;
  -webkit-mask: var(--mascara) center / contain no-repeat;
  mask: var(--mascara) center / contain no-repeat;
}
@keyframes heroPieza {
  from { opacity: 0; transform: scale(0.97); }
  to { opacity: 1; transform: none; }
}

/* El dibujo se retira cuando entra la pieza: el plano se convierte en el
   motor y queda solo la grilla. Antes la foto opaca tapaba las líneas;
   con el render transparente se verían cruzando por detrás. */
@keyframes heroFadeOut {
  from { opacity: 1; }
  to { opacity: 0; }
}
.hero-visual .blueprint g.draw:not(.draw-dashed),
.hero-visual .blueprint g.node {
  animation: heroFadeOut 700ms var(--ease-standard) 1850ms forwards;
}
/* "forwards" y no "both": antes de arrancar no debe pisar la entrada */
.hero-visual .blueprint .draw-dashed {
  animation: heroFade 600ms var(--ease-standard) 1320ms both,
             heroFadeOut 700ms var(--ease-standard) 1850ms forwards;
}
