/* ============================================================================
   Alex Cadenas — Web de servicios freelance
   ----------------------------------------------------------------------------
   PARA EDITAR COLORES / TIPOS / ESPACIADOS: cambia las variables de :root.
   Todo el sitio las consume; ningún componente hardcodea un color.
   El tema oscuro redefine esas mismas variables en [data-theme="dark"].

   RELACIÓN CON LA WEB DE CV: mismas tipografías, mismas métricas y mismos
   nombres de token que el repo cv-alex-cadenas, para que las dos webs se lean
   como la misma marca. Lo único que cambia a propósito es el acento primario
   (aquí teal en vez de indigo), para que se distinga que esta es la comercial.
   ========================================================================== */

:root {
  /* ---- Paleta --------------------------------------------------------- */
  --ink:        #14141a;   /* texto principal              */
  --ink-soft:   #3b3b46;   /* texto secundario             */
  --muted:      #74747f;   /* texto terciario / metadatos  */
  --line:       #e9e7e0;   /* líneas y bordes              */
  --line-soft:  #f1efe9;
  --paper:      #fbfaf7;   /* fondo de página              */
  --surface:    #ffffff;   /* tarjetas / superficies       */
  --surface-2:  #f6f4ef;   /* secciones alternas           */

  /* Paleta de acentos IDÉNTICA a la de la web de CV (repo cv-alex-cadenas):
     mismos valores y misma jerarquía, para que las dos webs sean la misma
     marca. Solo se añade --accent-4, que allí no existe. */
  --accent:      #4f46e5;  /* indigo */
  --accent-deep: #3a32c4;
  --accent-soft: #ecebfb;
  --accent-ink:  #ffffff;
  --accent-2:    #ff6a3d;  /* coral */
  --accent-2-soft:#ffede6;
  --accent-3:      #0f8a6b; /* teal */
  --accent-3-soft: #e3f5ef;
  --accent-4:      #5b6472; /* gris neutro: Product Management (secundario) */
  --accent-4-soft: #eef0f3;

  /* ---- Tipografía ----------------------------------------------------- */
  --font-display: "Space Grotesk", "Inter", system-ui, sans-serif;
  --font-body:    "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* ---- Métricas ------------------------------------------------------- */
  --radius:    18px;
  --radius-sm: 12px;
  --radius-lg: 28px;
  --container: 1140px;
  --gutter:    clamp(20px, 5vw, 64px);
  --shadow:    0 1px 2px rgba(20,20,26,.04), 0 12px 32px -16px rgba(20,20,26,.18);
  --shadow-sm: 0 1px 2px rgba(20,20,26,.05), 0 6px 18px -12px rgba(20,20,26,.16);
}

[data-theme="dark"] {
  --ink:        #f4f3ef;
  --ink-soft:   #c7c6c0;
  --muted:      #8f8f99;
  --line:       #2a2a33;
  --line-soft:  #20202a;
  --paper:      #0d0d12;
  --surface:    #16161d;
  --surface-2:  #1b1b23;
  --accent:      #8b85ff;
  --accent-deep: #a7a2ff;
  --accent-soft: #1e1b38;
  --accent-ink:  #0d0d12;
  --accent-2:    #ff7e57;
  --accent-2-soft:#2a1a12;
  --accent-3:      #34c99a;
  --accent-3-soft: #123028;
  --accent-4:      #93a0b2;
  --accent-4-soft: #1e232b;
  --shadow:    0 1px 2px rgba(0,0,0,.4), 0 18px 40px -20px rgba(0,0,0,.7);
  --shadow-sm: 0 1px 2px rgba(0,0,0,.4), 0 8px 22px -14px rgba(0,0,0,.6);
}

/* Cada bloque con data-v hereda el acento de su servicio. Así una tarjeta de
   UX Research usa el indigo sin que ningún componente sepa qué color es:
   todos escriben var(--v) y el color lo decide el atributo del contenedor. */
[data-v="cuali"]     { --v: var(--accent-3); --v-soft: var(--accent-3-soft); }
[data-v="uxr"]       { --v: var(--accent);   --v-soft: var(--accent-soft); }
[data-v="discovery"] { --v: var(--accent-2); --v-soft: var(--accent-2-soft); }
/* Product Management "puro" es un servicio secundario (no está entre los 3
   pilares), así que lleva un acento neutro a propósito: se distingue sin
   competir visualmente con los tres ejes de research. */
[data-v="pm"]        { --v: var(--accent-4); --v-soft: var(--accent-4-soft); }

/* ============================================================================
   Reset / base
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
[id] { scroll-margin-top: 84px; }   /* el nav sticky no debe tapar las anclas */

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--paper);
  line-height: 1.6;
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background .35s ease, color .35s ease;
  overflow-x: hidden;   /* evita scroll lateral en móvil por el carrusel */
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; border: 0; background: none; color: inherit; }
ul, ol { margin: 0; padding: 0; list-style: none; }
p { margin: 0; }
h1, h2, h3, h4 {
  font-family: var(--font-display); font-weight: 700; line-height: 1.08;
  margin: 0; letter-spacing: -0.02em;
}
svg { width: 1em; height: 1em; flex: none; }
::selection { background: var(--accent); color: var(--accent-ink); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }

/* ============================================================================
   Helpers de layout
   ========================================================================== */
.container { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--gutter); }

.section { padding-block: clamp(56px, 9vw, 116px); }
.section--alt { background: var(--surface-2); }
/* Para secciones de piezas cortas (testimonios): mismo lenguaje, menos aire
   arriba y abajo y cabecera más pegada al contenido. */
.section--tight { padding-block: clamp(38px, 5.5vw, 68px); }
.section--tight .section-head { margin-bottom: clamp(18px, 2.4vw, 26px); }
.section--tight .section-head p { font-size: 1rem; margin-top: .65rem; }

.section-head { max-width: 720px; margin-bottom: clamp(28px, 5vw, 52px); }
.section-head h2 { font-size: clamp(1.8rem, 4.4vw, 2.9rem); margin-top: .5rem; }
.section-head p { color: var(--ink-soft); font-size: 1.05rem; margin-top: .9rem; }
.section-head--row { max-width: none; display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; }
.section-head--row > div:first-child { max-width: 720px; }
/* Cabecera de Servicios: titular a la izquierda, tarjeta de tarifas a la
   derecha en el hueco que dejaba el h2 (ver .rates-card).
   Es una REJILLA, no un flex, por la alineación: el eyebrow ocupa la fila 1 a
   todo el ancho y la tarjeta arranca en la fila 2, la del h2. Así su borde
   superior queda a la altura del titular sin tener que sumar a mano la altura
   del eyebrow. El `margin-top` de la tarjeta es el ajuste óptico que falta: la
   caja de línea del h2 empieza por encima del alto de las mayúsculas
   (line-height 1.08 + la diferencia entre ascendente y altura de x), y Alex
   pidió alinear con la parte superior de las LETRAS, no de la caja. */
.section-head--svc {
  max-width: none;
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  column-gap: clamp(28px, 4vw, 56px); row-gap: .5rem;
  align-items: start;
}
.section-head--svc > .eyebrow { grid-column: 1 / -1; }
.section-head--svc .section-head__main { grid-column: 1; max-width: 720px; }
/* El .5rem de separación lo pone ya el row-gap de la rejilla. */
.section-head--svc .section-head__main h2 {
  margin-top: 0;
  /* Titular en UNA sola línea. El copy está escrito para caber ("3 formas…",
     con el 3 en cifra, no "Tres"): no alargarlo, ni en ES ni en EN. En móvil
     se deja partir, ahí no cabe de ninguna manera. */
  white-space: nowrap; font-size: clamp(1.7rem, 3.4vw, 2.7rem);
}
@media (max-width: 620px) {
  .section-head--svc .section-head__main h2 { white-space: normal; }
}
/* Ajuste óptico de la alineación con el alto de las mayúsculas del h2 (ver
   comentario del bloque): unos 6px a tamaño de escritorio. */
.section-head--svc .rates-card { grid-column: 2; margin-top: clamp(4px, .55vw, 9px); }

/* Bajo 900px no caben dos columnas: la tarjeta pasa a ancho completo debajo. */
@media (max-width: 900px) {
  .section-head--svc { grid-template-columns: minmax(0, 1fr); row-gap: 18px; }
  .section-head--svc .rates-card { grid-column: 1; max-width: 380px; margin-top: 0; }
}

.eyebrow {
  font-family: var(--font-display);
  font-size: .72rem; font-weight: 600; letter-spacing: .18em; text-transform: uppercase;
  color: var(--accent); display: inline-flex; align-items: center; gap: .5em;
}
.eyebrow::before { content: ""; width: 22px; height: 2px; background: currentColor; border-radius: 2px; }
/* Lo usa la cabecera de la sección Portfolio portada del CV (mismo valor). */
.eyebrow--xl { font-size: clamp(.78rem, 1.2vw, .92rem); }

.mini-title {
  font-family: var(--font-display); font-size: .78rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted);
  margin-bottom: 12px;
}

.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--v, var(--accent)); flex: none; }

/* ---- Grid de 3 columnas usado en varias secciones -------------------- */

@media (min-width: 720px) {  }
@media (min-width: 1000px) {  }

/* ---- Botones --------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .55em;
  padding: 13px 22px; border-radius: 999px;
  font-family: var(--font-display); font-weight: 600; font-size: .95rem;
  border: 1px solid transparent; cursor: pointer;
  transition: transform .18s ease, background .2s ease, border-color .2s ease, color .2s ease, box-shadow .2s ease;
  white-space: nowrap;
}
.btn svg { width: 1.05em; height: 1.05em; }
.btn:hover { transform: translateY(-1px); }
.btn--primary { background: var(--accent); color: var(--accent-ink); box-shadow: var(--shadow-sm); }
.btn--primary:hover { background: var(--accent-deep); }
.btn--ghost { border-color: var(--line); color: var(--ink); background: var(--surface); }
.btn--ghost:hover { border-color: var(--accent); color: var(--accent); }
/* Botón oscuro del hero, igual que en la web de CV. */
.btn--ink { background: var(--ink); color: var(--paper); }
.btn--ink:hover { box-shadow: var(--shadow); }
.btn--sm { padding: 10px 17px; font-size: .88rem; }

.icon-btn {
  width: 38px; height: 38px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink-soft);
  transition: color .2s, border-color .2s, background .2s;
}
.icon-btn svg { width: 18px; height: 18px; }
.icon-btn:hover { color: var(--accent); border-color: var(--accent); }

/* ---- Chips y etiquetas ----------------------------------------------- */
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  padding: 6px 12px; border-radius: 999px; font-size: .82rem; font-weight: 500;
  background: var(--surface); border: 1px solid var(--line); color: var(--ink-soft);
}
.chips--sm .chip { font-size: .78rem; padding: 5px 10px; }

@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
  70%  { box-shadow: 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* ---- Listas con check ------------------------------------------------ */
.ticks { display: grid; gap: 9px; }
.ticks li { display: flex; align-items: flex-start; gap: .6em; font-size: .93rem; color: var(--ink-soft); line-height: 1.5; }
.ticks svg { width: 15px; height: 15px; margin-top: .32em; color: var(--v, var(--accent)); }
.ticks--lg li { font-size: 1rem; }

/* ============================================================================
   Barra de progreso de scroll
   ========================================================================== */
.progress-bar {
  position: fixed; top: 0; left: 0; height: 3px; width: 0%; z-index: 60;
  background: linear-gradient(90deg, var(--accent), var(--accent-2), var(--accent-3));
}

/* ============================================================================
   Navegación
   ========================================================================== */
/* PORTADO TAL CUAL DESDE LA WEB DE CV. El menú móvil está oculto por defecto
   en cualquier ancho y solo se activa dentro del breakpoint de ≤900px, así el
   escritorio no cambia aunque esos elementos existan en el DOM. */
.nav {
  position: sticky; top: 0; z-index: 50;
  backdrop-filter: saturate(180%) blur(14px);
  background: color-mix(in srgb, var(--paper) 78%, transparent);
  border-bottom: 1px solid transparent;
  transition: border-color .3s ease, background .3s ease;
}
.nav.is-stuck { border-bottom-color: var(--line); }
.nav__inner { display: flex; align-items: center; gap: 18px; height: 66px; flex-wrap: nowrap; }

.brand { display: inline-flex; align-items: center; gap: 7px; font-family: var(--font-display); font-weight: 700; letter-spacing: -.01em; white-space: nowrap; font-size: 1.02rem; }
.brand__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); display: inline-block; transition: transform .2s; }
.brand:hover .brand__dot { transform: scale(1.4); }

/* El CTA de Contacto (.btn) vive dentro de .nav__links, detrás de Testimonios:
   de ahí el :not(.btn) en todas las reglas de enlace, para que no herede el
   pill de los enlaces normales ni el estado activo del scrollspy. */
.nav__links { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.nav__links a:not(.btn) {
  padding: 8px 12px; border-radius: 999px; font-size: .9rem; font-weight: 500; color: var(--ink-soft);
  transition: background .2s, color .2s; white-space: nowrap;
}
.nav__links a:not(.btn):hover { background: var(--surface-2); color: var(--ink); }
.nav__links a:not(.btn).is-active { background: var(--accent-soft); color: var(--accent-deep); font-weight: 700; }
[data-theme="dark"] .nav__links a:not(.btn).is-active { color: var(--accent); }
.nav__links .btn { margin-left: 10px; }

.nav__tools { display: flex; align-items: center; gap: 8px; }

.toggle {
  display: inline-flex; align-items: center; height: 38px; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: 999px; background: var(--surface); overflow: hidden;
}
.toggle button { height: 100%; padding: 0 12px; display: inline-flex; align-items: center; font-size: .8rem; font-weight: 600; color: var(--muted); font-family: var(--font-display); }
.toggle button.is-active { background: var(--ink); color: var(--paper); }

.nav .btn { height: 38px; box-sizing: border-box; padding: 0 16px; font-size: .88rem; }

.nav__menu-btn { display: none; }
.nav__mobile-panel { display: none; }

/* ============================================================================
   Hero
   ----------------------------------------------------------------------------
   PORTADO TAL CUAL DESDE LA WEB DE CV (repo cv-alex-cadenas). Si algo aquí
   parece raro (los paddings mínimos de .hero, el ::after desplazado detrás de
   la foto, el badge en position absolute), es intencionado: es exactamente el
   mismo bloque, para que las dos webs se vean idénticas en esta parte.
   Únicos cambios deliberados: los pilares heredan el color de su servicio vía
   data-v, y los chips de contacto se resetean respecto al .chip de pastilla
   que usa el resto de ESTA web (en el CV el .chip global ya era plano).
   ========================================================================== */
.hero { padding-block: clamp(8px, 1.2vw, 12px) clamp(6px, 1vw, 10px); position: relative; overflow: hidden; }
.hero__eyebrow-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; margin-bottom: clamp(8px, 1.2vw, 12px); }
.hero__eyebrow { font-size: clamp(.78rem, 1.2vw, .92rem); }
.hero__eyebrow-sub { color: inherit; font-weight: 600; }
.hero__exp-badge {
  font-family: var(--font-display); font-size: .72rem; font-weight: 600; color: var(--muted);
  border: 1px solid var(--line); border-radius: 999px; padding: 5px 12px; white-space: nowrap;
}
.hero__grid { display: grid; grid-template-columns: 1.5fr .9fr; gap: clamp(28px, 4.5vw, 56px); align-items: start; }
.hero__intro { min-width: 0; }
.hero h1 { font-size: clamp(2.1rem, 5.4vw, 3.6rem); line-height: .98; }
.hero h1 .accent { color: var(--accent); }
.hero__role { font-family: var(--font-display); font-weight: 500; font-size: clamp(1rem, 1.6vw, 1.15rem); color: var(--ink-soft); margin-top: 10px; line-height: 1.35; }
.hero__tagline { font-size: clamp(.88rem, 1.2vw, 1rem); line-height: 1.5; color: var(--ink-soft); margin-top: 14px; max-width: 44ch; }
.hero__cta { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.hero__cta .btn { padding: 9px 15px; font-size: .82rem; }
.hero__cta .btn svg { width: 14px; height: 14px; }

.hero__photo { --photo-size: clamp(160px, 20vw, 260px); display: flex; flex-direction: column; align-items: center; justify-self: end; margin-top: clamp(8px, 1.4vw, 16px); margin-right: 16px; }
.hero__photo-frame { position: relative; }
.hero__photo-frame img {
  width: var(--photo-size); aspect-ratio: 1; object-fit: cover; border-radius: 24px;
  border: 1px solid var(--line); background: var(--surface-2);
  filter: contrast(1.02) saturate(1.03);   /* en color; para B/N usa: grayscale(1) contrast(1.02) */
}
/* Bloque de color desplazado en diagonal detrás de la foto. z-index negativo
   para quedar bajo la imagen sin necesitar un wrapper extra. */
.hero__photo-frame::after {
  content: ""; position: absolute; inset: 16px -16px -16px 16px; border-radius: 24px; z-index: -1;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
}
.hero__badge {
  position: absolute; left: -10px; bottom: 14px; background: var(--surface); border: 1px solid var(--line);
  border-radius: 12px; padding: 8px 12px; box-shadow: var(--shadow-sm); font-size: .72rem; font-weight: 600;
  display: flex; align-items: center; gap: 7px; white-space: nowrap;
}
/* Verde fijo (no var(--accent)): el punto significa "disponible", no es marca. */
.hero__badge .dot { width: 7px; height: 7px; border-radius: 50%; background: #16a34a; box-shadow: 0 0 0 4px color-mix(in srgb,#16a34a 22%, transparent); flex: none; }
.hero__photo .hero__chips {
  display: flex; flex-direction: column; align-items: flex-start; width: var(--photo-size);
  gap: 9px; margin-top: 40px;
}
/* Reset del .chip de pastilla del resto de esta web: en el hero del CV los
   chips son texto plano con icono, sin fondo ni borde.
   IMPORTANTE (2026-07-29): en el CV la clase base .chip ya trae
   display:inline-flex y gap:.5em; aquí .chip es una pastilla y no los tiene,
   así que al quitarle el padding el icono quedaba pegado al texto y las cuatro
   líneas se veían apelmazadas. Hay que reponer esas dos propiedades a mano. */
.hero__chips .chip {
  display: inline-flex; align-items: center; gap: .55em;
  background: none; border: 0; padding: 0; border-radius: 0;
  white-space: normal; word-break: break-word; font-size: .82rem; line-height: 1.25;
}
.hero__chips .chip svg { width: 14px; height: 14px; color: var(--accent); flex: none; }
.hero__chips .chip a:hover { color: var(--accent); }

/* ---- Muro de logos de clientes ---- */
.clients { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding-block: 8px 28px; margin-top: clamp(4px,.8vw,8px); }
.clients__label { font-family: var(--font-display); font-size: .68rem; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); margin-bottom: 10px; }
.clients__logos { display: block; width: auto; height: auto; max-width: 100%; max-height: 68px; margin-inline: auto; opacity: .85; transition: opacity .2s; }
.clients__logos:hover { opacity: 1; }

/* ============================================================================
   Pilares de trabajo (portado del CV; aquí enlazan a la sección Servicios)
   ========================================================================== */
.pillars-block { padding-block: clamp(8px, 1.2vw, 14px) clamp(4px, .8vw, 8px); }
.pillars-block__title { font-size: clamp(1.05rem, 1.8vw, 1.3rem); margin-bottom: clamp(14px, 2vw, 20px); }
.pillars { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.pillar {
  position: relative; display: block; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 22px 22px 24px; transition: transform .25s, box-shadow .25s, border-color .25s; cursor: pointer;
}
/* Única desviación respecto al CV: el color del número y del hover sale de
   var(--v) (el data-v del pilar) en vez de ser siempre --accent. */
.pillar:hover, .pillar:focus-visible { transform: translateY(-4px); box-shadow: var(--shadow); border-color: color-mix(in srgb, var(--v, var(--accent)) 40%, var(--line)); outline: none; }
.pillar__num { font-family: var(--font-display); font-size: .78rem; font-weight: 700; color: var(--v, var(--accent)); padding-right: 30px; }
.pillar h3 { font-size: 1.12rem; margin: 8px 0 6px; }
.pillar p { color: var(--ink-soft); font-size: .88rem; line-height: 1.5; margin: 0; }
.pillar__go {
  position: absolute; top: 14px; right: 14px; width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center; background: var(--surface-2); color: var(--muted);
  transition: background .2s, color .2s, transform .2s;
}
.pillar__go svg { width: 12px; height: 12px; transform: rotate(-45deg); }
.pillar:hover .pillar__go, .pillar:focus-visible .pillar__go { background: var(--v, var(--accent)); color: var(--accent-ink); transform: translate(2px, -2px); }

/* ---- Responsive del hero (portado del @media max-width:900px del CV): la
   foto sube arriba y pasa a fila con los chips a su derecha; el badge deja de
   estar superpuesto y baja al flujo normal para no tapar nada. ---- */
@media (max-width: 900px) {
  .hero__grid { grid-template-columns: 1fr; }
  .hero__photo {
    order: -1; justify-self: stretch; --photo-size: clamp(84px, 24vw, 124px);
    flex-direction: row; align-items: flex-start; gap: 14px; margin-top: 0; margin-right: 0;
  }
  .hero__photo .hero__chips {
    width: auto; flex: 1; min-width: 0; align-items: flex-start; margin-top: 0;
  }
  .hero__photo .hero__chips .chip { justify-content: flex-start; }
  .hero__photo-frame::after { inset: 8px -8px -8px 8px; }
  .hero__badge {
    position: static; margin: 8px 0 0; left: auto; bottom: auto;
    width: 100%; max-width: var(--photo-size); box-sizing: border-box;
    white-space: normal; text-align: center; justify-content: center;
    font-size: .62rem; padding: 5px 8px; gap: 5px;
  }
  .pillars { grid-template-columns: 1fr; }

  /* ---- Nav en móvil (portado del CV) ---- */
  .nav__links { display: none; }
  .nav__inner .btn { display: none; }   /* el CTA vive en el panel desplegable, no en la barra */
  .nav__inner { gap: 10px; flex-wrap: wrap; row-gap: 6px; }  /* wrap = red de seguridad: en pantallas muy estrechas la barra pasa a 2 líneas en vez de recortarse */
  .nav__menu-btn { display: inline-flex; }

  .nav__mobile-panel {
    position: absolute; top: 100%; left: 0; right: 0; z-index: 49;
    flex-direction: column; gap: 2px;
    background: var(--surface); border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow);
    padding: 6px var(--gutter) calc(var(--gutter) * .7);
  }
  .nav__mobile-panel.is-open { display: flex; }
  .nav__mobile-links { display: flex; flex-direction: column; }
  .nav__mobile-links a {
    padding: 13px 2px; border-bottom: 1px solid var(--line-soft);
    font-weight: 600; font-size: .98rem; color: var(--ink);
  }
  .nav__mobile-links a:last-child { border-bottom: 0; }
  .nav__mobile-links a.is-active { color: var(--accent); }
  .nav__mobile-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
  .nav__mobile-actions .btn { display: inline-flex; flex: 1 1 160px; justify-content: center; height: 44px; }
}

@media (max-width: 480px) {
  /* Para que la barra (marca + ES/EN + tema + menú) quepa en una línea en
     móviles pequeños (~360px). El wrap de arriba ya evita el recorte. */
  .nav .container { padding-inline: 16px; }
  .nav__inner { gap: 6px; }
  .nav__tools { gap: 6px; }
  .brand { font-size: .88rem; gap: 5px; }
}

/* ============================================================================
   Perfil
   ========================================================================== */

@media (min-width: 900px) {  }

/* Tarjetas de competencias de la sección Perfil. Clase propia (no .pillar):
   .pillar es el bloque portado del hero del CV y tiene otras proporciones. */

/* ============================================================================
   Servicios
   ========================================================================== */
/* Selector de 3 pestañas + panel siempre abierto. Sustituye al acordeón de
   tarjetas anchas: nada de lo que se vende queda escondido tras un clic y los
   tres servicios se comparan de un vistazo desde la fila de pestañas.
   El color lo pone --v (data-v en la pestaña y en el panel). */
/* El hueco sobre "— SERVICIOS" era el doble de lo necesario: se sumaban el
   padding inferior de #perfil y el superior de esta sección (hasta 116px cada
   uno). Se recorta solo el de arriba, para no juntar Servicios con Cómo
   trabajo. */
#servicios { padding-top: clamp(24px, 3.4vw, 48px); }

.svc { display: grid; gap: clamp(18px, 2.6vw, 26px); }

.svc__tabs { display: grid; gap: 10px; grid-template-columns: 1fr; }
@media (min-width: 820px) { .svc__tabs { grid-template-columns: repeat(3, 1fr); gap: 14px; } }

.svc__tab {
  display: flex; align-items: center; gap: 14px; text-align: left;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: clamp(14px, 1.8vw, 18px); position: relative; overflow: hidden;
  transition: border-color .22s ease, box-shadow .22s ease, transform .22s ease, background .22s ease;
}
/* Franja superior de color: apagada en reposo, a todo color en la activa. */
.svc__tab::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: var(--v, var(--accent)); opacity: .22; transition: opacity .22s ease;
}
.svc__tab:hover { border-color: color-mix(in srgb, var(--v, var(--accent)) 35%, var(--line)); transform: translateY(-2px); }
.svc__tab[aria-selected="true"] {
  border-color: color-mix(in srgb, var(--v, var(--accent)) 55%, var(--line));
  box-shadow: var(--shadow); transform: none;
}
.svc__tab[aria-selected="true"]::before { opacity: 1; }

.svc__tab-icon {
  width: 44px; height: 44px; flex: none; border-radius: 13px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--v-soft, var(--accent-soft)); color: var(--v, var(--accent));
  transition: background .22s ease, color .22s ease;
}
.svc__tab-icon svg { width: 21px; height: 21px; }
.svc__tab[aria-selected="true"] .svc__tab-icon { background: var(--v, var(--accent)); color: #fff; }
.svc__tab-text { display: grid; gap: 3px; min-width: 0; }
.svc__tab-name { font-family: var(--font-display); font-weight: 700; font-size: 1.02rem; line-height: 1.25; }
.svc__tab-tagline { font-size: .84rem; color: var(--muted); line-height: 1.35; }
.svc__tab[aria-selected="true"] .svc__tab-tagline { color: var(--v, var(--accent)); font-weight: 600; }

/* Panel del servicio activo. El resto van con [hidden]. */
.svc__panels { position: relative; }
.svc__col { min-width: 0; }
.svc__panel {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg);
  border-top: 3px solid var(--v, var(--accent));
  padding: clamp(22px, 3.2vw, 36px);
  animation: svcIn .32s ease both;
}
.svc__panel[hidden] { display: none; }
@keyframes svcIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.svc__desc { color: var(--ink-soft); font-size: 1.02rem; max-width: 820px; }
.svc__intro .chips { margin-top: 16px; }

.svc__cols {
  display: grid; gap: 26px; grid-template-columns: 1fr;
  margin-top: clamp(22px, 3vw, 30px); padding-top: clamp(22px, 3vw, 28px);
  border-top: 1px solid var(--line);
}
@media (min-width: 820px) { .svc__cols { grid-template-columns: 1.05fr .95fr; gap: 40px; } }

.svc__col-title {
  display: inline-flex; align-items: center; gap: 8px; margin-bottom: 14px;
  font-family: var(--font-display); font-size: .78rem; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase; color: var(--muted);
}
.svc__col-title svg { width: 15px; height: 15px; color: var(--v, var(--accent)); }

/* "Qué recibes" se pinta sobre fondo tintado: es el bloque que más mira quien
   está decidiendo si contratar, y así se separa de la lista de "qué incluye". */
.svc__col--deliverables {
  background: var(--v-soft, var(--accent-soft)); border-radius: var(--radius);
  padding: clamp(18px, 2.2vw, 24px); align-self: start;
}
.deliverables { display: grid; gap: 11px; }
.deliverables li { display: flex; gap: 10px; align-items: flex-start; font-size: .94rem; line-height: 1.5; }
.deliverables li svg { width: 14px; height: 14px; flex: none; margin-top: .35em; color: var(--v, var(--accent)); }

.svc__foot {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 22px;
  margin-top: clamp(22px, 3vw, 30px); padding-top: clamp(20px, 2.6vw, 26px);
  border-top: 1px solid var(--line);
}
.svc__forwho { flex: 1 1 460px; }
.svc__forwho p { color: var(--ink-soft); font-size: .95rem; max-width: 720px; }

/* ---- Cuarta pestaña: Product Management, en formato barra ----
   Tercera iteración del bloque de PM (2026-07-30). Antes fue rejilla de 6
   tarjetas (`.extra`, ocupaba más que los 3 pilares) y luego tira de chips
   (`.cont`, encaje visual rechazado). Ahora es una pestaña MÁS del mismo
   componente: misma mecánica, mismo panel, pero con forma de barra a todo el
   ancho en lugar de tarjeta. En reposo cuesta ~46px; al activarla recibe el
   mismo espacio que un servicio. El acento es el gris neutro de data-v="pm", que
   es lo que la mantiene por debajo de los tres pilares en la jerarquía. */
.svc__tab--slim {
  grid-column: 1 / -1;              /* ocupa la fila entera bajo las 3 tarjetas */
  flex-direction: row; align-items: center; gap: 12px;
  padding: 11px 16px; text-align: left;
}
.svc__tab--slim .svc__tab-icon { width: 30px; height: 30px; border-radius: 9px; flex: none; }
.svc__tab--slim .svc__tab-icon svg { width: 16px; height: 16px; }
.svc__slim-name { font-family: var(--font-display); font-weight: 700; font-size: .94rem; }
.svc__slim-tagline {
  font-size: .84rem; color: var(--muted);
  /* La barra nunca debe partir en dos líneas: si no cabe, cae el tagline. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
.svc__slim-tagline::before { content: "· "; opacity: .5; }
.svc__slim-more {
  margin-left: auto; flex: none;
  display: inline-flex; align-items: center; gap: .3em;
  font-size: .78rem; font-weight: 600; color: var(--muted);
}
.svc__slim-more svg { width: 13px; height: 13px; transition: transform .18s ease; }
.svc__tab--slim:hover .svc__slim-more { color: var(--v); }
.svc__tab--slim:hover .svc__slim-more svg { transform: translateX(2px); }
.svc__tab--slim[aria-selected="true"] .svc__slim-tagline,
.svc__tab--slim[aria-selected="true"] .svc__slim-more { color: var(--v); }
.svc__tab--slim[aria-selected="true"] .svc__slim-more svg { transform: rotate(90deg); }
@media (max-width: 560px) {
  .svc__slim-tagline { display: none; }
}

/* Panel del PM. Sin las dos columnas de "qué incluye / qué recibes": son
   capacidades sueltas que se contratan a la carta, no un proyecto con
   entregables, así que van en rejilla de nombre + una línea. */
.pm-grid { display: grid; gap: 0 32px; grid-template-columns: 1fr; margin-top: 20px; }
@media (min-width: 700px)  { .pm-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1020px) { .pm-grid { grid-template-columns: repeat(3, 1fr); } }
.pm-grid__item {
  display: grid; gap: 3px; padding: 14px 0; border-top: 1px solid var(--line-soft);
}
.pm-grid__item strong { font-family: var(--font-display); font-size: .96rem; }
.pm-grid__item span { color: var(--ink-soft); font-size: .88rem; line-height: 1.5; }

/* Puente desde el panel de Discovery a la pestaña de PM. Enlace de texto, no
   botón: el CTA del panel ya es el botón oscuro y no debe tener competencia. */
.svc__next {
  display: inline-flex; align-items: center; gap: .4em; margin-top: 4px;
  font: inherit; font-size: .86rem; font-weight: 600; color: var(--muted);
  background: none; border: 0; padding: 0; cursor: pointer;
  transition: color .18s ease;
}
.svc__next:hover { color: var(--v, var(--accent)); }
.svc__next svg { width: 14px; height: 14px; }

/* ---- Tarjeta de tarifas, a la derecha de la cabecera de Servicios ----
   Sustituye (2026-07-30) a la banda `.rates-band` que cerraba la sección. El
   precio es la primera pregunta del visitante y el preciario no es público, así
   que este botón es el embudo real de la web: no puede estar al final. Va en el
   hueco que dejaba el titular, sin empujar nada hacia abajo. Fondo tintado y
   candado para que se lea como "material privado que te envío", no como un
   cuarto servicio ni como los CTA de "Preguntar por este servicio".
   Contenido reducido al mínimo (2026-07-30, "es muy grande"): etiqueta, botón
   y nota. Nada de párrafo explicativo — el candado ya dice que es privado. */
.rates-card {
  flex: 0 1 320px; align-self: start;
  background: linear-gradient(140deg, var(--accent-soft), color-mix(in srgb, var(--accent-2-soft) 55%, var(--accent-soft)));
  border: 1px solid color-mix(in srgb, var(--accent) 14%, transparent);
  border-radius: var(--radius-lg);
  padding: 14px clamp(14px, 1.8vw, 18px) 12px;
}
/* TRAMPA DE ESPECIFICIDAD, ya pisada: la tarjeta vive DENTRO de .section-head,
   y `.section-head p` (0,1,1 → font-size 1.05rem, margin-top .9rem) le gana a
   una clase suelta como `.rates-card__note` (0,1,0). Los tamaños de esta tarjeta
   SOLO funcionan con doble clase (`.rates-card .rates-card__x`, 0,2,0). Si se
   toca algo de aquí, no quitar el `.rates-card ` de delante. */
.rates-card p { margin-top: 0; }
.rates-card .rates-card__eyebrow {
  display: flex; align-items: center; gap: .45em;
  font-size: .7rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent);
}
.rates-card__eyebrow svg { width: 12px; height: 12px; }
.rates-card .btn { margin-top: 11px; width: 100%; justify-content: center; }
.rates-card .btn svg:first-child { margin-right: .1em; }
/* Nota al pie: letra pequeña deliberada. Es una tranquilidad para quien duda
   antes de pulsar, no información que haya que leer. */
.rates-card .rates-card__note {
  font-size: .62rem; line-height: 1.35; letter-spacing: .01em; color: var(--muted);
  margin-top: 6px; text-align: center;
}

/* ============================================================================
   Cómo trabajo
   ========================================================================== */
/* Timeline horizontal. Cada paso es una columna sin tarjeta: el nodo numerado
   se apoya sobre un raíl continuo que dibuja el ::before de cada paso y que el
   CSS recorta a media columna en el primero y el último de cada fila (de ahí
   los :nth-child por número de columnas en cada breakpoint). En móvil el mismo
   raíl gira a vertical y el layout pasa a lista.
   --flow-node: alto del nodo; el raíl se alinea a su centro. */
/* ---- Variante compacta de la sección (ver renderProcess) ----
   Objetivo: que Cómo trabajo entre en una pantalla, como la Trayectoria
   contraída. Se recorta por tres sitios a la vez —padding de sección,
   cabecera en dos columnas y cuerpo de texto algo menor— en vez de sacrificar
   contenido. */
.section--flow { padding-block: clamp(38px, 4.5vw, 60px); }
/* NO ensanchar el contenedor aquí. Se probó (max-width 1320px) para que las
   seis columnas respirasen y Alex lo detectó al instante: la sección se salía
   del ancho del resto de la web. Todas las secciones comparten --container. */
.section-head--flow {
  max-width: none; margin-bottom: clamp(22px, 3vw, 34px);
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: 14px 40px;
}
.section-head--flow h2 {
  /* El titular está escrito para caber en una línea; se fuerza para que no
     parta en dos y coma alto. En móvil se deja partir, ahí no cabe. */
  white-space: nowrap; font-size: clamp(1.65rem, 3.4vw, 2.45rem);
}
.section-head__lead { color: var(--ink-soft); font-size: .95rem; max-width: 520px; flex: 1 1 380px; }
@media (max-width: 560px) {
  .section-head--flow h2 { white-space: normal; }
  .section-head__lead { flex-basis: 100%; }
}

/* ============================================================================
   Cómo trabajo — stepper
   ----------------------------------------------------------------------------
   Dos piezas: un raíl de 6 nodos (navegación) y un escenario con el detalle de
   la fase activa. El estado vive en data-active del contenedor y el progreso
   del raíl en la variable --flow-p (0 → 1), que pone el JS.
   ========================================================================== */
.flow { --flow-node: 52px; display: grid; gap: clamp(20px, 2.6vw, 28px); }

/* ---- Raíl ---- */
.flow__rail {
  position: relative; display: grid; grid-auto-flow: column;
  grid-auto-columns: 1fr; align-items: start;
}
/* Línea base: va del centro del primer nodo al del último, de ahí los 1/12. */
/* z-index 0 en las líneas + z-index 1 en los nodos: sin esto, los pseudo
   posicionados del raíl se pintan POR ENCIMA de los nodos (que son estáticos)
   y la línea de progreso cruza por delante de los iconos. */
.flow__rail::before,
.flow__rail::after {
  content: ""; position: absolute; height: 3px; border-radius: 3px;
  top: calc(var(--flow-node) / 2 - 1.5px); left: calc(100% / 12);
  pointer-events: none; z-index: 0;
}
.flow__rail-item { position: relative; z-index: 1; }
.flow__rail::before { right: calc(100% / 12); background: var(--line); }
/* Tramo recorrido: se estira hasta el nodo activo. La transición es lo que da
   la sensación de "avanzar" al cambiar de paso. */
.flow__rail::after {
  width: calc((100% - 100% / 6) * var(--flow-p, 0));
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: width .55s cubic-bezier(.4, 0, .2, 1);
}

/* Sin gap: los dos huecos se reparten a mano (12px bajo el nodo, 2px bajo el
   número) en vez de 7+7. El número queda pegado a su etiqueta y deja aire
   suficiente para que el nodo activo, que crece un 14%, no lo tape — y la
   etiqueta se queda exactamente donde estaba (12+2 = 7+7). */
.flow__dot {
  display: grid; justify-items: center; gap: 0; width: 100%; padding: 0 4px;
  background: none; border: 0; cursor: pointer; text-align: center;
}
.flow__dot .flow__node { margin-bottom: 12px; }
.flow__node {
  width: var(--flow-node); height: var(--flow-node); border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface); color: var(--muted);
  border: 2px solid var(--line);
  box-shadow: 0 0 0 5px var(--surface-2);   /* recorta el raíl alrededor del nodo */
  transition: transform .3s cubic-bezier(.34, 1.4, .5, 1), background .3s ease,
              border-color .3s ease, color .3s ease, box-shadow .3s ease;
}
.flow__node svg { width: 21px; height: 21px; }

/* Pasos ya recorridos: rellenos en versión suave. */
.flow__dot.is-done .flow__node {
  background: var(--accent-soft); border-color: transparent; color: var(--accent);
}
/* Paso activo: relleno macizo, más grande y con halo. */
.flow__dot[aria-selected="true"] .flow__node {
  background: var(--accent); border-color: var(--accent); color: #fff;
  transform: scale(1.14);
  box-shadow: 0 0 0 5px var(--surface-2), 0 0 0 8px color-mix(in srgb, var(--accent) 22%, transparent),
              0 8px 20px color-mix(in srgb, var(--accent) 35%, transparent);
}
.flow__dot:hover .flow__node { transform: scale(1.08); }
.flow__dot[aria-selected="true"]:hover .flow__node { transform: scale(1.14); }

.flow__dot-n {
  font-family: var(--font-display); font-size: .68rem; font-weight: 700;
  letter-spacing: .1em; color: var(--muted); transition: color .3s ease;
  margin-bottom: 2px;
}
.flow__dot-label {
  font-size: .8rem; font-weight: 600; color: var(--ink-soft); line-height: 1.25;
  transition: color .3s ease;
}
.flow__dot[aria-selected="true"] .flow__dot-n,
.flow__dot[aria-selected="true"] .flow__dot-label { color: var(--accent-deep); }
[data-theme="dark"] .flow__dot[aria-selected="true"] .flow__dot-n,
[data-theme="dark"] .flow__dot[aria-selected="true"] .flow__dot-label { color: var(--accent); }

/* ---- Escenario: detalle de la fase activa ----
   min-height fija la altura al paso más largo para que el bloque no dé saltos
   al cambiar de fase (y para que la sección no se mueva bajo el cursor). */
.flow__stage {
  position: relative; min-height: 150px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: clamp(20px, 2.6vw, 28px);
  overflow: hidden;
}
/* Halo de color detrás del icono, para que el panel no sea una caja blanca. */
.flow__stage::before {
  content: ""; position: absolute; left: -60px; top: -70px; width: 260px; height: 260px;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 16%, transparent), transparent 68%);
  pointer-events: none;
}

.flow__panel { display: grid; grid-template-columns: auto 1fr; gap: 14px 18px; align-items: start; }
.flow__panel[hidden] { display: none; }
.flow__panel { animation: flowIn .42s cubic-bezier(.2, .7, .3, 1) both; }
@keyframes flowIn {
  from { opacity: 0; transform: translateX(14px); }
  to   { opacity: 1; transform: none; }
}

.flow__panel-body { min-width: 0; }
.flow__panel-icon {
  width: 46px; height: 46px; border-radius: 14px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent);
}
.flow__panel-icon svg { width: 22px; height: 22px; }
.flow__panel-step {
  font-family: var(--font-display); font-size: .7rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; color: var(--accent);
  margin-bottom: 4px;
}
.flow__panel h3 { font-size: clamp(1.1rem, 2.2vw, 1.4rem); }
.flow__panel-desc { color: var(--ink-soft); font-size: .97rem; margin-top: 8px; max-width: 70ch; }

/* El entregable de la fase: ocupa las dos columnas, bajo el texto. */
.flow__out {
  grid-column: 1 / -1;
  display: flex; gap: 9px; align-items: flex-start; margin-top: 4px;
  background: var(--accent-soft); border-radius: 12px; padding: 11px 14px;
  font-size: .88rem; line-height: 1.45; color: var(--ink-soft);
}
.flow__out svg { width: 14px; height: 14px; flex: none; margin-top: .3em; color: var(--accent); }
.flow__out em {
  display: block; font-style: normal; font-size: .68rem; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; color: var(--accent-deep); margin-bottom: 2px;
}
[data-theme="dark"] .flow__out em { color: var(--accent); }

/* ---- Móvil: el raíl pasa a tira deslizable ----
   Seis nodos no caben en 360px; en vez de apilarlos (que rompería la lectura
   de recorrido) la fila se desliza en horizontal con snap. */
@media (max-width: 700px) {
  .flow { --flow-node: 46px; }
  .flow__rail {
    grid-auto-columns: 104px; overflow-x: auto; scroll-snap-type: x proximity;
    scrollbar-width: none; padding-bottom: 4px;
    margin-inline: calc(var(--gutter) * -1); padding-inline: var(--gutter);
  }
  .flow__rail::-webkit-scrollbar { display: none; }
  /* Con scroll horizontal los porcentajes del raíl dejan de cuadrar: se
     simplifica a una línea continua bajo toda la tira. */
  .flow__rail::before { left: var(--gutter); right: var(--gutter); }
  .flow__rail::after { display: none; }
  .flow__rail-item { scroll-snap-align: center; }
  .flow__panel { grid-template-columns: 1fr; }
  .flow__stage { min-height: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .flow__panel { animation: none; }
  .flow__node, .flow__rail::after { transition: none; }
}

/* ============================================================================
   Tarjeta de acceso al modal de IA (2026-07-31, cuarta versión de esa sección)
   ----------------------------------------------------------------------------
   `.proceso-grid` pone el stepper (`.flow`) y la tarjeta lado a lado desde
   900px; por debajo, la tarjeta cae debajo a todo ancho. `align-items: stretch`
   (por defecto en grid) es lo que hace que la tarjeta iguale el alto combinado
   del raíl + el panel de detalle sin fijar un alto a mano — si el contenido
   del raíl o del panel crece, la tarjeta crece con ellos.
   ========================================================================== */
.proceso-grid { display: grid; grid-template-columns: 1fr; gap: clamp(16px, 2.2vw, 24px); }
@media (min-width: 900px) { .proceso-grid { grid-template-columns: minmax(0, 1fr) 240px; } }

/* Es un <button>, no un <div>, así que se resetean los estilos por defecto.
   Fondo degradado sólido (no plano) a propósito: es la única tarjeta de la
   sección con color de fondo en vez de blanco — tiene que leerse como "esto
   abre algo", no como una tarjeta más de contenido. */
.proceso-ai-card {
  display: flex; flex-direction: column; justify-content: space-between;
  width: 100%; font: inherit; text-align: left; color: #fff;
  border: 0; border-radius: var(--radius-lg); cursor: pointer;
  padding: clamp(18px, 2.2vw, 22px);
  background: linear-gradient(155deg, var(--accent-3), color-mix(in srgb, var(--accent-3) 62%, black));
  transition: transform .25s, box-shadow .25s;
}
.proceso-ai-card:hover, .proceso-ai-card:focus-visible {
  transform: translateY(-4px); box-shadow: var(--shadow); outline: none;
}
.proceso-ai-card__top { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.proceso-ai-card__icon {
  width: 34px; height: 34px; border-radius: 10px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, .18);
}
.proceso-ai-card__icon svg { width: 17px; height: 17px; }
.proceso-ai-card__title { font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; }
.proceso-ai-card__tagline { font-size: .85rem; line-height: 1.45; opacity: .92; }
.proceso-ai-card__cta {
  display: flex; align-items: center; gap: .4em; margin-top: 18px;
  font-size: .85rem; font-weight: 600;
}
.proceso-ai-card__cta svg { width: 14px; height: 14px; }

/* ============================================================================
   Modal de IA — mismo patrón técnico que case-modal/evidence-modal
   ----------------------------------------------------------------------------
   No se inventa un cuarto sistema de modal: overlay + diálogo + botón de
   cerrar circular arriba a la derecha, cierre con Esc o clic fuera, scroll de
   fondo bloqueado con la misma clase `html.evidence-modal-open` que ya usan
   los otros dos modales del sitio.
   `container-type: inline-size` en el diálogo es lo que permite que `.ai-grid`
   y `.ai-gains__list` (definidos más arriba) decidan sus columnas por el
   ancho del propio diálogo (`@container`) y no por el de la ventana
   (`@media`) — con la ventana grande pero el diálogo limitado a 820px, un
   `@media` habría disparado 3 columnas aunque no cupieran. */
.ai-modal { position: fixed; inset: 0; z-index: 200; display: none; align-items: center; justify-content: center; padding: clamp(12px, 3vw, 40px); }
.ai-modal.is-open { display: flex; }
.ai-modal__backdrop { position: absolute; inset: 0; background: rgba(10, 10, 14, .76); backdrop-filter: blur(3px); animation: evidenceFadeIn .18s ease; }
.ai-modal__dialog {
  /* Ensanchado (2026-07-31): con 820px, columnas de 3 —y luego de 2, tras
     quitar "Vuestros datos"— seguían envolviendo frases a dos líneas y el
     modal necesitaba scroll. A 960px las columnas tienen sitio de sobra para
     una sola línea por ítem. */
  position: relative; z-index: 1; width: min(960px, 100%);
  container-type: inline-size;
  max-height: min(88vh, 760px);
  /* dvh: ver comentario de .portfolio-accordion (evita el salto en iOS). */
  max-height: min(88dvh, 760px);
  overflow-y: auto;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg);
  box-shadow: var(--shadow); animation: evidenceZoomIn .2s ease;
  /* Recortado (2026-07-31, junto con la síntesis del contenido): con textos
     de una línea por ítem, el objetivo es que quepa entero sin que
     overflow-y llegue a activarse en una ventana normal. */
  padding: clamp(22px, 3vw, 32px);
}
.ai-modal__close {
  position: absolute; top: 16px; right: 16px; z-index: 3; width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center; background: var(--surface); border: 1px solid var(--line);
  color: var(--ink-soft); box-shadow: var(--shadow-sm); transition: background .2s, color .2s, transform .2s;
}
.ai-modal__close:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); transform: scale(1.08); }
.ai-modal__close svg { width: 15px; height: 15px; }
.ai-modal__head { max-width: 640px; margin-bottom: clamp(18px, 2.4vw, 26px); padding-right: 36px; }
.ai-modal__head h2 { font-size: clamp(1.3rem, 2.6vw, 1.7rem); margin: 8px 0 10px; }
.ai-modal__head p:last-child { color: var(--ink-soft); font-size: .95rem; }

/* ============================================================================
   Rejilla de flexibilidad, pie de "Cómo trabajo" (2026-07-31, segunda versión)
   ----------------------------------------------------------------------------
   Reemplaza dos intentos anteriores: una tira de "Cómo no trabajo" y, después,
   una banda de dos columnas con "lo que no negocio" al lado. Ninguna convenció
   a Alex — ni el copy de las cabeceras ni el tratamiento silencioso heredado
   de las negaciones (tintado, sin halo, pensado para material de apoyo, no
   para lo que aquí es el mensaje principal). Ahora es una rejilla de tarjetas
   con icono, mismo lenguaje visual que `.pillar` del hero: halo al hover y
   borde que se tiñe con el acento de la tarjeta. El color rota entre los tres
   acentos de marca vía `--card-c` (puesto inline por tarjeta en app.js) para
   que seis tarjetas seguidas no se lean monocromas.
   ========================================================================== */
.flex-block { margin-top: clamp(28px, 3.6vw, 40px); }
.flex-block__title { font-size: clamp(1.3rem, 2.4vw, 1.7rem); margin: 10px 0 0; }
.flex-block__lead { color: var(--ink-soft); font-size: .95rem; margin-top: 8px; max-width: 62ch; }

.flex-grid {
  display: grid; grid-template-columns: 1fr; gap: 14px;
  margin-top: clamp(18px, 2.4vw, 24px);
}
/* Ahora son solo 4 tarjetas (2026-07-31): a partir de 900px caben en una sola
   fila sin que queden estrechas, así que se salta el estado de 3 columnas que
   tenía sentido con 6. */
@media (min-width: 640px) { .flex-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px) { .flex-grid { grid-template-columns: repeat(4, 1fr); } }

.flex-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 20px 20px 22px;
  transition: transform .25s, box-shadow .25s, border-color .25s;
}
.flex-card:hover {
  transform: translateY(-4px); box-shadow: var(--shadow);
  border-color: color-mix(in srgb, var(--card-c, var(--accent)) 40%, var(--line));
}
.flex-card__icon {
  width: 32px; height: 32px; border-radius: 9px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--card-c, var(--accent)) 14%, transparent);
  color: var(--card-c, var(--accent));
  margin-bottom: 12px;
}
[data-theme="dark"] .flex-card__icon { background: color-mix(in srgb, var(--card-c, var(--accent)) 24%, transparent); }
.flex-card__icon svg { width: 16px; height: 16px; }
.flex-card__title { font-size: 1rem; margin: 0 0 6px; }
.flex-card__desc { color: var(--ink-soft); font-size: .87rem; line-height: 1.5; margin: 0; }

/* ============================================================================
   IA EN EL PROCESO (cuarta versión — modal, no sección, 2026-07-31)
   ----------------------------------------------------------------------------
   Ya no es una sección (`#ia` no existe): el contenido se abre en modal desde
   `.proceso-ai-card`, a la derecha del stepper de Cómo trabajo. `.ai-grid`,
   `.ai-col*`, `.ai-gains*` y `.ai-gain*` de aquí en adelante son el CUERPO DEL
   MODAL — mismo texto íntegro de la versión anterior (columnas con frases
   completas, compromisos con su k/v), NO recortar sin que Alex lo pida.
   El modal es más estrecho que una sección a todo ancho, así que sus rejillas
   de 3 columnas ya no pueden depender del ancho de VIEWPORT (`@media`): con
   la ventana grande pero el diálogo limitado a 820px, un `@media` dispararía
   3 columnas aunque no quepan. Se usan `@container` en su lugar, anclados al
   `container-type: inline-size` de `.ai-modal__dialog` más abajo.
   ========================================================================== */
.ai-grid { display: grid; gap: clamp(18px, 2.4vw, 26px); }
/* Solo 2 columnas ahora ("Vuestros datos" se eliminó, 2026-07-31): el umbral
   baja de 620 a 480px porque dos columnas necesitan menos ancho que tres para
   verse bien. */
@container (min-width: 480px) { .ai-grid { grid-template-columns: repeat(2, 1fr); } }

.ai-col {
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg);
  padding: clamp(16px, 2vw, 20px);
  /* El filo de color es lo único que distingue las tres columnas. Con
     border-top y no con un pseudo, para no pelear con el border-radius. */
  border-top: 3px solid var(--ai-c, var(--line));
  transition: transform .25s, box-shadow .25s, border-color .25s;
}
.ai-col:hover {
  transform: translateY(-4px); box-shadow: var(--shadow);
  border-color: color-mix(in srgb, var(--ai-c) 40%, var(--line));
}
.ai-col--does  { --ai-c: var(--accent-3); }
.ai-col--never { --ai-c: var(--muted); }

.ai-col__title {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-display); font-size: 1.02rem; font-weight: 700;
  margin-bottom: 14px;
}
.ai-col__icon {
  width: 28px; height: 28px; flex: none; border-radius: 9px;
  display: inline-flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--ai-c) 13%, transparent);
  color: var(--ai-c);
}
.ai-col__icon svg { width: 15px; height: 15px; }

/* Cada línea lleva ahora un icono real delante (antes: un punto gris vía
   ::before). Mismo tratamiento que `.ticks` en Servicios. */
.ai-col__list { display: grid; gap: 10px; }
.ai-col__list li {
  display: flex; align-items: flex-start; gap: .6em;
  font-size: .87rem; line-height: 1.5; color: var(--ink-soft);
}
.ai-col__list li svg { width: 14px; height: 14px; flex: none; margin-top: .3em; color: var(--ai-c); }

/* ---- Compromisos como tarjetas con icono (antes: lista plana de k/v) ----
   Mismo lenguaje visual que `.pillar` del hero y `.flex-card` de Cómo
   trabajo: halo al hover, borde que se tiñe, color rotando entre los tres
   acentos de marca. Es la parte que a Alex le pareció "horrible" en prosa
   plana; aquí tiene el mismo peso visual que el resto del sitio. */
.ai-gains { margin-top: clamp(20px, 2.6vw, 28px); }
.ai-gains__title { margin-bottom: 16px; }

.ai-gains__list { display: grid; gap: 14px; }
@container (min-width: 620px) { .ai-gains__list { grid-template-columns: repeat(3, 1fr); } }

.ai-gain {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 20px 20px 22px;
  transition: transform .25s, box-shadow .25s, border-color .25s;
}
.ai-gain:hover {
  transform: translateY(-4px); box-shadow: var(--shadow);
  border-color: color-mix(in srgb, var(--gain-c, var(--accent)) 40%, var(--line));
}
.ai-gain__icon {
  width: 32px; height: 32px; border-radius: 9px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--gain-c, var(--accent)) 14%, transparent);
  color: var(--gain-c, var(--accent));
  margin-bottom: 12px;
}
[data-theme="dark"] .ai-gain__icon { background: color-mix(in srgb, var(--gain-c, var(--accent)) 24%, transparent); }
.ai-gain__icon svg { width: 16px; height: 16px; }
.ai-gain__k { font-size: 1.02rem; margin: 0 0 6px; }
.ai-gain__v { color: var(--ink-soft); font-size: .87rem; line-height: 1.5; margin: 0; }

/* ============================================================================
   TRAYECTORIA — PORTADA TAL CUAL DESDE LA WEB DE CV (repo cv-alex-cadenas)
   ----------------------------------------------------------------------------
   Timeline, roles agrupados, roles plegables, puntos de color por vertiente y
   leyenda. Extraído literalmente del stylesheet original.
   ========================================================================== */

/* ============================================================================
   Puntos de color por vertiente (dots) + leyenda
   ========================================================================== */
.v-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; margin-right: 3px; vertical-align: middle; }
.v-dot--pm { background: var(--accent); }
.v-dot--research { background: var(--accent-3); }
.v-dot--transversal { background: var(--accent-2); }
.v-dots { display: inline-flex; align-items: center; margin-right: 8px; flex: none; }
.tag-legend { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-bottom: clamp(24px, 4vw, 40px); }
.tag-legend__item { display: inline-flex; align-items: center; gap: 6px; font-size: .82rem; color: var(--muted); font-weight: 500; }
/* ============================================================================
   Timeline / Trayectoria
   ========================================================================== */
.timeline { position: relative; margin-left: 6px; }
.timeline::before { content: ""; position: absolute; left: 7px; top: 8px; bottom: 8px; width: 2px; background: var(--line); }
.tl-item { position: relative; padding-left: 38px; padding-bottom: 26px; }
.tl-item:last-child { padding-bottom: 0; }
.tl-item::before {
  content: ""; position: absolute; left: 0; top: 6px; width: 16px; height: 16px; border-radius: 50%;
  background: var(--surface); border: 3px solid var(--line);
}
.tl-item.is-current::before { border-color: var(--accent); background: var(--accent); box-shadow: 0 0 0 5px var(--accent-soft); }
.tl-item__top { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px; }
.tl-item__role { font-family: var(--font-display); font-weight: 700; font-size: 1.16rem; }
.tl-item__org { color: var(--accent); font-weight: 600; }
.tl-item__meta { display: flex; flex-wrap: wrap; gap: 6px 14px; color: var(--muted); font-size: .85rem; margin-top: 3px; }
.tl-item__meta .pill { background: var(--surface-2); border-radius: 999px; padding: 2px 10px; }
.tl-item__bullets { margin-top: 12px; display: grid; gap: 8px; }
.tl-item--group .tl-item__role { color: var(--accent); }
.tl-positions { position: relative; margin-top: 16px; padding-left: 20px; display: grid; gap: 22px; }
.tl-pos { position: relative; }
.tl-pos::before {
  content: ""; position: absolute; left: -25px; top: 6px; width: 8px; height: 8px; border-radius: 50%;
  background: var(--surface); border: 2px solid var(--line); z-index: 1;
}
.tl-pos:not(:last-child)::after {
  content: ""; position: absolute; left: -21px; top: 10px; bottom: -32px; width: 2px; background: var(--line);
}
.tl-pos__top { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; }
.tl-pos__role { font-family: var(--font-display); font-weight: 600; font-size: 1rem; }
.tl-pos__date { color: var(--muted); font-size: .8rem; font-family: var(--font-display); }
.tl-pos .tl-item__bullets { margin-top: 8px; }
.tl-item__bullets li { display: flex; align-items: baseline; color: var(--ink-soft); font-size: .95rem; line-height: 1.55; }
/* Contenido de un rol: por defecto se ve el párrafo-resumen y los bullets
   completos quedan ocultos; "ver más" invierte cuál de los dos se muestra. */
.tl-summary { color: var(--ink-soft); font-size: .95rem; line-height: 1.6; margin: 8px 0 0; }
/* Solo se ocultan los bullets que acompañan a un resumen (rol con "ver más").
   Los roles sin resumen (p.ej. Client Executive) no pasan por .tl-summary y
   deben quedar siempre visibles: si el selector fuera .tl-role-content
   .tl-item__bullets, los ocultaría también a ellos sin ningún botón que
   pueda revelarlos de nuevo. */
.tl-summary + .tl-item__bullets { display: none; }
.tl-role-content.is-expanded .tl-item__bullets { display: grid; }
.tl-role-content.is-expanded .tl-summary { display: none; }
.tl-more {
  margin: 4px 0 0; display: inline-flex; align-items: center; gap: 4px;
  font-size: .82rem; font-weight: 600; color: var(--accent); background: none; border: 0; cursor: pointer; padding: 0;
}
.tl-more:hover { text-decoration: underline; }
/* Roles antiguos/menos relevantes: cada uno es su propio .tl-item (con punto
   en la línea temporal) enlazado mediante una pequeña línea a una tarjeta
   enmarcada que contiene el rol, contraído por defecto; clic en la cabecera
   expande/colapsa el panel con los bullets. */
.tl-compact { padding-bottom: 20px; }
.tl-compact::after {
  content: ""; position: absolute; left: 16px; top: 13px; width: 22px; height: 2px; background: var(--line);
}
.tl-compact__card { border: 1px solid var(--line); border-radius: 12px; background: var(--surface-2); padding: 14px 16px; }
.tl-compact__head { cursor: pointer; user-select: none; }
.tl-compact__date { color: var(--muted); font-size: .82rem; font-family: var(--font-display); margin-left: auto; }
.tl-compact__chev { width: 13px; height: 13px; color: var(--muted); flex: none; transition: transform .2s; }
.tl-compact__chev svg { width: 100%; height: 100%; }
.tl-compact.is-open .tl-compact__chev { transform: rotate(90deg); }
.tl-compact__panel { display: none; margin-top: 10px; }
.tl-compact.is-open .tl-compact__panel { display: block; }
.tl-compact .tl-item__bullets { margin-top: 0; }
.tl-item__rec { display: inline-flex; align-items: center; gap: 5px; color: var(--accent); font-weight: 600; }
.tl-item__rec svg { width: 13px; height: 13px; }
.tl-item__rec:hover { text-decoration: underline; }
@media print {
  .tl-item { break-inside: avoid; }
}

/* ============================================================================
   Trayectoria — vista contraída (resumen) y despliegue al timeline completo
   ----------------------------------------------------------------------------
   Esta parte NO viene del CV: allí el timeline se ve entero siempre. Aquí la
   sección arranca en data-expanded="false" mostrando una fila por etapa, y el
   botón despliega el bloque portado. El alto se anima con grid-template-rows
   0fr→1fr (mismo truco que en Servicios) para llegar a alto automático sin
   medir píxeles en JS.
   ========================================================================== */
/* La vista contraída es una lista corta: con el padding estándar de .section
   y el margen normal de .section-head quedaba un bloque casi vacío de aire
   arriba, en medio y abajo. Aquí se recortan los tres. Ojo: solo aplica
   mientras está contraída; al desplegar recupera el respiro normal porque el
   contenido sí lo pide. */
#perfil { padding-block: clamp(34px, 5vw, 56px); }
#perfil .section-head { margin-bottom: clamp(16px, 2.2vw, 24px); }
#perfil[data-expanded="true"] { padding-block: clamp(48px, 8vw, 96px); }
#perfil[data-expanded="true"] .section-head { margin-bottom: clamp(24px, 4vw, 40px); }

.tl-brief-wrap { margin-top: 0; }
.tl-brief { display: grid; gap: 0; }
.tl-brief__item {
  display: grid; gap: 1px 20px; align-items: baseline;
  grid-template-columns: 1fr;
  padding: 11px 0; border-top: 1px solid var(--line);
  position: relative;
}
.tl-brief__item:last-child { border-bottom: 1px solid var(--line); }
@media (min-width: 700px) {
  .tl-brief__item { grid-template-columns: 190px 1fr; padding: 12px 0; }
}
.tl-brief__date {
  font-family: var(--font-display); font-size: .78rem; font-weight: 600;
  letter-spacing: .04em; color: var(--muted); white-space: nowrap;
}
/* Punto de "actualidad" en la etapa en curso, con el mismo verde que el badge
   de disponibilidad del hero (significa lo mismo: sigue activo). */
.tl-brief__item.is-current .tl-brief__date::before {
  content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: #16a34a; margin-right: 7px; vertical-align: middle;
  box-shadow: 0 0 0 3px color-mix(in srgb, #16a34a 20%, transparent);
}
.tl-brief__body { display: grid; gap: 3px; min-width: 0; }
.tl-brief__org { font-family: var(--font-display); font-weight: 700; font-size: 1.02rem; line-height: 1.25; }
.tl-brief__role { color: var(--ink-soft); font-size: .9rem; line-height: 1.45; }
.tl-brief__hint { color: var(--muted); font-size: .86rem; margin-top: 12px; max-width: 60ch; }

.tl-full {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .45s ease, margin-top .45s ease;
  margin-top: 0;
}
#perfil[data-expanded="true"] .tl-full { grid-template-rows: 1fr; margin-top: clamp(28px, 4vw, 40px); }
.tl-full__inner { overflow: hidden; min-height: 0; }
/* El resumen desaparece al desplegar: las dos vistas dicen lo mismo y verlas a
   la vez duplica la lista de empresas. */
#perfil[data-expanded="true"] .tl-brief-wrap { display: none; }

.tl-toggle {
  display: inline-flex; align-items: center; gap: .55em;
  margin-top: 16px;
  padding: 11px 20px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface);
  font-family: var(--font-display); font-weight: 600; font-size: .9rem; color: var(--ink);
  transition: border-color .2s, color .2s, transform .2s;
}
.tl-toggle:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-1px); }
.tl-toggle svg { width: 15px; height: 15px; transition: transform .3s ease; transform: rotate(90deg); }
#perfil[data-expanded="true"] .tl-toggle svg { transform: rotate(-90deg); }

/* ============================================================================
   PORTFOLIO — PORTADO TAL CUAL DESDE LA WEB DE CV (repo cv-alex-cadenas)
   ----------------------------------------------------------------------------
   Bloque extraído literalmente del stylesheet original (reglas, formato y
   comentarios incluidos). Cubre el acordeón de vertientes, el panel de
   Research con sus cintas de cifras, el mosaico de propuestas, el modal de
   caso y el visor del deck. NO reescribir a ojo: comparar siempre con el
   original antes de tocar nada aquí.
   ========================================================================== */

/* ============================================================================
   Portfolio — acordeón de vertientes (Product / Research / Transversal)
   Cada tarjeta tiene 3 estados (data-state):
   - idle:      por defecto, antes de clicar nada. Las 3 tarjetas ocupan el
                mismo ancho y alto que tendrá el acordeón una vez expandido,
                mostrando título + resumen de lo que hay dentro.
   - collapsed: otra tarjeta está activa → franja fina, texto rotado 90º.
   - active:    esta tarjeta está expandida → panel completo con scroll
                interno y un botón para volver al estado idle.
   La altura del acordeón es siempre la misma (no crece al expandir), para
   que las 3 tarjetas por defecto ya ocupen el espacio final.
   ========================================================================== */
.section--portfolio { padding-block: clamp(28px, 4vw, 44px) clamp(24px, 4vw, 40px); }
.section--portfolio .section-head--portfolio { margin-bottom: clamp(20px, 3vw, 28px); max-width: none; }
.portfolio-accordion {
  display: flex; gap: 14px; align-items: stretch;
  height: clamp(460px, 58vh, 620px);
  /* dvh sobre vh: en Safari de iOS, vh se calcula sobre el viewport con la
     barra de direcciones visible, así que el acordeón "saltaba" de tamaño al
     hacer scroll y ocultarse la barra. dvh sigue el viewport real en cada
     momento. Declaración duplicada a propósito: los navegadores que no
     entienden dvh descartan la línea y se quedan con la de vh de arriba. */
  height: clamp(460px, 58dvh, 620px);
}
.portfolio-card {
  position: relative; flex: 1 1 0; min-width: 0; display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface);
  overflow: hidden; cursor: pointer;
  transition: flex-grow .55s cubic-bezier(.2,.7,.2,1), flex-basis .55s cubic-bezier(.2,.7,.2,1),
    border-color .25s, box-shadow .25s, background-color .35s ease;
}
.portfolio-card:hover { border-color: color-mix(in srgb, var(--pf-accent, var(--accent)) 35%, var(--line)); }
.portfolio-card[data-state="collapsed"] { flex: 0 0 56px; }
/* El estado "active" NO redefine flex: se queda en el flex:1 1 0 base (igual
   que "idle"). Es justo esto lo que permite que la transición se vea — al
   activar una tarjeta, las OTRAS dos pasan a flex:0 0 76px y la activa toma
   automáticamente todo el espacio libre restante. Si aquí pusiéramos
   "flex-basis: auto" la transición no animaría (auto no es interpolable). */
.portfolio-card[data-state="active"] { cursor: default; box-shadow: var(--shadow); background: var(--surface); }
/* Idle: mismo fondo de color que la franja colapsada (--pf-soft); solo al
   expandir (active) el fondo vuelve a blanco/superficie. */
.portfolio-card[data-state="idle"] { background: var(--pf-soft); }
.portfolio-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.portfolio-card--pm { --pf-accent: var(--accent); --pf-soft: var(--accent-soft); }
.portfolio-card--research { --pf-accent: var(--accent-3); --pf-soft: var(--accent-3-soft); }
.portfolio-card--transversal { --pf-accent: var(--accent-2); --pf-soft: var(--accent-2-soft); }
.portfolio-card--research .step__n { background: var(--accent-3); }
.portfolio-card--research .card__icon { background: var(--accent-3-soft); color: var(--accent-3); }
.portfolio-card--transversal .card__icon { background: var(--accent-2-soft); color: var(--accent-2); }
/* Los 3 bloques internos están siempre en el DOM; solo se muestra el que
   corresponde al estado de la tarjeta (idle / collapsed / active). */
.portfolio-card__teaser, .portfolio-card__spine, .portfolio-card__panel { display: none; }
/* Estado idle: cabecera + icono + título/resumen + pie de datos.
   El contenido fluye desde arriba y el pie (teaser-meta) es lo único anclado
   abajo con margin-top:auto — así no queda un vacío en mitad de la card. */
.portfolio-card[data-state="idle"] .portfolio-card__teaser {
  display: flex; flex-direction: column; flex: 1; padding: clamp(22px, 2.8vw, 30px);
  position: relative; overflow: hidden;
}
/* Halo decorativo: círculo grande del color de la vertiente asomando por la
   esquina superior derecha. Da profundidad al fondo plano sin competir con el
   texto (queda por debajo de todo vía z-index en los hijos). */
.portfolio-card[data-state="idle"] .portfolio-card__teaser::before {
  content: ""; position: absolute; top: -46%; right: -30%;
  width: 88%; aspect-ratio: 1; border-radius: 50%;
  background: var(--pf-accent); opacity: .07; pointer-events: none;
  transition: transform .45s ease, opacity .45s ease;
}
.portfolio-card[data-state="idle"]:hover .portfolio-card__teaser::before { transform: scale(1.12) translate(-4%, 4%); opacity: .1; }
.portfolio-card__teaser > * { position: relative; z-index: 1; }
.portfolio-card__teaser-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.portfolio-card__teaser .portfolio-card__num { background: var(--surface); }
.portfolio-card__teaser-arrow {
  width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center; flex: none;
  background: var(--surface); color: var(--pf-accent); transition: transform .2s, background .2s, color .2s;
}
.portfolio-card__teaser-arrow svg { width: 14px; height: 14px; transform: rotate(-45deg); }
.portfolio-card[data-state="idle"]:hover .portfolio-card__teaser-arrow { background: var(--pf-accent); color: var(--accent-ink); transform: translate(2px,-2px); }
/* Icono sobre disco blanco: le da masa y lo separa del fondo tintado, en vez
   de flotar suelto sobre el color. */
.portfolio-card__teaser-icon {
  margin-top: clamp(20px, 3vw, 30px); align-self: flex-start; line-height: 0;
  width: clamp(60px, 7vw, 74px); aspect-ratio: 1; border-radius: 50%;
  display: grid; place-items: center; color: var(--pf-accent);
  background: var(--surface); box-shadow: var(--shadow-sm);
  transition: transform .3s ease;
}
.portfolio-card[data-state="idle"]:hover .portfolio-card__teaser-icon { transform: translateY(-3px); }
.portfolio-card__teaser-icon svg { width: 46%; height: 46%; }
.portfolio-card__teaser-body { margin-top: clamp(20px, 2.6vw, 28px); }
.portfolio-card__teaser h3 {
  font-size: clamp(1.05rem, 1.7vw, 1.26rem); line-height: 1.25; margin: 0;
  text-wrap: balance;
}
/* Filete corto del color de la vertiente entre título y resumen: separa los
   dos niveles de lectura sin meter una línea a todo el ancho. */
.portfolio-card__teaser h3::after {
  content: ""; display: block; width: 34px; height: 2px; border-radius: 2px;
  background: var(--pf-accent); margin: 12px 0 0; opacity: .55;
}
.portfolio-card__teaser p { color: var(--ink-soft); margin: 12px 0 0; font-size: .875rem; line-height: 1.6; }
/* Pie de datos: cierra la card por abajo y absorbe el espacio sobrante, así
   las 3 quedan alineadas por el pie aunque los resúmenes midan distinto. */
.portfolio-card__teaser-meta {
  list-style: none; margin: auto 0 0; padding: 16px 0 0;
  display: flex; flex-wrap: wrap; gap: 6px 8px;
  border-top: 1px solid color-mix(in srgb, var(--pf-accent) 18%, transparent);
}
.portfolio-card__teaser-meta li {
  font-family: var(--font-display); font-weight: 700; font-size: .68rem;
  letter-spacing: .04em; text-transform: uppercase; color: var(--pf-accent);
  background: var(--surface); padding: 5px 10px; border-radius: 999px;
}
/* Estado collapsed: franja fina, texto rotado */
.portfolio-card[data-state="collapsed"] .portfolio-card__spine {
  display: flex; flex-direction: column; align-items: center; justify-content: space-between;
  flex: 1; padding: 18px 0; background: var(--pf-soft); color: var(--pf-accent);
}
.portfolio-card__spine-text {
  writing-mode: vertical-rl; transform: rotate(180deg); font-family: var(--font-display);
  font-weight: 700; font-size: .84rem; letter-spacing: .01em; white-space: nowrap;
}
.portfolio-card__spine-arrow {
  width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center;
  background: var(--surface); color: var(--pf-accent); transform: rotate(90deg); flex: none;
}
.portfolio-card__spine-arrow svg { width: 11px; height: 11px; }
/* Estado active: panel completo con scroll interno + botón de volver.
   El contenido (panel-inner) entra con un fundido/desplazamiento breve
   ligeramente retrasado (ver setActiveModule en wire()), para que se note
   que la tarjeta se "expande" en vez de aparecer de golpe. */
.portfolio-card[data-state="active"] .portfolio-card__panel { display: flex; flex: 1; min-width: 0; min-height: 0; flex-direction: column; position: relative; }
.portfolio-card__panel-inner {
  flex: 1; min-height: 0; overflow-y: auto; padding: clamp(22px, 3vw, 34px);
  opacity: 0; transform: translateY(10px);
  transition: opacity .4s ease, transform .4s ease;
}
.portfolio-card__panel-inner.is-in { opacity: 1; transform: none; }
.portfolio-card__close {
  position: absolute; top: clamp(14px, 2vw, 20px); right: clamp(14px, 2vw, 20px); z-index: 2;
  width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center;
  background: var(--surface); border: 1px solid var(--line); color: var(--ink-soft);
  box-shadow: var(--shadow-sm); transition: background .2s, color .2s, transform .2s;
}
.portfolio-card__close svg { width: 14px; height: 14px; }
.portfolio-card__close:hover { background: var(--pf-accent); border-color: var(--pf-accent); color: var(--accent-ink); transform: scale(1.06); }
.portfolio-card__head { margin-bottom: clamp(18px, 2.5vw, 26px); max-width: 640px; padding-right: 40px; }
.portfolio-card__num {
  display: inline-block; font-family: var(--font-display); font-weight: 700; font-size: .76rem;
  color: var(--pf-accent); background: var(--pf-soft); padding: 4px 11px; border-radius: 999px;
}
.portfolio-card__head .portfolio-card__num { margin-bottom: 10px; }
.portfolio-card__head .eyebrow, .portfolio-card__head .eyebrow::before { color: var(--pf-accent); }
.portfolio-card__head h3 { font-size: clamp(1.25rem, 2.1vw, 1.6rem); margin-top: 8px; }
.portfolio-card__head p { color: var(--ink-soft); margin: 10px 0 0; font-size: .95rem; }
/* Cabecera sin lead (panel de PM): menos margen inferior, porque lo que viene
   debajo son tarjetas con su propio aire interno. */
.portfolio-card__head--compact { margin-bottom: 0; }
@media (max-width:900px) {
  .portfolio-accordion { flex-direction: column; height: auto; }
  .portfolio-accordion.is-expanded { height: auto; }
  .portfolio-card { flex: 1 1 auto; }
  .portfolio-card[data-state="collapsed"] { flex: 0 0 auto; }
  .portfolio-card[data-state="active"] { flex: 1 1 auto; }
  .portfolio-card[data-state="collapsed"] .portfolio-card__spine { flex-direction: row; justify-content: flex-start; gap: 12px; padding: 14px 18px; }
  .portfolio-card__spine-text { writing-mode: horizontal-tb; transform: none; }
  .portfolio-card__spine-arrow { transform: rotate(0deg); }
  .portfolio-card__panel-inner { max-height: 68vh; max-height: 68dvh; }
}
/* ============================================================================
   Modal de evidencias (visor de documentos sin salir de la página)
   ========================================================================== */
html.evidence-modal-open, html.evidence-modal-open body { overflow: hidden; }
.evidence-modal { position: fixed; inset: 0; z-index: 200; display: none; align-items: center; justify-content: center; padding: clamp(16px, 4vw, 40px); }
.evidence-modal.is-open { display: flex; }
.evidence-modal__backdrop { position: absolute; inset: 0; background: rgba(10,10,14,.72); backdrop-filter: blur(2px); animation: evidenceFadeIn .18s ease; }
.evidence-modal__dialog {
  position: relative; z-index: 1; max-width: min(880px, 94vw); max-height: 90vh; max-height: 90dvh;
  background: var(--surface); border-radius: var(--radius-lg); padding: 14px 14px 18px;
  display: flex; flex-direction: column; gap: 10px; box-shadow: 0 24px 70px rgba(0,0,0,.4);
  animation: evidenceZoomIn .2s ease;
}
.evidence-modal__img {
  max-width: 100%; max-height: 72vh; width: auto; height: auto; object-fit: contain; border-radius: 12px; display: block; margin: 0 auto; background: var(--surface-2);
  max-height: 72dvh;   /* ver comentario de .portfolio-accordion: dvh evita el salto de tamaño en iOS al ocultarse la barra de direcciones */
}
.evidence-modal__footer { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 10px 18px; }
.evidence-modal__caption { text-align: center; color: var(--muted); font-size: .82rem; }
.evidence-modal__external {
  display: none; align-items: center; gap: 7px; padding: 8px 16px; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent-deep); font-size: .8rem; font-weight: 700;
  font-family: var(--font-display); white-space: nowrap; transition: background .2s;
}
[data-theme="dark"] .evidence-modal__external { color: var(--accent); }
.evidence-modal__external:hover { background: var(--accent); color: #fff; }
.evidence-modal__external svg { width: 14px; height: 14px; }
.evidence-modal__close {
  position: absolute; top: -16px; right: -16px; width: 36px; height: 36px; border-radius: 50%;
  background: var(--ink); color: var(--surface); border: none; display: grid; place-items: center;
  cursor: pointer; box-shadow: 0 6px 18px rgba(0,0,0,.3); transition: transform .15s;
}
.evidence-modal__close:hover { transform: scale(1.08); }
.evidence-modal__close svg { width: 16px; height: 16px; }
@media (max-width:480px) {
  .evidence-modal__close { top: -12px; right: 4px; }
}
@keyframes evidenceFadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes evidenceZoomIn { from { opacity: 0; transform: scale(.96); } to { opacity: 1; transform: scale(1); } }
/* ============================================================================
   Módulo Research: resumen (texto) + acceso al portfolio (miniatura), en 2
   columnas a partir de cierto ancho. Miniatura con look de "mazo apilado"
   (2 cartas de fondo desplazadas detrás de la portada real) y su
   visor/lightbox para pasar las páginas.
   ========================================================================== */
.research-panel { display: flex; flex-direction: column; min-height: 100%; }
.research-summary { display: grid; grid-template-columns: 1fr; gap: 28px; align-items: start; }
@media (min-width:860px) {
  .research-summary { grid-template-columns: 1.05fr .95fr; gap: clamp(28px, 4vw, 52px); }
}
.research-summary__deck { display: flex; flex-direction: column; }
/* Fila de cifras clave al pie del panel: rellena el hueco que deja el resumen
   corto con información real (no aire), y se separa del resumen con margin-top:
   auto para que siempre quede pegada a la base del panel, sea cual sea su alto. */
.research-stats {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px 28px;
  margin-top: auto; padding-top: 24px; border-top: 1px solid var(--line);
}
@media (min-width:640px) {
  .research-stats { grid-template-columns: repeat(4, 1fr); }
}
/* min-width:0 es necesario porque .research-stat__track mide su ancho como
   "max-content" (para no partir los items en varias líneas); sin esto, el
   tamaño automático de la celda de grid heredaría ese ancho enorme en vez
   de respetar la columna 1fr, aunque el overflow esté oculto visualmente. */
.research-stat { min-width: 0; display: flex; flex-direction: column; }
/* Número + título en la misma línea (antes el título iba debajo, en gris):
   así se gana una línea entera de alto libre para las cintas de abajo, y el
   título en verde/negrita hace de "etiqueta" de lo que viene a continuación. */
.research-stat__head { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.research-stat__n {
  display: block; font-family: var(--font-display); font-weight: 700;
  font-size: clamp(1.1rem, 1.8vw, 1.3rem); color: var(--pf-accent, var(--accent-3));
}
.research-stat__label {
  display: block; color: var(--pf-accent, var(--accent-3)); font-weight: 700;
  font-size: .82rem; line-height: 1.3; white-space: nowrap;
}
/* El stat sin lista (años de research) es el único sin cinta debajo, así que
   junto a los demás (con 1-2 cintas) le sobra alto libre. En vez de dejarlo
   como aire vacío, se agranda mucho y se centra en el alto de la celda para
   que ocupe ese hueco con intención (es también el dato más "titular"). */
.research-stat--hero { justify-content: center; flex: 1; }
.research-stat--hero .research-stat__head { flex-direction: column; align-items: flex-start; gap: 2px; }
.research-stat--hero .research-stat__n { font-size: clamp(2.4rem, 5vw, 3.4rem); line-height: 1; }
.research-stat--hero .research-stat__label { font-size: 1rem; white-space: normal; }
/* Cintilla tipo "banner de noticias": la lista real (sectores, metodologías,
   softwares) se desplaza sola en horizontal en vez de escribirse como frase
   larga, así la fila mantiene siempre un alto fijo (sin provocar scroll en
   la card) sea cual sea el número de items. El track duplica la lista una
   vez (items+items) y anima translateX 0 → -50%: como la segunda mitad es
   idéntica a la primera, el bucle no se nota.
   Para listas largas (sectores/metodologías, >12 items) se reparte en 2
   cintas — .research-stat--dual — que se desplazan en sentidos opuestos
   (.research-stat__track--reverse anima 0 → +50% en vez de -50%): se lee
   mejor que una sola cinta interminable y queda más vivo visualmente. */
.research-stat__marquee {
  margin-top: 6px; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.research-stat--dual .research-stat__marquee:first-of-type { margin-top: 8px; }
.research-stat--dual .research-stat__marquee { margin-top: 6px; }
.research-stat__track {
  display: flex; align-items: baseline; gap: 8px; width: max-content;
  animation-name: research-marquee; animation-timing-function: linear; animation-iteration-count: infinite;
}
.research-stat__track--reverse { animation-name: research-marquee-reverse; }
.research-stat--ticker:hover .research-stat__track { animation-play-state: paused; }
/* Texto plano en vez de "pills" (sin fondo/borde): más cerca de un ticker de
   noticias real, y deja ver más items a la vez en el mismo ancho. Los items
   van en mayúsculas pequeñas separados por un punto en verde; ese punto es
   el único acento de color para no competir con el número/título de arriba. */
.research-stat__track span {
  white-space: nowrap; font-size: .74rem; font-weight: 600; color: var(--ink-soft);
  text-transform: uppercase; letter-spacing: .03em;
}
.research-stat__track .research-stat__dot { color: var(--pf-accent, var(--accent-3)); font-size: .7rem; font-weight: 700; text-transform: none; letter-spacing: 0; }
@keyframes research-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes research-marquee-reverse { from { transform: translateX(-50%); } to { transform: translateX(0); } }
@media (prefers-reduced-motion:reduce) {
  .research-stat__track { animation: none; }
  .research-stat__marquee { overflow-x: auto; }
}
/* Wrapper sin overflow:hidden: es donde viven las cartas de fondo (::before/::after).
   Si el recorte estuviera en el mismo elemento que las pseudo-cartas, se recortarían
   a sí mismas y no se verían asomando por detrás. */
.deck-thumb-wrap { position: relative; margin-top: 28px; padding: 0 14px 14px 0; }
.deck-thumb-wrap::before, .deck-thumb-wrap::after {
  content: ""; position: absolute; inset: 0 14px 14px 0; border-radius: var(--radius-lg);
  background: var(--surface-2); border: 1px solid var(--line);
}
.deck-thumb-wrap::before { transform: translate(7px, -7px) rotate(1.2deg); opacity: .85; }
.deck-thumb-wrap::after { transform: translate(14px, -14px) rotate(2.4deg); opacity: .55; }
.deck-thumb {
  position: relative; z-index: 1; display: block; width: 100%;
  border: 1px solid var(--line); border-radius: var(--radius-lg); overflow: hidden;
  background: var(--surface-2); cursor: pointer; padding: 0; text-align: left;
  box-shadow: var(--shadow-sm); transition: transform .2s, box-shadow .2s;
}
.deck-thumb:hover, .deck-thumb:focus-visible { transform: translateY(-3px); box-shadow: var(--shadow); }
.deck-thumb img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; object-position: top; display: block; }
.deck-thumb__scrim {
  position: absolute; inset: 0; background: linear-gradient(0deg, rgba(10,10,14,.88) 0%, rgba(10,10,14,.4) 42%, rgba(10,10,14,.05) 75%, rgba(10,10,14,0) 100%);
}
.deck-thumb__cta {
  position: absolute; left: 16px; bottom: 14px; display: inline-flex; align-items: center; gap: 8px;
  color: #fff; font-family: var(--font-display); font-weight: 700; font-size: .92rem;
}
.deck-thumb__cta svg { width: 18px; height: 18px; }
.deck-thumb__count {
  position: absolute; top: 12px; right: 12px; padding: 5px 12px; border-radius: 999px;
  background: rgba(10,10,14,.55); color: #fff; font-size: .74rem; font-weight: 700;
  font-family: var(--font-display); letter-spacing: .02em; backdrop-filter: blur(3px);
}
.deck-disclaimer { margin-top: 8px; color: var(--muted); font-size: .74rem; line-height: 1.5; }
/* Mosaico de capturas (Transversal): 2 columnas x 3 filas, todas visibles a la
   vez (a diferencia del deck-thumb de arriba, que esconde el resto detrás de
   una sola miniatura). aspect-ratio 16/9 en vez de más cuadrado para mantener
   el bloque bajo y evitar que el panel necesite scroll. width:88% reduce el
   bloque de forma proporcional (ancho y alto a la vez, sin recortar la
   imagen) lo justo para que quepa sin scroll. */
.proposals-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; margin-top: 4px; width: 88%; }
.proposals-grid__item {
  position: relative; display: block; width: 100%; aspect-ratio: 16 / 9; padding: 0;
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
  background: var(--surface-2); cursor: pointer; box-shadow: var(--shadow-sm);
  transition: transform .2s, box-shadow .2s;
}
.proposals-grid__item:hover, .proposals-grid__item:focus-visible { transform: translateY(-2px); box-shadow: var(--shadow); }
.proposals-grid__item img { width: 100%; height: 100%; object-fit: cover; object-position: top; display: block; }
/* z-index por encima de .case-modal (200): el visor puede abrirse desde las
   miniaturas del aside de un caso, y al cerrarlo se vuelve al caso. */
.deck-modal { position: fixed; inset: 0; z-index: 210; display: none; align-items: center; justify-content: center; padding: clamp(16px, 4vw, 40px); }
.deck-modal.is-open { display: flex; }
.deck-modal__backdrop { position: absolute; inset: 0; background: rgba(10,10,14,.8); backdrop-filter: blur(2px); animation: evidenceFadeIn .18s ease; }
.deck-modal__dialog {
  position: relative; z-index: 1; width: min(1200px, 94vw); max-height: 92vh; max-height: 92dvh;
  background: var(--surface); border-radius: var(--radius-lg); padding: 16px 16px 18px;
  display: flex; flex-direction: column; gap: 12px; box-shadow: 0 24px 70px rgba(0,0,0,.45);
  animation: evidenceZoomIn .2s ease;
}
.deck-modal__img {
  width: 100%; max-height: 76vh; object-fit: contain; border-radius: 10px; display: block; background: var(--surface-2);
  max-height: 76dvh;   /* ver comentario de .portfolio-accordion */
}
.deck-modal__footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 0 4px; }
.deck-modal__caption { color: var(--ink-soft); font-size: .88rem; }
.deck-modal__count { color: var(--muted); font-size: .82rem; font-family: var(--font-display); font-weight: 700; white-space: nowrap; }
.deck-modal__close {
  position: absolute; top: -16px; right: -16px; width: 36px; height: 36px; border-radius: 50%;
  background: var(--ink); color: var(--surface); border: none; display: grid; place-items: center;
  cursor: pointer; box-shadow: 0 6px 18px rgba(0,0,0,.3); transition: transform .15s; z-index: 2;
}
.deck-modal__close:hover { transform: scale(1.08); }
.deck-modal__close svg { width: 16px; height: 16px; }
.deck-modal__nav {
  position: absolute; top: 50%; transform: translateY(-50%); width: 44px; height: 44px; border-radius: 50%;
  border: none; background: rgba(10,10,14,.55); color: #fff; font-size: 1.4rem; line-height: 1;
  display: grid; place-items: center; cursor: pointer; transition: background .2s; z-index: 2;
}
.deck-modal__nav:hover { background: var(--ink); }
.deck-modal__nav.prev { left: 10px; }
.deck-modal__nav.next { right: 10px; }
@media (max-width:640px) {
  .deck-modal__dialog { padding: 12px 10px 14px; }
  /* 44px, no 36px: por debajo de ese tamaño el botón es difícil de acertar
     con el dedo (referencia habitual de accesibilidad táctil ~44px). */
  .deck-modal__nav { width: 44px; height: 44px; font-size: 1.3rem; }
  .deck-modal__close { top: -12px; right: 4px; }
}
/* Color por vertiente (usa la primera vertiente del caso) */
.case--research .kicker { color: var(--accent-3); }
.case--research .case__client { background: var(--accent-3-soft); color: var(--accent-3); }
.case--research .outcome::before { color: var(--accent-3); }
.case--transversal .kicker { color: var(--accent-2); }
.case--transversal .case__client { background: var(--accent-2-soft); color: var(--accent-2); }
.case--transversal .outcome::before { color: var(--accent-2); }
.outcome {
  display: inline-flex; align-items: center; gap: .55em; padding: 9px 14px;
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface-2);
  font-family: var(--font-display); font-weight: 600; font-size: .85rem; color: var(--ink);
}
.outcome::before { content: "✓"; font-weight: 700; color: var(--accent); }
/* El panel de PM se estira a toda la altura disponible y reparte: cabecera
   arriba (tamaño natural) y la rejilla de casos ocupando el resto. Así las dos
   tarjetas llenan el alto del acordeón en vez de desbordarlo y obligar a
   hacer scroll, que es justo lo que 02 y 03 evitan. */
.pm-panel { display: flex; flex-direction: column; min-height: 100%; }
.case-access {
  display: grid; grid-template-columns: 1fr; gap: 16px;
  margin-top: clamp(16px, 2.2vw, 22px); flex: 1; min-height: 0;
}
@media (min-width:560px) {
  .case-access { grid-template-columns: repeat(2, 1fr); }
}
.case-access__item {
  position: relative; display: flex; flex-direction: column; text-align: left;
  border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface);
  padding: clamp(16px, 2.2vw, 22px); cursor: pointer; font: inherit; color: inherit;
  box-shadow: var(--shadow-sm); transition: transform .2s, box-shadow .2s, border-color .2s;
  overflow: hidden;
}
.case-access__item:hover, .case-access__item:focus-visible {
  transform: translateY(-3px); box-shadow: var(--shadow); border-color: color-mix(in srgb, var(--accent) 35%, var(--line));
}
/* Cabecera: logo del producto a la izquierda, flecha a la derecha. El logo va
   sobre una placa blanca para que funcione igual en claro y en oscuro sin
   invertir colores (el de InOpinia lleva rojo, no admite invert). */
.case-access__top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.case-access__logo {
  display: grid; place-items: center; height: 42px; padding: 0 14px;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius-sm);
}
[data-theme="dark"] .case-access__logo { background: #fff; border-color: transparent; }
.case-access__logo img { max-height: 22px; max-width: 100px; width: auto; height: auto; display: block; }
.case-access__arrow {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  display: grid; place-items: center; background: var(--accent-soft); color: var(--accent-deep);
  transition: background .2s, color .2s, transform .2s;
}
[data-theme="dark"] .case-access__arrow { color: var(--accent); }
.case-access__arrow svg { width: 14px; height: 14px; transform: rotate(-45deg); }
.case-access__item:hover .case-access__arrow { background: var(--accent); color: var(--accent-ink); transform: translate(2px,-2px); }
.case-access__body { margin-top: clamp(14px, 1.8vw, 18px); }
.case-access__client { font-size: 1.1rem; margin: 0; line-height: 1.2; }
.case-access__role {
  display: block; margin-top: 4px;
  font-family: var(--font-display); font-size: .68rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--accent);
}
.case-access__title { color: var(--ink); font-size: .92rem; font-weight: 600; line-height: 1.35; margin: 11px 0 0; }
.case-access__blurb { color: var(--ink-soft); font-size: .84rem; line-height: 1.55; margin: 8px 0 0; }
/* Pie: ancla la card por abajo (margin-top:auto) para que las dos queden
   alineadas aunque los textos midan distinto, y deja explícito que se abre. */
.case-access__cta {
  display: inline-flex; align-items: center; gap: .45em; margin-top: auto; padding-top: 14px;
  font-family: var(--font-display); font-weight: 700; font-size: .78rem; color: var(--accent-deep);
}
[data-theme="dark"] .case-access__cta { color: var(--accent); }
.case-access__cta svg { width: 14px; height: 14px; transition: transform .2s; }
.case-access__item:hover .case-access__cta svg { transform: translateX(3px); }
/* ---- Modal de caso: mismo patrón que .evidence-modal (backdrop + diálogo
   centrado) pero con contenido de texto largo, así que va a 2 columnas y más
   ancho: un aside fijo con la "portada" del caso (cliente, título, chips de
   resultado) sobre fondo tintado, y una columna de lectura con los bloques
   numerados en medida acotada. Reutiliza html.evidence-modal-open para
   bloquear el scroll de fondo (misma clase que evidence-modal y deck-modal). */
.case-modal { position: fixed; inset: 0; z-index: 200; display: none; align-items: center; justify-content: center; padding: clamp(12px, 3vw, 40px); }
.case-modal.is-open { display: flex; }
.case-modal__backdrop { position: absolute; inset: 0; background: rgba(10,10,14,.76); backdrop-filter: blur(3px); animation: evidenceFadeIn .18s ease; }
/* dialog → body → grid encadenan flex + min-height:0 para que la altura máxima
   la imponga solo el diálogo (88vh) y el scroll caiga dentro de las columnas,
   sin que el borde/radio del diálogo recorte contenido. */
.case-modal__dialog {
  position: relative; z-index: 1; width: min(1080px, 100%);
  /* Tope absoluto además del relativo: en pantallas muy altas un 88vh suelto
     estiraba el diálogo y dejaba el aside flotando en mitad de un vacío. */
  max-height: min(88vh, 720px);
  /* dvh: ver comentario de .portfolio-accordion (evita el salto en iOS). */
  max-height: min(88dvh, 720px);
  display: flex; overflow: hidden;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg);
  box-shadow: var(--shadow); animation: evidenceZoomIn .2s ease;
}
.case-modal__body { display: flex; flex: 1; min-width: 0; min-height: 0; }
.case-modal__close {
  position: absolute; top: 16px; right: 16px; z-index: 3; width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center; background: var(--surface); border: 1px solid var(--line);
  color: var(--ink-soft); box-shadow: var(--shadow-sm); transition: background .2s, color .2s, transform .2s;
}
.case-modal__close:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); transform: scale(1.08); }
.case-modal__close svg { width: 15px; height: 15px; }
/* Móvil: scrollea la rejilla entera (aside + lectura como un solo bloque).
   Escritorio: la rejilla no scrollea, cada columna gestiona su propio scroll —
   .case-modal__read es la caja fija y .case-modal__blocks el scrollport. */
.case-modal__grid { display: grid; grid-template-columns: 1fr; flex: 1; min-width: 0; min-height: 0; max-height: 100%; overflow-y: auto; }
.case-modal__read { position: relative; min-width: 0; }
@media (min-width:860px) {
  .case-modal__grid { grid-template-columns: minmax(260px, 320px) 1fr; overflow: hidden; align-items: stretch; }
  .case-modal__aside { overflow-y: auto; min-height: 0; }
  .case-modal__read { display: flex; min-height: 0; overflow: hidden; }
  .case-modal__blocks { flex: 1; min-height: 0; overflow-y: auto; }
}
/* Aside = portada del caso. Fondo tintado con el acento de la vertiente para
   separarlo visualmente de la columna de lectura sin necesidad de un borde. */
.case-modal__aside {
  display: flex; flex-direction: column; align-items: flex-start;
  padding: clamp(26px, 3.4vw, 40px); background: var(--accent-soft);
  border-bottom: 1px solid var(--line);
}
@media (min-width:860px) {
  .case-modal__aside { border-bottom: 0; border-right: 1px solid var(--line); justify-content: center; }
  .case-modal__aside:has(.case-modal__shots), .case-modal__aside:has(.case-modal__note) { justify-content: flex-start; }
}
.case-modal__kicker {
  font-family: var(--font-display); font-size: .7rem; letter-spacing: .18em; text-transform: uppercase;
  font-weight: 700; color: var(--accent-deep); padding-right: 46px;
}
[data-theme="dark"] .case-modal__kicker { color: var(--accent); }
.case-modal__client-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 16px; }
.case-modal__client {
  display: inline-flex; padding: 6px 14px; border-radius: 999px;
  background: var(--accent); color: var(--accent-ink);
  font-weight: 700; font-size: .84rem; font-family: var(--font-display); letter-spacing: .01em;
}
.case-modal__site {
  display: inline-flex; align-items: center; gap: .4em;
  font-size: .78rem; font-weight: 600; color: var(--accent-deep);
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 40%, transparent); padding-bottom: 1px;
  transition: color .2s, border-color .2s;
}
[data-theme="dark"] .case-modal__site { color: var(--accent); }
.case-modal__site:hover { color: var(--ink); border-color: var(--ink); }
.case-modal__site svg { width: 12px; height: 12px; }
.case-modal__title {
  font-size: clamp(1.35rem, 2.6vw, 1.85rem); line-height: 1.2; margin: 16px 0 0;
  color: var(--ink); text-wrap: balance;
}
.case-modal__metrics { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 24px; }
/* Chips más compactos que .outcome del listado (caben 6 en una columna estrecha)
   y sobre fondo blanco, que aquí el fondo del aside ya va tintado. */
.case-modal__metrics .outcome {
  padding: 6px 11px; font-size: .76rem; gap: .4em;
  background: var(--surface); border-color: color-mix(in srgb, var(--accent) 22%, var(--line));
}
/* Álbum de capturas del aside: reutiliza .deck-thumb-wrap / .deck-thumb del
   módulo Research (portada con mazo apilado + contador). Aquí solo se ajusta
   el margen superior, que allí lo da el propio bloque. */
.case-modal__shots { margin-top: 26px; }
.case-modal__shots-title {
  display: block; font-family: var(--font-display); font-weight: 700; font-size: .68rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--accent-deep); margin-bottom: 10px;
}
[data-theme="dark"] .case-modal__shots-title { color: var(--accent); }
.case-modal__shots .deck-thumb-wrap { margin-top: 14px; }
/* Las capturas son casi cuadradas, así que la portada va 4/3 en vez del 16/9
   del deck de Research: con un apaisado tan marcado solo se veía la cabecera
   de la pantalla. */
.case-modal__shots .deck-thumb img { aspect-ratio: 4 / 3; }
/* Aviso de confidencialidad: para casos sin nada público que enseñar. Va en
   gris y con candado — es una aclaración, no una credencial más. */
.case-modal__note {
  display: flex; gap: 10px; margin: 26px 0 0; padding: 14px 16px;
  background: var(--surface); border-radius: var(--radius-sm);
  color: var(--muted); font-size: .78rem; line-height: 1.55;
}
.case-modal__note svg { width: 15px; height: 15px; flex: none; margin-top: 2px; }
/* Columna de lectura: bloques numerados, medida acotada (~62ch) y separadores
   suaves entre secciones — es lo que hace legible un caso de 7 bloques. */
.case-modal__blocks { padding: clamp(26px, 3.4vw, 42px); }
.case-modal__block {
  display: grid; grid-template-columns: auto 1fr; gap: 16px; align-items: start;
  padding-bottom: 22px; margin-bottom: 22px; border-bottom: 1px solid var(--line-soft);
}
.case-modal__block:last-child { border-bottom: 0; padding-bottom: 0; margin-bottom: 0; }
.case-modal__block-n {
  font-family: var(--font-display); font-weight: 700; font-size: .74rem; line-height: 1;
  color: var(--accent); background: var(--accent-soft);
  min-width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
}
.case-modal__block-text { min-width: 0; max-width: 62ch; }
.case-modal__block h4 {
  font-family: var(--font-display); font-size: 1.02rem; font-weight: 700; color: var(--ink);
  margin: 4px 0 8px; letter-spacing: -.01em;
}
.case-modal__block p { margin: 0; color: var(--ink-soft); font-size: .95rem; line-height: 1.68; }
/* Bloque destacado al cierre de la columna: banda invertida (fondo --ink,
   texto --paper) para que pese visualmente sin competir con el aside, que ya
   va tintado con el acento. Al usar las dos variables invertidas, el contraste
   se mantiene solo en tema claro y oscuro. No lleva número: no es un paso más
   de la lista, es una segunda capa del caso. */
.case-modal__highlight {
  margin-top: 28px; padding: clamp(22px, 2.6vw, 28px);
  background: var(--ink); border-radius: var(--radius); max-width: 62ch;
}
.case-modal__highlight-eyebrow {
  display: inline-block; font-family: var(--font-display); font-weight: 700;
  font-size: .68rem; letter-spacing: .18em; text-transform: uppercase; color: var(--accent-soft);
}
.case-modal__highlight h4 {
  font-family: var(--font-display); font-size: clamp(1.05rem, 1.9vw, 1.22rem); font-weight: 700;
  color: var(--paper); margin: 10px 0 10px; letter-spacing: -.01em;
}
.case-modal__highlight p {
  margin: 0; font-size: .95rem; line-height: 1.68;
  color: color-mix(in srgb, var(--paper) 78%, var(--ink));
}
/* Aviso de "hay más abajo": degradado que difumina el texto contra el fondo
   del diálogo + chevron que rebota. Absoluto al borde inferior de
   .case-modal__read (la caja fija), no dentro del scroll, para que se ancle
   siempre al final visible de la columna y nunca corte un párrafo a media
   altura. .is-end (puesto por wireCaseModalScroll) lo desvanece al llegar al
   final o cuando el caso cabe entero sin scroll. En móvil no se pinta: ahí
   scrollea la rejilla completa y el gesto ya es evidente. */
.case-modal__scroll-cue { display: none; }
@media (min-width:860px) {
  .case-modal__scroll-cue {
    position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; pointer-events: none;
    height: 92px; display: flex; align-items: flex-end; justify-content: center; padding-bottom: 16px;
    background: linear-gradient(180deg, transparent 0%, var(--surface) 68%);
    opacity: 1; transition: opacity .25s ease;
  }
}
.case-modal__read.is-end .case-modal__scroll-cue { opacity: 0; }
.case-modal__scroll-cue-chip {
  display: grid; place-items: center; width: 32px; height: 32px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--line); color: var(--accent);
  box-shadow: var(--shadow-sm); animation: caseScrollCue 1.9s ease-in-out infinite;
}
.case-modal__scroll-cue-chip svg { width: 15px; height: 15px; transform: rotate(90deg); }
@keyframes caseScrollCue {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(4px); }
}
@media (prefers-reduced-motion:reduce) {
  .case-modal__scroll-cue-chip { animation: none; }
}
@media print {
  .portfolio-accordion { display: block !important; height: auto !important; }
  .portfolio-card { display: block !important; margin-bottom: 24px; }
  .portfolio-card__spine, .portfolio-card__teaser { display: none !important; }
  .portfolio-card__panel { display: block !important; }
  .portfolio-card__panel-inner { overflow: visible !important; max-height: none !important; opacity: 1 !important; transform: none !important; }
  .portfolio-card__head { break-after: avoid; }
}

/* ============================================================================
   Testimonios — PORTADO TAL CUAL DEL CV (bloque "Respaldo" de cv-alex-cadenas)
   ----------------------------------------------------------------------------
   Copia literal de las reglas .respaldo* y .carousel__nav del stylesheet
   original (2026-07-29, a petición de Alex: "el carrusel de recomendaciones de
   mi CV, idéntico"). Sustituye al carrusel de scroll-snap con .quote que había
   aquí, ya eliminado. Ojo: .carousel__nav aquí es el BOTÓN redondo, no el
   contenedor de flechas que era antes en esta web.
   ========================================================================== */
.respaldo { display: flex; gap: 18px; margin-top: 0; transition: transform .4s cubic-bezier(.2,.7,.2,1); }
.respaldo__item {
  flex: 0 0 calc((100% - 2 * 18px) / 3); box-sizing: border-box;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px; margin: 0;
}
.respaldo__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.respaldo__icon { width: 20px; height: 20px; color: var(--accent); opacity: .5; flex: 0 0 auto; }
.respaldo__icon svg { width: 100%; height: 100%; }
.respaldo blockquote {
  margin: 0; font-size: .9rem; color: var(--ink-soft); line-height: 1.55;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; overflow: hidden;
}
.respaldo figcaption { margin-top: 10px; display: flex; flex-direction: column; }
.respaldo figcaption strong { font-size: .85rem; }
.respaldo figcaption span { color: var(--muted); font-size: .75rem; }
.respaldo__link {
  display: inline-flex; align-items: center; gap: 4px; margin-left: auto; text-align: right;
  font-size: .72rem; font-weight: 600; color: var(--accent); white-space: nowrap;
}
.respaldo__link svg { width: 12px; height: 12px; }
.respaldo__link:hover { text-decoration: underline; }

/* Botones redondos de navegación. En el CV viven en la galería y el carrusel
   los reutiliza; aquí, como no hay galería, se traen con él. */
.carousel__nav {
  position: absolute; top: calc(50% - 44px); transform: translateY(-50%);
  width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center;
  font-size: 1.7rem; line-height: 1; padding-bottom: 4px;
  background: color-mix(in srgb, var(--surface) 86%, transparent); border: 1px solid var(--line);
  box-shadow: var(--shadow-sm); backdrop-filter: blur(6px); transition: background .2s, color .2s, transform .2s;
}
.carousel__nav.prev { left: 16px; } .carousel__nav.next { right: 16px; }
.carousel__nav:hover { background: var(--ink); color: var(--paper); }

/* Carrusel que envuelve .respaldo: reutiliza los botones .carousel__nav ya
   definidos para la galería, sólo se recentran y reposicionan aquí. */
.respaldo-carousel { position: relative; margin-top: 20px; padding: 0 56px; }
.respaldo-carousel__viewport { overflow: hidden; }
.respaldo-carousel .carousel__nav { top: 50%; transform: translateY(-50%); }
.respaldo-carousel .carousel__nav.prev { left: 0; }
.respaldo-carousel .carousel__nav.next { right: 0; }
.respaldo-carousel .carousel__nav:disabled { opacity: .3; pointer-events: none; }
@media (max-width: 900px) {
  .respaldo-carousel .respaldo__item { flex-basis: calc((100% - 18px) / 2); }
}
@media (max-width: 620px) {
  .respaldo-carousel { padding: 0 44px; }
  .respaldo-carousel .respaldo__item { flex-basis: 100%; }
}

/* ============================================================================
   Contacto
   ========================================================================== */

@media (min-width: 940px) {  }

.contact__main .eyebrow { margin-bottom: 12px; }

@media (min-width: 620px) {  }

/* ============================================================================
   CONTACTO — PANEL PORTADO DEL FOOTER DE LA WEB DE CV (repo cv-alex-cadenas)
   ----------------------------------------------------------------------------
   Mismas reglas que el footer oscuro del original. Aquí es una <section> con
   id="contacto" en vez de un <footer>, pero conserva la clase .footer para
   heredar el CSS tal cual.
   ========================================================================== */

/* El footer es un panel oscuro fijo en ambos temas (texto claro siempre legible). */
.footer { background: #14141a; color: #f4f3ef; border-radius: var(--radius-lg) var(--radius-lg) 0 0; margin-top: clamp(20px,3vw,40px); }
[data-theme="dark"] .footer { background: #191921; border-top: 1px solid #2c2c36; }
.footer .container { padding-block: clamp(48px,8vw,96px); }
.footer h2 { font-size: clamp(2rem, 6vw, 4rem); color: #ffffff; max-width: 16ch; }
.footer__actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 18px 28px; margin-top: 28px; }
.footer__cta { display: flex; flex-wrap: wrap; gap: 12px; }
.footer .btn--ghost { border-color: rgba(255,255,255,.25); color: #ffffff; background: transparent; }
.footer .btn--ghost:hover { border-color: #ffffff; }
.footer .btn--primary { background: #ffffff; color: #14141a; }
.footer__contact-row { display: flex; flex-wrap: wrap; gap: 10px; }
.footer__contact-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; border-radius: 50%;
  background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.2); color: #ffffff;
  transition: transform .2s, background .2s, border-color .2s;
}
.footer__contact-btn svg { width: 19px; height: 19px; }
.footer__contact-btn:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); transform: translateY(-2px); }
.footer__meta { display: flex; flex-wrap: wrap; justify-content: flex-start; gap: 16px; margin-top: clamp(40px,6vw,72px); padding-top: 24px; border-top: 1px solid rgba(255,255,255,.14); color: rgba(255,255,255,.6); font-size: .85rem; }
.footer__meta a:hover { color: var(--paper); }

/* ---- Bloque "Qué pasa después de escribirme", dentro del panel oscuro.
   No existe en el CV: es propio de esta web, con los colores adaptados al
   fondo oscuro del footer en vez de a las superficies claras. ---- */
.footer-steps {
  margin-top: clamp(36px, 5vw, 56px); padding-top: clamp(28px, 4vw, 40px);
  border-top: 1px solid rgba(255,255,255,.14);
}
.footer-steps__title {
  font-family: var(--font-display); font-size: .78rem; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: rgba(255,255,255,.55);
  margin-bottom: 22px;
}
.footer-steps__list { display: grid; gap: 22px; grid-template-columns: 1fr; }
@media (min-width: 760px) { .footer-steps__list { grid-template-columns: repeat(3, 1fr); gap: 28px; } }
.footer-steps__list li { display: flex; gap: 14px; align-items: flex-start; }
.footer-steps__n {
  font-family: var(--font-display); font-size: .76rem; font-weight: 700; letter-spacing: .08em;
  color: #ffffff; background: rgba(255,255,255,.1); border: 1px solid rgba(255,255,255,.2);
  width: 34px; height: 34px; flex: none; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
}
.footer-steps__list strong { font-family: var(--font-display); font-size: .98rem; color: #ffffff; }
.footer-steps__list p { color: rgba(255,255,255,.62); font-size: .89rem; margin-top: 4px; line-height: 1.5; }

/* El panel de contacto es la última sección: sin margen superior extra ni
   esquinas redondeadas abajo (en el CV era un <footer> real). */
.footer { margin-top: clamp(20px,3vw,40px); }
.footer__meta a { color: rgba(255,255,255,.6); }

/* ============================================================================
   Animaciones de entrada
   ========================================================================== */
.reveal { opacity: 0; transform: translateY(16px); transition: opacity .6s ease, transform .6s ease; }
.reveal.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
  .reveal { opacity: 1; transform: none; }
}

