/* ==========================================================================
   Linktree Practimatch — styles.css

   Los tokens de :root y [data-theme="light"] son un espejo 1:1 de globals.css
   (el design system de practimatch.com). Se replican aquí en vez de importarlos
   porque globals.css usa `@import "tailwindcss"` y requiere un build; esta
   página es standalone. Si cambias un token allá, cámbialo aquí.

   Lo único añadido son los stops del brand guide que globals.css no tokeniza,
   los acentos derivados (blue, mint), los gradientes de 7 stops, los colores
   exactos del logo y el layout local — marcados como EXTENSIÓN más abajo.
   ========================================================================== */

/* ── Design Tokens (shared) — espejo de globals.css:5-57 ── */
:root {
  /* Sin esto los scrollbars y los controles nativos se quedan en claro sobre
     el fondo #131315. Va aquí y no en el bloque EXTENSIÓN porque no es un
     color, es la declaración del esquema. */
  color-scheme: dark;

  /* Accent (same in both themes) */
  --color-accent-green: #5cdf8b;
  --color-accent-green-bright: #5fe18d;
  --color-accent-teal: #5dadba;
  --color-accent-teal-light: #83d3e0;
  --color-accent-purple: #5a60fb;
  --color-accent-purple-light: #bfc1ff;
  --color-accent-green-bg: rgba(0, 134, 70, 0.3);
  --color-accent-green-border: rgba(92, 223, 139, 0.2);
  --color-accent-purple-bg: rgba(90, 96, 251, 0.2);
  --color-accent-purple-border: rgba(90, 96, 251, 0.3);

  /* Gradients (same in both themes) */
  --gradient-brand: linear-gradient(90deg, #5fe18d, #5dadba, #5a60fb);
  --gradient-brand-135: linear-gradient(135deg, #5fe18d, #5dadba, #5a60fb);
  --gradient-green-teal: linear-gradient(90deg, #5fe18d, #5dadba);
  --gradient-teal-purple: linear-gradient(90deg, #5dadba, #5a60fb);

  /* Spacing */
  --section-py: 8rem;
  --section-px: 2rem;
  --container-max: 1280px;

  /* Radius */
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-full: 9999px;

  /* Shadows */
  --shadow-header: 0px 0px 40px rgba(90, 96, 251, 0.08);
  --shadow-glow-green: 0px 0px 40px rgba(95, 225, 141, 0.2);
  --shadow-glow-purple: 0px 0px 40px rgba(90, 96, 251, 0.15);

  /* Dark defaults */
  --color-bg-primary: #131315;
  --color-bg-secondary: #1b1b1d;
  --color-bg-surface: #201f21;
  --color-bg-surface-raised: #2a2a2c;
  --color-bg-surface-hover: #353437;
  --color-bg-overlay: rgba(9, 9, 11, 0.6);

  --color-text-primary: #e5e1e4;
  --color-text-secondary: #a1a1aa;
  --color-text-muted: #8a8a94;
  --color-text-on-gradient: #03006d;
  --color-text-inverse: #ffffff;

  --color-border-default: rgba(255, 255, 255, 0.1);
  --color-border-subtle: rgba(255, 255, 255, 0.08);
  --color-border-faint: rgba(255, 255, 255, 0.05);

  /* ── EXTENSIÓN (no está en globals.css) ────────────────────────────────
     Los 4 stops intermedios del brand guide que globals.css deja fuera (1, 4
     y 7 ya existen como accent green-bright / teal / purple). Ver
     _Guide Brand Practimatch.png → COLOR PALETTE (7 swatches).           */
  --color-brand-1: #5fe18d;  /* = --color-accent-green-bright */
  --color-brand-2: #5eda92;
  --color-brand-3: #5dc4a6;
  --color-brand-4: #5dadba;  /* = --color-accent-teal */
  --color-brand-5: #5c9cca;
  --color-brand-6: #5c8cd7;
  --color-brand-7: #5a60fb;  /* = --color-accent-purple */

  /* Acentos de los stops 3 y 6, con par claro/oscuro como los otros accents.
     globals.css no los tiene porque no tokeniza esos stops. Hacen falta para
     que las 5 tarjetas recorran la rampa sin repetir acento ni caer en un stop
     sin variante legible sobre fondo claro. */
  --color-accent-mint: #5dc4a6;  /* = --color-brand-3 */
  --color-accent-blue: #5c8cd7;  /* = --color-brand-6 */

  /* Tinta sobre --gradient-brand-* . A propósito SIN override en tema claro:
     el gradiente es el mismo en ambos temas, así que la tinta tampoco puede
     cambiar. (--color-text-on-gradient sí cambia y por eso no sirve aquí.) */
  --color-ink-on-brand: #03006d;

  /* Rampa completa de 7 stops — sin el banding del gradiente de 3 */
  --gradient-brand-full: linear-gradient(
    100deg,
    #5fe18d, #5eda92, #5dc4a6, #5dadba, #5c9cca, #5c8cd7, #5a60fb
  );

  /* Misma rampa pero ponderada: comprime los azules medios para que el morado
     domine el final, como en el lockup de logos/Logotipo_4.jpg ("match" en
     índigo sólido). Con stops equidistantes el final sale azul claro. */
  --gradient-wordmark: linear-gradient(
    100deg,
    #5fe18d 0%, #5eda92 11%, #5dc4a6 24%, #5dadba 37%,
    #5c9cca 51%, #5c8cd7 64%, #5a60fb 88%
  );

  /* Colores exactos extraídos de logos/Logotipo.ai (difieren del guide:
     el verde del logo es más claro y menos saturado que #5FE18D) */
  --logo-green: #96e78a;
  --logo-blue: #5c60f8;

  /* Layout local del linktree */
  --shell-max: 480px;
  --spotlight-strength: 20%;
  --card-alpha: 80%;
}

/* ── Light Theme Overrides — espejo de globals.css:60-93 ── */
[data-theme="light"] {
  color-scheme: light;

  --color-bg-primary: #fafafa;
  --color-bg-secondary: #f4f4f5;
  --color-bg-surface: #ffffff;
  --color-bg-surface-raised: #f0f0f2;
  --color-bg-surface-hover: #e8e8ea;
  --color-bg-overlay: rgba(255, 255, 255, 0.85);

  --color-text-primary: #18181b;
  --color-text-secondary: #52525b;
  --color-text-muted: #71717a;
  --color-text-on-gradient: #ffffff;
  --color-text-inverse: #09090b;

  --color-border-default: rgba(0, 0, 0, 0.1);
  --color-border-subtle: rgba(0, 0, 0, 0.06);
  --color-border-faint: rgba(0, 0, 0, 0.04);

  --shadow-header: 0px 0px 40px rgba(0, 0, 0, 0.06);
  --shadow-glow-green: 0px 0px 40px rgba(95, 225, 141, 0.15);
  --shadow-glow-purple: 0px 0px 40px rgba(90, 96, 251, 0.1);

  /* Stronger badge backgrounds for light mode */
  --color-accent-green: #16a34a;
  --color-accent-green-bright: #15803d;
  --color-accent-green-bg: rgba(0, 134, 70, 0.12);
  --color-accent-green-border: rgba(0, 134, 70, 0.3);
  --color-accent-teal: #0d7c8a;
  --color-accent-teal-light: #0e7490;
  --color-accent-purple: #4f46e5;
  --color-accent-purple-light: #4338ca;
  --color-accent-purple-bg: rgba(79, 70, 229, 0.1);
  --color-accent-purple-border: rgba(79, 70, 229, 0.25);

  /* Extensión: mismos tonos oscurecidos para contraste sobre blanco.
     Ambos superan 3:1 sobre #fafafa (mínimo WCAG para grafismo no textual:
     tiñen icono, chevron y spotlight, nunca texto). */
  --color-accent-mint: #0e8060;
  --color-accent-blue: #2c6ba8;

  /* Extensión: en claro el spotlight y el vidrio necesitan otra calibración */
  --spotlight-strength: 10%;
  --card-alpha: 84%;
}

/* ==========================================================================
   Base
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  /* vh de reserva: svh no existe antes de Safari 15.4 / Chrome 108 y sin el
     fallback el min-height se resolvía a `auto`. */
  min-height: 100vh;
  min-height: 100svh;
  background: var(--color-bg-primary);
  color: var(--color-text-primary);
  font-family: "Inter", ui-sans-serif, system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  /* iOS pinta un flash gris al tocar; el feedback lo damos con :active */
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.4s ease, color 0.4s ease;
}

/* Focus — heredado tal cual de globals.css:108-111 */
*:focus-visible {
  outline: 2px solid var(--color-accent-teal);
  outline-offset: 2px;
}

a {
  color: inherit;
  text-decoration: none;
}

::selection {
  background: color-mix(in oklab, var(--color-accent-purple) 30%, transparent);
  color: var(--color-text-primary);
}

/* Contenedor del sprite de iconos (<symbol> + <use>). Fuera de flujo y sin
   tamaño; no se usa display:none para no arriesgar el resolver de <use>. */
.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* Utilidad: visible solo para lectores de pantalla */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   Aurora de fondo — el glow verde/morado de practimatch.com
   ========================================================================== */

.aurora {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

/* Sin `filter: blur()` a propósito. Un blur de 90px sobre un elemento de
   ~1000px que además está animado obliga a re-rasterizarlo cada frame: medido
   en 1.2 fps (peor frame 1033 ms). La caída multi-stop del radial-gradient se
   ve igual de suave y se compone en GPU. */
/* lvmax en vez de vmax: en móvil, al ocultarse la barra de URL cambia vh, y con
   vmax eso redimensiona los blobs y fuerza repintado en pleno scroll. lvmax se
   fija al viewport grande y no se mueve. vmax queda de fallback. */
.aurora::before,
.aurora::after {
  content: "";
  position: absolute;
  width: 70vmax;
  height: 70vmax;
  width: 70lvmax;
  height: 70lvmax;
  border-radius: 50%;
  opacity: 0.16;
  will-change: transform;
}

.aurora::before {
  top: -28vmax;
  left: -18vmax;
  top: -28lvmax;
  left: -18lvmax;
  background: radial-gradient(
    circle,
    rgba(95, 225, 141, 1) 0%,
    rgba(95, 225, 141, 0.55) 30%,
    rgba(95, 225, 141, 0.18) 52%,
    rgba(95, 225, 141, 0) 74%
  );
  animation: drift-a 26s ease-in-out infinite alternate;
}

.aurora::after {
  bottom: -32vmax;
  right: -20vmax;
  bottom: -32lvmax;
  right: -20lvmax;
  background: radial-gradient(
    circle,
    rgba(90, 96, 251, 1) 0%,
    rgba(90, 96, 251, 0.55) 30%,
    rgba(90, 96, 251, 0.18) 52%,
    rgba(90, 96, 251, 0) 74%
  );
  animation: drift-b 32s ease-in-out infinite alternate;
}

[data-theme="light"] .aurora::before,
[data-theme="light"] .aurora::after {
  opacity: 0.22;
}

@keyframes drift-a {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(8lvmax, 6lvmax, 0) scale(1.12); }
}

@keyframes drift-b {
  from { transform: translate3d(0, 0, 0) scale(1.08); }
  to   { transform: translate3d(-7lvmax, -5lvmax, 0) scale(1); }
}

/* ==========================================================================
   Layout
   ========================================================================== */

/* Los env(safe-area-inset-*) evitan que el notch/isla dinámica y el indicador
   de inicio tapen contenido. Requiere viewport-fit=cover en el <meta>. */
.shell {
  width: 100%;
  max-width: var(--shell-max);
  margin: 0 auto;
  padding-top: max(clamp(3rem, 8vh, 6rem), calc(env(safe-area-inset-top, 0px) + 3.5rem));
  padding-bottom: max(3rem, calc(env(safe-area-inset-bottom, 0px) + 2rem));
  padding-left: max(1.5rem, calc(env(safe-area-inset-left, 0px) + 0.75rem));
  padding-right: max(1.5rem, calc(env(safe-area-inset-right, 0px) + 0.75rem));
  display: flex;
  flex-direction: column;
  gap: 2.25rem;
}

/* El <footer> vive fuera de <main> para conservar el landmark contentinfo,
   así que .shell agrupa a ambos y .stack lleva el ritmo interno. */
.stack {
  display: flex;
  flex-direction: column;
  gap: 2.25rem;
}

/* ==========================================================================
   Theme toggle
   ========================================================================== */

.theme-toggle {
  position: fixed;
  top: max(1rem, calc(env(safe-area-inset-top, 0px) + 0.5rem));
  right: max(1rem, calc(env(safe-area-inset-right, 0px) + 0.5rem));
  z-index: 10;
  display: grid;
  place-items: center;
  /* 44px = mínimo de área táctil recomendado (WCAG 2.5.5 / iOS HIG) */
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-full);
  /* Opaco: al hacer scroll pasa por encima de las tarjetas y sin
     backdrop-filter una versión translúcida dejaría ver el texto de abajo. */
  background: var(--color-bg-surface);
  color: var(--color-text-secondary);
  cursor: pointer;
  transition: color 0.25s, border-color 0.25s, transform 0.25s, background-color 0.25s;
}

@media (hover: hover) {
  .theme-toggle:hover {
    color: var(--color-accent-teal);
    border-color: var(--color-accent-teal);
    transform: scale(1.06);
  }
}

.theme-toggle:active {
  transform: scale(0.92);
}

.theme-toggle svg {
  width: 19px;
  height: 19px;
  grid-area: 1 / 1;
  transition: opacity 0.3s, transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Oscuro → se ofrece el sol. Claro → se ofrece la luna. */
.theme-toggle .icon-sun { opacity: 1; transform: rotate(0) scale(1); }
.theme-toggle .icon-moon { opacity: 0; transform: rotate(-90deg) scale(0.5); }
[data-theme="light"] .theme-toggle .icon-sun { opacity: 0; transform: rotate(90deg) scale(0.5); }
[data-theme="light"] .theme-toggle .icon-moon { opacity: 1; transform: rotate(0) scale(1); }

/* ==========================================================================
   Header
   ========================================================================== */

.masthead {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.85rem;
}

.logo-mark {
  width: 68px;
  height: auto;
  filter: drop-shadow(var(--shadow-glow-green));
}

/* Los colores del isotipo salen de los tokens, no de los atributos del SVG
   (los atributos de presentación no aceptan var(); los hex del markup son solo
   el fallback si esta hoja no llega a cargar). */
.logo-mark .logo-body { fill: var(--logo-green); }
.logo-mark stop { stop-color: var(--logo-blue); }

.wordmark {
  margin: 0;
  font-family: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
  font-size: clamp(2.4rem, 11vw, 3.1rem);
  font-weight: 800;
  letter-spacing: -0.035em;
  line-height: 1.05;
  /* Fallback para navegadores sin background-clip: text */
  color: var(--color-accent-teal);
  background: var(--gradient-wordmark);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .wordmark {
    background: none;
    -webkit-text-fill-color: currentColor;
  }
}

.tagline {
  margin: 0;
  max-width: 32ch;
  color: var(--color-text-secondary);
  font-size: 0.975rem;
}

/* ── Marquee de taglines del brand guide ──
   Usa los keyframes marquee-scroll que globals.css define pero nunca aplica. */
@keyframes marquee-scroll {
  0%   { transform: translateX(0); }
  100% { transform: translateX(-50%); }
}

.marquee {
  width: 100%;
  overflow: hidden;
  margin-top: 0.35rem;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 20%, #000 80%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 20%, #000 80%, transparent);
}

.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee-scroll 24s linear infinite;
}

/* Dentro de @media (hover: hover) como el resto: en táctil el :hover se queda
   pegado tras el toque y el marquee se congelaba hasta tocar otra cosa. */
@media (hover: hover) {
  .marquee:hover .marquee-track {
    animation-play-state: paused;
  }
}

.marquee-group {
  display: flex;
  flex-shrink: 0;
  gap: 1.5rem;
  padding-right: 1.5rem;
}

.marquee-group span {
  color: var(--color-accent-teal);
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  white-space: nowrap;
}

.marquee-group span::after {
  content: "·";
  margin-left: 1.5rem;
  color: var(--color-text-muted);
  letter-spacing: 0;
}

/* ==========================================================================
   Enlaces
   ========================================================================== */

.links {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.link {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  gap: 0.95rem;
  padding: 0.9rem 1rem;
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-lg);
  /* La primera declaración es el fallback: sin soporte de color-mix la segunda
     se descarta y la tarjeta quedaría transparente sobre la aurora. */
  background: var(--color-bg-surface);
  background: color-mix(in oklab, var(--color-bg-surface) var(--card-alpha), transparent);
  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.25s,
    border-color 0.25s, background-color 0.25s;
}

.link > * {
  position: relative;
  z-index: 1;
}

/* :hover va SIEMPRE dentro de @media (hover: hover). En táctil el navegador
   deja el :hover pegado tras el toque y la tarjeta se queda "levantada" hasta
   que tocas otra cosa. :focus-visible sí es incondicional (teclado). */
.link:focus-visible {
  transform: translateY(-2px);
  border-color: transparent;
  box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.55), var(--shadow-glow-purple);
}

[data-theme="light"] .link:focus-visible {
  box-shadow: 0 10px 30px -14px rgba(0, 0, 0, 0.22), var(--shadow-glow-purple);
}

@media (hover: hover) {
  .link:hover {
    transform: translateY(-2px);
    border-color: transparent;
    box-shadow: 0 10px 30px -12px rgba(0, 0, 0, 0.55), var(--shadow-glow-purple);
  }

  [data-theme="light"] .link:hover {
    box-shadow: 0 10px 30px -14px rgba(0, 0, 0, 0.22), var(--shadow-glow-purple);
  }
}

/* Feedback al pulsar — es lo único que percibe el usuario táctil */
.link:active {
  transform: scale(0.985);
  transition-duration: 0.08s;
}

/* Con ratón la tarjeta ya está levantada al pulsar: sin esto :active pisaba el
   translateY del :hover (misma especificidad, gana el que va después) y la
   tarjeta caía de golpe al hacer clic. */
@media (hover: hover) {
  .link:hover:active {
    transform: translateY(-2px) scale(0.985);
  }
}

/* Borde con gradiente que se enciende en hover (mask-composite: solo el borde) */
.link::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  padding: 1px;
  border-radius: inherit;
  background: var(--gradient-brand-full);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: 0;
  transition: opacity 0.3s;
  pointer-events: none;
}

.link:focus-visible::before {
  opacity: 1;
}

@media (hover: hover) {
  .link:hover::before { opacity: 1; }
}

/* En táctil el borde con gradiente se enciende al pulsar, que es el único
   momento en que hay "hover" real. */
@media (hover: none) {
  .link:active::before { opacity: 1; }
}

/* Spotlight que sigue el cursor, teñido con el acento de cada tarjeta
   (--mx/--my las escribe el JS) */
.link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  background: radial-gradient(
    220px circle at var(--mx, 50%) var(--my, 50%),
    color-mix(in oklab, var(--accent, var(--color-accent-teal)) var(--spotlight-strength), transparent),
    transparent 68%
  );
  opacity: 0;
  transition: opacity 0.35s;
  pointer-events: none;
}

@media (hover: hover) {
  .link:hover::after { opacity: 1; }
}

/* ── Icono ── */
.link-icon {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 10px;
  border: 1px solid var(--color-border-subtle);
  background: var(--color-bg-surface-raised);
  color: var(--accent, var(--color-text-primary));
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1), border-color 0.3s;
}

@media (hover: hover) {
  .link:hover .link-icon {
    transform: scale(1.07) rotate(-3deg);
    border-color: color-mix(in oklab, var(--accent, var(--color-accent-teal)) 45%, transparent);
  }
}

.link-icon svg {
  width: 20px;
  height: 20px;
}

/* El sitio web lleva el gradiente completo en vez de un acento plano.
   La tinta NO usa --color-text-on-gradient: ese token pasa a #fff en tema claro
   y el icono quedaba blanco sobre el teal del centro del gradiente (2.4:1).
   Como el gradiente es idéntico en ambos temas, la tinta se fija (6.8:1). */
.link-icon.is-brand {
  background: var(--gradient-brand-135);
  border-color: transparent;
  color: var(--color-ink-on-brand);
}

/* ── Texto ── */
.link-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.link-label {
  font-family: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--color-text-primary);
}

.link-handle {
  font-size: 0.8rem;
  color: var(--color-text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Chevron ── */
.link-arrow {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  color: var(--color-text-muted);
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1), color 0.3s;
}

.link:focus-visible .link-arrow {
  transform: translateX(4px);
  color: var(--accent, var(--color-accent-teal));
}

@media (hover: hover) {
  .link:hover .link-arrow {
    transform: translateX(4px);
    color: var(--accent, var(--color-accent-teal));
  }
}

/* ==========================================================================
   Compartir
   ========================================================================== */

.share {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.8rem 1rem;
  border: 1px dashed var(--color-border-default);
  border-radius: var(--radius-lg);
  background: transparent;
  color: var(--color-text-secondary);
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
  /* transform incluido: sin él el scale del :active saltaba en seco */
  transition: color 0.25s, border-color 0.25s, background-color 0.25s,
    transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

@media (hover: hover) {
  .share:hover {
    color: var(--color-accent-teal);
    border-color: var(--color-accent-teal);
    background: color-mix(in oklab, var(--color-accent-teal) 8%, transparent);
  }
}

.share:active {
  transform: scale(0.985);
  color: var(--color-accent-teal);
  border-color: var(--color-accent-teal);
}

.share svg {
  width: 16px;
  height: 16px;
}

/* Toast */
.toast {
  position: fixed;
  left: 50%;
  bottom: max(1.5rem, calc(env(safe-area-inset-bottom, 0px) + 1rem));
  /* % y no vw: en escritorio 100vw incluye la barra de scroll, así que el toast
     podía asomar por debajo de ella. Al ser fixed, el 100% es el viewport. */
  max-width: calc(100% - 2.5rem);
  z-index: 20;
  padding: 0.65rem 1.15rem;
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-full);
  background: var(--color-bg-surface-raised);
  color: var(--color-text-primary);
  font-size: 0.85rem;
  font-weight: 600;
  box-shadow: 0 12px 32px -12px rgba(0, 0, 0, 0.6);
  opacity: 0;
  transform: translate(-50%, 12px);
  transition: opacity 0.3s, transform 0.3s;
  pointer-events: none;
}

.toast.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ==========================================================================
   Footer
   ========================================================================== */

.footer {
  margin-top: 0.5rem;
  text-align: center;
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

.footer .rule {
  height: 1px;
  margin: 0 auto 1.25rem;
  width: 56px;
  border-radius: var(--radius-full);
  background: var(--gradient-brand-full);
  opacity: 0.7;
}

.footer p {
  margin: 0.2rem 0;
}

/* ==========================================================================
   Entrada escalonada
   ========================================================================== */

/* Solo keyframe `from` + fill-mode `backwards`, NO `both`.
   Con `both` el keyframe final (`transform: none`) queda fijado para siempre, y
   como las animaciones ganan al CSS normal en la cascada, pisaba el
   translateY(-2px) del hover y el scale(0.985) del :active — los estados se
   veían "muertos". Con solo `from`, la animación interpola hacia el valor
   natural del elemento y al terminar lo suelta. */
@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
}

.reveal {
  animation: rise 0.65s cubic-bezier(0.22, 1, 0.36, 1) backwards;
  animation-delay: var(--d, 0s);
}

/* ==========================================================================
   Responsive
   ========================================================================== */

/* Pantallas angostas (iPhone SE, Galaxy A0x y similares) */
@media (max-width: 370px) {
  .shell { gap: 1.75rem; }
  .stack { gap: 1.75rem; }
  .links { gap: 0.6rem; }

  .link {
    gap: 0.75rem;
    padding: 0.8rem 0.85rem;
  }

  .link-icon { width: 40px; height: 40px; }
  .link-label { font-size: 0.9rem; }
  .link-handle { font-size: 0.75rem; }

  .logo-mark { width: 58px; }
  .tagline { font-size: 0.9rem; }

  .marquee-group span {
    font-size: 0.6rem;
    letter-spacing: 0.16em;
  }
}

/* Móvil en horizontal: el alto útil se desploma, así que se recorta el aire
   vertical para que las tarjetas sigan visibles sin scrollear tanto. */
@media (max-height: 560px) and (orientation: landscape) {
  .shell {
    padding-top: max(2rem, calc(env(safe-area-inset-top, 0px) + 1.5rem));
    padding-bottom: max(2rem, calc(env(safe-area-inset-bottom, 0px) + 1rem));
    gap: 1.5rem;
  }

  .stack { gap: 1.5rem; }
  .masthead { gap: 0.6rem; }
  .logo-mark { width: 48px; }
  .wordmark { font-size: clamp(2rem, 6vh, 2.6rem); }
  .marquee { display: none; }
}

/* Punteros gruesos (dedo): agranda un poco el objetivo táctil de las tarjetas */
@media (pointer: coarse) {
  .link { padding-block: 1rem; }
  .share { padding-block: 0.95rem; }
}

/* ==========================================================================
   Reduced motion — heredado de globals.css:169-180 y extendido para la
   aurora, el marquee y la entrada (que con duration 0.01ms harían jank).
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }

  .marquee-track,
  .aurora::before,
  .aurora::after {
    animation: none !important;
  }

  .reveal {
    opacity: 1;
    animation: none !important;
  }

  .link:hover,
  .link:hover:active,
  .link:focus-visible,
  .link:active,
  .share:active,
  .theme-toggle:active {
    transform: none;
  }
}

/* ==========================================================================
   Alto contraste / colores forzados
   ========================================================================== */

/* Modo de contraste alto de Windows: el sistema fuerza su paleta y descarta
   background-image. El wordmark, que es un gradiente recortado sobre texto
   transparente, desaparecía por completo. */
@media (forced-colors: active) {
  .wordmark {
    background: none;
    -webkit-text-fill-color: currentColor;
    color: CanvasText;
  }

  /* Los bordes translúcidos se resuelven a transparente: sin esto las tarjetas
     pierden su contorno y quedan como texto suelto. */
  .link,
  .share,
  .theme-toggle {
    border-color: CanvasText;
  }

  .aurora { display: none; }
}

/* "Aumentar contraste" (iOS/macOS/Windows): los bordes al 10% de alfa y el
   texto secundario son lo primero que se pierde. */
@media (prefers-contrast: more) {
  .link,
  .share,
  .theme-toggle {
    border-color: var(--color-text-secondary);
  }

  .tagline,
  .footer {
    color: var(--color-text-primary);
  }
}
