/* ============================================================================
   BreedVerified: Sistema visual base
   Paleta compartida con FinanzaX Decide por decisión de marca documentada en
   docs/BreedVerified-Doc00.md (negro puro + acento dorado), pero este
   archivo se escribió desde cero para este proyecto: no hay importación ni
   copia de código entre los dos repositorios.
   ========================================================================== */
:root {
  --negro: #0C0C0F;
  --superficie: #141418;
  --superficie-alta: #1B1B20;
  --borde: #2A2A30;
  --texto: #F2F0EA;
  --tenue: #A8A29A;
  --dorado: #8A6A14;
  --dorado-hover: #6E5410;
  --dorado-texto: #D9A93B;
  /* Solid-fill button gold: #8A6A14 on --negro text is 3.86:1, below the
     4.5:1 WCAG AA text threshold (Agente 8, "Los Genios del Marketing
     Digital", 21 sep 2026). #B8891F keeps the same hue family but clears
     AA (6.17:1); the hover/focus state reuses --dorado-texto (9.01:1),
     already used elsewhere as the bright accent, so it reads as a real
     state change, not a coincidence. Scoped to .boton-principal and
     .saltar-al-contenido, the only two places --dorado backs body text;
     --dorado itself is left alone for the many decorative/border and non-
     text uses (accent overlays, card borders, icon hover) elsewhere in
     this file, which meet the lower 3:1 non-text/graphics threshold. */
  --dorado-boton: #B8891F;

  --fuente: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --texto-xs: 0.8rem;
  --texto-sm: 0.9rem;
  --texto-base: 1rem;
  --radio: 6px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  /* `clip`, not `hidden`: clips the horizontal overflow that the
     100vw-breakout pattern (.hero-dividido, .ficha-envoltorio) would
     otherwise cause, without turning html/body into a scroll container.
     `overflow-x: hidden` here disabled `position: sticky` on every
     descendant sitewide (Chrome/Safari: any axis of html/body set to
     something other than visible makes them the scrolling box, and a
     sticky element's nearest scrolling ancestor stops being the real
     viewport) -- found 22 sep 2026 building the Shop ficha's sticky
     cover, which fell back to scrolling away like `position: static`.
     `clip` has no scroll-container side effect and needs no `auto`
     partner on the other axis. Verified: no horizontal scrollbar
     (scrollWidth == clientWidth) and sticky holds its `top` across a
     scroll on both html and body. */
  overflow-x: clip;
  overflow-y: visible;
  background: var(--negro);
  color: var(--texto);
  font-family: var(--fuente);
  font-size: 16px;
  line-height: 1.6;
}

/* Cross-document View Transitions (page-to-page morphs). Pure CSS opt-in,
   no JavaScript: a browser without support ignores the at-rule and
   navigation behaves exactly as before, never broken or half-applied.
   Only three single-instance elements get a shared name; two elements can
   never share a name in one document (the transition would silently turn
   off), and build-pages.py fails the build if a page ever does:
     - the HEADER logo only (the footer repeats class="logo"),
     - the breed page's main photo (.foto-raza, one per breed page),
     - the split-hero photo on the home, /dogs/ and /cats/ pages. */
@view-transition { navigation: auto; }
.cabecera .logo { view-transition-name: bv-logo; }
.foto-raza { view-transition-name: bv-foto-raza; }
.hero-dividido-foto { view-transition-name: bv-hero-foto; }
/* Both photos live in boxes that keep the same proportions between pages,
   but `cover` guarantees a morph never squashes a photo if they differ. */
::view-transition-old(bv-foto-raza), ::view-transition-new(bv-foto-raza),
::view-transition-old(bv-hero-foto), ::view-transition-new(bv-hero-foto) {
  height: 100%; object-fit: cover;
}
/* The pseudo-element tree these transitions create is not part of the
   normal DOM, so a universal reduced-motion rule elsewhere would not reach
   it: it is switched off separately. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) {
    animation: none !important;
  }
}

/* Breed pages only: a whisper of life in the empty black side margins,
   never touching the centered .medida content column itself. The tint
   comes from --acento-pagina, a color unique to that breed's own main
   photo (set inline per page), so no two breed pages share the same
   glow. Fades to pure black well before reaching the content column. */
body.pagina-acentuada {
  background:
    radial-gradient(900px 700px at -5% 120px,
      color-mix(in srgb, var(--acento-pagina, var(--dorado)) var(--acento-intensidad, 16%), var(--negro)) 0%,
      var(--negro) 60%),
    radial-gradient(900px 700px at 105% 640px,
      color-mix(in srgb, var(--acento-pagina, var(--dorado)) var(--acento-intensidad, 16%), var(--negro)) 0%,
      var(--negro) 60%),
    var(--negro);
}

a { color: var(--dorado-texto); text-decoration: none; }
a:hover, a:focus-visible { text-decoration: underline; }

.contenedor { max-width: 1100px; margin: 0 auto; padding: 0 24px; }
.medida { max-width: 72ch; }

.saltar-al-contenido {
  position: absolute; left: -999px; top: 0; background: var(--dorado-boton);
  color: var(--negro); padding: 0.6rem 1rem; z-index: 100;
}
.saltar-al-contenido:focus { left: 0; }

.cabecera {
  border-bottom: 1px solid var(--borde);
  padding: 1.1rem 0;
}
.cabecera-fila {
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
}
.logo {
  display: flex; align-items: center; gap: 0.55rem;
  font-weight: 700; font-size: 1.15rem; color: var(--texto);
}
.logo-marca { color: var(--dorado-texto); }
.logo-icono { display: block; width: 28px; height: 28px; }
/* Wraps the nav and the index button as ONE flex child of .cabecera-fila
   (which keeps exactly two children: logo and this), so the utility button
   never spreads out with uneven gaps under space-between. The space
   between the nav links and the button is explicit (margin-left on
   .boton-indice plus a divider), never a shared gap: a utility button must
   read as a separate function, not as a fifth nav destination. */
.cabecera-derecha { display: flex; align-items: center; flex-wrap: nowrap; }
.nav-principal { display: flex; gap: 1.5rem; flex-shrink: 0; }
.nav-principal a { color: var(--tenue); font-size: 0.95rem; }
.nav-principal a:hover, .nav-principal a:focus-visible { color: var(--dorado-texto); }

.boton-indice {
  display: inline-flex; align-items: center; justify-content: center;
  position: relative;
  width: 34px; height: 34px; flex: none;
  margin-left: 1.75rem;
  border-radius: var(--radio); border: 1px solid var(--borde);
  background: transparent; color: var(--tenue); cursor: pointer; padding: 0;
  font-family: inherit;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.boton-indice[hidden] { display: none; }
/* Divider centered in the 1.75rem margin above: if that margin changes,
   move `left` to half of the new value. */
.boton-indice::before {
  content: '';
  position: absolute;
  left: -0.875rem; top: 50%;
  transform: translateY(-50%);
  width: 1px; height: 22px;
  background: var(--borde);
}
.boton-indice:hover, .boton-indice:focus-visible { color: var(--texto); border-color: var(--tenue); }

/* Desktop-only anticipation cues, gated by (hover: hover) and
   (pointer: fine): the plain color change above already works for
   everyone, and none of this ever replaces a tap or a click. The underline
   is a background gradient, not a pseudo-element, so it is never clipped
   by the horizontally scrolling .barra-razas. */
@media (hover: hover) and (pointer: fine) {
  .nav-principal a, .barra-razas a {
    background: linear-gradient(currentColor, currentColor) left bottom / 0 1px no-repeat;
    transition: color 0.2s ease, background-size 0.25s ease;
  }
  .nav-principal a:hover, .nav-principal a:focus-visible,
  .barra-razas a:hover, .barra-razas a:focus-visible {
    background-size: 100% 1px;
    text-decoration: none;
  }
  a.tarjeta {
    transition: transform 0.2s ease, border-color 0.2s ease;
  }
  a.tarjeta:hover, a.tarjeta:focus-visible {
    transform: translateY(-2px);
    border-color: var(--dorado);
    text-decoration: none;
  }
}

main { padding: 3.5rem 0 4rem; }

/* Split hero: a real photo on the right, fading into the site's own
   black from its left edge (never a hard cut), with left-aligned
   headline/value-prop/CTA on the left. Used on the homepage (dog+cat
   together) and, with a single-species photo each, on the /dogs/ and
   /cats/ index heroes only, never on individual breed pages (each of
   those already has its own real photo doing that job). Full viewport
   width via the classic negative-margin breakout, since the page body
   otherwise lives inside .contenedor's max-width. */
.hero-dividido {
  position: relative;
  width: 100vw;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
  margin-top: -3.5rem;
  margin-bottom: 2.5rem;
  min-height: 480px;
  display: flex;
  align-items: stretch;
  overflow: hidden;
  background: var(--negro);
}
.hero-dividido-texto {
  position: relative;
  z-index: 1;
  width: 46%;
  flex: none;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.25rem;
  padding: 3rem clamp(1.5rem, 4vw, 3.5rem) 3rem clamp(1.5rem, 6vw, 6rem);
}
.hero-dividido-texto h1,
.hero-dividido-texto p { text-align: left; }
.hero-dividido-texto p { color: var(--texto); font-size: 1.05rem; }
.hero-dividido-foto { position: relative; width: 54%; flex: none; }
.hero-dividido-foto img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero-dividido-foto::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(to right, var(--negro) 0%, rgba(12,12,15,0) 40%),
    radial-gradient(90% 90% at 48% 42%, rgba(12,12,15,0) 20%, var(--negro) 100%);
}

/* /dogs/ and /cats/ share ONE hero size (user decision, 19 sep 2026): the
   photo box is 54% wide and always 4:5, whatever the proportions of the
   photo inside it. The image leaves the flow (absolute) and covers the box,
   so a landscape photo is cropped at the sides rather than setting its own
   height. Before this, each hero took its height from its own photo (4:5 for
   the cat, 16:9 for the dog). Home does not use this class. On a phone the
   box is the plain 100% x 280px strip of .hero-dividido, for both pages. */
@media (min-width: 781px) {
  .hero-dividido-uniforme .hero-dividido-foto { aspect-ratio: 4 / 5; }
  .hero-dividido-uniforme .hero-dividido-foto img { position: absolute; inset: 0; }
}

@media (max-width: 780px) {
  .hero-dividido { flex-direction: column; min-height: 0; }
  .hero-dividido-texto { width: 100%; padding: 2.25rem 1.5rem 1.5rem; }
  .hero-dividido-foto { width: 100%; height: 280px; order: -1; }
  .hero-dividido-foto::after {
    background:
      linear-gradient(to bottom, rgba(12,12,15,0) 55%, var(--negro) 100%),
      radial-gradient(120% 90% at 50% 42%, rgba(12,12,15,0) 20%, var(--negro) 100%);
  }
}
h1 { font-size: clamp(2rem, 1.4rem + 2vw, 2.9rem); line-height: 1.1; margin: 0 0 0.75rem; }
h2 { font-size: 1.5rem; margin: 2.25rem 0 0.75rem; }
p { margin: 0 0 1rem; }
/* The lead paragraph directly under an h1, on breed pages and legal
   pages alike. Used to be two different hardcoded inline values
   (1.08rem, 1.1rem) that drifted apart between templates with no
   shared source of truth (Agente 7 finding, 6 sep 2026). One class. */
.parrafo-lead { font-size: 1.1rem; }
.tenue { color: var(--tenue); }

.tarjeta {
  background: var(--superficie);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  padding: 1.5rem;
}

.rejilla {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1.25rem;
  margin: 1.5rem 0;
}

/* Affiliate product card, ".tarjeta" plus a photo and a price/CTA row.
   Approved design (6 sep 2026, see productos_recomendados() in
   build-pages.py): reuses the existing .rejilla/.tarjeta grid rather
   than a new layout. Built then so the markup pattern and visuals were
   locked in, but not called from any page yet: the plan was to add
   this block breed by breed only once real, verified, breed-specific
   products and real affiliate links existed -- which happened
   2026-09-10 with the first Neakasa approvals.

   The CTA started as .boton-secundario on purpose, so it would not
   compete with the lead magnet's gold CTA on the same page. Reversed
   2026-09-10, once real cards actually shipped: reviewed on-page, a
   quiet button read as a low-effort recommendation, undermining an
   affiliate pick the copy already frames as genuinely worth buying.
   Now .boton-principal, the same solid gold as the lead-magnet CTA.
   Both are real calls to action on the page; nothing here uses the
   separate metallic/shine treatment (that exists in a sibling project,
   reserved for one specific calculator result, not a button). */
.tarjeta-producto { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.tarjeta-producto-foto {
  aspect-ratio: 4 / 3;
  background: var(--superficie-alta);
  border-bottom: 1px solid var(--borde);
  display: flex; align-items: center; justify-content: center;
}
.tarjeta-producto-foto img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Banner de red de afiliados (ej. Awin cshow.php): imagen fija de baja
   resolucion (300x250 tipico), nunca una foto propia de alta resolucion.
   Estirarla con width/height:100% como el caso normal de arriba la
   agranda muy por encima de su tamano nativo dentro de una card ancha,
   viendose borrosa (confirmado: contenedor renderizado a 676x564 contra
   una imagen nativa de 300x250, un estiro de 2.25x). Esta variante nunca
   crece mas alla de su tamano real; si la card es mas angosta que 300px
   se reduce proporcionalmente, nunca al reves.

   El CONTENEDOR tambien necesita su propia variante (no solo la img):
   dejar .tarjeta-producto-foto con su aspect-ratio:4/3 normal, a lo
   ancho de toda la card, deja un marco vacio grande alrededor de la
   imagen ya reducida a su tamano real -- se ve como una caja vacia con
   una imagen chica flotando adentro (encontrado 2026-09-10, revision
   visual tras el fix de arriba). Esta variante hace que el contenedor
   se ajuste al tamano real de la imagen en vez de forzar la caja
   ancha/alta original. */
.tarjeta-producto-foto.tarjeta-producto-foto-nativo {
  aspect-ratio: unset;
  width: fit-content;
  max-width: 100%;
  align-self: center;
}
.tarjeta-producto-foto img.imagen-tamano-nativo {
  width: auto; height: auto; max-width: 100%; max-height: 100%; object-fit: contain;
}
.tarjeta-producto-cuerpo {
  padding: 1.1rem 1.25rem 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex: 1;
}
.tarjeta-producto-cuerpo h3 { margin: 0; font-size: 1.02rem; }
.tarjeta-producto-nota { margin: 0; flex: 1; }
.tarjeta-producto-pie {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 0.35rem;
}
.tarjeta-producto-precio { font-weight: 700; font-size: 1rem; }
.tarjeta-producto-boton { padding: 0.5rem 1rem; font-size: 0.88rem; }
/* Sits below the price/CTA row, not repeated as a full sentence on
   every card: the one full FTC-style disclosure sentence lives once,
   above the whole grid (see productos_recomendados()), so this is
   just a quiet per-link marker. */
.etiqueta-afiliado {
  display: block;
  margin-top: 0.6rem;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--tenue);
}

/* Compact ebook promo card (Home, /dogs/, 2026-09-22): cover beside text,
   moderate size, deliberately not a hero. Neither .hero-dividido nor
   .ficha-fila/.ficha-visual fit here without fighting their own mechanics:
   .hero-dividido depends on the 100vw/negative-margin breakout, which
   *is* the hero effect this card exists to avoid; .ficha-fila's sticky
   320px visual column is built for the full Shop ficha, not for shrinking
   into a card. New, small, additive class instead, reusing the existing
   .tarjeta box (background/border/radius) and the price+button row
   pattern already proven in .tarjeta-producto-pie/-precio. */
/* Proportion (2026-09-22, commit 2100d9f): 210px, sized to keep the same
   ~34% image share as the Shop ficha's 320px cover against its 624.8px
   text column (a relative-proportion match, since this card's own row is
   narrower, ~626px). Flat single-layer shadow, no tilt -- a real product
   thumbnail, not a framed photo.

   2026-09-27, same day: briefly replaced with the ficha's absolute 320px
   size and its full tilt/shadow treatment everywhere a cover appears.
   Reverted the same day after Wilfre reviewed it: at that size and with
   the 3D tilt, the cover read as "a photo in a frame" and oversized for a
   compact card, not as a normal product image. Back to this file's
   original 2100d9f criterion -- proportion of the row it actually lives
   in, not a fixed absolute number borrowed from a different, much wider
   context (Shop's own full-width ficha). See .hero-ebook-chip-portada
   below for the same criterion measured fresh against its own, different
   row width. (Shop's own comparator cards, further down this file, later
   moved to a third treatment -- literally reusing the ficha's own 320px
   .ficha-visual component instead of a scaled proportion; that change is
   specific to the comparator and does not apply here.) */
.tarjeta-ebook { display: flex; align-items: center; gap: 1.5rem; }
.tarjeta-ebook-portada { flex: none; width: 210px; }
.tarjeta-ebook-portada img {
  width: 100%; display: block; border-radius: 4px;
  box-shadow: 0 8px 20px -10px rgba(0, 0, 0, 0.5);
}
.tarjeta-ebook-cuerpo { flex: 1 1 0; min-width: 0; }
.tarjeta-ebook-precio-fila {
  display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap;
  margin-top: 0.9rem;
}
.tarjeta-ebook-precio { font-weight: 700; font-size: 1.05rem; }
/* Button full width (2026-09-28): diagnosed live after Wilfre flagged an
   empty gap next to the button on Home, where .tarjeta-ebook-cuerpo is
   now only ~222px wide (ecc8502's 2-column grid, half of a 506px card).
   .tarjeta-ebook-cuerpo itself was already filling the card correctly
   (flex:1 1 0, measured flush to the card's padded edge -- not the bug).
   The real cause: the button's own single-line content ("See what is
   inside the ebook") measures ~258px, wider than the 222px row, so it
   was wrapping onto its own flex line and then shrinking down to fit --
   an unpredictable, awkward mid-word wrap rather than a deliberate
   layout. Made it explicit instead: full width, same convention already
   used by .ficha-visual-compra .boton in the Shop ficha. It still sits
   next to the price when there's room (wider columns); flex-wrap already
   drops it to its own line otherwise, now sized on purpose instead of by
   accident. */
.tarjeta-ebook-precio-fila .boton { width: 100%; }
@media (max-width: 560px) {
  .tarjeta-ebook { flex-direction: column; align-items: flex-start; }
  .tarjeta-ebook-portada { width: 140px; }
}

/* Separates two adjacent gold-CTA blocks (e.g. an affiliate product card
   right before the lead-magnet form) so they read as two distinct page
   sections, not one competing immediately after the other. No color
   change on purpose (Agente 6 finding, 2026-09-10, reviewed with Wilfre):
   both stay .boton-principal; the fix is space and a real dividing line,
   not demoting either button. Neutral --borde, not --dorado, so the line
   itself doesn't read as a third accent competing for attention. */
.separador-seccion {
  border-top: 1px solid var(--borde);
  margin: 3.5rem 0 0.5rem;
}

.boton {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0.75rem 1.4rem; border-radius: var(--radio); font-weight: 600;
  font-size: 0.98rem; border: 1px solid transparent; cursor: pointer;
  text-decoration: none;
}
.boton-principal { background: var(--dorado-boton); color: var(--negro); }
.boton-principal:hover, .boton-principal:focus-visible { background: var(--dorado-texto); text-decoration: none; }
.boton-secundario { background: transparent; color: var(--texto); border-color: var(--borde); }
.boton-secundario:hover, .boton-secundario:focus-visible { border-color: var(--dorado); color: var(--dorado-texto); text-decoration: none; }
.grupo-botones { display: flex; flex-wrap: wrap; gap: 0.9rem; }

.aviso-construccion {
  background: var(--superficie);
  border: 1px dashed var(--borde);
  border-radius: var(--radio);
  padding: 1.5rem;
  margin: 1.5rem 0;
}

/* ============================================================================
   Ficha de venta (Shop): portada como protagonista, fija (sticky) en una
   columna mientras la columna de texto se lee. Escritura del panel de
   marketing "Los Genios del Marketing Digital", segunda corrida, 22 sep
   2026, dirección B ("portada grande fija, sin animar") elegida por el
   dueño sobre tres bocetos. Mismo truco de fuga de .medida (72ch) que ya
   usa .hero-dividido: 100vw + margen negativo, para volver a abrir hasta
   el ancho de .contenedor (1100px) sin tocar armazon().
   ========================================================================== */
.ficha-envoltorio {
  position: relative; width: 100vw; left: 50%; right: 50%;
  margin-left: -50vw; margin-right: -50vw;
}
.ficha-fila { display: flex; align-items: flex-start; gap: 56px; padding: 0.5rem 0 3rem; }
.ficha-texto { flex: 1 1 0; min-width: 0; max-width: 62ch; }
.ficha-texto h1 { margin-top: 0; }
.ficha-texto h2 { margin-top: 2.25rem; }
.ficha-visual { width: 320px; flex: none; position: sticky; top: 88px; }
.ficha-portada-marco {
  border-radius: 6px; overflow: hidden; position: relative;
  box-shadow: 0 30px 60px -15px rgba(0, 0, 0, 0.65), 0 0 0 1px rgba(255, 255, 255, 0.05);
  transform: perspective(1400px) rotateY(-6deg);
}
.ficha-portada-marco img { width: 100%; display: block; }
/* Compact buy button inside the 320px sticky column, distinct from the
   main .boton-principal usage elsewhere which sizes to its own content:
   full column width and a touch smaller so "Buy now, $54.99" never wraps
   or crowds the fixed-width column. */
.ficha-visual-compra { margin-top: 1.1rem; }
.ficha-visual-compra .boton { width: 100%; font-size: 0.92rem; padding: 0.7rem 1rem; }
.ficha-visual-stats { margin-top: 1.1rem; display: flex; flex-direction: column; gap: 0.5rem; }
.ficha-visual-stats span { display: flex; align-items: center; gap: 0.5rem; font-size: 0.85rem; color: var(--tenue); }
.ficha-visual-stats .punto { width: 5px; height: 5px; min-width: 5px; border-radius: 50%; background: var(--dorado-texto); }
@media (max-width: 900px) {
  .ficha-fila { flex-direction: column; gap: 2rem; }
  .ficha-texto { max-width: none; }
  /* order: -1 keeps the cover the first thing a phone visitor sees
     (still "protagonista"), not buried after ~9000px of text once the
     sticky sidebar collapses into a single column. */
  .ficha-visual { position: static; width: 100%; max-width: 300px; margin: 0 auto; order: -1; }
}

.ficha-precio-fila { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; margin: 1.4rem 0; }
.ficha-precio { font-size: 1.9rem; font-weight: 700; }
.ficha-enlace-politica { font-size: 0.9rem; }

.ficha-tabla { width: 100%; border-collapse: collapse; margin: 1rem 0 0.5rem; font-size: 0.92rem; }
.ficha-tabla th, .ficha-tabla td { text-align: left; padding: 0.55rem 0.75rem; border-bottom: 1px solid var(--borde); }
.ficha-tabla th { color: var(--tenue); font-weight: 600; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.03em; }
.ficha-tabla td:last-child, .ficha-tabla th:last-child { text-align: right; }

.ficha-muestra { margin: 1.25rem 0; }
.ficha-muestra-imagenes { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; margin: 0.75rem 0; }
.ficha-muestra-imagenes a { display: block; border-radius: var(--radio); overflow: hidden; border: 1px solid var(--borde); }
.ficha-muestra-imagenes img { width: 100%; display: block; }
.ficha-muestra-nota { font-size: var(--texto-sm); color: var(--tenue); margin-top: 0.4rem; }

.ficha-no-es { margin: 0; padding-left: 1.2rem; }
.ficha-no-es li { margin-bottom: 0.5rem; }

.ficha-refunds {
  background: var(--superficie); border: 1px solid var(--borde); border-radius: var(--radio);
  padding: 1.5rem 1.75rem; margin: 2rem 0 1.5rem;
}
.ficha-refunds h2 { margin-top: 0; }
.ficha-refunds p { margin: 0 0 0.9rem; }
.ficha-refunds p:last-child { margin-bottom: 0; }

.ficha-descargo { font-size: var(--texto-sm); color: var(--tenue); }

/* Alternates the sticky-visual/text column order between the two Shop
   fichas (2026-09-27, Wilfre's request after reviewing the two-ficha page):
   without this, both fichas read the same way top to bottom and the page
   feels like a repeated template instead of two distinct products. Applied
   to the cat ficha's .ficha-fila only; the dog ficha keeps its original,
   already-approved order (text left, cover right). order:-1 here only
   matters above the 900px breakpoint -- the existing mobile rule already
   forces .ficha-visual first on phones for both fichas, so nothing changes
   there. */
.ficha-fila--invertida .ficha-visual { order: -1; }

/* Shop comparator (2026-09-27): a fast "just let me buy" pair of cards
   above the two long detailed fichas, added after Wilfre reviewed the page
   and found the detailed fichas made the actual purchase decision too slow
   to reach. Equal size and treatment for both cards on purpose: neither
   book should read as the primary one. */
.comparador {
  display: grid; grid-template-columns: 1fr 1fr; gap: 2.5rem;
  margin: 2rem 0 3.5rem;
}
@media (max-width: 700px) {
  .comparador { grid-template-columns: 1fr; gap: 2rem; }
}
/* min-width:0 (2026-09-27, found by testing at 375px): without it, a 1fr
   grid track won't shrink narrower than its content's min-content size,
   and a child with an explicit 320px width (the cover, to match the
   ficha) counts toward that -- the card and its cover overflowed past the
   viewport edge instead of the cover's own max-width:100% kicking in.

   Boxless (2026-09-27, third revision same day): dropped the
   background/border/radius/padding box that wrapped each card. Wilfre
   sent reference screenshots of the target look: the cover floats
   directly on the page background, no surrounding card chrome -- the
   same look .ficha-visual already has in the detailed fichas below,
   which also sit with no box of their own. */
.comparador-tarjeta {
  text-align: center; display: flex; flex-direction: column; align-items: center;
  min-width: 0;
}
/* Cover: literally reuses .ficha-visual/.ficha-portada-marco, the same
   markup and classes as the detailed ficha's sticky sidebar below on this
   same page (2026-09-27, third revision same day). Superseded the prior
   same-day approach of a smaller (150px), flat, tiltless cover sized to
   this card's own ~34% proportion (the 2100d9f criterion) -- Wilfre's
   fresh reference screenshots showed the comparator cover should be the
   ficha's own component and size (320px, two-layer shadow, perspective
   tilt), not a scaled-down lookalike. This only applies here: Home's
   .tarjeta-ebook-portada and the /dogs//cats/ .hero-ebook-chip-portada
   keep the flat 2100d9f-proportion treatment from the prior revision,
   unchanged -- this is a Shop-comparator-specific reuse of the ficha's
   own dramatic sticky-cover component, not a reversal of that criterion
   elsewhere.

   Bug found and fixed 2026-09-28, above the 900px breakpoint only (below
   it, .ficha-visual is already position:static from its own responsive
   rule further down, so this never showed on phone/tablet widths): the
   reused .ficha-visual kept its position:sticky from the detailed ficha
   below, where a long article gives it room to make sense. Here,
   .comparador-tarjeta is barely taller than .ficha-visual itself (~30px
   of slack), so on scroll .ficha-visual sticks at top:88px and visually
   freezes there for that ~30px scroll window, while its sibling
   .comparador-detalles ("See all the details") is not sticky and keeps
   scrolling normally -- for that window the two paint on top of each
   other. Confirmed by toggling position live in the browser at 1920px:
   forcing this rule below removes the overlap outright, at every scroll
   position. Turning off sticky here doesn't affect the detailed ficha's
   own sidebar further down the page (different element instance, same
   class, unscoped .ficha-visual rule above still applies there). */
.comparador-tarjeta .ficha-visual { position: static; }
.comparador-detalles { font-size: 0.85rem; color: var(--tenue); margin-top: 0.5rem; }

/* Three-step trust strip (2026-09-27), between the comparator and the
   detailed fichas. Same for both books on purpose: it's about the
   methodology, not a single title, so it doesn't repeat per ficha. */
.pasos-confianza {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem;
  margin: 0 0 3rem; padding: 1.75rem 0;
  border-top: 1px solid var(--borde); border-bottom: 1px solid var(--borde);
}
@media (max-width: 700px) {
  .pasos-confianza { grid-template-columns: 1fr; gap: 1.1rem; text-align: center; }
}
.paso { display: flex; align-items: baseline; gap: 0.6rem; }
@media (max-width: 700px) { .paso { justify-content: center; } }
.paso-numero { font-weight: 700; color: var(--dorado-texto); font-size: 1.05rem; flex: none; }
.paso p { margin: 0; font-size: 0.95rem; }

/* /cats/ ebook mention, second attempt (2026-09-27). The first attempt (a
   full-width banner row, even a short one) still added a new row that
   pushed Neakasa down by its own height plus margins -- any extra row does
   that, regardless of how short. Wilfre's correction: don't add a row at
   all if the layout already has unused space to use instead. It does:
   .hero-dividido-texto is a flex column with justify-content:center inside
   a row whose height is set by .hero-dividido-foto (the photo), so the
   text column sits centered with real slack above and below it (measured
   live: ~312px of unused space on each side at desktop width). A compact
   chip added after the hero's own button grows the centered content block
   but not the row itself, so Neakasa (and everything else after the hero)
   sits at exactly the same position as before any ebook mention existed. */
/* Column layout, image top / info below (2026-09-27, final pass): tried a
   row layout first (image beside text, like .tarjeta-ebook) with
   flex-wrap for narrow widths; with max-width:fit-content it wrapped
   (stacked) even though everything fit on one line at the width it
   computed -- a real intrinsic-size/wrap-layout inconsistency in this
   engine, reproduced directly (forcing flex-wrap:nowrap at that exact
   width laid it out side by side with room to spare). Rather than fight
   it, made the column layout the deliberate design: image on top, info
   below, the same card language the comparator's own stacked cards
   already use. Two properties both needed to size it correctly, not one:
   align-items:flex-start keeps the image/info left-aligned instead of
   stretched to the card's width, and align-self:flex-start keeps the CARD
   ITSELF shrink-wrapped to its widest child (the 320px image) inside
   .hero-dividido-texto's own flex column, instead of stretching to fill
   the full text column width (measured both ways: 357.19px with
   align-self, a stray 504-602px without it depending on viewport). */
.hero-ebook-chip {
  display: flex; flex-direction: column; align-items: flex-start; gap: 1rem;
  align-self: flex-start;
  margin-top: 1.5rem; padding: 0.85rem 1.1rem;
  background: var(--superficie); border: 1px solid var(--borde); border-radius: var(--radio);
}
/* Title/price and the button, stacked below the cover. */
.hero-ebook-chip-info { display: flex; flex-direction: column; align-items: flex-start; gap: 0.75rem; }
/* Cover sized with the 2100d9f criterion (2026-09-27, reverted after a
   same-day detour to the ficha's absolute 320px + full tilt/shadow --
   Wilfre's review: "a photo in a frame," oversized for this chip).
   Measured THIS component's own available width live: .hero-dividido-texto
   is 504px of actual content width at desktop (644px outer minus its own
   left/right padding), the space this chip has to work with even though
   it doesn't stretch to fill it. Same ~34% share .tarjeta-ebook uses:
   504 * 0.34 = 171px, not the borrowed 320px. Flat single-layer shadow, no
   tilt. Title/price sizes brought back down from the sizes tuned for a
   320px cover -- they looked oversized and empty next to a cover this
   size. (Shop's own comparator cards moved to a third treatment since --
   reusing the ficha's 320px .ficha-visual component directly -- specific
   to that context, not a change to this chip's criterion.) */
.hero-ebook-chip-portada { width: 171px; max-width: 100%; flex: none; }
.hero-ebook-chip-portada img {
  width: 100%; display: block; border-radius: 4px;
  box-shadow: 0 8px 20px -10px rgba(0, 0, 0, 0.5);
}
.hero-ebook-chip-texto { display: flex; flex-direction: column; gap: 0.35rem; }
.hero-ebook-chip-titulo { font-size: 0.85rem; color: var(--tenue); }
.hero-ebook-chip-precio { font-weight: 700; font-size: 1.1rem; }

/* Breed page header photo. A real, licensed, high-quality photo of the
   specific breed goes here once sourced (Agent 12). Never a stock photo,
   never used as a full-page background, see BreedVerified-Doc00.md. */
.foto-raza {
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radio);
  overflow: hidden;
  margin-bottom: 1.5rem;
}
.foto-raza img { width: 100%; height: 100%; object-fit: cover; display: block; }
.foto-raza-pendiente {
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radio);
  margin-bottom: 1.5rem;
  border: 1px dashed var(--borde);
  background: var(--superficie);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 1.5rem;
}

/* Edge-to-edge, not boxed: with 10 breed names a centered pill wastes
   space, so this breaks out to full viewport width (same technique as
   .hero-dividido) and scrolls horizontally on narrow screens instead of
   wrapping to multiple lines. */
.barra-razas {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  position: relative;
  width: 100vw;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
  margin-bottom: 1.5rem;
  padding: 0.9rem clamp(1rem, 4vw, 3rem);
  background: var(--superficie);
  border-top: 1px solid var(--borde);
  border-bottom: 1px solid var(--borde);
  font-size: 0.85rem;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.barra-razas-etiqueta { color: var(--tenue); font-weight: 600; white-space: nowrap; flex: none; }
.barra-razas a, .barra-razas-actual { white-space: nowrap; flex: none; }
.barra-razas a { color: var(--tenue); }
.barra-razas a:hover, .barra-razas a:focus-visible { color: var(--dorado-texto); }
.barra-razas-actual {
  color: var(--dorado-texto);
  font-weight: 600;
  border-bottom: 2px solid var(--dorado);
  padding-bottom: 2px;
}

/* Sources-verified badge, same shape/spirit as FinanzaX Decide's "Pricing
   verified [date]" marker (.marcador-fecha / .punto-vivo there): a small
   pill above the breed's h1 stating when this page's sources were last
   checked. Adapted, not copied: this file has no shared code with FXD. */
.marcador-fecha {
  display: inline-flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
  font-size: var(--texto-sm); color: var(--tenue);
  border: 1px solid var(--borde); border-radius: 999px;
  padding: 0.35rem 0.85rem; margin-bottom: 1rem;
}
.punto-vivo {
  width: 7px; height: 7px; border-radius: 50%; background: var(--dorado-texto);
  flex: none;
}

/* Slow rotating gallery of extra breed photos, breed pages only (never
   category or index pages). Controls are always visible, never hidden
   behind hover, per BreedVerified-Doc00.md: auto-advance is a convenience,
   not the only way to move between photos. */
.galeria-raza {
  position: relative;
  margin: 0 0 1.5rem;
}
.galeria-pista {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radio);
  overflow: hidden;
  background: var(--superficie);
}
.galeria-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.6s ease;
}
.galeria-img.activa { opacity: 1; }
.galeria-boton {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  border: 1px solid var(--borde);
  background: rgba(12, 12, 15, 0.55);
  color: var(--texto);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.galeria-boton:hover, .galeria-boton:focus-visible {
  background: var(--dorado);
  color: var(--negro);
  border-color: var(--dorado);
}
.galeria-anterior { left: 0.6rem; }
.galeria-siguiente { right: 0.6rem; }
.galeria-puntos {
  display: flex;
  justify-content: center;
  gap: 0.4rem;
  margin-top: 0.6rem;
}
.galeria-punto {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  border: none;
  background: var(--borde);
  cursor: pointer;
  padding: 0;
}
.galeria-punto.activo { background: var(--dorado-texto); }

.datos-rapidos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 1px;
  background: var(--borde);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  overflow: hidden;
  margin: 1.5rem 0;
}
.dato-rapido {
  background: var(--superficie);
  padding: 1rem 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.dato-rapido .valor { font-weight: 700; font-size: 1.05rem; }
.dato-rapido .etiqueta { color: var(--tenue); font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.04em; }

.pregunta {
  border-bottom: 1px solid var(--borde);
  padding: 1.25rem 0;
}
.pregunta:last-child { border-bottom: none; }
.pregunta h3 { margin: 0 0 0.5rem; font-size: 1.1rem; }
.pregunta p { margin: 0; }

.nota-metodologia { font-size: var(--texto-sm); color: var(--tenue); margin-top: 1rem; }

.pie {
  border-top: 1px solid var(--borde);
  padding: 2.75rem 0 2rem;
  margin-top: 3rem;
  background: var(--superficie);
}
.pie p { color: var(--tenue); font-size: var(--texto-sm); }
.pie-rejilla {
  display: grid;
  gap: 1.75rem;
  margin-bottom: 1.75rem;
}
@media (min-width: 780px) {
  .pie-rejilla { grid-template-columns: 1.2fr 1fr 1fr 1fr; }
}
.pie-rejilla h4 {
  margin: 0 0 0.75rem;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--tenue);
}
.pie-rejilla ul { list-style: none; margin: 0; padding: 0; }
.pie-rejilla li { margin-bottom: 0.5rem; }
.pie-rejilla ul a { color: var(--texto); font-size: 0.9rem; text-decoration: none; }
.pie-rejilla ul a:hover, .pie-rejilla ul a:focus-visible { color: var(--dorado-texto); text-decoration: underline; }
p.pie-cta {
  border-top: 1px solid var(--borde);
  padding-top: 1.25rem;
  margin-bottom: 1.25rem;
  font-size: 0.95rem;
  color: var(--texto);
}
.pie-cta a { font-weight: 600; }
.pie-legal p { margin-bottom: 0.6rem; }
.pie-legal p:last-child { margin-bottom: 0; }

/* Homepage only (see foto_cta_pie in armazon()): same split pattern as
   .hero-dividido, scaled down to a banner, replacing an earlier
   full-bleed-background-behind-text version that read as a tight,
   disproportionate close-up with no real text/photo separation (real
   bug, fixed 6 sep 2026: see the "verificacion de recorte renderizado"
   note on object-position below). Every other page keeps the plain
   .pie-cta above, no split, no image.
   Full viewport width via the same negative-margin breakout as
   .hero-dividido and .barra-razas (real bug, 6 sep 2026: left boxed
   inside .pie's .contenedor, this read as a floating card with visible
   side margins and four rounded corners instead of a full-bleed strip
   like the hero above it). No border-radius here for the same reason
   .hero-dividido and .barra-razas have none: a full-bleed element has
   no visible edge for a corner to round against, so any radius just
   nicks a stray notch at the exact left/right edge of the viewport.
   min-height scales with viewport width (clamp, not a fixed 200px) so
   the photo panel's aspect ratio stays sane on very wide screens too:
   at a fixed 200px, a 44%-of-viewport-wide panel on a 2560px screen
   would need a much heavier vertical crop of the source photo than the
   200px figure was ever checked against. */
.pie-cta-dividido {
  position: relative;
  width: 100vw;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
  display: flex;
  align-items: stretch;
  overflow: hidden;
  margin-bottom: 1.25rem;
  min-height: clamp(200px, 16vw, 320px);
  background: var(--negro);
}
.pie-cta-dividido-texto {
  width: 56%;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
}
.pie-cta-dividido-texto .pie-cta {
  border-top: none;
  margin: 0;
  padding: 1.5rem clamp(1.25rem, 3vw, 2.5rem);
  max-width: 46ch;
  font-size: 1.4rem;
  line-height: 1.4;
}
.pie-cta-dividido-texto .pie-cta a { font-weight: 700; }
.pie-cta-dividido-foto { position: relative; width: 44%; flex: none; }
.pie-cta-dividido-foto img {
  /* No object-position default here on purpose: verify per image
     against this specific container's real proportions (see
     foto_cta_pie_pos in armazon()), never assume from the source file
     or copy a value from a differently-shaped container. */
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.pie-cta-dividido-foto::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to right, var(--negro) 0%, rgba(12,12,15,0) 42%);
}

@media (max-width: 680px) {
  .pie-cta-dividido { flex-direction: column; min-height: 0; }
  .pie-cta-dividido-texto { width: 100%; }
  .pie-cta-dividido-texto .pie-cta { font-size: 1.15rem; padding: 1.5rem 1.25rem; }
  .pie-cta-dividido-foto { width: 100%; height: 200px; order: -1; }
  .pie-cta-dividido-foto::after {
    background: linear-gradient(to bottom, rgba(12,12,15,0) 55%, var(--negro) 100%);
  }
}

@media (max-width: 640px) {
  .cabecera-fila { flex-wrap: wrap; gap: 0.75rem; position: relative; }
  .nav-principal { gap: 1rem; flex-wrap: wrap; flex-basis: 100%; }
  /* The nav always takes its own row under the logo at this width (flex-basis
     above), so the index button can leave the flow and stay in the top-right
     corner of the logo row without ever overlapping a nav link. Without
     flex-basis the nav only wrapped below ~484px, and between 484 and 640px
     the button sat on top of "Shop" (measured, Agente 7). */
  .cabecera-derecha { display: contents; }
  .boton-indice { position: absolute; top: -3px; right: 24px; margin-left: 0; }
  .boton-indice::before { display: none; }
}

/* Expanded site index (overlay). Native <dialog> (site-map-overlay.js):
   focus trap, ::backdrop and Escape-to-close come free, no custom modal.
   It complements the navigation, never replaces it. It paints in the
   browser's top layer, above .cookies (z-index 50) with no z-index war. */
.indice-dialogo {
  width: min(92vw, 940px);
  max-height: min(88vh, 820px);
  margin: auto;
  padding: 0;
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  background: var(--superficie);
  color: var(--texto);
  overscroll-behavior: contain;
}
.indice-dialogo[open] { display: flex; flex-direction: column; }
.indice-dialogo::backdrop { background: rgba(12, 12, 15, 0.78); }
html:has(.indice-dialogo[open]) { overflow: hidden; }
.indice-cabecera {
  flex: none;
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.1rem 1.35rem; border-bottom: 1px solid var(--borde);
  background: var(--superficie);
}
.indice-cabecera h2 { margin: 0; font-size: var(--texto-base); }
.indice-cerrar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  border: none; background: transparent; color: var(--tenue); cursor: pointer; padding: 0;
}
.indice-cerrar:hover, .indice-cerrar:focus-visible { color: var(--texto); }
.indice-cuerpo { padding: 1.35rem; overflow-y: auto; flex: 1; min-height: 0; }
.indice-grupo + .indice-grupo { margin-top: 1.75rem; }
.indice-grupo h3 {
  font-size: var(--texto-xs); text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--tenue); margin: 0 0 0.75rem;
}
.indice-rejilla { display: grid; gap: 0.75rem; grid-template-columns: repeat(2, 1fr); }
@media (min-width: 560px) { .indice-rejilla { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 880px) { .indice-rejilla { grid-template-columns: repeat(4, 1fr); } }
.indice-tarjeta {
  display: block; text-decoration: none; color: inherit;
  border: 1px solid var(--borde); border-radius: var(--radio);
  overflow: hidden; background: var(--superficie-alta);
  transition: border-color 0.2s ease;
}
.indice-tarjeta:hover, .indice-tarjeta:focus-visible { border-color: var(--dorado); text-decoration: none; }
.indice-tarjeta[aria-current="page"] { border-color: var(--dorado); }
/* height:auto is required: the width/height HTML attributes on the <img> (there to reserve space
   before it loads) would otherwise pin the height at 180px and override aspect-ratio. */
.indice-tarjeta img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; background: var(--negro); }
.indice-tarjeta-titulo { display: block; padding: 0.55rem 0.7rem; font-size: var(--texto-sm); font-weight: 600; }
@media (min-width: 560px) { .indice-tarjeta-titulo { font-size: var(--texto-base); } }
@media (hover: hover) and (pointer: fine) {
  .indice-tarjeta { transition: transform 0.2s ease, border-color 0.2s ease; }
  .indice-tarjeta:hover, .indice-tarjeta:focus-visible { transform: translateY(-2px); }
}

/* Cookie consent banner. Fixed to the bottom, present in every page's HTML
   but hidden by default via the native `hidden` attribute; consent.js
   reveals it only when there is no stored choice yet. */
.cookies {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 50;
  background: var(--superficie-alta);
  border-top: 1px solid var(--borde);
  padding: 1rem 0;
}
.cookies-fila {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.cookies-fila p { margin: 0; font-size: var(--texto-sm); color: var(--tenue); max-width: 60ch; }
.cookies-botones { display: flex; gap: 0.75rem; flex-shrink: 0; }
