/* ==========================================================================
   bb2026 — PAGINA DE CONTACTO.

   Namespace .bb-ct-page (body) y .bb-ct*. No toca la portada, ni el pie,
   ni el menu, ni el cursor, ni ningun z-index existente. De la cabecera
   solo ANULA lo imprescindible, y con la clase del body, nunca tocando
   header.css (ver bloque CABECERA SOBRE MEDIA PANTALLA).

   JERARQUIA DE CAPAS QUE YA EXISTE (no se rompe): contenido 0-99,
   overlay de menu 300, barra 400, dialogos 500+, salto al contenido 999,
   cursor 1200, cortina 1500. Aqui no se pasa de 3.

   ##################### MEDIDAS DE CONTRASTE (WCAG AA) ##################
   Todas MEDIDAS, no estimadas. Metodo: composicion alfa canal a canal en
   sRGB, linealizacion ((c/255+0.055)/1.055)^2.4, luminancia relativa
   0.2126R + 0.7152G + 0.0722B y (L1+0.05)/(L2+0.05).

   Referencias fijas:
     --bb-paper #F7F5F2 -> L = 0.914903
     --bb-ink   #1C1B19 -> L = 0.011039   (28, 27, 25)
     --bb-body  #565451 -> L = 0.089126
     --bb-accent #2E4A42 -> L = 0.058728

   1. TEXTO CLARO DEL PANEL sobre el PEOR CASO IMAGINABLE de la foto
      (zona de fotografia blanco puro, sRGB 255) mas el velo inferior:
        velo 0,78 de tinta -> 0,78*28 + 0,22*255 = 77,94  (L = 0.076145)
        texto --bb-paper (L = 0.914903)
        contraste = 0.964903 / 0.126145 = 7,65:1     CUMPLE 4,5:1
      El velo llega a 0,78 en el 62% de la altura del panel y solo crece
      hacia abajo, asi que 7,65:1 es el peor punto de TODA la banda de
      texto, no el mejor.

   2. MICRO-ROTULO del panel (--bb-paper al 78% de opacidad) sobre ese
      mismo peor caso:
        mezcla = 0,78*paper + 0,22*77,94 -> (209,81 / 208,08 / 205,39)
        L = 0.632431
        contraste = 0.682431 / 0.126145 = 5,41:1     CUMPLE 4,5:1
      Por eso el rotulo NO usa --bb-label (#A6A8AB): MEDIDO sobre este
      mismo fondo da 3,49:1 y NO cumple. Regla dura del proyecto: ese gris
      solo vale sobre fondo oscuro de verdad (el overlay verde), no sobre
      una fotografia velada.

   3. LOGOTIPO CLARO de la barra sobre el peor caso mas el velo superior:
        velo superior 0,50 + borde alto del inferior 0,10
        alfa combinada = 1 - 0,50*0,90 = 0,55
        0,55*28 + 0,45*255 = 130,15  (L = 0.223703)
        contraste = 0.964903 / 0.273703 = 3,53:1
      3,53:1 CUMPLE el umbral de 3:1 que WCAG 1.4.11 pide para un
      elemento GRAFICO, que es lo que el logotipo es. Para llevarlo a
      4,5:1 haria falta 0,585 de tinta en la franja alta y eso ya no se
      lee como velo: se lee como una banda negra sobre la fotografia,
      que es el defecto que la clienta senialo. Decision consciente y
      anotada; el texto del panel (caso 1) si va a 7,65:1.

   4. ETIQUETAS DEL FORMULARIO (--bb-body sobre papel):
        contraste = 0.964903 / 0.139126 = 6,94:1     CUMPLE 4,5:1

   5. MINI TEXTO LEGAL (--bb-body sobre papel, 12px):
        contraste = 0.964903 / 0.139126 = 6,94:1     CUMPLE 4,5:1

   6. ACENTO sobre papel (filete de foco, boton, enlaces):
        contraste = 0.964903 / 0.108728 = 8,88:1     CUMPLE 4,5:1 y 3:1

   7. FILETE INFERIOR DE LOS CAMPOS (borde de un control de formulario,
      umbral 3:1 de WCAG 1.4.11):
        rgba(28,27,25,0.50) sobre papel -> (137,5 / 136 / 133,5)
        L = 0.246766
        contraste = 0.964903 / 0.296766 = 3,25:1     CUMPLE 3:1
      NO se usa --bb-ink-soft (#58565322) para esto: MEDIDO da 1,3:1 y un
      campo cuyo borde no se ve es un campo que no se sabe que existe.
      --bb-ink-soft se sigue usando en los filetes DECORATIVOS de
      separacion, donde no hay umbral que cumplir.
   #######################################################################
   ========================================================================== */

/* --------------------------------------------------------------------------
   CASCARA DE PAGINA
   -------------------------------------------------------------------------- */

/* Fondo de carga en BLANCO puro, igual que la portada y los servicios: es
   lo que se ve debajo de la cortina y detras del panel mientras la
   persiana baja. El papel calido se percibia como gris. */
body.bb-ct-page { background: var(--bb-load-bg); }

/* header.php reserva el alto de la barra fija en todas las paginas que no
   son la portada (.bb-main--offset). Aqui el panel va A SANGRE desde
   arriba, asi que ese hueco se anula. Se hace por CSS —con la clase del
   body, que gana en especificidad— y NO tocando header.php. */
body.bb-ct-page .bb-main--offset { padding-top: 0; }

/* --------------------------------------------------------------------------
   CABECERA SOBRE MEDIA PANTALLA

   EL PROBLEMA (solo a partir de 1024px, donde hay dos columnas):

   inc/contact-enqueue.php engancha el filtro 'bb_has_bleed_hero', asi que
   la barra arranca con .bb-bar--over-dark. Eso pone CLAROS el logotipo Y
   la hamburguesa. Pero aqui el panel fotografico ocupa solo la MITAD
   IZQUIERDA: el logotipo (izquierda) esta sobre foto y necesita ser
   claro, mientras que la hamburguesa (derecha) esta sobre PAPEL y en
   claro seria invisible.
   Y al hacer scroll, .bb-bar.is-stuck pinta fondo papel en TODO el ancho,
   lo que dejaria una franja de papel cruzando la fotografia: el mismo
   defecto que la clienta ya senialo una vez.

   LA SOLUCION reutiliza un patron que ya existe en el tema: el degradado
   con CORTE DURO al 50% con el que header.css resuelve este mismo
   problema cuando el menu esta abierto (bloque 'body.bb-nav-open .bb-bar'
   a >=1024px, donde el panel del menu tambien ocupa media pantalla). El
   corte al 50% coincide EXACTAMENTE con el borde de .bb-ct__aside, porque
   la rejilla es minmax(0,1fr) minmax(0,1fr): dos mitades iguales. Si esa
   proporcion cambiara, hay que igualar aqui el porcentaje.

   ################## CUENTA DE ESPECIFICIDAD (comprobada) ###############
   La especificacion de la tarea daba (0,2,0) a la regla de header.css.
   MEDIDO, no es esa: :not() NO es gratis, aporta la especificidad de su
   argumento.

     .bb-bar--over-dark:not(.is-stuck) .bb-burger
       clases: .bb-bar--over-dark + .is-stuck (dentro del :not) + .bb-burger
       -> (0,3,0)

     body.bb-ct-page:not(.bb-nav-open) .bb-bar--over-dark:not(.is-stuck) .bb-burger
       elementos: body                                  -> 1
       clases: .bb-ct-page + .bb-nav-open + .bb-bar--over-dark
               + .is-stuck + .bb-burger                 -> 5
       -> (0,5,1)

   (0,5,1) > (0,3,0): gana sin necesidad de !important, que es lo que se
   pedia comprobar. El !important no se usa en ninguna regla de este
   bloque.

   POR QUE TODO EL BLOQUE VA DENTRO DE :not(.bb-nav-open): con el menu
   abierto, header.css ya resuelve la barra (verde a la izquierda,
   transparente a la derecha sobre el panel) con reglas de especificidad
   (0,3,1) —la MISMA que tendria 'body.bb-ct-page .bb-bar.is-stuck'—. En
   empate manda el orden, y contact.css se carga DESPUES de header.css:
   sin el :not, esta hoja ganaria y pintaria papel encima del verde del
   menu. Con el :not, la regla simplemente no existe mientras el menu
   esta abierto y header.css hace su trabajo intacto.

   POR DEBAJO DE 1024px NO HAY NINGUNA ANULACION: la foto ocupa todo el
   ancho y el comportamiento por defecto (claro sobre foto, papel al
   fijarse) es exactamente el correcto.
   -------------------------------------------------------------------------- */
@media (min-width: 1024px) {

  /* La barra fijada solo pinta papel en la MITAD DERECHA. */
  body.bb-ct-page:not(.bb-nav-open) .bb-bar.is-stuck {
    background: linear-gradient(to right, transparent 0 50%, var(--bb-paper) 50% 100%);
    box-shadow: none;
  }

  /* Sobre la foto el logotipo va CLARO siempre, tambien fijada la barra
     (por defecto .is-stuck lo devolveria a tinta y quedaria negro sobre
     la fotografia). */
  body.bb-ct-page:not(.bb-nav-open) .bb-bar.is-stuck .bb-bar__logo-img--claro { opacity: 1; }
  body.bb-ct-page:not(.bb-nav-open) .bb-bar.is-stuck .bb-bar__logo-img--tinta { opacity: 0; }

  /* La hamburguesa esta sobre PAPEL: tinta, no papel. Ver la cuenta de
     especificidad arriba. */
  body.bb-ct-page:not(.bb-nav-open) .bb-bar--over-dark:not(.is-stuck) .bb-burger {
    color: var(--bb-ink);
  }
}

/* --------------------------------------------------------------------------
   REJILLA: SPLIT A SANGRE

   ####### minmax(0, 1fr) Y NUNCA 1fr #######
   Una pista '1fr' es minmax(auto, 1fr) y se mide POR CONTENIDO. Con un
   marco de foto dentro (aspect-ratio o imagen absoluta) eso es una
   referencia circular y el navegador devuelve anchos absurdos
   (33.554.432px medidos en este proyecto). Regla general, sin
   excepciones.

   align-items: start es OBLIGATORIO, no cosmetico: el valor por defecto
   de un item de rejilla es 'stretch', que le da la altura de la fila
   completa. Un elemento tan alto como su contenedor de scroll no puede
   pegarse (position: sticky no tiene recorrido donde pegarse) y la
   columna izquierda se iria con el scroll.
   -------------------------------------------------------------------------- */
.bb-ct {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 1024px) {
  .bb-ct {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: start;
  }
}

/* --------------------------------------------------------------------------
   COLUMNA IZQUIERDA — PANEL FOTOGRAFICO

   ESTA ES LA APORTACION PROPIA SOBRE LA REFERENCIA (nordicaphotography),
   donde el banner se va con el scroll: aqui la columna se queda FIJA a
   100svh y el formulario pasa por delante de la fotografia. Por debajo de
   1024px no hay dos columnas, asi que el panel vuelve a ser un hero
   normal y se va con el scroll.

   svh y no vh: en movil, vh cuenta la barra de direcciones del navegador
   como si no existiera y el panel se corta.
   -------------------------------------------------------------------------- */
/* POR DEBAJO DE 1024px EL ALTO NO PUEDE SER FIJO.
   Medido a 390x844: con height: 78svh (658px) el contenido del panel
   —micro-rotulo + h1 + entradilla + los 5 pares del NAP en UNA columna—
   es mas alto que el panel, desbordaba HACIA ARRIBA y el overflow:
   hidden lo recortaba: de "HABLEMOS" solo se veia la mitad inferior y el
   rotulo "CONTACTO" no se veia en absoluto.
   Por eso 78svh pasa a ser MINIMO y no medida: el panel crece con su
   contenido y ya no puede recortarlo.
   El overflow: hidden NO se toca: es lo que recorta el Ken Burns y la
   persiana de entrada. El defecto era el alto, no el recorte.

   Los dos velos y sus cifras de contraste MEDIDAS siguen igual: el marco
   es absolute inset: 0, asi que crece con el panel y el velo ascendente
   sigue cubriendo toda la banda de texto (7,65:1 o mejor, caso 1). No se
   introduce ningun color nuevo. */
.bb-ct__aside {
  position: relative;
  height: auto;
  min-height: 78svh;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  /* Respaldo mientras la foto carga: la tinta del sistema, nunca un gris
     que se lea como agujero. */
  background: var(--bb-ink);
}

@media (min-width: 1024px) {
  .bb-ct__aside {
    position: sticky;
    top: 0;
    height: 100svh;
  }
}

/* EL MARCO es quien lleva el recorte de la persiana. La foto y los dos
   velos van DENTRO, en absoluto: asi los velos se revelan CON la foto y
   no se pintan enteros sobre el blanco de carga (que es lo que producia
   el "lavado gris"). Nunca imagen en flujo con height: 100%. */
.bb-ct__frame {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.bb-ct__img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   VELOS — dos capas, cada una con un trabajo distinto.
   Las cifras MEDIDAS estan en la cabecera de esta hoja (casos 1, 2 y 3).
   -------------------------------------------------------------------------- */
.bb-ct__veil {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* DESCENDENTE, franja alta: para que el logotipo CLARO de la barra se lea
   sobre cualquier fotografia (caso 3: 3,53:1, umbral grafico 3:1). Muere
   a 240px, por debajo de la barra mas alta (88px en escritorio) con
   holgura de sobra, asi que no lava la fotografia ni alcanza al texto. */
.bb-ct__veil--top {
  background: linear-gradient(
    to bottom,
    rgba(28, 27, 25, 0.50) 0,
    rgba(28, 27, 25, 0) 240px
  );
}

/* ASCENDENTE y mas fuerte: para el texto. Llega a 0,78 de tinta en el 62%
   de la altura y de ahi hacia abajo solo crece, asi que TODA la banda de
   texto esta a 7,65:1 o mejor (caso 1). El 10% del borde superior es lo
   que se suma al velo descendente en la cuenta del logotipo. */
.bb-ct__veil--bot {
  background: linear-gradient(
    to top,
    rgba(28, 27, 25, 0.88) 0%,
    rgba(28, 27, 25, 0.78) 62%,
    rgba(28, 27, 25, 0.26) 84%,
    rgba(28, 27, 25, 0.10) 100%
  );
}

/* --------------------------------------------------------------------------
   TEXTO SUPERPUESTO DEL PANEL, anclado ABAJO
   -------------------------------------------------------------------------- */
/* EL HUECO DE LA BARRA FIJA SE RESERVA EN TODOS LOS ANCHOS, no solo en
   escritorio. Medido a 390px: sin esta reserva el logotipo de la barra se
   pintaba justo ENCIMA del h1. Con el panel de alto automatico el texto
   empieza por debajo de la barra y ya no puede colisionar con ella
   aunque el texto crezca. */
.bb-ct__over {
  position: relative;
  z-index: 2;
  width: 100%;
  padding: calc(var(--bb-bar-h) + var(--bb-s4)) var(--bb-gutter) var(--bb-s4);
  color: var(--bb-paper);
}

@media (min-width: 1024px) {
  .bb-ct__over {
    /* Arriba se deja pasar la barra fija; el bloque sigue anclado abajo
       por el align-items: flex-end del panel. */
    padding: calc(var(--bb-bar-h) + var(--bb-s4)) var(--bb-gutter) var(--bb-s5);
  }
}

/* Micro-rotulo. NO usa --bb-label: sobre este fondo da 3,49:1 medidos y
   no cumple. Va papel al 78% -> 5,41:1 (caso 2). */
.bb-ct__label {
  margin: 0 0 var(--bb-s2);
  font-family: var(--bb-font-display);
  font-weight: 500;
  font-size: var(--bb-size-label);
  text-transform: uppercase;
  letter-spacing: var(--bb-track-label);
  line-height: 1.4;
  color: var(--bb-paper);
  opacity: 0.78;
}

.bb-ct__h1 {
  color: var(--bb-paper);
  margin: 0 0 var(--bb-s2);
}

.bb-ct__lead {
  margin: 0 0 var(--bb-s4);
  max-width: 34ch;
  font-family: var(--bb-font-body);
  font-size: var(--bb-size-body);
  line-height: 1.7;
  color: var(--bb-paper);
}

/* NAP: pares rotulo/dato en dos columnas a partir de 480px. El rotulo es
   micro-etiqueta; el dato, cuerpo.

   La celda de la rejilla es .bb-ct__nap-row (una pareja completa), no el
   dt y el dd por separado: si fueran items independientes, cada fila
   saldria "rotulo | dato" en lugar de "rotulo encima, dato debajo". Por
   eso la plantilla envuelve cada pareja en un <div> (HTML5 lo admite
   dentro de <dl> exactamente para esto). */
.bb-ct__nap {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--bb-s3);
  margin: 0 0 var(--bb-s4);
}
.bb-ct__nap-row { min-width: 0; }
.bb-ct__nap dt {
  font-family: var(--bb-font-display);
  font-weight: 500;
  font-size: var(--bb-size-label);
  text-transform: uppercase;
  letter-spacing: var(--bb-track-label);
  color: var(--bb-paper);
  opacity: 0.78;
  margin-bottom: 2px;
}
.bb-ct__nap dd {
  margin: 0;
  font-family: var(--bb-font-body);
  font-size: 0.9375rem; /* 15px */
  line-height: 1.6;
  color: var(--bb-paper);
}
.bb-ct__nap a { color: var(--bb-paper); }
.bb-ct__nap a:hover,
.bb-ct__nap a:focus-visible { color: var(--bb-paper); opacity: 0.75; }
.bb-ct__nap :focus-visible { outline-color: var(--bb-paper); }

@media (min-width: 480px) {
  .bb-ct__nap {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--bb-s3) var(--bb-s4);
  }
  /* El correo es la cadena mas larga del bloque y no parte bien: ocupa la
     fila entera para que no fuerce el ancho de su columna. */
  .bb-ct__nap-row--wide { grid-column: 1 / -1; }
}

.bb-ct__social { color: var(--bb-paper); }
.bb-ct__social :focus-visible { outline-color: var(--bb-paper); }

/* --------------------------------------------------------------------------
   ENTRADA DEL PANEL — persiana vertical DESCENDENTE, en CSS puro.

   Va en CSS y no en JS porque el estado inicial tiene que estar aplicado
   ANTES del primer pintado; si lo pusiera el JS se veria la foto un
   fotograma antes de colapsar. Misma direccion que el hero de la portada
   y el de servicio, que es el estilo aprobado para la entrada de pagina.

   ############ TRAMPA PAGADA: LOS DOS EXTREMOS, 4 COMPONENTES ###########
   Un inset() de 4 componentes NO interpola contra uno de 1: el navegador
   serializa inset(0% 0% 100% 0%) con tres o cuatro piezas e inset(0) con
   una, y con estructuras distintas la animacion se queda CLAVADA en el
   valor inicial y salta al final. Por eso los dos fotogramas de abajo
   llevan los CUATRO lados explicitos y todos en %.
   #######################################################################

   'both' es obligatorio: durante el retardo (mientras pasa la cortina
   blanca) el elemento tiene que estar ya en el estado 'from'.

   TODO EL BLOQUE VIVE DENTRO DE prefers-reduced-motion: no-preference.
   Si estuviera fuera, el retardo dejaria la foto oculta medio segundo
   incluso con las animaciones neutralizadas.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {

  .bb-ct__frame {
    animation: bb-ct-open 1.25s var(--bb-ease-diag) var(--bb-delay-curtain) both;
  }

  /* Cascada del texto, con los retardos pedidos. */
  .bb-ct__label { animation: bb-ct-rise 0.9s var(--bb-ease) 0.55s both; }
  .bb-ct__h1    { animation: bb-ct-rise 0.9s var(--bb-ease) 0.68s both; }
  .bb-ct__lead  { animation: bb-ct-rise 0.9s var(--bb-ease) 0.80s both; }
  .bb-ct__nap,
  .bb-ct__social { animation: bb-ct-rise 0.9s var(--bb-ease) 0.92s both; }

  /* KEN BURNS: se REUTILIZAN los @keyframes bb-ken de home-kenburns.css
     (12s, curva simetrica, alternate, escala 1 -> 1,07, deriva 1,2%), que
     es el valor aprobado. Esa hoja aplica la animacion solo a
     .bb-hhero__img y .bb-hstrip__img, que son selectores de la portada;
     aqui se aplica al selector propio, exactamente como hace
     service.css con .bb-shero__img. NO se copia la aritmetica: esta
     documentada en home-kenburns.css y ahi se queda.
     No choca con la persiana: la persiana es clip-path sobre el MARCO y
     el Ken Burns es transform sobre la IMAGEN. */
  .bb-ct__img {
    animation: bb-ken 12s cubic-bezier(0.45, 0, 0.55, 1) infinite alternate;
  }
}

@keyframes bb-ct-open {
  from { clip-path: inset(0% 0% 100% 0%); }
  to   { clip-path: inset(0% 0% 0% 0%); }
}
@keyframes bb-ct-rise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Con la opacidad del label a 0,78, el keyframe de entrada la llevaria a
   1 y el rotulo quedaria mas claro de lo medido. Se corrige con su propio
   fotograma final. */
@media (prefers-reduced-motion: no-preference) {
  .bb-ct__label { animation-name: bb-ct-rise-soft; }
}
@keyframes bb-ct-rise-soft {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 0.78; transform: translateY(0); }
}

/* --------------------------------------------------------------------------
   COLUMNA DERECHA — RITMO DE SECCIONES
   -------------------------------------------------------------------------- */
.bb-ct__main {
  background: var(--bb-paper);
  /* min-width: 0 para que un <pre>, una palabra larga o el textarea no
     puedan ensanchar la columna por encima de su pista. */
  min-width: 0;
}

.bb-ct-sec {
  padding-block: var(--bb-s5);
  border-top: 1px solid var(--bb-ink-soft);
}
.bb-ct-sec:first-child { border-top: none; }

.bb-ct-sec__in {
  width: 100%;
  max-width: 640px;
  margin-inline: auto;
  padding-inline: var(--bb-gutter);
}

.bb-ct-sec__label {
  margin: 0 0 var(--bb-s3);
  font-family: var(--bb-font-display);
  font-weight: 500;
  font-size: var(--bb-size-label);
  text-transform: uppercase;
  letter-spacing: var(--bb-track-label);
  line-height: 1.4;
  /* --bb-body y NO --bb-label: sobre papel el gris claro da 2,19:1.
     Regla dura del proyecto. 6,94:1 medidos (caso 4). */
  color: var(--bb-body);
}

@media (min-width: 1024px) {
  .bb-ct-sec { padding-block: var(--bb-s6); }
  .bb-ct-sec__in { padding-inline: var(--bb-s5); }
}

/* --------------------------------------------------------------------------
   INTRO — BLOQUE RETIRADO EL 13-10-2026

   La columna derecha abria con "Como escribirme", dos parrafos antes del
   primer campo. Se quito por peticion de la clienta y con el se van sus
   dos reglas (.bb-ct-intro__p): no quedan selectores huerfanos en esta
   hoja. El texto sigue guardado en inc/contact-copy.php, marcado sin uso.
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   FORMULARIO — editorial, no cajas.

   Cada campo es UNA LINEA: fondo transparente, sin bordes salvo el filete
   inferior. La etiqueta va ENCIMA, en micro-etiqueta. Al foco el filete
   pasa a 2px de acento y ADEMAS se conserva el outline del sistema: son
   dos seniales distintas y la segunda es la que ve quien navega con
   teclado. Nunca 'outline: none' sin sustituto visible.
   -------------------------------------------------------------------------- */
.bb-ct-form-sec__title { margin: 0 0 var(--bb-s4); }

.bb-ct-form__fields {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--bb-s4);
  margin: 0 0 var(--bb-s4);
}

/* Parejas a dos columnas a partir de 620px. minmax(0,1fr), nunca 1fr. */
.bb-ct-form__pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--bb-s4);
}
@media (min-width: 620px) {
  .bb-ct-form__pair {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--bb-s3);
  }
}

.bb-ct-field { min-width: 0; }

.bb-ct-field__label {
  display: block;
  margin-bottom: var(--bb-s1);
  font-family: var(--bb-font-display);
  font-weight: 500;
  font-size: var(--bb-size-label);
  text-transform: uppercase;
  letter-spacing: var(--bb-track-label);
  line-height: 1.4;
  color: var(--bb-body); /* 6,94:1 medidos. NUNCA --bb-label sobre papel. */
}
.bb-ct-field__req {
  margin-left: 4px;
  color: var(--bb-accent); /* 8,88:1 */
}

.bb-ct-field__input {
  display: block;
  width: 100%;
  /* 44px de alto minimo: objetivo tactil comodo en movil. */
  min-height: 44px;
  padding: var(--bb-s1) 0;
  background: transparent;
  border: none;
  /* 3,25:1 medidos: un control de formulario necesita 3:1 (WCAG 1.4.11) y
     --bb-ink-soft solo da 1,3:1. Ver caso 7 en la cabecera. */
  border-bottom: 1px solid rgba(28, 27, 25, 0.5);
  border-radius: 0;
  font-family: var(--bb-font-body);
  font-size: var(--bb-size-body);
  line-height: 1.6;
  color: var(--bb-ink);
  transition: border-color 0.3s var(--bb-ease), border-width 0.3s var(--bb-ease);
}

/* Al foco el filete engorda a 2px de acento. El padding-bottom baja 1px
   para compensar el pixel que gana el borde: sin eso, el campo salta. */
.bb-ct-field__input:focus {
  border-bottom-width: 2px;
  border-bottom-color: var(--bb-accent);
  padding-bottom: calc(var(--bb-s1) - 1px);
}

/* El outline del sistema (base.css: 2px de acento, offset 3px) SE
   CONSERVA. El offset sube a 4px para que no se pise con el filete. */
.bb-ct-field__input:focus-visible {
  outline: 2px solid var(--bb-accent);
  outline-offset: 4px;
}

/* Campo en error: el filete se pone en tinta llena (15,81:1) y no en un
   rojo nuevo. El sistema de diseno no tiene rojo, y meter uno solo para
   esto abriria un color mas que habria que definir en dos temas. La
   senial de error la lleva el TEXTO del aviso, que es la que de verdad
   dice que pasa; el color nunca es el unico canal. */
.bb-ct-field.is-error .bb-ct-field__input {
  border-bottom-width: 2px;
  border-bottom-color: var(--bb-ink);
  padding-bottom: calc(var(--bb-s1) - 1px);
}

.bb-ct-field__area {
  min-height: 132px;
  resize: vertical;
  /* El auto-crecimiento del JS escribe height en linea; overflow hidden
     evita la barra interna de un fotograma mientras recalcula. */
  overflow: hidden;
}

.bb-ct-field__hint,
.bb-ct-field__count {
  display: block;
  margin-top: var(--bb-s1);
  font-family: var(--bb-font-body);
  font-size: 0.75rem; /* 12px */
  line-height: 1.5;
  color: var(--bb-body); /* 6,94:1 */
}
.bb-ct-field__count { text-align: right; }

.bb-ct-field__err {
  margin: var(--bb-s1) 0 0;
  font-family: var(--bb-font-body);
  font-size: 0.8125rem; /* 13px */
  line-height: 1.5;
  color: var(--bb-ink); /* 15,81:1 */
  font-weight: 700;
}
/* Vacio no ocupa: el parrafo existe siempre en el DOM (para
   aria-describedby y para que el JS escriba dentro), pero mientras no
   diga nada no debe abrir hueco. :empty es exacto aqui porque el JS
   escribe con textContent. */
.bb-ct-field__err:empty { margin: 0; }

/* --- SELECT ---
   appearance: none y chevron propio. El chevron es un SVG en data: URI:
   regla dura de cero peticiones a terceros, y ademas una imagen externa
   para 12x8px seria una peticion por una flecha. El color va escrito en
   el data: URI (%23565451 = --bb-body) porque un data: URI no hereda
   currentColor. */
.bb-ct-field__selwrap { position: relative; }
.bb-ct-field__select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: var(--bb-s3);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23565451' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 2px center;
  background-size: 12px 8px;
  cursor: pointer;
}
/* El desplegable en su estado vacio se lee como marcador de posicion, no
   como un valor elegido. */
.bb-ct-field__select:invalid { color: var(--bb-body); }
/* La lista desplegada la pinta el sistema operativo, no el CSS; esto solo
   asegura que las opciones se lean en papel si el navegador las hereda. */
.bb-ct-field__select option { color: var(--bb-ink); }

/* --- CASILLA DE CONSENTIMIENTO ---
   Se estila EL PROPIO input con appearance: none. No se oculta con
   display:none ni se tapa con un <span> falso: asi conserva su rol, su
   estado (marcado / no marcado) y su foco nativos, que es justo lo que
   se pierde con la tecnica del span.
   La marca es un SVG en data: URI y no un ::after: un input es un
   elemento reemplazado y el soporte de pseudoelementos sobre el, aunque
   funciona en los navegadores actuales, no esta garantizado por la
   especificacion. background-image si lo esta. */
.bb-ct-check {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  gap: var(--bb-s2);
  align-items: start;
}
/* 22px Y NO 16px. WCAG 2.2 (2.5.8, AA) pide 24x24 para un objetivo; la
   <label> asociada ya amplia el area pulsable muy por encima de eso,
   pero 16px en la casilla OBLIGATORIA de un formulario es incomodo de
   acertar. 22px se queda a 2px del umbral sin desequilibrar la linea de
   texto de 15px/1.6 (24px de alto de linea): con 1px de margen superior
   la casilla queda centrada en su renglon. */
.bb-ct-check__box {
  appearance: none;
  -webkit-appearance: none;
  width: 22px;
  height: 22px;
  margin: 1px 0 0;
  background: transparent;
  border: 1px solid var(--bb-ink);
  border-radius: 0;
  cursor: pointer;
  /* El objetivo tactil real se agranda con el propio <label>, que es
     clicable entero y mide bastante mas de 44px de alto. */
}
.bb-ct-check__box:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8.5 6.2 11.7 13 4.9' fill='none' stroke='%232E4A42' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  /* La marca crece con la casilla y mantiene la misma proporcion que
     tenia a 16px (14/16 = 19,25/22, redondeado a 19px). */
  background-size: 19px 19px;
}
.bb-ct-check__box:focus-visible {
  outline: 2px solid var(--bb-accent);
  outline-offset: 3px;
}
.bb-ct-field--check.is-error .bb-ct-check__box { border-width: 2px; }

.bb-ct-check__label {
  font-family: var(--bb-font-body);
  font-size: 0.9375rem; /* 15px */
  line-height: 1.6;
  color: var(--bb-body); /* 6,94:1 */
  cursor: pointer;
}
.bb-ct-check__label .bb-link { color: var(--bb-accent); } /* 8,88:1 */

/* --- HONEYPOT ---
   Fuera de pantalla y NO display:none. Un display:none lo detectan ya
   bastantes bots (y algunos navegadores no envian el campo), mientras que
   una posicion fuera del viewport lo deja en el DOM y en el envio, que es
   lo que la trampa necesita. El envoltorio lleva aria-hidden en el HTML,
   asi que ningun lector de pantalla lo anuncia. */
.bb-ct-form__hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* --- PIE DEL FORMULARIO --- */
.bb-ct-form__foot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--bb-s2);
  margin-bottom: var(--bb-s4);
}
.bb-ct-form__submit { cursor: pointer; }
.bb-ct-form__submit[disabled] { opacity: 0.55; cursor: progress; }
.bb-ct-form__note {
  margin: 0;
  font-family: var(--bb-font-body);
  font-size: 0.8125rem; /* 13px */
  line-height: 1.5;
  color: var(--bb-body); /* 6,94:1 */
}

/* --- MINI TEXTO LEGAL --- */
.bb-ct-form__legal {
  margin: 0;
  padding-top: var(--bb-s3);
  border-top: 1px solid var(--bb-ink-soft);
  font-family: var(--bb-font-body);
  font-size: 0.75rem; /* 12px */
  line-height: 1.7;
  color: var(--bb-body); /* 6,94:1 medidos (caso 5) */
}
.bb-ct-form__legal strong { color: var(--bb-ink); }

/* --- RESUMEN DE ERRORES --- */
.bb-ct-errors {
  margin: 0 0 var(--bb-s4);
  padding: var(--bb-s3);
  background: var(--bb-white);
  /* Filete de acento a la izquierda: la senial no es solo el color, es
     tambien la posicion y el texto del titulo. */
  border-left: 3px solid var(--bb-accent);
}
.bb-ct-errors:focus-visible { outline: 2px solid var(--bb-accent); outline-offset: 3px; }
.bb-ct-errors__title {
  margin: 0 0 var(--bb-s1);
  font-family: var(--bb-font-display);
  font-weight: 700;
  font-size: 0.9375rem;
  color: var(--bb-ink);
}
.bb-ct-errors__list {
  margin: 0;
  padding-left: var(--bb-s3);
  font-family: var(--bb-font-body);
  font-size: 0.875rem; /* 14px */
  line-height: 1.7;
  color: var(--bb-body);
}
.bb-ct-errors__list a { color: var(--bb-ink); text-decoration: underline; }

/* --- PANEL DE CONFIRMACION (sustituye al formulario) --- */
.bb-ct-ok__title { margin: 0 0 var(--bb-s3); }
.bb-ct-ok__p { margin: 0 0 var(--bb-s3); }
.bb-ct-ok__back { margin: var(--bb-s2) 0 0; }
.bb-ct-ok:focus-visible { outline: 2px solid var(--bb-accent); outline-offset: 6px; }

/* --------------------------------------------------------------------------
   QUE PASA DESPUES — tres pasos, filetes de separacion.
   Numero en Jost 700 y titulo en Jost 300: la mezcla bold/thin es el
   recurso tipografico aprobado por la clienta.
   -------------------------------------------------------------------------- */
.bb-ct-steps__list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.bb-ct-steps__item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--bb-s3);
  align-items: start;
  padding-block: var(--bb-s3);
  border-top: 1px solid var(--bb-ink-soft);
}
.bb-ct-steps__item:first-child { border-top: none; padding-top: 0; }

.bb-ct-steps__n {
  font-family: var(--bb-font-display);
  font-weight: 700;
  font-size: 1.5rem;
  line-height: 1;
  letter-spacing: 0.02em;
  color: var(--bb-ink);
}
.bb-ct-steps__title {
  margin: 0 0 var(--bb-s1);
  font-family: var(--bb-font-display);
  font-weight: 300;
  font-size: 1.25rem;
  line-height: 1.3;
  letter-spacing: 0.01em;
  color: var(--bb-ink);
}
.bb-ct-steps__text { margin: 0; }
.bb-ct-steps__note {
  margin: var(--bb-s4) 0 0;
  padding-top: var(--bb-s3);
  border-top: 1px solid var(--bb-ink-soft);
  font-family: var(--bb-font-body);
  font-size: 0.8125rem;
  line-height: 1.7;
  color: var(--bb-body);
}

/* --------------------------------------------------------------------------
   PREGUNTAS FRECUENTES — siempre abiertas, editorial.
   Pregunta en EB Garamond italica, respuesta en Mulish, filete de
   separacion. NO es un acordeon: ese recurso ya es el de las paginas de
   servicio.
   -------------------------------------------------------------------------- */
.bb-ct-faq__list { margin: 0; }
.bb-ct-faq__item {
  padding-block: var(--bb-s3);
  border-top: 1px solid var(--bb-ink-soft);
}
.bb-ct-faq__item:first-child { border-top: none; padding-top: 0; }

.bb-ct-faq__q {
  margin: 0 0 var(--bb-s1);
  font-family: var(--bb-font-lyric);
  font-weight: 400;
  font-style: italic;
  font-size: 1.375rem; /* 22px */
  line-height: 1.3;
  color: var(--bb-ink);
}
.bb-ct-faq__a { margin: 0; }

@media (min-width: 768px) {
  .bb-ct-faq__q { font-size: 1.5rem; }
}

/* --------------------------------------------------------------------------
   MAPA — marcador dibujado en CSS + tarjeta de papel.
   En la carga NO hay iframe: solo se inserta tras un clic (ver
   template-parts/contact/map.php y assets/js/contact.js).
   -------------------------------------------------------------------------- */
/* EL MARCO OCUPA EL ANCHO COMPLETO DE LA COLUMNA. Antes compartia el
   ancho con la tarjeta superpuesta (iframe 510px de una columna util de
   ~640px); ahora que la tarjeta esta debajo el mapa se lee entero.
   La proporcion 16/10 da el alto; el min-height se conserva como suelo
   por si la proporcion no se aplicara (contenedores en pista 1fr). */
.bb-ct-map__box {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 10;
  margin-bottom: var(--bb-s3);
  background: var(--bb-white);
  border: 1px solid var(--bb-ink-soft);
  min-height: 320px;
}

/* MARCADOR DIBUJADO Y BOTON "VER EL MAPA": RETIRADOS EL 13-10-2026.

   El mapa esperaba un clic y mientras tanto se pintaba una reticula de
   filetes con una chincheta (.bb-ct-map__stage, __grid, __pin) y un boton
   a pantalla completa (.bb-ct-map__load). La clienta ha pedido que el mapa
   se vea directamente, asi que el iframe lo sirve PHP y esos cinco
   selectores ya no tienen nodo al que aplicarse: se van con ellos.

   Lo que implica en privacidad esta anotado en template-parts/contact/map.php.
   Si vuelve el clic previo, el CSS esta en la copia del 13-10-2026. */

.bb-ct-map__frame {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 320px;
  border: 0;
}

/* TARJETA DE PAPEL — SIEMPRE DEBAJO DEL MAPA Y A TODO EL ANCHO.
   Superpuesta tapaba el marcador del estudio: medido, ocupaba el 42,4%
   del area del iframe y elementsFromPoint en el centro exacto del mapa
   la devolvia por encima del iframe. Ponerla a un lado no cabe (columna
   util ~640px = mapa 510 + tarjeta 320 + hueco) y cualquier esquina
   sigue invadiendo el centro, porque la tarjeta mide el 63% del ancho
   del mapa. Debajo es la unica posicion que garantiza que el marcador no
   se tapa nunca.

   AQUI NO SE USA bb_tag(). Renderiza un bloque de 120x120 en absoluto
   con top: 0 que empezaba 29px por encima del borde de la tarjeta y se
   comia el titulo y la mitad de la direccion (medido a 1512px y a
   390px), y ademas repetia el propio titulo ("Estudio" / "El estudio").
   Una caja de 120px dentro de una tarjeta de 320px es el 37% del ancho:
   bb_tag() es para la esquina de un panel grande, no para una tarjeta de
   datos. NO SE REUBICA NI SE LE HACE SITIO CON PADDING: no va.
   El padding superior vuelve a var(--bb-s3): los var(--bb-s4) de antes
   solo existian para dejar sitio a esa etiqueta.

   CERO CIFRAS DE CONTRASTE NUEVAS EN ESTE ARREGLO: no se cambia ni un
   color. El fondo de la tarjeta sigue siendo var(--bb-paper), asi que los
   ratios ya medidos de su texto (direccion en tinta 15,81:1, horario en
   var(--bb-body) 6,94:1, enlaces en acento 8,88:1) valen tal cual. Al
   bajar de encima del blanco del mapa al papel de la pagina, la tarjeta
   se distingue por su filete de 1px var(--bb-ink-soft) —el mismo que
   enmarca el mapa—, que es separacion de superficie y no de texto: no
   entra en el umbral 4,5:1. Si algun dia se le pone fondo blanco, hay que
   volver a medir y anotar aqui las cifras. */
.bb-ct-map__card {
  position: relative;
  z-index: 3;
  padding: var(--bb-s3);
  background: var(--bb-paper);
  border: 1px solid var(--bb-ink-soft);
}

/* Los datos en columnas. minmax(0, 200px) y nunca minmax(200px, ...):
   una pista con minimo fijo desborda el contenedor en cuanto no cabe.
   Una sola columna por debajo de 600px. */
.bb-ct-map__card-grid {
  display: grid;
  gap: var(--bb-s3);
}
@media (min-width: 600px) {
  .bb-ct-map__card-grid {
    grid-template-columns: repeat(auto-fit, minmax(0, 200px));
    gap: var(--bb-s3) var(--bb-s4);
  }
}
/* En la rejilla los margenes inferiores los sustituye el gap. */
.bb-ct-map__card-grid > * { margin-bottom: 0; }

.bb-ct-map__card-title {
  margin: 0 0 var(--bb-s2);
  font-family: var(--bb-font-display);
  font-weight: 500;
  font-size: var(--bb-size-label);
  text-transform: uppercase;
  letter-spacing: var(--bb-track-label);
  color: var(--bb-body);
}
.bb-ct-map__addr {
  margin: 0 0 var(--bb-s2);
  font-style: normal;
  font-family: var(--bb-font-body);
  font-size: var(--bb-size-body);
  line-height: 1.6;
  color: var(--bb-ink);
}
.bb-ct-map__hours {
  margin: 0 0 var(--bb-s3);
  font-family: var(--bb-font-body);
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--bb-body);
}
.bb-ct-map__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bb-s1) var(--bb-s3);
  margin: 0;
  font-family: var(--bb-font-display);
  font-weight: 500;
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
}
.bb-ct-map__links a { color: var(--bb-accent); } /* 8,88:1 */

/* A 900px solo crece el suelo del marco. La tarjeta YA NO se superpone:
   el bloque que la ponia en absoluto abajo a la derecha es exactamente
   lo que tapaba el marcador del mapa. */
@media (min-width: 900px) {
  .bb-ct-map__box { min-height: 420px; }
  .bb-ct-map__frame { min-height: 420px; }
}

.bb-ct-map__notice {
  margin: 0;
  font-family: var(--bb-font-body);
  font-size: 0.75rem; /* 12px */
  line-height: 1.6;
  color: var(--bb-body); /* 6,94:1 */
}
.bb-ct-map__notice a { color: var(--bb-accent); }

/* --------------------------------------------------------------------------
   MOVIMIENTO REDUCIDO — todo en su estado final visible.

   Ni cortina (la retira home-curtain.css), ni panel fijo, ni Ken Burns, y
   NINGUN recorte: los bloques que en modo normal abre page-reveals.js
   quedan visibles porque este CSS nunca les aplica clip-path por su
   cuenta. Que no haya aqui ninguna regla de clip-path es la garantia.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .bb-ct__aside {
    position: static;
  }
  .bb-ct__frame,
  .bb-ct__img,
  .bb-ct__label,
  .bb-ct__h1,
  .bb-ct__lead,
  .bb-ct__nap,
  .bb-ct__social {
    animation: none;
  }
  .bb-ct__frame { clip-path: none; }
}
