/* =============================================================
   Kit Herramientas — sistema de diseño compartido
   Claymorphism + Neumorphism + Glassmorphism
   Un solo archivo, por secciones (convención 01 §6)
   ============================================================= */

/* =============================================================
   0. Tipografias, servidas desde el propio sitio
   -------------------------------------------------------------
   Outfit titula e Inter lee: la misma letra que el resto de Daia. No van desde
   Google Fonts (cambiado el 28 de agosto de 2026) — una peticion menos a un
   tercero que ve la IP de cada visitante, y dos conexiones menos antes de
   pintar la primera letra.

   La tercera, JetBrains Mono, se fue del todo: se usaba en cuatro sitios para
   enseñar un codigo hexadecimal o un enlace, y por eso no valia la pena bajar
   una fuente entera. En su lugar va la monoespaciada del sistema, que pesa cero
   y en un Mac o un iPhone es SF Mono.
   ============================================================= */
@font-face {
  font-family: "Outfit";
  src: url("assets/fuentes/outfit.woff2") format("woff2");
  font-weight: 400 800;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("assets/fuentes/inter.woff2") format("woff2");
  font-weight: 400 700;
  font-display: swap;
}

/* =============================================================
   1. Tokens
   ============================================================= */
:root {
  /* Tipografía */
  --display: "Outfit", "Segoe UI", system-ui, sans-serif;
  --sans: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* Neutros — claro */
  /* Grises de la casa. Eran azulados (`#e9edf7`); Daia es blanco y gris, y el
     color lo pone la familia de cada herramienta, nunca el fondo. */
  --bg: #F0F1F4;
  --bg-deep: #E6E8EC;
  --surface: #F8F9FB;
  --surface-2: #EDEFF3;
  --text: #16181D;
  --text-soft: #4B5262;
  --text-mute: #5F6678;   /* 4,6:1 sobre --bg */
  --line: rgba(22, 24, 29, 0.09);
  --line-strong: rgba(22, 24, 29, 0.16);

  /* Acento por defecto: el de la EMPRESA, no el de una familia.
     La portada del kit no pertenece a ninguna de las cuatro, y pintarla del
     color de una seria coronarla por encima de las otras tres. Va en tinta:
     blanco y gris, como la landing de Daia. Cada herramienta lo sobreescribe
     con el `data-hue` de SU familia. */
  --accent: #16181D;
  --accent-2: #3A3F4B;
  --accent-ink: #ffffff;
  --accent-soft: rgba(22, 24, 29, 0.08);

  /* Semánticos */
  --ok: #10b981;
  --warn: #f59e0b;
  --err: #ef4444;

  /* --- Variantes para TEXTO ---------------------------------------------
     Un color vale para pintar un relleno y no valer para escribir encima: la
     norma pide 3:1 para un elemento de interfaz pero 4,5:1 para el texto. Los
     tokens de arriba se quedan como están —son los que dan la identidad en
     rellenos, bordes y barras— y estos son sus versiones oscurecidas, con el
     mismo tono, para cuando el color va en un `color:`.
     En tema oscuro no hace falta oscurecer nada: sobre un fondo casi negro los
     originales ya pasan de sobra, así que allí valen los mismos. */
  --accent-text: #16181D;   /* tinta: 15,6:1 */
  --ok-text: #0a7753;       /* 4,75:1 */
  --warn-text: #915e06;     /* 4,71:1 */
  --err-text: #d41212;      /* 4,60:1 */

  /* --- Variantes para RELLENO con texto blanco encima -------------------
     El acento vivo con un rótulo blanco encima se queda en 4,47:1 el mejor
     caso y en 2,54:1 el peor: los botones principales, que son el texto más
     importante de la página, no llegaban a AA en ninguna sección. Estas son
     las versiones a las que el blanco sí les llega, con el mismo tono. Valen
     igual en los dos temas: siguen destacando sobre el fondo (≈3,9:1, por
     encima del 3:1 que pide un elemento de interfaz). */
  --accent-fill: #16181D;
  --accent-2-fill: #3A3F4B;

  /* El anillo de foco hereda de la variante de texto, que ya está calculada
     para pasar 4,5:1 contra el fondo — muy por encima del 3:1 que la norma
     pide a un indicador. Se declara aparte para poder cambiarlo sin tocar el
     color de los textos. */
  --focus: var(--accent-text);

  /* Sombras neumórficas (luz arriba-izquierda) */
  --neu-light: rgba(255, 255, 255, 0.95);
  --neu-dark: rgba(150, 156, 170, 0.42);
  --neu-out:
    -7px -7px 16px var(--neu-light),
    7px 7px 20px var(--neu-dark);
  --neu-out-sm:
    -3px -3px 7px var(--neu-light),
    3px 3px 9px var(--neu-dark);
  --neu-in:
    inset -4px -4px 9px var(--neu-light),
    inset 4px 4px 10px var(--neu-dark);

  /* Sombras clay (volumen + luz interior) */
  --clay-shadow:
    0 18px 40px -12px rgba(60, 72, 120, 0.36),
    0 6px 14px -6px rgba(60, 72, 120, 0.22);
  --clay-inset:
    inset 0 -7px 12px -6px rgba(60, 72, 120, 0.24),
    inset 0 8px 14px -4px rgba(255, 255, 255, 0.85);

  /* Glass */
  --glass-bg: rgba(255, 255, 255, 0.66);
  --glass-bg-solid: rgba(255, 255, 255, 0.92);
  --glass-line: rgba(255, 255, 255, 0.72);
  --glass-blur: blur(20px) saturate(175%);

  /* --- Escala tipográfica -----------------------------------------------
     Había 41 tamaños distintos repartidos entre 0,58 y 1,6 rem: doce de ellos
     dentro de un margen de 0,12 rem, que nadie distingue pero que el proyecto
     arrastraba igual. Esto es una escala de ocho peldaños, y el más pequeño es
     el suelo: 12 px. Por debajo de ahí no se lee, por mucho que sea una
     etiqueta en versalita. */
  --t-xs: 0.75rem;      /* 12 px · etiquetas, versalitas, metadatos */
  --t-sm: 0.8125rem;    /* 13 px · texto de apoyo y pies */
  --t-base: 0.875rem;   /* 14 px · cuerpo de interfaz */
  --t-md: 1rem;         /* 16 px · cuerpo de lectura */
  --t-lg: 1.125rem;     /* 18 px · entradillas */
  --t-xl: 1.375rem;     /* 22 px */
  --t-2xl: 1.75rem;     /* 28 px */
  --t-3xl: 2.25rem;     /* 36 px */

  /* Radios */
  --r-xs: 10px;
  --r-sm: 14px;
  --r-md: 20px;
  --r-lg: 28px;
  --r-xl: 36px;
  --r-pill: 999px;

  /* Ritmo */
  --gutter: clamp(1.1rem, 4vw, 2.5rem);
  --maxw: 1180px;
  --maxw-narrow: 760px;

  /* Easings (01 §11) */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in: cubic-bezier(0.7, 0, 0.84, 0);
  --ease-soft: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* -------------------------------------------------------------------------
   Paletas por FAMILIA — se aplican con data-hue en <html>

   Estas doce herramientas no son un kit suelto: son parte de Daia, y cada una
   pertenece a una de las seis familias. El color no es de la herramienta, es de
   la familia, y la fuente es `daia/recursos/identidad/categorias.json`.

   Antes los cuatro grupos eran «legal / archivos / diseno / productividad», con
   colores elegidos para este sitio (indigo, celeste, rosa, verde). El reparto
   tampoco cuadraba: el editor de PDF iba con el compresor de imagenes, que son
   dos cosas distintas — uno es papeleo y el otro es un archivo que pesa mucho.

   CADA FAMILIA TRAE TRES TONOS Y NINGUNO SOBRA
     `--accent`       el color de la lamina. Rellenos grandes, barras, bordes.
     `--accent-text`  el mismo, oscurecido hasta pasar 4,5:1 sobre `--bg`. Es el
                      unico que puede ir en un `color:`.
     `--accent-fill`  el mismo, oscurecido hasta que el BLANCO encima pasa
                      4,5:1. Es el de los botones principales.
   Con el color de la lamina a secas, el naranja con letras blancas se queda en
   2,41:1 y el verde en 2,98:1. Se ven; no se leen.
   ------------------------------------------------------------------------- */
/* Los monitos de estado, uno por familia. Van como variables para que las reglas de
   mas abajo sean UNA sola: el CSS no sabe de familias, solo pide `var(--monito-error)`
   y cada `data-hue` pone el suyo. Se reparten con
   `daia/recursos/mascotas/repartir-poses.py`. */
[data-hue="educacion"] {
  --monito-vacio: url("assets/img/monito/educacion-vacio.png");
  --monito-exito: url("assets/img/monito/educacion-exito.png");
  --monito-error: url("assets/img/monito/educacion-error.png");
  --accent: #6C5CE7;
  --accent-2: #8B7FEC;
  --accent-soft: rgba(108, 92, 231, 0.13);
  --accent-text: #6858E6;        /* 4,68:1 sobre --bg */
  --accent-fill: #6C5CE7;        /* blanco encima: 4,86:1 */
  --accent-2-fill: #5442CE;
}
[data-hue="documentos"] {
  --monito-vacio: url("assets/img/monito/documentos-vacio.png");
  --monito-exito: url("assets/img/monito/documentos-exito.png");
  --monito-error: url("assets/img/monito/documentos-error.png");
  --accent: #4A78D1;
  --accent-2: #6E96DE;
  --accent-soft: rgba(74, 120, 209, 0.13);
  --accent-text: #386ACC;        /* 4,67:1 sobre --bg */
  --accent-fill: #4272CF;        /* blanco encima: 4,63:1 */
  --accent-2-fill: #35609F;
}
[data-hue="digitales"] {
  --monito-vacio: url("assets/img/monito/digitales-vacio.png");
  --monito-exito: url("assets/img/monito/digitales-exito.png");
  --monito-error: url("assets/img/monito/digitales-error.png");
  --accent: #E89435;
  --accent-2: #F0B368;
  --accent-soft: rgba(232, 148, 53, 0.14);
  --accent-text: #A25F12;        /* el naranja de la lamina se queda en 2,41:1 */
  --accent-fill: #A96313;        /* blanco encima: 4,70:1 */
  --accent-2-fill: #8A5010;
}
[data-hue="comunicacion"] {
  --monito-vacio: url("assets/img/monito/comunicacion-vacio.png");
  --monito-exito: url("assets/img/monito/comunicacion-exito.png");
  --monito-error: url("assets/img/monito/comunicacion-error.png");
  --accent: #36A6A6;
  --accent-2: #5FC0C0;
  --accent-soft: rgba(54, 166, 166, 0.14);
  --accent-text: #287A7A;        /* el turquesa de la lamina se queda en 2,93:1 */
  --accent-fill: #298080;        /* blanco encima: 4,70:1 */
  --accent-2-fill: #226B6B;
}

/* Tema oscuro — solo se redefinen tokens, nunca colores sueltos (gotcha B.8) */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #14161d;
    --bg-deep: #0f1117;
    --surface: #1b1e27;
    --surface-2: #22262f;
    --text: #eef1f8;
    --text-soft: #b3bcd0;
    --text-mute: #808ba3;
    --line: rgba(255, 255, 255, 0.10);
    --line-strong: rgba(255, 255, 255, 0.18);

    --neu-light: rgba(255, 255, 255, 0.055);
    --neu-dark: rgba(0, 0, 0, 0.58);
    --clay-shadow:
      0 18px 40px -12px rgba(0, 0, 0, 0.62),
      0 6px 14px -6px rgba(0, 0, 0, 0.45);
    --clay-inset:
      inset 0 -7px 12px -6px rgba(0, 0, 0, 0.5),
      inset 0 8px 14px -4px rgba(255, 255, 255, 0.09);

    --glass-bg: rgba(30, 34, 45, 0.62);
    --glass-bg-solid: rgba(30, 34, 45, 0.94);
    --glass-line: rgba(255, 255, 255, 0.13);

    /* Sobre fondo casi negro los colores vivos ya pasan de sobra, así que aquí
       las variantes de texto vuelven a ser los originales. La única excepción
       es el índigo de «legal», que se queda en 4,04:1 y hay que aclarar. */
    --accent-text: #7174f2;
    --ok-text: #10b981;
    --warn-text: #f59e0b;
    --err-text: #ef4444;
  }
}
:root[data-theme="dark"] {
  --bg: #14161d;
  --bg-deep: #0f1117;
  --surface: #1b1e27;
  --surface-2: #22262f;
  --text: #eef1f8;
  --text-soft: #b3bcd0;
  --text-mute: #808ba3;
  --line: rgba(255, 255, 255, 0.10);
  --line-strong: rgba(255, 255, 255, 0.18);

  --neu-light: rgba(255, 255, 255, 0.055);
  --neu-dark: rgba(0, 0, 0, 0.58);
  --clay-shadow:
    0 18px 40px -12px rgba(0, 0, 0, 0.62),
    0 6px 14px -6px rgba(0, 0, 0, 0.45);
  --clay-inset:
    inset 0 -7px 12px -6px rgba(0, 0, 0, 0.5),
    inset 0 8px 14px -4px rgba(255, 255, 255, 0.09);

  --glass-bg: rgba(30, 34, 45, 0.62);
  --glass-bg-solid: rgba(30, 34, 45, 0.94);
  --glass-line: rgba(255, 255, 255, 0.13);

  --accent-text: #787bf3;   /* contra --surface, que en oscuro es lo más exigente */
  --ok-text: #10b981;
  --warn-text: #f59e0b;
  --err-text: #f04d4d;      /* el #ef4444 se quedaba en 4,42:1 sobre --surface */
}

/* En oscuro cada familia recupera su tono vivo para el texto. Los cuatro estan
   medidos contra `--surface` (#1b1e27), que es el fondo mas exigente de los dos:
   el morado y el azul hay que aclararlos, el naranja y el turquesa ya pasan. */
:root[data-theme="dark"][data-hue="educacion"],
:root[data-theme="dark"] [data-hue="educacion"] { --accent-text: #8477EB; }
:root[data-theme="dark"][data-hue="documentos"],
:root[data-theme="dark"] [data-hue="documentos"] { --accent-text: #5C86D6; }
:root[data-theme="dark"][data-hue="digitales"],
:root[data-theme="dark"] [data-hue="digitales"] { --accent-text: #E89435; }
:root[data-theme="dark"][data-hue="comunicacion"],
:root[data-theme="dark"] [data-hue="comunicacion"] { --accent-text: #36A6A6; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"])[data-hue="educacion"],
  :root:not([data-theme="light"]) [data-hue="educacion"] { --accent-text: #8477EB; }
  :root:not([data-theme="light"])[data-hue="documentos"],
  :root:not([data-theme="light"]) [data-hue="documentos"] { --accent-text: #5C86D6; }
  :root:not([data-theme="light"])[data-hue="digitales"],
  :root:not([data-theme="light"]) [data-hue="digitales"] { --accent-text: #E89435; }
  :root:not([data-theme="light"])[data-hue="comunicacion"],
  :root:not([data-theme="light"]) [data-hue="comunicacion"] { --accent-text: #36A6A6; }
}

/* =============================================================
   2. Reset & base
   ============================================================= */
*, *::before, *::after { box-sizing: border-box; margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  tab-size: 2;
  overflow-x: clip;          /* clip, no hidden — no rompe sticky (B.2) */
  scroll-behavior: smooth;
}

body {
  font-family: var(--sans);
  /* En rem, no en píxeles: quien ha subido el tamaño de letra en los ajustes
     del navegador lo hace porque lo necesita, y un valor fijo en px se lo
     ignora. Toda la escala cuelga de aquí. */
  font-size: var(--t-md);
  line-height: 1.62;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
  overscroll-behavior-y: none;
  min-height: 100svh;
  position: relative;
}

/* Velo que baja el contraste del fondo para que el texto siempre gane.
   Antes había, ademas, dos manchas de color difuminadas (blur 90px) detras de
   este velo — el sustrato pensado para el glass. Se quitaron: el sitio ya no
   usa glassmorphism en el fondo, y sin nada que desenfocar detras, esas
   manchas solo ensuciaban el gris de las tarjetas. */
body > .bg-veil {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(120% 90% at 50% 0%, transparent 0%, var(--bg) 78%),
    linear-gradient(180deg, transparent 0%, var(--bg-deep) 100%);
  opacity: 0.72;
}

img, svg, video, canvas { display: block; max-width: 100%; }
img { height: auto; }
button { font: inherit; color: inherit; cursor: pointer; border: 0; background: none; }
input, select, textarea { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }
p { text-wrap: pretty; }
h1, h2, h3, h4 { text-wrap: balance; line-height: 1.08; letter-spacing: -0.022em; font-family: var(--display); font-weight: 700; }
::selection { background: var(--accent); color: var(--accent-ink); }

/* Anillo de foco.
   Va con --focus y no con --accent porque un indicador de foco es un elemento
   de interfaz: necesita 3:1 contra lo que tiene al lado, y el acento vivo se
   queda en 2,16:1 en la sección verde. --focus hereda de --accent-text, que
   está calculado para pasar de sobra.
   El desplazamiento saca el anillo fuera del elemento, así que el contraste
   que cuenta es contra el fondo de la página, también cuando el elemento
   enfocado es un botón de color.
   No se toca el border-radius: el contorno ya sigue el del propio elemento, y
   forzarlo cuadraba las esquinas de los botones de pastilla al enfocarlos. */
:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

/* =============================================================
   3. Utilidades
   ============================================================= */
.container {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--narrow { max-width: var(--maxw-narrow); }

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

.skip-link {
  position: fixed; top: -100px; left: 1rem;
  padding: 0.7rem 1.15rem;
  background: var(--accent); color: var(--accent-ink);
  z-index: 9999; border-radius: var(--r-sm); font-weight: 600;
}
.skip-link:focus { top: 1rem; }

.stack > * + * { margin-top: 1rem; }
.center { text-align: center; }
.hidden { display: none !important; }

/* =============================================================
   4. Tipografía
   ============================================================= */
.eyebrow {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-size: var(--t-xs); font-weight: 700;   /* suelo tipográfico: 12 px */
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent-text);
}
h1, .h1 { font-size: clamp(1.95rem, 5.2vw, 3.1rem); }
h2, .h2 { font-size: clamp(1.5rem, 3.6vw, 2.15rem); }
h3, .h3 { font-size: clamp(1.12rem, 2.2vw, 1.35rem); }
.lede {
  font-size: clamp(1rem, 1.9vw, 1.15rem);
  color: var(--text-soft);
  max-width: 62ch;
}
.muted { color: var(--text-mute); }
.tiny { font-size: var(--t-sm); }
/* Sin encoger. El 0,92em de antes corregía que una monoespaciada se ve más
   gruesa a igual tamaño, pero al ser relativo se multiplicaba sobre el del
   contenedor y salía de la escala: 11 px dentro de una etiqueta —por debajo del
   suelo— y 16,9 px dentro de una entradilla. La corrección óptica se hace ahora
   igualando la altura de la x, que no toca el tamaño calculado. */
code, kbd, .mono {
  font-family: var(--mono);
  font-size-adjust: ex-height 0.53;
}

/* =============================================================
   5. Superficies — la firma visual
   ============================================================= */

/* --- Claymorphism: volumen blando, luz interior, bordes gordos --- */
.clay {
  background: linear-gradient(145deg, var(--surface) 0%, var(--surface-2) 100%);
  border-radius: var(--r-lg);
  box-shadow: var(--clay-shadow), var(--clay-inset);
  border: 1px solid var(--line);
}
.clay--accent {
  background: linear-gradient(145deg, var(--accent-fill) 0%, var(--accent-2-fill) 100%);
  color: var(--accent-ink);
  border-color: transparent;
  box-shadow:
    0 18px 40px -12px color-mix(in srgb, var(--accent) 55%, transparent),
    var(--clay-inset);
}
.clay--xl { border-radius: var(--r-xl); }

/* --- Neumorphism: monocromo, dos sombras opuestas --- */
.neu {
  background: var(--bg);
  border-radius: var(--r-md);
  box-shadow: var(--neu-out);
  border: none;
}
.neu--sunk {
  background: var(--bg);
  border-radius: var(--r-md);
  box-shadow: var(--neu-in);
}
.neu--sm { border-radius: var(--r-sm); box-shadow: var(--neu-out-sm); }

/* --- Glassmorphism: SIEMPRE con fallback sólido (gotcha B.12) --- */
.glass {
  background: var(--glass-bg-solid);      /* fallback opaco primero */
  border: 1px solid var(--glass-line);
  border-radius: var(--r-lg);
  box-shadow:
    0 16px 44px -16px rgba(30, 40, 80, 0.34),
    inset 0 1px 0 rgba(255, 255, 255, 0.5);
}
@supports ((backdrop-filter: blur(20px)) or (-webkit-backdrop-filter: blur(20px))) {
  .glass {
    background: var(--glass-bg);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
  }
}

/* =============================================================
   6. Componentes
   ============================================================= */

/* --- Botones --- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 0.55rem;
  padding: 0.78rem 1.4rem;
  border-radius: var(--r-pill);
  font-weight: 650;
  font-size: var(--t-md);
  line-height: 1.2;
  letter-spacing: -0.01em;
  transition:
    transform 0.22s var(--ease-bounce),
    box-shadow 0.22s var(--ease-out),
    background-color 0.22s var(--ease-out),
    opacity 0.2s var(--ease-out);
  will-change: transform;
  text-align: center;
}
.btn svg { width: 1.1em; height: 1.1em; flex: none; }

.btn--primary {
  background: linear-gradient(145deg, var(--accent-fill) 0%, var(--accent-2-fill) 100%);
  color: var(--accent-ink);
  box-shadow:
    0 10px 24px -8px color-mix(in srgb, var(--accent) 62%, transparent),
    inset 0 -3px 8px -3px rgba(0, 0, 0, 0.28),
    inset 0 3px 8px -3px rgba(255, 255, 255, 0.55);
}
.btn--primary:hover {
  transform: translateY(-2px) scale(1.015);
  box-shadow:
    0 16px 32px -10px color-mix(in srgb, var(--accent) 70%, transparent),
    inset 0 -3px 8px -3px rgba(0, 0, 0, 0.28),
    inset 0 3px 8px -3px rgba(255, 255, 255, 0.55);
}
.btn--primary:active { transform: translateY(1px) scale(0.985); }

.btn--soft {
  background: var(--bg);
  color: var(--text);
  box-shadow: var(--neu-out-sm);
}
.btn--soft:hover { transform: translateY(-2px); box-shadow: var(--neu-out); }
.btn--soft:active { transform: translateY(0); box-shadow: var(--neu-in); }

.btn--ghost {
  background: transparent;
  color: var(--text-soft);
  border: 1px solid var(--line-strong);
}
.btn--ghost:hover { color: var(--text); border-color: var(--accent); background: var(--accent-soft); }

.btn--lg { padding: 1.02rem 2rem; font-size: var(--t-md); }
.btn--block { display: flex; width: 100%; }
.btn[disabled], .btn[aria-disabled="true"] {
  opacity: 0.5; cursor: not-allowed; transform: none !important;
}

/* --- Campos de formulario --- */
.field { display: block; }
.field + .field { margin-top: 0.9rem; }
.field > .label,
.label {
  display: block;
  font-size: var(--t-sm);
  font-weight: 650;
  color: var(--text-soft);
  margin-bottom: 0.4rem;
  letter-spacing: 0.005em;
}
.input,
.select,
.textarea {
  width: 100%;
  padding: 0.76rem 1rem;
  background: var(--bg);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  box-shadow: var(--neu-in);
  color: var(--text);
  transition: box-shadow 0.22s var(--ease-out), border-color 0.22s var(--ease-out);
}
.textarea { min-height: 120px; resize: vertical; line-height: 1.6; }
/* El halo de --accent-soft es un lavado del 13 % de opacidad: bonito, pero
   como único indicador de foco es prácticamente invisible. Se queda como
   refuerzo y el anillo de verdad lo pone :focus-visible. */
.input:focus,
.select:focus,
.textarea:focus {
  border-color: var(--accent);
  box-shadow: var(--neu-in), 0 0 0 3px var(--accent-soft);
}
.input:focus-visible,
.select:focus-visible,
.textarea:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}
.input::placeholder, .textarea::placeholder { color: var(--text-mute); }
.select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-soft) 50%),
                    linear-gradient(135deg, var(--text-soft) 50%, transparent 50%);
  background-position: calc(100% - 19px) 52%, calc(100% - 13px) 52%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 2.4rem;
}
.field-row {
  display: grid;
  gap: 0.9rem;
  grid-template-columns: 1fr;
}
@media (min-width: 540px) {
  .field-row--2 { grid-template-columns: 1fr 1fr; }
  .field-row--3 { grid-template-columns: repeat(3, 1fr); }
}
.hint { font-size: var(--t-xs); color: var(--text-mute); margin-top: 0.35rem; }

/* Rango neumórfico */
.range {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 12px;
  background: var(--bg);
  border-radius: var(--r-pill);
  box-shadow: var(--neu-in);
}
/* Un deslizador sin anillo de foco deja al teclado sin saber dónde está, y
   aquí hay deslizadores para el margen del QR, la calidad del compresor o el
   ajuste fino de un color. */
.range:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 4px;
}
.range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 24px; height: 24px; border-radius: 50%;
  background: linear-gradient(145deg, var(--accent-fill), var(--accent-2-fill));
  box-shadow: 0 3px 8px -2px color-mix(in srgb, var(--accent) 70%, transparent);
  cursor: pointer;
  transition: transform 0.18s var(--ease-bounce);
}
.range::-webkit-slider-thumb:hover { transform: scale(1.16); }
.range::-moz-range-thumb {
  width: 24px; height: 24px; border: 0; border-radius: 50%;
  background: linear-gradient(145deg, var(--accent-fill), var(--accent-2-fill));
  cursor: pointer;
}

/* Checkbox / switch */
.switch { display: inline-flex; align-items: center; gap: 0.65rem; cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch-track {
  width: 46px; height: 26px; flex: none;
  background: var(--bg);
  box-shadow: var(--neu-in);
  border-radius: var(--r-pill);
  position: relative;
  transition: background-color 0.24s var(--ease-out);
}
.switch-track::after {
  content: "";
  position: absolute; top: 3px; left: 3px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.24);
  transition: transform 0.28s var(--ease-bounce), background-color 0.24s var(--ease-out);
}
.switch input:checked + .switch-track { background: linear-gradient(145deg, var(--accent-fill), var(--accent-2-fill)); }
.switch input:checked + .switch-track::after { transform: translateX(20px); background: #fff; }
.switch input:focus-visible + .switch-track { outline: 2px solid var(--accent); outline-offset: 3px; }

/* Chips / segmented */
.chips { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.chip {
  padding: 0.44rem 0.92rem;
  border-radius: var(--r-pill);
  font-size: var(--t-base); font-weight: 600;
  background: var(--bg);
  box-shadow: var(--neu-out-sm);
  color: var(--text-soft);
  transition: all 0.2s var(--ease-out);
}
.chip:hover { color: var(--text); transform: translateY(-1px); }
.chip[aria-pressed="true"], .chip.is-active {
  background: linear-gradient(145deg, var(--accent-fill), var(--accent-2-fill));
  color: var(--accent-ink);
  box-shadow: 0 6px 14px -5px color-mix(in srgb, var(--accent) 65%, transparent);
}

/* --- Tarjeta de herramienta: el componente central (03 §2) --- */
.tool-card {
  position: relative;
  padding: clamp(1.15rem, 3.4vw, 2rem);
  border-radius: var(--r-xl);
  overflow: hidden;
}
.tool-card__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  margin-bottom: 1.1rem;
}
.tool-card__title { font-size: var(--t-md); font-weight: 700; font-family: var(--display); }

/* --- El monito de cada estado ---------------------------------------------
   Va en el CSS y no en el HTML de las doce herramientas a proposito: el estado ya
   se decide con `data-state` en la tarjeta, asi que aqui basta colgarse de el.
   Doce archivos que no hay que tocar, y una herramienta nueva lo hereda sola.

   Solo en `idle` (todavia no has soltado nada) y en `error` (algo se rompio). En
   `done` NO: ahi la persona quiere ver su resultado, y un monito de noventa pixeles
   encima empuja hacia abajo justo lo que vino a buscar. El exito se dice en el aviso
   flotante, que sale y se va. */
.tool-card [data-when~="idle"]::before,
.tool-card [data-when~="error"]::before {
  content: "";
  display: block;
  width: 104px; height: 96px;
  margin: 0 auto 0.9rem;
  background-repeat: no-repeat;
  background-position: bottom center;
  background-size: contain;
}
.tool-card [data-when~="idle"]::before  { background-image: var(--monito-vacio); }
.tool-card [data-when~="error"]::before { background-image: var(--monito-error); }
@media (max-width: 30rem) {
  .tool-card [data-when~="idle"]::before,
  .tool-card [data-when~="error"]::before { width: 78px; height: 72px; }
}

/* Estados: un solo data-state gobierna la vista (03 §2) */
.tool-card [data-when] { display: none; }
.tool-card[data-state="idle"]    [data-when~="idle"],
.tool-card[data-state="engine"]  [data-when~="engine"],
.tool-card[data-state="working"] [data-when~="working"],
.tool-card[data-state="done"]    [data-when~="done"],
.tool-card[data-state="error"]   [data-when~="error"] { display: block; }
.tool-card[data-state="idle"]    [data-when~="idle"].is-flex,
.tool-card[data-state="engine"]  [data-when~="engine"].is-flex,
.tool-card[data-state="working"] [data-when~="working"].is-flex,
.tool-card[data-state="done"]    [data-when~="done"].is-flex,
.tool-card[data-state="error"]   [data-when~="error"].is-flex { display: flex; }
.tool-card[data-state="idle"]    [data-when~="idle"].is-grid,
.tool-card[data-state="done"]    [data-when~="done"].is-grid,
.tool-card[data-state="working"] [data-when~="working"].is-grid { display: grid; }

/* --- Dropzone --- */
.dropzone {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 0.7rem;
  min-height: 190px;
  padding: 1.6rem 1.2rem;
  text-align: center;
  border-radius: var(--r-lg);
  background: var(--bg);
  box-shadow: var(--neu-in);
  border: 2px dashed var(--line-strong);
  cursor: pointer;
  transition: border-color 0.22s var(--ease-out), background-color 0.22s var(--ease-out), transform 0.22s var(--ease-out);
}
.dropzone:hover { border-color: var(--accent); }
.dropzone.is-over {
  border-color: var(--accent);
  background: var(--accent-soft);
  transform: scale(1.012);
}
.dropzone__icon {
  width: 62px; height: 62px;
  color: var(--accent-text);
  animation: floaty 3.6s var(--ease-soft) infinite alternate;
}
.dropzone__title { font-weight: 700; font-family: var(--display); font-size: var(--t-md); }
.dropzone__sub { font-size: var(--t-base); color: var(--text-mute); }
.dropzone input[type="file"] { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

/* --- Barra de progreso --- */
.progress {
  height: 12px;
  border-radius: var(--r-pill);
  background: var(--bg);
  box-shadow: var(--neu-in);
  overflow: hidden;
}
.progress__bar {
  height: 100%;
  width: 0%;
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  background-size: 200% 100%;
  transition: width 0.35s var(--ease-out);
  animation: shimmer 1.8s linear infinite;
}
.progress__label {
  display: flex; justify-content: space-between; gap: 1rem;
  font-size: var(--t-base); color: var(--text-soft);
  margin-bottom: 0.5rem;
}

/* --- Badges y avisos --- */
.badge {
  display: inline-flex; align-items: center; gap: 0.45rem;
  padding: 0.42rem 0.9rem;
  border-radius: var(--r-pill);
  font-size: var(--t-sm); font-weight: 600;
  background: var(--accent-soft);
  color: var(--accent-text);
}
.badge--privacy {
  background: color-mix(in srgb, var(--ok) 14%, transparent);
  color: color-mix(in srgb, var(--ok) 82%, var(--text));
}
.notice {
  display: flex; gap: 0.7rem; align-items: flex-start;
  padding: 0.85rem 1.05rem;
  border-radius: var(--r-sm);
  font-size: var(--t-base);
  background: var(--surface-2);
  border-left: 3px solid var(--accent);
  color: var(--text-soft);
}
.notice--warn { border-left-color: var(--warn); background: color-mix(in srgb, var(--warn) 10%, var(--surface-2)); }
.notice--err  { border-left-color: var(--err);  background: color-mix(in srgb, var(--err) 10%, var(--surface-2)); }

/* --- Toast --- */
.toast-host {
  position: fixed; z-index: 999;
  left: 50%; bottom: 1.6rem;
  transform: translateX(-50%);
  display: flex; flex-direction: column; gap: 0.5rem;
  pointer-events: none;
  width: min(92vw, 420px);
}
.toast--ok::before {
  content: "";
  width: 34px; height: 32px; flex: 0 0 34px;
  background: var(--monito-exito) no-repeat bottom center / contain;
}
.toast--ok { display: flex; align-items: center; gap: 0.6rem; text-align: left; }

.toast {
  padding: 0.78rem 1.15rem;
  border-radius: var(--r-pill);
  font-size: var(--t-base); font-weight: 600;
  text-align: center;
  background: var(--glass-bg-solid);
  border: 1px solid var(--glass-line);
  box-shadow: 0 12px 30px -10px rgba(20, 25, 45, 0.42);
  animation: toastIn 0.34s var(--ease-bounce);
}
@supports ((backdrop-filter: blur(20px)) or (-webkit-backdrop-filter: blur(20px))) {
  .toast { background: var(--glass-bg); -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur); }
}
.toast--ok  { color: color-mix(in srgb, var(--ok) 84%, var(--text)); }
.toast--err { color: color-mix(in srgb, var(--err) 84%, var(--text)); }
.toast.is-out { animation: toastOut 0.28s var(--ease-in) forwards; }

/* --- Tablas --- */
.table-wrap { overflow-x: auto; border-radius: var(--r-md); }
table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--t-base);
  min-width: 480px;
}
table.data th, table.data td {
  padding: 0.66rem 0.8rem;
  text-align: left;
  border-bottom: 1px solid var(--line);
}
table.data th {
  font-weight: 700; font-size: var(--t-xs);
  text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--text-mute);
}
table.data tbody tr:hover { background: var(--accent-soft); }
table.data td.num, table.data th.num { text-align: right; font-family: var(--mono); }

/* =============================================================
   7. Secciones y layout
   ============================================================= */

/* --- Header --- */
.site-header {
  position: sticky; top: 0; z-index: 50;
  padding-block: 0.7rem;
  background: var(--glass-bg-solid);
  border-bottom: 1px solid var(--line);
}
@supports ((backdrop-filter: blur(16px)) or (-webkit-backdrop-filter: blur(16px))) {
  .site-header {
    background: color-mix(in srgb, var(--bg) 72%, transparent);
    -webkit-backdrop-filter: blur(16px) saturate(160%);
    backdrop-filter: blur(16px) saturate(160%);
  }
}
.site-header__inner {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
.brand { display: inline-flex; align-items: center; gap: 0.62rem; font-family: var(--display); font-weight: 800; letter-spacing: -0.03em; }
/* La pastilla del logo.
   El fondo es un TINTE claro del color de la familia y no el color a pleno: dentro va el
   monito, que es tinta casi negra, y sobre el color lleno pierde el cuerpo y quedan
   flotando los lentes. Es la misma regla que en las demas apps de Daia. */
.brand__mark {
  width: 36px; height: 36px; flex: none;
  border-radius: 11px;
  background: var(--accent-soft);
  box-shadow: inset 0 -3px 8px rgba(22, 24, 29, 0.07);
  display: flex; align-items: flex-end; justify-content: center;
  overflow: hidden;
  color: var(--accent-text);
}
.brand__mark svg { width: 20px; height: 20px; margin-bottom: 8px; }
/* Apoyado abajo y no centrado: el monito tiene aire sobre la cabeza, y centrado se
   queda diminuto dentro de un cuadrado de 36 px. */
.brand__mark img { width: 32px; height: auto; margin-bottom: -1px; }
.header-actions { display: flex; align-items: center; gap: 0.5rem; }
.icon-btn {
  width: 40px; height: 40px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--bg);
  box-shadow: var(--neu-out-sm);
  color: var(--text-soft);
  transition: transform 0.2s var(--ease-bounce), box-shadow 0.2s var(--ease-out), color 0.2s var(--ease-out);
}
.icon-btn:hover { color: var(--accent-text); transform: translateY(-2px); }
.icon-btn:active { box-shadow: var(--neu-in); transform: translateY(0); }
.icon-btn svg { width: 19px; height: 19px; }

/* --- Cabecera de herramienta --- */
.tool-hero { padding-block: clamp(1.6rem, 4vw, 2.6rem) 1.2rem; text-align: center; }

/* El personaje de la familia, encima del titular.
   Sale una vez por pantalla y en pequeño: es la firma que dice de qué familia
   es esta herramienta, no una ilustración. Si saliera grande o repetido, a la
   tercera pantalla nadie lo mira. */
.tool-hero__mono {
  /* `flex` y no `inline-flex`: el antetitulo de debajo es un `.eyebrow`, que va
     en `inline-flex`, y con los dos en linea el monito se le pegaba al lado en
     vez de quedar encima. */
  display: flex; align-items: flex-end; justify-content: center;
  margin-inline: auto;
  width: 92px; height: 74px; margin-bottom: 0.6rem;
  border-radius: 22px; overflow: hidden;
  background: var(--accent-soft);
}
.tool-hero__mono img { width: 86px; height: auto; margin-bottom: -2px; }
.tool-hero h1 { margin-block: 0.5rem 0.6rem; }
.tool-hero .lede { margin-inline: auto; }

/* El nombre de la herramienta y, debajo, lo que hace.
   Son las dos mitades del mismo titular y no dos titulares: «Código» es como se
   llama y «Generador de códigos QR» es la frase por la que la gente llega desde
   el buscador. Si se quita la segunda, el nombre no le dice nada a quien entra
   por primera vez; si se quita la primera, la herramienta no tiene nombre. */
/* El nombre de marca dentro de la tarjeta de la portada. Va delante de lo que
   hace la herramienta, en la letra de titulos y en el color de su familia: es
   como se llama, y lo de al lado es para qué sirve. */
.tool-tile__nombre {
  display: block;
  font-family: var(--display);
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-text);
  margin-bottom: 0.15rem;
}

.tool-h1__que {
  display: block;
  margin-top: 0.35rem;
  font-family: var(--sans);
  font-size: clamp(0.95rem, 2.2vw, 1.1rem);
  font-weight: 500;
  letter-spacing: 0;
  color: var(--text-soft);
}
.tool-shell { padding-bottom: clamp(2rem, 5vw, 3.4rem); }

/* --- Secciones de contenido --- */
.section { padding-block: clamp(2.2rem, 6vw, 4rem); }
.section__head { margin-bottom: clamp(1.3rem, 3vw, 2rem); }
.section--tint { background: color-mix(in srgb, var(--surface) 55%, transparent); }

/* --- Rejilla de tarjetas --- */
.grid {
  display: grid;
  gap: clamp(0.9rem, 2.2vw, 1.4rem);
  grid-template-columns: 1fr;
}
@media (min-width: 540px) { .grid--2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 720px) { .grid--3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 960px) { .grid--3 { grid-template-columns: repeat(3, 1fr); } .grid--4 { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 720px) and (max-width: 959px) { .grid--4 { grid-template-columns: repeat(2, 1fr); } }

/* --- Tarjeta de herramienta en el hub --- */
.tool-tile {
  display: flex; flex-direction: column; gap: 0.7rem;
  padding: 1.35rem;
  border-radius: var(--r-lg);
  position: relative;
  overflow: hidden;
  transition: transform 0.3s var(--ease-out), box-shadow 0.3s var(--ease-out);
  height: 100%;
}
.tool-tile:hover { transform: translateY(-5px); }
/* El logo es el monito de la herramienta, con su propia pose (logo-<slug>.png):
   ver assets/img/monito/. Va en una mancha CLARA del color de la familia
   (--accent-soft), nunca sobre el gradiente oscuro que llevaba el SVG de
   antes — el monito es tinta casi negra sobre transparente y ahí se disuelve. */
.tool-tile__icon {
  width: 64px; height: 64px; flex: none;
  padding: 4px;
  border-radius: 17px;
  display: grid; place-items: center;
  background: var(--accent-soft);
  box-shadow: var(--clay-inset);
  transition: transform 0.3s var(--ease-bounce);
}
.tool-tile:hover .tool-tile__icon { transform: rotate(-7deg) scale(1.08); }
.tool-tile__icon img { width: 100%; height: 100%; object-fit: contain; }
.tool-tile h3 { font-size: var(--t-md); }
.tool-tile p { font-size: var(--t-base); color: var(--text-soft); flex: 1; }
.tool-tile__go {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-size: var(--t-base); font-weight: 700; color: var(--accent-text);
}
.tool-tile__go svg { width: 15px; height: 15px; transition: transform 0.25s var(--ease-out); }
.tool-tile:hover .tool-tile__go svg { transform: translateX(4px); }

/* --- Pasos "cómo funciona" --- */
.steps { counter-reset: step; }
.step { position: relative; padding-left: 3.4rem; }
.step::before {
  counter-increment: step;
  content: counter(step);
  position: absolute; left: 0; top: 0;
  width: 2.4rem; height: 2.4rem;
  display: grid; place-items: center;
  border-radius: 50%;
  font-family: var(--display); font-weight: 800; font-size: var(--t-md);
  background: linear-gradient(145deg, var(--accent-fill), var(--accent-2-fill));
  color: var(--accent-ink);
  box-shadow: 0 8px 16px -7px color-mix(in srgb, var(--accent) 60%, transparent);
}
.step h3 { font-size: var(--t-md); margin-bottom: 0.25rem; }
.step p { font-size: var(--t-base); color: var(--text-soft); }

/* --- FAQ --- */
.faq details {
  border-radius: var(--r-md);
  padding: 0.1rem 1.1rem;
  background: var(--surface);
  border: 1px solid var(--line);
  transition: box-shadow 0.25s var(--ease-out);
}
.faq details + details { margin-top: 0.6rem; }
.faq details[open] { box-shadow: var(--neu-out-sm); }
.faq summary {
  cursor: pointer; list-style: none;
  padding-block: 0.95rem;
  font-weight: 650; font-size: var(--t-md);
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  font-family: var(--mono); font-size: var(--t-xl); font-weight: 400;
  color: var(--accent-text); flex: none;
  transition: transform 0.28s var(--ease-bounce);
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq details > p, .faq details > ul { padding-bottom: 1rem; font-size: var(--t-base); color: var(--text-soft); }
.faq details > ul { padding-left: 1.2rem; }

/* --- Texto SEO --- */
.prose { max-width: 68ch; }
.prose h2 { margin-top: 1.8rem; margin-bottom: 0.6rem; }
.prose h3 { margin-top: 1.3rem; margin-bottom: 0.4rem; }
.prose p, .prose ul, .prose ol { color: var(--text-soft); font-size: var(--t-md); }
.prose p + p { margin-top: 0.8rem; }
.prose ul, .prose ol { margin-top: 0.7rem; padding-left: 1.3rem; }
.prose li + li { margin-top: 0.35rem; }
.prose strong { color: var(--text); font-weight: 650; }
.prose a { color: var(--accent-text); text-decoration: underline; text-underline-offset: 3px; }

/* --- Huecos de publicidad ---------------------------------------------------
   EL HUECO NO EXISTE HASTA QUE HAYA UN ANUNCIO DE VERDAD DENTRO (29 ago 2026)

   Estos huecos venian del kit original con un recuadro punteado y la palabra
   PUBLICIDAD escrita, vacios. Asi, la pagina enseña veinticinco cajas que parecen
   rotas — y ademas contradicen la regla 1 de la portada de Daia, que dice que aqui
   no hay anuncios y que la familia Digitales remata con «las cinco cosas por las
   que uno termina en una pagina con anuncios. Aqui no».

   No se borraron: el dia que se decida poner publicidad, se pega el codigo dentro
   del `div` y el hueco aparece solo. Hasta entonces no se ve nada.

   `:has()` es lo que lo hace posible sin JavaScript: el hueco se esconde mientras
   no contenga un `ins`, un `iframe` o un `script`, que es la forma que tiene todo
   anuncio. Lo soportan todos los navegadores actuales; en uno viejisimo el hueco
   se veria vacio, que es lo que pasaba antes de esto.

   Y el rotulo va en `::before` y no escrito dentro: la ley pide que un anuncio se
   pueda distinguir del contenido, asi que cuando haya anuncio hay rotulo — pero
   el texto no puede quedarse pegado al lado del anuncio, que es lo que pasaria si
   siguiera dentro del div. */
.ad-slot:not(:has(ins, iframe, script)) { display: none; }

.ad-slot {
  min-height: 96px;
  margin-block: clamp(1.4rem, 3.5vw, 2.4rem);
  display: grid; place-items: center;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  color: var(--text-mute);
  font-size: var(--t-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.ad-slot::before { content: "Publicidad"; display: block; margin-bottom: 0.4rem; }
.ad-slot--leaderboard { min-height: 110px; }

/* --- Footer --- */
.site-footer {
  padding-block: clamp(2rem, 5vw, 3rem) 1.6rem;
  border-top: 1px solid var(--line);
  margin-top: clamp(2rem, 5vw, 3.5rem);
  font-size: var(--t-base);
  color: var(--text-soft);
}
.site-footer__grid {
  display: grid; gap: 1.6rem;
  grid-template-columns: 1fr;
  margin-bottom: 1.6rem;
}
@media (min-width: 720px) { .site-footer__grid { grid-template-columns: 1.4fr 1fr 1fr; } }
.site-footer h4 { font-size: var(--t-xs); text-transform: uppercase; letter-spacing: 0.12em; color: var(--text-mute); margin-bottom: 0.7rem; }
.site-footer ul { list-style: none; }
.site-footer li + li { margin-top: 0.4rem; }
.site-footer a:hover { color: var(--accent-text); }
.site-footer__bottom {
  display: flex; flex-wrap: wrap; gap: 0.7rem 1.4rem;
  justify-content: space-between; align-items: center;
  padding-top: 1.2rem; border-top: 1px solid var(--line);
  font-size: var(--t-sm); color: var(--text-mute);
}

/* --- Migas --- */
.crumbs { font-size: var(--t-sm); color: var(--text-mute); padding-top: 1rem; }
.crumbs a:hover { color: var(--accent-text); }
.crumbs span { opacity: 0.5; margin-inline: 0.35rem; }

/* =============================================================
   8. Efectos y animaciones
   ============================================================= */
@keyframes floaty {
  from { transform: translateY(-5px); }
  to   { transform: translateY(5px); }
}
@keyframes shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}
@keyframes toastIn {
  from { opacity: 0; transform: translateY(14px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes toastOut {
  to { opacity: 0; transform: translateY(10px) scale(0.97); }
}
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes pulseSoft {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}

.spinner {
  width: 22px; height: 22px;
  border-radius: 50%;
  border: 2.5px solid var(--accent-soft);
  border-top-color: var(--accent);
  animation: spin 0.75s linear infinite;
}

/* Reveals al hacer scroll — umbral bajo + red de seguridad en JS (gotcha A.8) */
[data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.7s var(--ease-out), transform 0.7s var(--ease-out);
}
[data-reveal].is-revealed { opacity: 1; transform: none; }
[data-reveal][style*="--d"] { transition-delay: var(--d); }

/* Tilt suave en tarjetas — solo con puntero fino, nunca gated por reduced-motion (A.2) */
@media (hover: hover) and (pointer: fine) {
  [data-tilt] { transition: transform 0.3s var(--ease-out); transform-style: preserve-3d; }
}

/* Sin JS: el contenido debe verse igual (01 §13) */
.no-js [data-reveal] { opacity: 1; transform: none; }
.js-required { display: none; }
.no-js .js-required { display: flex; }
.no-js .js-only { display: none !important; }

/* =============================================================
   9. Responsive
   ============================================================= */
@media (max-width: 539px) {
  .tool-card { padding: 1.05rem; border-radius: var(--r-lg); }
  .btn { padding: 0.72rem 1.15rem; }
  .btn--lg { padding: 0.92rem 1.5rem; font-size: var(--t-md); }

  /* La cabecera no cabía: marca (171 px) + «Más herramientas» (136) + tema
     (44) + huecos suman 371 y el ancho útil de un móvil de 360 es 325, así
     que el botón de tema se salía de la pantalla. Se retira el enlace, que
     está repetido en las migas y en el pie, y la marca sigue llevando al
     inicio. */
  .header-actions .btn--ghost { display: none; }
}

/* =============================================================
   9b. Ergonomía táctil
   -------------------------------------------------------------
   Un dedo no acierta un objetivo de menos de 44 px y medio kit se quedaba
   entre 26 y 41. La consulta suma dos condiciones porque ninguna basta sola:
   el ancho pilla el móvil de verdad y `pointer: coarse` pilla la tableta o el
   portátil táctil, que son anchos pero se manejan con el dedo igual.
   ============================================================= */
@media (max-width: 700px), (pointer: coarse) {
  /* Los rótulos van centrados en flex, así que subir el mínimo reparte el
     aire arriba y abajo sin descolocar nada. */
  .btn { min-height: 44px; }
  .btn--lg { min-height: 48px; }

  /* Las pastillas hacen de pestañas en media docena de herramientas: son el
     control que más se pulsa y el que más corto se quedaba (36 px). */
  .chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
  }
  /* 0,5 rem clavados dejaban dos pastillas a exactamente 8 px; con 0,55 hay
     margen de sobra para no pulsar la de al lado. */
  .chips { gap: 0.55rem; }

  .icon-btn { width: 44px; height: 44px; }
  .icon-btn svg { width: 21px; height: 21px; }

  /* El interruptor se pulsa por la etiqueta entera, no por el carril */
  .switch { min-height: 44px; }

  /* Los paneles plegables se abren tocando el resumen */
  summary { min-height: 44px; }

  .input, .select { min-height: 44px; }
  input[type="color"] { min-height: 44px; }

  /* Un <input type=range> no admite pseudo-elementos propios, así que la
     zona pulsable tiene que ser el campo entero: se sube a 44 px y el carril
     visual se muda al pseudo-elemento del navegador, que sigue midiendo 12.
     El desplazamiento del pulgar lo recentra sobre el carril. */
  .range { height: 44px; background: transparent; box-shadow: none; }
  .range::-webkit-slider-runnable-track {
    height: 12px;
    border-radius: var(--r-pill);
    background: var(--bg);
    box-shadow: var(--neu-in);
  }
  .range::-webkit-slider-thumb { margin-top: -6px; }
  .range::-moz-range-track {
    height: 12px;
    border-radius: var(--r-pill);
    background: var(--bg);
    box-shadow: var(--neu-in);
  }

  /* Una fila de campos apilada deja las etiquetas muy juntas; con el campo a
     44 px de alto conviene algo más de aire entre uno y otro. */
  .field-row { gap: 1rem; }
  .field + .field { margin-top: 1.05rem; }

  /* (Aquí había un suelo con max() para el monoespaciado, que corregía el
     0,92em de la regla base. Ya no hace falta: el monoespaciado hereda el
     tamaño tal cual, así que nunca baja del suelo ni se sale de la escala.) */
}

/* =============================================================
   10. Reduced motion — solo lo intrusivo (gotcha A.2)
   ============================================================= */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .dropzone__icon { animation: none; }
  .progress__bar { animation: none; }
  /* NO se desactivan: hovers, fades, transiciones de color, count-ups, reveals */
}

/* =============================================================
   11. Impresión
   ============================================================= */
@media print {
  .site-header, .site-footer, .ad-slot, .btn, .crumbs { display: none !important; }
  .bg-veil { display: none !important; }
  body { background: #fff; color: #000; }
  .clay, .glass, .neu { box-shadow: none; border: 1px solid #ccc; }
}
