/* =========================================================================
   Cinema HD — tema oscuro estilo plataforma de streaming
   Orden: tokens · reset · accesibilidad · layout · raíl · barra superior
          buscador · héroe · populares · pestañas · chips · rejilla · banner
          secciones · filtros · paginación · reproductor · episodios
          avisos · pie · barra inferior · responsive
   ========================================================================= */

/* ------------------------------------------------------------ 1. Tokens */
:root {
    /* Superficies. Cuatro escalones: cada uno sube ~1 punto de luz, lo justo
       para separar planos sin que el negro se vuelva gris. */
    /* #141414 es el fondo de Netflix y el del clon (PRIMARY.main en
       clonetemplate/src/theme/palette.ts). Los escalones de encima salen de
       las superficies que usa el mini-portal y el modal de detalle. */
    --bg:        #141414;
    --surface:   #181818;
    --surface-2: #2A2A2A;
    --surface-3: #333333;

    /* Texto sobre superficie opaca. Ratios medidos (WCAG 2.1; texto normal
       necesita 4.5:1):
         --text    19.99:1 sobre --bg  ·  18.66:1 sobre --surface
         --text-2   9.05:1 sobre --bg  ·   8.44:1 sobre --surface
         --text-3   5.23:1 sobre --bg  ·   4.88:1 sobre --surface
       --text-3 cae a 4.02:1 sobre --surface-3 y NO cumple ahí: en esa
       superficie el texto usa --text-2 (6.95:1). */
    --text:      #FFFFFF;
    --text-2:    #B3B3B3;   /* el gris de los textos secundarios de Netflix */
    --text-3:    #808080;

    /* Texto que va ENCIMA de una imagen (barra superior, buscador flotante,
       iconos del raíl). Bajo el velo superior del héroe —alfa .62— y con la
       imagen más desfavorable posible (blanco puro) --text-2 se queda en
       2.60:1. Este gris claro da 4.64:1 en ese mismo caso. */
    --text-media: #E4E7F0;

    /* Acento. --accent cumple como TEXTO sobre fondo oscuro (6.18:1 en --bg),
       pero el blanco sobre --accent sólo da 3.24:1. Todo relleno azul con
       texto blanco usa --accent-solid (4.91:1). */
    --accent:       #1E90FF;
    --accent-dark:  #0A6FD8;
    --accent-solid: #0A6FD8;
    --accent-tint:  rgba(30, 144, 255, .14);

    /* Rojo de destacado. Igual caso: --hot vale para bordes, halos e iconos
       (5.48:1 en --bg); los rellenos rojos con texto blanco usan --hot-deep
       (6.85:1). */
    --hot:       #FF2D55;
    --hot-deep:  #B3123A;
    --hot-tint:  rgba(255, 45, 85, .14);

    --star: #FFB800;   /* 11.53:1 sobre --bg: vale también como texto */
    --ok:   #34D399;
    --warn: #FBBF24;

    --border:   rgba(255, 255, 255, .08);
    --border-2: rgba(255, 255, 255, .16);
    /* Borde de las piezas de vidrio que van sobre la imagen. */
    --border-media: rgba(255, 255, 255, .22);

    /* Botones del clon: el principal es blanco sobre negro y el secundario un
       gris translúcido (#6d6d6eb3, y #6d6d6e66 al pasar por encima). No hay
       ningún botón azul en Netflix. */
    --btn:        #FFFFFF;
    --btn-texto:  #000000;
    --btn-2:      rgba(109, 109, 110, .7);
    --btn-2-hover: rgba(109, 109, 110, .4);

    /* Netflix apenas redondea: los carteles llevan 4 px y los botones 4 px. */
    --r-sm: 4px;  --r-md: 4px;  --r-lg: 6px;  --r-xl: 8px;  --r-pill: 4px;

    /* Sobre negro una sombra negra no se ve: la profundidad la da el borde
       claro. Las sombras sólo separan capas flotantes del contenido. */
    --sh-1: 0 1px 2px rgba(0, 0, 0, .5);
    --sh-2: 0 12px 32px rgba(0, 0, 0, .55);
    --sh-3: 0 28px 64px rgba(0, 0, 0, .7);
    --sh-accent: 0 10px 30px rgba(30, 144, 255, .35);
    --sh-hot:    0 14px 38px rgba(255, 45, 85, .45);

    /* Sin raíl de iconos: el clon no lo tiene y la navegación entera vive en
       la barra de arriba, como en Netflix. */
    --rail-w: 0px;
    /* 60 px de margen lateral y 70 px de barra: son las dos constantes del
       clon (px: "60px" en MainHeader y APP_BAR_HEIGHT en src/constant). */
    --gap: 60px;
    --header-h: 70px;
    --ease: cubic-bezier(.16, 1, .3, 1);
    --overlay-top: 0px;

    color-scheme: dark;
}

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

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    scroll-padding-top: 90px;
    background: var(--bg);
}

body {
    font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    background: var(--bg);
    color: var(--text);
    min-height: 100vh;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    overflow-x: hidden;
}

/* `hidden` vale display:none en la hoja del navegador, pero cualquier regla
   de autor con display (p. ej. .ep-grid{display:grid}) la gana. Sin esto se
   veían todas las temporadas a la vez. */
[hidden] { display: none !important; }

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
ul { list-style: none; }
svg { display: block; }
code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .9em;
    background: var(--surface-3); color: var(--text-2); padding: 2px 6px; border-radius: 6px;
}
hr { border: 0; border-top: 1px solid var(--border); }
::selection { background: var(--accent-solid); color: #fff; }

* { scrollbar-color: var(--surface-3) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 99px; }
::-webkit-scrollbar-thumb:hover { background: #33333F; }

/* ---------------------------------------------------- 3. Accesibilidad */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
:focus:not(:focus-visible) { outline: none; }

.skip-link {
    position: absolute; left: -9999px; top: 8px; z-index: 2000;
    background: var(--accent-solid); color: #fff; padding: 12px 18px;
    border-radius: var(--r-md); font-weight: 700;
}
.skip-link:focus { left: 12px; }

/* Existe para lectores de pantalla y buscadores, pero no se dibuja. No se usa
   display:none porque eso también lo oculta al lector. */
.solo-lectores {
    position: absolute !important; width: 1px; height: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
    /* Se anulan las transformaciones de reposo que responden al ratón; la
       escala de la tarjeta activa del carrusel se mantiene porque no es
       movimiento, es la marca de estado. */
    .card:hover .card-art,
    .pop-card:hover:not(.is-active),
    .btn-watch:hover, .btn-trailer:hover, .btn-list:hover { transform: none !important; }
}

/* ------------------------------------------------------------ 4. Layout */
/* Una sola columna a lo ancho de la pantalla, con 60 px de margen: el clon no
   centra el contenido en una caja, deja que las filas lleguen a los bordes. */
.shell {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
    max-width: none;
    margin: 0;
    padding: 0 var(--gap);
}
/* La barra de arriba es fija: sin este hueco el contenido nace debajo de ella.
   En la portada NO hace falta, porque el héroe pasa por detrás a propósito. */
body:not(:has(.hero)) .shell { padding-top: var(--header-h); }

/* Separación entre filas: 3vw es lo que deja el clon entre carruseles, así el
   espacio crece con la pantalla en lugar de quedarse fijo. */
.main { position: relative; min-width: 0; display: flex; flex-direction: column; gap: clamp(24px, 3vw, 52px); }

body:has(.railnav) { padding-left: 0; }

.scrim {
    position: fixed; inset: 0; z-index: 90;
    background: rgba(0, 0, 0, .72);
    backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
    animation: fade .2s ease;
}
@keyframes fade { from { opacity: 0 } to { opacity: 1 } }

/* --------------------------------------- 5. Raíl de iconos: ya no existe
   El clon no tiene columna de iconos a la izquierda: toda la navegación está
   en la barra de arriba. Se deja la regla que lo oculta porque el marcado aún
   lo pinta (y sigue sirviendo de menú en el modo televisor). */
.railnav { display: none; }

/* --------------------------------------------- 6. Barra superior (Netflix)
   Copiada de clonetemplate/src/components/layouts/MainHeader.tsx:
     · 70 px de alto y 60 px de margen lateral (APP_BAR_HEIGHT y px: "60px")
     · fija arriba y TRANSPARENTE mientras no se ha desplazado la página
     · al pasar de esos 70 px se rellena con el color de fondo y gana sombra
       (el hook useOffSetTop del clon; aquí lo pone app.js con .is-solido)
   ------------------------------------------------------------------------ */
.topnav {
    position: fixed; top: 0; left: 0; right: 0; z-index: 60;
    display: flex; align-items: center; gap: 24px;
    height: var(--header-h);
    padding: 0 var(--gap);
    background: transparent; border: 0;
    transition: background-color .3s ease, box-shadow .3s ease;
}
/* Degradado sutil hacia abajo mientras es transparente: sin él los enlaces se
   pierden sobre las zonas claras de la imagen. */
.topnav::before {
    content: ''; position: absolute; inset: 0 0 -40px; z-index: -1;
    background: linear-gradient(to bottom, rgba(0, 0, 0, .72), transparent);
    pointer-events: none;
    transition: opacity .3s ease;
}
.topnav.is-solido { background: var(--bg); box-shadow: 0 4px 20px rgba(0, 0, 0, .6); }
.topnav.is-solido::before { opacity: 0; }

/* Marca a la izquierda, en rojo y en versalitas, ocupando el sitio del logo. */
.topnav-brand {
    order: -1; flex: none;
    font-size: 1.35rem; font-weight: 900; letter-spacing: .04em;
    color: var(--hot); text-transform: uppercase; white-space: nowrap;
}
.topnav-brand:hover { color: var(--hot); }

.topnav-links { display: flex; align-items: center; gap: 20px; flex: none; min-width: 0; }
.topnav-links a {
    display: inline-flex; align-items: center;
    min-height: 40px;
    font-size: .87rem; font-weight: 400; color: #e5e5e5;
    white-space: nowrap;
    transition: color .2s;
}
.topnav-links a:hover { color: #b3b3b3; }
/* El enlace de la sección en la que estás va en blanco y con más cuerpo: es la
   única marca de activo que usa Netflix. */
.topnav-links a.is-active { color: #fff; font-weight: 700; }
/* Los separadores «·» entre enlaces desaparecen: el clon no los tiene. */
.topnav-links a + a::before { content: none; }

.topnav-user { display: flex; align-items: center; gap: 16px; flex: none; }
.topnav-nombre { font-size: .82rem; color: #e5e5e5; }
/* Avatar cuadrado con las esquinas apenas redondeadas (variant="rounded"). */
.avatar {
    width: 32px; height: 32px; border-radius: 4px;
    display: grid; place-items: center;
    background: var(--hot-deep); color: #fff; font-size: .8rem;
}
.topnav-menu { display: none; }

/* --------------------------------------------------------- 7. Buscador */
.searchbar {
    position: relative;
    display: flex; align-items: center;
    width: 100%; max-width: 640px;
}
.searchbar i, .searchbar > svg, .searchbar .searchbar-icon {
    position: absolute; left: 16px; z-index: 1;
    color: var(--text-media); opacity: .8; font-size: .82rem; pointer-events: none;
}
.searchbar input {
    width: 100%; min-height: 44px;
    padding: 11px 18px 11px 42px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-pill);
    font-size: .86rem; font-weight: 500; color: var(--text);
    transition: border-color .16s, box-shadow .16s, background .16s;
}
.searchbar input::placeholder { color: var(--text-media); opacity: .72; }
.searchbar input:focus {
    outline: none; border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-tint);
}
.searchbar input::-webkit-search-cancel-button { display: none; }
.searchbar button {
    position: absolute; right: 4px;
    width: 40px; height: 40px; display: grid; place-items: center;
    border-radius: 50%; color: var(--text-media);
}
.searchbar button:hover { background: rgba(255, 255, 255, .12); color: var(--text); }

/* Píldora estrecha de vidrio, pegada a la izquierda, sobre la imagen. */
/* Dentro de la barra, justo detrás del último enlace: ni flotando debajo ni
   ocupando una franja para ella sola. El «auto» de la derecha empuja al grupo
   del usuario contra el borde. */
.searchbar-compacta { width: min(250px, 100%); max-width: 250px; margin-right: auto; flex: none; }
.searchbar-compacta input {
    background: rgba(255, 255, 255, .10);
    border: 1px solid var(--border-media);
    backdrop-filter: blur(14px) saturate(140%); -webkit-backdrop-filter: blur(14px) saturate(140%);
    color: var(--text);
    min-height: 42px; padding: 10px 16px 10px 40px; font-size: .82rem;
}
.searchbar-compacta input:focus { background: rgba(255, 255, 255, .16); border-color: var(--accent); }
/* Ya no flota en ninguna página: vive en la barra, en la misma línea que los
   enlaces, y por eso no necesita posición propia. */

/* --- buscador antiguo de la barra superior --- */
.search { position: relative; flex: 1; min-width: 0; display: flex; align-items: center; }
.search-icon { position: absolute; left: 15px; color: var(--text-3); font-size: .88rem; pointer-events: none; }
.search-input {
    width: 100%; min-height: 44px; padding: 11px 84px 11px 40px;
    background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-pill);
    font-size: .9rem; font-weight: 500; color: var(--text);
    transition: border-color .15s, box-shadow .15s, background .15s;
}
.search-input::placeholder { color: var(--text-3); }
.search-input:focus {
    outline: none; background: var(--surface-3);
    border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-tint);
}
.search-input::-webkit-search-cancel-button { display: none; }
.search-clear {
    position: absolute; right: 46px; width: 26px; height: 26px; display: grid; place-items: center;
    border-radius: 50%; color: var(--text-2); background: var(--surface-3); font-size: .72rem;
}
.search-clear:hover { color: var(--text); }
.search-kbd {
    position: absolute; right: 12px; font-size: .68rem; font-weight: 700; color: var(--text-2);
    background: var(--surface-3); border: 1px solid var(--border); border-radius: 6px;
    padding: 2px 7px; font-family: inherit;
}
.search-suggest {
    position: absolute; top: calc(100% + 8px); left: 0; right: 0; z-index: 70;
    background: var(--surface); border: 1px solid var(--border-2); border-radius: var(--r-lg);
    box-shadow: var(--sh-3); overflow: hidden; max-height: 60vh; overflow-y: auto; padding: 6px;
}
.suggest-item {
    display: flex; align-items: center; gap: 11px; min-height: 44px;
    padding: 8px 10px; border-radius: var(--r-md); width: 100%; text-align: left;
}
.suggest-item:hover, .suggest-item.is-active { background: var(--surface-2); }
.suggest-item img { width: 34px; height: 50px; object-fit: cover; border-radius: 6px; flex: none; background: var(--surface-3); }
.suggest-title { font-size: .86rem; font-weight: 700; display: block; color: var(--text); }
.suggest-meta { font-size: .74rem; color: var(--text-2); }
.suggest-empty { padding: 16px; text-align: center; color: var(--text-2); font-size: .85rem; }

/* En escritorio los envoltorios de la hoja móvil desaparecen con
   display:contents, así que el formulario sigue siendo hijo directo de la
   barra y la maquetación no cambia. */
.search-sheet, .sheet-bar { display: contents; }
.sheet-back, .topbar-brand, .tabbar, .topbar-buscar, .back-fab { display: none; }

/* ------------------------------------------------------------- 8. Héroe */
.hero {
    /* 56.25vw = 16:9 ocupando todo el ancho: es la altura que usa el clon
       para el billboard, y por eso la imagen llega hasta el borde. */
    position: relative;
    width: auto; height: 56.25vw; max-height: 88vh; min-height: 460px;
    display: block; padding: 0;
    background: var(--bg);
    overflow: hidden;
    /* Los últimos 14,7vw del héroe son sólo el degradado que funde la imagen
       con el fondo: ahí no hay nada que ver. Se sube el resto de la página para
       meterse en esa franja, que es lo que hace Netflix con su primera fila.
       Sin esto quedaban más de 200 px de negro entre los botones y la fila.
       El tope está en que la fila no toque el bloque de texto del héroe: con
       -16vw quedan unos 75 px de aire, que es lo justo. */
    margin-bottom: -16vw;
}
@media (max-width: 900px) {
    /* Aquí manda el min-height del héroe, no el 56,25vw, así que el degradado
       es proporcionalmente más corto y hay menos que recuperar. */
    .hero { margin-bottom: -7vw; }
}
/* A sangre: se sale del relleno del contenedor. */
.main > .hero, .shell > .hero,
.main > .hero-carousel, .shell > .hero-carousel {
    margin-left: calc(var(--gap) * -1);
    margin-right: calc(var(--gap) * -1);
    margin-top: 0;
}

.hero-media {
    position: absolute; inset: 0; z-index: 0;
    width: 100%; height: 100%; object-fit: cover; object-position: center 20%;
    background: var(--surface-2);
}
.hero-media img { width: 100%; height: 100%; object-fit: cover; object-position: center 20%; }

/* Cambio de título sin recargar (fila de populares).
   La imagen no se apaga del todo (.35) ni se queda quieta: un acercamiento
   mínimo mientras se funde es lo que hace que parezca una app y no un cambio
   de src. Los tiempos van emparejados con los del JS. */
.hero-media { transition: opacity .34s var(--ease), transform .7s var(--ease); }
.hero-media.is-cambiando { opacity: .35; transform: scale(1.04); }

.hero-body > * { transition: opacity .3s var(--ease), transform .3s var(--ease); }
.hero-body.is-saliendo > * { opacity: 0; transform: translateY(-10px); }
.hero-body.is-entrando > * { animation: heroEntra .42s var(--ease) both; }
/* Escalonado: el título entra primero y el resto lo sigue. Lo mismo que hace
   Netflix al pasar de un destacado a otro. */
.hero-body.is-entrando > *:nth-child(1) { animation-delay: 0s; }
.hero-body.is-entrando > *:nth-child(2) { animation-delay: .05s; }
.hero-body.is-entrando > *:nth-child(3) { animation-delay: .10s; }
.hero-body.is-entrando > *:nth-child(4) { animation-delay: .15s; }
.hero-body.is-entrando > *:nth-child(5) { animation-delay: .20s; }
@keyframes heroEntra {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    .hero-media, .hero-body > * { transition: none; }
    .hero-body.is-entrando > * { animation: none; }
}

/* Tres capas de velo, cada una con un trabajo:
   1) banda superior (.62): es la que da contraste a los enlaces y al buscador
      flotante; con la imagen más clara posible --text-media queda en 4.64:1.
   2) vertical desde abajo: sostiene el bloque de texto del héroe.
   3) lateral desde la izquierda: oscurece la columna de lectura sin apagar
      la mitad derecha de la imagen. */
/* Los dos degradados del clon, con sus valores literales:
   1) lateral a 77 grados, que oscurece la columna de lectura y muere al 85%
      sin llegar al cuarto derecho de la imagen;
   2) inferior, que funde la foto con el fondo (#141414) en los últimos
      14.7vw, para que la primera fila de carteles nazca de la imagen. */
.hero-shade {
    position: absolute; inset: 0; z-index: 1; pointer-events: none;
    transition: opacity .5s;
}
.hero-shade::before {
    content: ''; position: absolute; top: 0; left: 0; bottom: 0; right: 26.09%;
    background: linear-gradient(77deg, rgba(0, 0, 0, .6), transparent 85%);
}
.hero-shade::after {
    content: ''; position: absolute; bottom: 0; left: 0; width: 100%;
    height: 14.7vw;
    background-image: linear-gradient(180deg,
        hsla(0, 0%, 8%, 0) 0,
        hsla(0, 0%, 8%, .15) 15%,
        hsla(0, 0%, 8%, .35) 29%,
        hsla(0, 0%, 8%, .58) 44%,
        var(--bg) 68%,
        var(--bg));
    background-repeat: repeat-x;
}
/* Si el marcado no trae la capa, la pinta el propio héroe. */
.hero:not(:has(.hero-shade))::after {
    content: ''; position: absolute; bottom: 0; left: 0; width: 100%; height: 14.7vw;
    background-image: linear-gradient(180deg, hsla(0, 0%, 8%, 0) 0, var(--bg) 68%, var(--bg));
    pointer-events: none;
}

.hero-body {
    position: absolute; z-index: 10;
    left: var(--gap); bottom: 35%; top: 0;
    width: 36%; min-width: 0;
    display: flex; flex-direction: column; align-items: flex-start;
    justify-content: flex-end; gap: 24px;
}

.hero-eyebrow, .eyebrow {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: .7rem; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
    color: var(--accent); background: var(--accent-tint);
    padding: 6px 13px; border-radius: var(--r-pill);
}
/* Título grande, como el h2 de MUI que usa el clon (60 px), y una sola línea:
   si no cabe, se corta. Un billboard con el título en tres líneas no existe. */
.hero-title {
    font-size: clamp(2rem, 4.4vw, 3.75rem); font-weight: 700; line-height: 1.1;
    letter-spacing: -.02em; color: #fff;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    max-width: 100%;
}
.hero-title2 {
    font-size: clamp(1.05rem, 1.9vw, 1.6rem); font-weight: 700;
    color: #fff; opacity: .92; margin-top: -14px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.hero-eyebrow, .eyebrow {
    font-size: .78rem; font-weight: 700; letter-spacing: .16em;
    text-transform: uppercase; color: var(--text-2);
}
/* Sinopsis: h5 de MUI (24 px) y tres líneas, exactamente como el clon. */
.hero-text {
    font-size: clamp(.95rem, 1.15vw, 1.5rem); line-height: 1.4; color: #fff;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
    text-shadow: 0 2px 6px rgba(0, 0, 0, .5);
}
.hero-text.is-open { -webkit-line-clamp: unset; }
.hero-more { font-size: .85rem; font-weight: 700; color: #fff; min-height: 40px; display: inline-flex; align-items: center; }
.hero-sub { font-size: .95rem; font-weight: 500; color: var(--text-2); }
.hero-sub > * + *::before { content: '·'; margin-right: 8px; color: var(--text-3); }
.hero-stars { display: flex; align-items: center; gap: 5px; font-size: .95rem; color: var(--star); }
.hero-stars strong { color: #fff; margin-left: 6px; font-weight: 700; }
.hero-votos { color: var(--text-2); font-weight: 500; font-size: .85rem; margin-left: 4px; }
.hero-facts { font-size: .95rem; font-weight: 500; color: var(--text-2); }
.hero-actions, .hero-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; }

/* ---- Los dos botones del billboard ----
   PlayButton.tsx: relleno blanco, texto negro, en negrita, sin mayúsculas
   forzadas, con el icono grande delante.
   MoreInfoButton.tsx: gris translúcido #6d6d6eb3, y #6d6d6e66 al pasar. */
.btn-watch {
    display: inline-flex; align-items: center; gap: 10px;
    padding: 8px 26px 8px 22px; border-radius: var(--r-sm);
    font-size: clamp(1rem, 1.5vw, 1.55rem); font-weight: 700; line-height: 1.5;
    background: var(--btn); color: var(--btn-texto);
    border: 0; white-space: nowrap; cursor: pointer;
    transition: background-color .2s;
}
.btn-watch i { font-size: 1.1em; }
.btn-watch:hover { background: rgba(255, 255, 255, .75); color: #000; }
.btn-watch:active { background: rgba(255, 255, 255, .65); }

.btn-trailer {
    display: inline-flex; align-items: center; gap: 10px;
    padding: 8px 26px 8px 22px; border-radius: var(--r-sm);
    font-size: clamp(1rem, 1.5vw, 1.55rem); font-weight: 700; line-height: 1.5;
    background: var(--btn-2); color: #fff; border: 0;
    white-space: nowrap; cursor: pointer;
    transition: background-color .2s;
}
.btn-trailer:hover { background: var(--btn-2-hover); color: #fff; }

/* Sello de edad del clon (MaturityRate.tsx): sin caja completa, sólo una
   barra clara a la izquierda sobre un gris translúcido. */
.hero-edad {
    display: inline-flex; align-items: center;
    padding: 8px 24px 8px 12px; font-size: 1.05rem; color: #fff;
    border-left: 3px solid #dcdcdc; background: #33333399;
}

.hero-carousel { position: relative; }
.hero-track {
    display: flex; overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none; -ms-overflow-style: none;
}
.hero-track::-webkit-scrollbar { display: none; }
.hero-slide { flex: 0 0 100%; scroll-snap-align: start; scroll-snap-stop: always; min-width: 0; }
.hero-carousel .hero { margin: 0; }
.hero-carousel.is-single .hero-track { overflow: visible; }
.hero-nav {
    position: absolute; top: 50%; transform: translateY(-50%); z-index: 5;
    width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center;
    background: rgba(18, 18, 24, .8); border: 1px solid var(--border-media);
    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    color: var(--text); opacity: 0; transition: opacity .2s, background .2s;
}
.hero-carousel:hover .hero-nav, .hero-nav:focus-visible { opacity: 1; }
.hero-nav:hover { background: var(--accent-solid); border-color: transparent; }
.hero-prev { left: 16px; } .hero-next { right: 16px; }
@media (hover: none) { .hero-nav { display: none; } }

.hero-dots {
    display: flex; justify-content: center; gap: 2px;
    position: absolute; left: 0; right: 0; bottom: 14px; z-index: 4;
}
/* El punto se dibuja con ::before para que el botón conserve 40x40 de zona
   pulsable aunque el punto visible mida 7 px. */
.hero-dot { width: 40px; height: 40px; display: grid; place-items: center; }
.hero-dot::before {
    content: ''; width: 7px; height: 7px; border-radius: var(--r-pill);
    background: rgba(255, 255, 255, .34); transition: width .22s var(--ease), background .22s;
}
.hero-dot.is-active::before { width: 22px; background: var(--accent); }
.hero-dot:hover::before { background: var(--text-2); }
.hero-dot.is-active:hover::before { background: var(--accent); }

/* Póster del héroe antiguo (ficha de detalle). */
.hero-bg { display: none; }
.hero-poster { width: 150px; flex: none; }
.hero-poster img, .hero-poster .card-img-empty {
    width: 150px; height: 225px; object-fit: cover;
    border-radius: var(--r-md); background: var(--surface-3);
    border: 1px solid var(--border-2); box-shadow: var(--sh-2);
}

/* --------------------------------------------------------- 9. Populares
 * Una bandeja translúcida con pósters limpios: sin rótulo encima de la imagen.
 * El póster ya identifica la película, y el texto superpuesto sólo tapaba la
 * cara del cartel y se partía en tres líneas con los títulos largos.
 *
 * La bandeja se solapa con el héroe de arriba, así que va semitransparente y
 * con desenfoque: se apoya en el arte en lugar de cortarlo con un rectángulo.
 */
.popular { position: relative; z-index: 4; }
/* La tarjeta cuyo título se está viendo en el arte grande de arriba: un filo
   rojo, que es la única diferencia con una fila cualquiera. */
.popular .card.is-active .card-art {
    outline: 2px solid var(--hot); outline-offset: 0;
    box-shadow: 0 0 0 5px rgba(255, 45, 85, .16), 0 16px 38px rgba(0, 0, 0, .6);
}
.popular .section-head { margin-bottom: 10px; }
.popular .section-title { margin-bottom: 10px; }

.popular-caja { background: none; border: 0; border-radius: 0; padding: 0; overflow: visible; }
.popular-track {
    --pop-gap: 12px;
    /* Cuatro y media: en apaisado, seis dejaban tarjetas de 189x106, demasiado
       pequeñas para reconocer nada. La media de la quinta invita a deslizar. */
    --pop-visibles: 4.4;
    display: flex; align-items: center; gap: var(--pop-gap);
    overflow-x: auto; overflow-y: visible;
    /* Arriba hace falta hueco para que la tarjeta ampliada no se corte
       (overflow-x:auto también recorta en vertical) y el margen negativo lo
       devuelve. Abajo el hueco se queda: ahí va la barra de deslizar. */
    padding-block: 24px 14px; margin-top: -24px;
    scrollbar-width: none; -ms-overflow-style: none;
}
.popular-track::-webkit-scrollbar { display: none; }

/* Barra de deslizar propia (la del navegador se oculta arriba). El carril
   ocupa todo el ancho y el mango dice qué parte de la fila se está viendo. */
.popular-barra {
    height: 5px; margin: 2px 2px 0;
    border-radius: 99px; background: rgba(255, 255, 255, .09);
    position: relative; cursor: pointer;
}
.popular-barra-mango {
    position: absolute; top: 0; bottom: 0; left: 0;
    width: 30%; min-width: 32px;
    border-radius: 99px; background: rgba(255, 255, 255, .34);
    transition: background .18s;
}
.popular-barra:hover .popular-barra-mango { background: rgba(255, 255, 255, .55); }
.popular-barra.is-arrastrando .popular-barra-mango { background: var(--hot); }
/* Si la fila entra entera no hay nada que deslizar: sobra la barra. */
.popular-barra[hidden] { display: none; }

.pop-card {
    /* Apaisado 16:9, como el resto de las filas. Con carteles verticales esta
       fila era la única distinta de la página y cantaba.
       El ancho sale de descontar los huecos y repartir el resto, así la última
       cae justo en el borde y se entiende que hay más detrás. */
    position: relative;
    flex: 0 0 calc((100% - (var(--pop-visibles) - 1) * var(--pop-gap)) / var(--pop-visibles));
    /* Sin esto manda el tamaño natural de la imagen (el mínimo automático de un
       elemento flexible) y entran menos de las previstas. */
    min-width: 0;
    aspect-ratio: 16/9;
    border-radius: 12px; overflow: hidden;
    background: var(--surface-2);
    box-shadow: 0 6px 18px rgba(0, 0, 0, .45);
    /* El borde de la seleccionada se pinta con outline, no con border: así no
       empuja el tamaño del póster y la fila no baila al cambiar de tarjeta. */
    outline: 2px solid transparent; outline-offset: 0;
    transition: transform .32s var(--ease), outline-color .22s, box-shadow .32s var(--ease);
}
.pop-card img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Sin arte apaisado: el cartel desenfocado de fondo y el cartel entero encima,
   igual que en las tarjetas del catálogo. */
.pop-card.card-art--relleno .card-fondo {
    position: absolute; inset: 0; z-index: 0;
    filter: blur(18px) brightness(.55); transform: scale(1.15);
}
.pop-card.card-art--relleno .card-img { position: relative; z-index: 1; object-fit: contain; }

/* Igual que en una app de televisión: la tarjeta crece con un retardo corto al
   entrar (para que pasar el ratón por encima de la fila no dispare seis
   ampliaciones seguidas) y se recoge de golpe al salir. */
.pop-card {
    transition:
        transform .34s cubic-bezier(.2, .7, .2, 1) 0s,
        outline-color .22s,
        box-shadow .34s cubic-bezier(.2, .7, .2, 1);
}
.pop-card:hover {
    transform: scale(1.06); z-index: 2;
    transition-delay: .12s;
    box-shadow: 0 18px 40px rgba(0, 0, 0, .6);
}
.pop-card.is-active {
    transform: scale(1.12);
    outline-color: var(--hot);
    box-shadow: 0 0 0 6px rgba(255, 45, 85, .14), 0 18px 42px rgba(0, 0, 0, .62);
    z-index: 3;
}
/* Reflejo suave al pasar por encima: sin él el póster ampliado se ve plano. */
.pop-card::after {
    content: ''; position: absolute; inset: 0; pointer-events: none;
    background: linear-gradient(200deg, rgba(255, 255, 255, .16), transparent 46%);
    opacity: 0; transition: opacity .3s var(--ease);
}
.pop-card:hover::after, .pop-card.is-active::after { opacity: 1; }
.pop-rank {
    position: absolute; left: 6px; bottom: 4px; z-index: 2;
    font-size: 1.8rem; font-weight: 800; line-height: 1; color: #fff;
    text-shadow: 0 2px 14px rgba(0, 0, 0, .9);
}

/* Sólo la punta de flecha, a la derecha y fuera de la bandeja: el hueco lo
   abre el padding-right de .popular. */
.popular-nav {
    position: absolute; right: 0; top: 50%; transform: translateY(-50%); z-index: 6;
    width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center;
    background: transparent; border: 0;
    color: rgba(255, 255, 255, .78); font-size: 1.5rem;
    transition: color .18s, transform .16s;
}
/* Si la sección lleva cabecera, el centro geométrico queda por encima del
   centro de los pósters: se baja la mitad del alto de la cabecera. */
.popular:has(.section-title) .popular-nav { top: calc(50% + 20px); }
.popular-nav:hover { color: #fff; transform: translateY(-50%) scale(1.14); }
.popular-nav:active { transform: translateY(-50%) scale(.94); }
/* Al final del recorrido la flecha desaparece del todo: una flecha apagada que
   sigue ocupando sitio sólo genera clics que no hacen nada. */
.popular-nav:disabled { opacity: 0; pointer-events: none; }
/* La de volver se apoya sobre el borde de la bandeja (a la izquierda no hay
   hueco reservado), así que necesita sombra para leerse sobre un póster. */
.popular-prev { right: auto; left: 0; }

/* ------------------------------------------------------- 10. Pestañas */
.tabsrow {
    display: flex; align-items: center; justify-content: center;
    gap: clamp(14px, 3vw, 44px);
    overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none;
    margin-bottom: 22px;
}
.tabsrow::-webkit-scrollbar { display: none; }
.tabsrow a {
    position: relative;
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    min-height: 44px; padding: 0 4px 10px;
    font-size: .85rem; font-weight: 600; color: var(--text-2); white-space: nowrap;
    transition: color .16s;
}
.tabsrow a i, .tabsrow a svg { font-size: .9em; opacity: .9; }
.tabsrow a:hover { color: var(--text); }
/* Punto bajo la pestaña activa. Se dibuja siempre y se anima en escala, así
   el ancho no salta al cambiar de pestaña. */
.tabsrow a::after {
    content: ''; position: absolute; left: 50%; bottom: 0;
    width: 5px; height: 5px; margin-left: -2.5px; border-radius: 50%;
    background: var(--accent);
    transform: scale(0); transition: transform .24s var(--ease);
}
.tabsrow a:hover::after { transform: scale(.6); background: var(--text-3); }
.tabsrow a.is-active { color: var(--text); font-weight: 700; }
.tabsrow a.is-active::after { transform: scale(1); background: var(--accent); }

/* ---------------------------------------------------------- 11. Chips */
.chiprow {
    display: flex; align-items: center; justify-content: center;
    gap: 10px; flex-wrap: nowrap;
    overflow-x: auto; padding: 2px 0 10px;
    scrollbar-width: none; -ms-overflow-style: none;
}
.chiprow::-webkit-scrollbar { display: none; }
/* En una fila con scroll, justify-content:center deja el primer elemento
   inalcanzable al desbordar; con margen automático se centra sólo cuando
   sobra sitio. */
.chiprow > :first-child { margin-left: auto; }
.chiprow > :last-child { margin-right: auto; }
/* Píldoras anchas y todas iguales, como en la referencia: el texto centrado y
   un ancho mínimo común evita que «Acción» y «Ciencia Ficción» parezcan dos
   controles distintos. */
.chiprow .chip {
    justify-content: center;
    min-width: clamp(96px, 11.5vw, 178px);
    min-height: 44px;
}

.chip {
    display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
    min-height: 40px; padding: 8px 18px; border-radius: var(--r-pill);
    font-size: .8rem; font-weight: 600; color: var(--text-2);
    background: var(--surface-2); border: 1px solid var(--border);
    transition: background .15s, color .15s, border-color .15s;
}
.chip:hover { background: var(--surface-3); color: var(--text); border-color: var(--border-2); }
/* Fondo --accent-solid en vez de --accent: con --accent el blanco se queda en
   3.24:1 y este texto es normal, no grande. */
.chip.is-active {
    background: var(--accent-solid); color: #fff; border-color: transparent;
    box-shadow: 0 6px 18px rgba(30, 144, 255, .28);
}
.chip.is-active:hover { background: var(--accent-solid); color: #fff; }
.chip em { font-style: normal; font-size: .7rem; font-weight: 800; opacity: .7; }

/* Flecha final de la fila: sin fondo, sólo el icono. */
.chiprow-mas {
    display: inline-grid; place-items: center; flex: none;
    width: 40px; height: 40px; border-radius: 50%;
    background: none; border: 0; color: var(--text-2); font-size: .95rem;
    transition: color .15s, background .15s;
}
.chiprow-mas:hover { color: var(--text); background: var(--surface-2); }

.chip-remove { padding: 6px 12px 6px 15px; font-size: .79rem; }
.chip-remove:hover { border-color: var(--hot); color: var(--hot); }
.chip-x { font-size: .66rem; opacity: .6; margin-left: 2px; }
.chip-clear {
    font-size: .79rem; font-weight: 700; color: var(--text-2);
    min-height: 40px; padding: 0 8px; display: inline-flex; align-items: center;
}
.chip-clear:hover { color: var(--hot); text-decoration: underline; }
.mini-chip {
    display: inline-flex; align-items: center; min-height: 34px; padding: 5px 12px;
    border-radius: var(--r-pill); font-size: .77rem; font-weight: 700;
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text-2);
}
.mini-chip:hover { border-color: var(--accent); color: var(--accent); }
.mini-chip.is-active { background: var(--accent-solid); color: #fff; border-color: transparent; }
.quick-links { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }

.pills { display: flex; flex-wrap: wrap; gap: 8px; }
.pill {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: .78rem; font-weight: 700; color: var(--text-2);
    background: var(--surface-2); border: 1px solid var(--border);
    padding: 6px 12px; border-radius: var(--r-pill); white-space: nowrap;
}
.pill-link { min-height: 34px; }
.pill-link:hover { border-color: var(--accent); color: var(--accent); }
.pill-star   { color: var(--star); background: rgba(255, 184, 0, .12); border-color: rgba(255, 184, 0, .22); }
.pill-new    { color: var(--hot); background: var(--hot-tint); border-color: rgba(255, 45, 85, .26); }
.pill-series { color: var(--accent); background: var(--accent-tint); border-color: transparent; }
.pill-tag    { color: var(--text-2); background: var(--surface-3); border-color: transparent; }

/* --------------------------------------------------------- 12. Botones */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 9px;
    min-height: 40px; padding: 10px 18px; border-radius: var(--r-md);
    font-size: .87rem; font-weight: 700; white-space: nowrap;
    border: 1px solid transparent;
    transition: transform .15s var(--ease), background .15s, box-shadow .15s, border-color .15s;
}
.btn:active { transform: scale(.97); }
.btn-lg { min-height: 48px; padding: 13px 26px; font-size: .92rem; }
.btn-sm { min-height: 40px; padding: 8px 14px; font-size: .81rem; }
.btn-primary { background: var(--accent-solid); color: #fff; box-shadow: var(--sh-accent); }
.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 16px 38px rgba(30, 144, 255, .45); }
.btn-ghost { background: var(--surface-2); color: var(--text); border-color: var(--border-2); }
.btn-ghost:hover { background: var(--surface-3); border-color: var(--accent); color: var(--accent); }
.btn-play { min-height: 46px; padding: 12px 32px; border-radius: var(--r-pill); font-size: .9rem; }
.btn-fav.is-fav { color: var(--hot); border-color: var(--hot); background: var(--hot-tint); }
.btn-fav i { transition: transform .18s var(--ease); }
.btn-fav.is-fav i { transform: scale(1.15); }
.dot-badge {
    min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--r-pill);
    background: var(--accent-solid); color: #fff; font-size: .68rem; font-weight: 800;
    display: inline-grid; place-items: center;
}

/* Bloque ancho de carga: se lee como continuación de la lista, no como
   acción principal, así que va en gris y sin borde. */
.showmore {
    display: flex; align-items: center; justify-content: center; gap: 10px;
    width: 100%; min-height: 52px; margin: 28px 0 8px; padding: 14px 24px;
    background: var(--surface-2); border: 0; border-radius: var(--r-md);
    color: var(--text-2);
    font-size: .85rem; font-weight: 700;
    transition: background .18s, color .18s;
}
.showmore i, .showmore svg { font-size: .9em; }
.showmore:hover { background: var(--surface-3); color: var(--text); }
.showmore:active { transform: scale(.995); }

/* --------------------------------------- 13. Cabeceras de sección y rails */
.section-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 14px; flex-wrap: wrap; margin-bottom: 16px;
}
.section-title {
    display: flex; align-items: center; gap: 10px;
    font-size: clamp(1.05rem, 1.4vw, 1.5rem); font-weight: 700;
    letter-spacing: -.01em; color: #e5e5e5;
}
/* El icono sin pastilla de color: en el clon el rótulo de una fila es texto y
   nada más, y la mancha azul rompía la fila de carteles. */
.section-title > i {
    flex: none; font-size: .72em; opacity: .55;
    background: none; color: inherit; width: auto; height: auto;
}
.section-count { font-size: .78rem; font-weight: 500; color: var(--text-3); }
.section-more {
    display: inline-flex; align-items: center; gap: 6px;
    min-height: 40px; padding: 0 12px; margin-right: -12px;
    border-radius: var(--r-md);
    font-size: .78rem; font-weight: 700; color: var(--accent);
    transition: gap .15s, background .15s;
}
.section-more:hover { gap: 9px; background: var(--accent-tint); }

.rail { position: relative; }
/* Sin scroll-snap: junto a scrollBy({behavior:'smooth'}) Chrome cancelaba el
   desplazamiento y devolvía el carrusel a la primera tarjeta. */
.rail-track {
    display: flex; gap: 16px;
    overflow-x: auto; overflow-y: hidden;
    /* Hueco arriba y abajo para que la tarjeta ampliada no se corte
       (overflow-x:auto recorta también en vertical) y margen negativo para
       devolver el espacio al resto de la página. */
    padding: 26px 2px 24px; margin-block: -22px -12px;
    scrollbar-width: none; -ms-overflow-style: none;
}
.rail-track::-webkit-scrollbar { display: none; }
/* 244 px: con 16:9 son 137 de alto, la misma altura de miniatura que enseña el
   clon en una bandeja de escritorio. Con los 160 de antes quedaban en 90. */
.rail-track > .card { flex: 0 0 244px; }
.rail-nav {
    position: absolute; top: calc(50% - 34px); transform: translateY(-50%); z-index: 5;
    width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center;
    background: rgba(18, 18, 24, .88); border: 1px solid var(--border-2);
    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    color: var(--text); opacity: 0; transition: opacity .2s, background .2s;
}
.rail:hover .rail-nav, .rail-nav:focus-visible { opacity: 1; }
.rail-nav:hover { background: var(--accent-solid); border-color: transparent; }
.rail-nav:disabled { opacity: 0 !important; pointer-events: none; }
.rail-prev { left: -14px; } .rail-next { right: -14px; }
@media (hover: none) { .rail-nav { display: none; } }

/* -------------------------------------------------------- 14. Tarjetas */
/* Apaisadas: el mínimo sube de 150 a 210 px porque una miniatura 16:9 de
   150 px sólo mide 84 px de alto y deja de leerse. El hueco horizontal baja a
   10 px —Netflix casi pega las miniaturas— y el vertical a 22, que con la
   tarjeta más baja ya separa de sobra una fila de la siguiente. */
.grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 22px 10px;
}
/* En pantallas anchas el auto-fill llegaría a 8-9 columnas y las miniaturas se
   quedan diminutas: se fija en 6. */
@media (min-width: 1440px) {
    .grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}
/* Entre 1200 y 1440 el auto-fill saltaría de 6 a 4 de golpe y dejaría filas
   cojas: se fijan 5, que es lo que enseña el clon a ese ancho. */
@media (min-width: 1201px) and (max-width: 1439.98px) {
    .grid { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}
/* Los escalones intermedios se escriben como tramos cerrados y no como
   max-width encadenados: los cortes de la sección 22 (1024 antes que 900) no
   van en orden y un max-width suelto acabaría ganando donde no debe. */
@media (min-width: 901px) and (max-width: 1200px) {
    .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (min-width: 721px) and (max-width: 900px) {
    .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.card { display: flex; flex-direction: column; gap: 9px; min-width: 0; }
/* 16:9 y no 2/3: Netflix dejó el cartel vertical hace años y todas sus
   bandejas usan arte apaisado, que es además lo que pinta el mini-portal. */
.card-art {
    position: relative; aspect-ratio: 16/9;
    border-radius: var(--r-md); overflow: hidden;
    background: var(--surface-2);
    transition: transform .32s var(--ease), box-shadow .32s var(--ease);
}
/* Ampliación tipo Netflix: crece con retardo al entrar y se recoge al instante
   al salir, así recorrer la fila con el ratón no dispara seis animaciones. En
   los carruseles la tarjeta crece desde su propio lado para que la primera y la
   última no se salgan por el borde de la pantalla. */
.card:hover .card-art, .card:focus-visible .card-art {
    transform: translateY(-8px) scale(1.06);
    box-shadow: 0 22px 46px rgba(0, 0, 0, .62);
    transition-delay: .14s;
}
.rail-track > .card:first-child .card-art { transform-origin: left center; }
.rail-track > .card:last-child  .card-art { transform-origin: right center; }
.card:hover .card-title { color: #fff; }
.card-title { transition: color .18s; }
/* La fila entera se apaga un poco menos la tarjeta señalada: es lo que hace que
   la mirada vaya sola a donde está el cursor. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
    .rail-track:hover > .card:not(:hover) .card-art { opacity: .62; }
    .card-art { transition: transform .32s var(--ease), box-shadow .32s var(--ease), opacity .32s var(--ease); }
}

/* El hueco animado reserva el espacio exacto (aspect-ratio), así que nada se
   mueve cuando el póster acaba de cargar. */
.card-art::before {
    content: ''; position: absolute; inset: 0; z-index: 0;
    background: linear-gradient(100deg, var(--surface-2) 30%, var(--surface-3) 50%, var(--surface-2) 70%);
    background-size: 220% 100%;
    animation: cargando 1.4s ease-in-out infinite;
}
.card-art:has(.card-img.is-loaded)::before,
.card-art:has(.card-img-empty)::before { animation: none; opacity: 0; }
@keyframes cargando { to { background-position: -220% 0; } }

.card-img {
    width: 100%; height: 100%; object-fit: cover; position: relative; z-index: 1;
    opacity: 0; transition: opacity .35s ease;
}
.card-img.is-loaded { opacity: 1; }
/* Sin JavaScript nunca llega la clase is-loaded: se muestran igualmente. */
.no-js .card-img { opacity: 1; }

/* --- Títulos sin arte apaisado (~30 % del catálogo) ---------------------
   Recortar un cartel vertical a 16:9 se lleva por delante la cara, y estirarlo
   lo deforma. La salida es la misma que usa Netflix cuando le falta el
   apaisado: el propio cartel de fondo, ampliado y desenfocado, y el cartel
   entero centrado encima. El scale(1.15) existe porque blur() difumina también
   hacia fuera de la caja y sin ese margen extra asomaría un halo claro en los
   bordes; brightness(.55) lo hunde para que no compita con el de delante. */
.card-fondo {
    position: absolute; inset: 0; z-index: 1;
    width: 100%; height: 100%; object-fit: cover;
    filter: blur(18px) brightness(.55);
    transform: scale(1.15);
    /* El desenfoque es caro de repintar en una rejilla de 30 tarjetas: se
       aísla para que el navegador lo cachee como capa. */
    will-change: transform;
}
.card-art--relleno .card-img {
    z-index: 2; object-fit: contain;
}
/* El hueco animado sobra en cuanto hay fondo: el cartel desenfocado ya cubre
   toda la caja y el brillo del esqueleto se colaba por debajo. */
.card-art--relleno::before { animation: none; opacity: 0; }
.card-img-empty {
    width: 100%; height: 100%; display: grid; place-items: center;
    color: var(--text-3); font-size: 1.8rem; background: var(--surface-2);
}

/* Velo inferior al pasar el ratón: da cuerpo al play y al corazón. */
.card-art::after {
    content: ''; position: absolute; inset: 0; z-index: 2;
    background: linear-gradient(to top, rgba(0, 0, 0, .78) 0%, transparent 46%);
    opacity: 0; transition: opacity .25s;
}
.card:hover .card-art::after { opacity: 1; }

.card-play {
    position: absolute; inset: 0; margin: auto;
    width: 52px; height: 52px; z-index: 4;
    display: grid; place-items: center; border-radius: 50%;
    background: rgba(255, 255, 255, .94); color: #08080C; font-size: 1rem;
    opacity: 0; transform: scale(.7);
    transition: opacity .25s var(--ease), transform .25s var(--ease), background .18s;
}
.card:hover .card-play { opacity: 1; transform: scale(1); }
.card-play:hover { background: #fff; }
.card-play:focus-visible { opacity: 1; transform: scale(1); }

/* Corazón: 40x40 de zona pulsable con el círculo dibujado dentro, para
   cumplir el mínimo táctil sin comerse el póster. */
.card-fav {
    position: absolute; right: 4px; bottom: 4px; z-index: 5;
    width: 40px; height: 40px; display: grid; place-items: center; border-radius: 50%;
    color: #fff; font-size: .8rem;
    opacity: 0; transform: scale(.85);
    transition: opacity .18s, transform .18s var(--ease);
}
.card-fav::before {
    content: ''; position: absolute; width: 30px; height: 30px; border-radius: 50%;
    background: rgba(0, 0, 0, .62);
    backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
    border: 1px solid var(--border-2);
    transition: background .18s, border-color .18s;
}
.card-fav i { position: relative; z-index: 1; }
.card:hover .card-fav, .card-fav:focus-visible { opacity: 1; transform: none; }
.card-fav.is-fav { opacity: 1; transform: none; }
.card-fav.is-fav::before { background: var(--hot-deep); border-color: transparent; }
.card-fav:active { transform: scale(.9); }

/* Distintivos sobre el póster. El diseño nuevo deja la carátula limpia, pero
   las reglas siguen aquí para las vistas que aún los pintan. */
.badge {
    position: absolute; top: 8px; left: 8px; z-index: 3;
    display: inline-flex; align-items: center; gap: 5px;
    font-size: .64rem; font-weight: 800; letter-spacing: .03em;
    padding: 4px 9px; border-radius: 7px; color: #fff;
    background: rgba(8, 8, 12, .78);
    border: 1px solid var(--border);
    backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.badge-rating { left: auto; right: 8px; color: var(--star); }
.badge-warn { background: var(--hot-deep); border-color: transparent; }

.card-progreso {
    position: absolute; left: 0; right: 0; bottom: 0; z-index: 4;
    height: 4px; background: rgba(255, 255, 255, .18);
}
/* Rojo y no azul: en la referencia la línea de lo ya visto es la marca de
   «lo tuyo», y el azul aquí es el color de los enlaces. */
.card-progreso span { display: block; height: 100%; background: var(--hot); }
/* La capa de encima no debe tapar la línea de avance: ésta va por encima y a
   la capa se le deja hueco abajo. */
/* ---------------------------------------------------------- 15. Banner */
.banner {
    position: relative; isolation: isolate; overflow: hidden;
    display: flex; align-items: flex-end;
    min-height: 380px;
    border-radius: var(--r-lg);
    padding: clamp(24px, 4vw, 48px);
    background: var(--surface);
    border: 1px solid var(--border);
}
.banner img, .banner-media {
    position: absolute; inset: 0; z-index: -2;
    width: 100%; height: 100%; object-fit: cover; object-position: center 25%;
}
.banner::before {
    content: ''; position: absolute; inset: 0; z-index: -1;
    background:
        linear-gradient(to top, rgba(8, 8, 12, .96) 0%, rgba(8, 8, 12, .72) 40%, rgba(8, 8, 12, .12) 100%),
        linear-gradient(to right, rgba(8, 8, 12, .92) 0%, rgba(8, 8, 12, .45) 50%, transparent 88%);
}
.banner-body { position: relative; z-index: 1; max-width: 620px; display: flex; flex-direction: column; gap: 12px; }

/* Sello de edad: cuadrado rojo. Con --hot el blanco encima da 3.65:1, así que
   el relleno usa --hot-deep (6.85:1). */
.banner-badge {
    display: grid; place-items: center;
    width: 44px; height: 44px; flex: none;
    border-radius: var(--r-sm);
    background: var(--hot-deep); color: #fff;
    font-size: .95rem; font-weight: 800; letter-spacing: -.02em;
}
.banner-meta {
    display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
    font-size: .82rem; font-weight: 700; color: var(--text-2);
}
.banner-meta > * { display: inline-flex; align-items: center; gap: 6px; }
.banner-meta .banner-badge + * { margin-left: 2px; }
.banner-title {
    font-size: clamp(1.6rem, 3.4vw, 2.6rem); font-weight: 800;
    line-height: 1.05; letter-spacing: -.025em; text-transform: uppercase;
    text-shadow: 0 2px 20px rgba(0, 0, 0, .8);
}
.banner-text {
    color: var(--text-2); font-size: .9rem; max-width: 58ch;
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.banner-tabs { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 2px; }
.banner-tabs a, .banner-tabs button {
    display: inline-flex; align-items: center; min-height: 40px; padding: 0 14px;
    border-radius: var(--r-pill);
    background: rgba(255, 255, 255, .07); border: 1px solid var(--border);
    font-size: .8rem; font-weight: 700; color: var(--text-2);
    transition: background .15s, color .15s, border-color .15s;
}
.banner-tabs a:hover, .banner-tabs button:hover { background: rgba(255, 255, 255, .14); color: var(--text); }
.banner-tabs .is-active {
    background: var(--accent-tint); color: var(--accent); border-color: rgba(30, 144, 255, .34);
}
.banner-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; margin-top: 6px; }

/* --------------------------------------------------------- 16. Filtros */
.catalog { display: block; }
/* Sin position:sticky: son tres filas (~180 px) y, sumadas a la barra
   superior, se quedaban pegadas tapando la primera fila de tarjetas. */
.filters {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--r-lg); padding: 14px; margin-bottom: 22px;
    display: flex; flex-direction: column; gap: 12px;
}
.filter-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.filter-types { overflow-x: auto; flex-wrap: nowrap; scrollbar-width: none; padding-bottom: 2px; }
.filter-types::-webkit-scrollbar { display: none; }
.filter-row + .filter-row { border-top: 1px solid var(--border); padding-top: 11px; }
.filter-tools { gap: 8px; }

.select-wrap { position: relative; display: inline-flex; align-items: center; }
.select-label { position: absolute; left: 12px; color: var(--text-2); font-size: .8rem; pointer-events: none; }
.select-wrap:has(.select-label) .select { padding-left: 32px; }
.select {
    appearance: none; -webkit-appearance: none;
    min-height: 40px; padding: 9px 30px 9px 13px; border-radius: var(--r-md);
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
    font-size: .81rem; font-weight: 700; cursor: pointer; max-width: 200px;
}
.select:hover { border-color: var(--border-2); }
.select option { background: var(--surface-2); color: var(--text); }
.select-wrap::after {
    content: '\f078'; font-family: 'Font Awesome 6 Free'; font-weight: 900;
    position: absolute; right: 12px; font-size: .6rem; color: var(--text-2); pointer-events: none;
}

.toggle {
    display: inline-flex; align-items: center; gap: 9px;
    min-height: 40px; padding: 0 12px 0 10px; border-radius: var(--r-md);
    font-size: .81rem; font-weight: 700; color: var(--text-2); transition: background .15s;
}
.toggle:hover { background: var(--surface-2); color: var(--text); }
.toggle-track {
    width: 38px; height: 21px; border-radius: var(--r-pill);
    background: var(--surface-3); border: 1px solid var(--border-2);
    position: relative; transition: background .2s, border-color .2s; flex: none;
}
.toggle-knob {
    position: absolute; top: 2px; left: 2px; width: 15px; height: 15px; border-radius: 50%;
    background: var(--text-2); transition: transform .2s var(--ease), background .2s;
}
.toggle.is-on { color: var(--accent); }
.toggle.is-on .toggle-track { background: var(--accent-solid); border-color: transparent; }
.toggle.is-on .toggle-knob { transform: translateX(17px); background: #fff; }

/* Altura acotada: con 25 géneros el panel nunca tapa el catálogo y los
   botones de aplicar/restablecer quedan siempre pegados abajo. */
.panel {
    border-top: 1px solid var(--border); padding-top: 14px;
    animation: slide .22s var(--ease);
    max-height: min(58vh, 560px); overflow-y: auto; overscroll-behavior: contain;
}
@keyframes slide { from { opacity: 0; transform: translateY(-6px) } to { opacity: 1; transform: none } }
.panel-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 22px; }
.panel-block { min-width: 0; }
.panel fieldset { border: 0; }
.panel legend, .panel-sub legend {
    display: flex; align-items: baseline; gap: 8px;
    font-size: .72rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
    color: var(--text-2); margin-bottom: 9px;
}
.panel legend small { text-transform: none; letter-spacing: 0; font-weight: 600; color: var(--text-3); }
.panel-sub + .panel-sub { margin-top: 16px; }
.panel-actions {
    display: flex; gap: 10px; margin-top: 16px; padding: 14px 0 2px;
    border-top: 1px solid var(--border);
    position: sticky; bottom: -2px; background: var(--surface); z-index: 2;
}

.check-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 4px; }
.check-grid-1 { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }
.check {
    display: flex; align-items: center; gap: 9px;
    min-height: 40px; padding: 6px 9px; border-radius: var(--r-sm);
    font-size: .81rem; font-weight: 600; color: var(--text-2); cursor: pointer; transition: background .15s, color .15s;
}
.check:hover { background: var(--surface-2); color: var(--text); }
.check input { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; flex: none; }
.check span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.check em { font-style: normal; font-size: .7rem; font-weight: 700; color: var(--text-3); }
.check:has(input:checked) { background: var(--accent-tint); color: var(--accent); }
.check:has(input:checked) em { color: var(--accent); }

.range-row { display: flex; align-items: center; gap: 10px; }
.input {
    min-height: 40px; padding: 9px 12px; border-radius: var(--r-md);
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
    font-size: .84rem; font-weight: 600; min-width: 0;
}
.input::placeholder { color: var(--text-3); }
.input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }
.input-num { width: 100%; }
.range-sep { color: var(--text-2); font-size: .8rem; }
.range { flex: 1; accent-color: var(--accent); min-height: 24px; }
.range-out { font-size: .8rem; font-weight: 800; color: var(--accent); min-width: 78px; text-align: right; }
.hint { font-size: .75rem; color: var(--text-2); margin-top: 7px; display: flex; gap: 6px; align-items: flex-start; }

/* ------------------------------------------------------ 17. Paginación */
.pager { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; justify-content: center; margin-top: 26px; }
.pager-btn {
    display: inline-flex; align-items: center; gap: 7px;
    min-width: 40px; height: 40px; padding: 0 14px; justify-content: center;
    border-radius: var(--r-md);
    font-size: .84rem; font-weight: 700; color: var(--text-2);
    background: var(--surface-2); border: 1px solid var(--border);
    transition: background .15s, color .15s, border-color .15s;
}
.pager-btn:hover { background: var(--surface-3); color: var(--text); border-color: var(--border-2); }
.pager-num { padding: 0 10px; }
.pager-btn.is-active {
    background: var(--accent-solid); color: #fff; border-color: transparent;
    box-shadow: 0 6px 16px rgba(30, 144, 255, .3);
}
.pager-btn.is-disabled { opacity: .38; pointer-events: none; }
.pager-gap { color: var(--text-2); padding: 0 3px; }
.pager-info { width: 100%; text-align: center; font-size: .78rem; color: var(--text-2); margin-top: 8px; }

/* ----------------------------------------------------- 18. Reproductor */
.crumbs {
    display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
    font-size: .8rem; font-weight: 600; color: var(--text-2);
}
.crumbs a:hover { color: var(--accent); }
.crumbs i { font-size: .6rem; color: var(--text-3); }

.player-card, .episodes {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--r-xl); padding: 22px;
}
.player-card { position: relative; overflow: hidden; }
.player-card::before {
    content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
    background: linear-gradient(90deg, var(--accent), transparent 70%);
}
.player-head { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; margin-bottom: 14px; }

.segmented {
    display: flex; gap: 5px; padding: 5px;
    background: var(--surface-2); border: 1px solid var(--border);
    border-radius: var(--r-md); max-width: 100%;
}
.segmented-scroll { overflow-x: auto; scrollbar-width: none; margin-bottom: 16px; }
.segmented-scroll::-webkit-scrollbar { display: none; }
.segment {
    display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
    min-height: 40px; padding: 8px 15px; border-radius: var(--r-sm);
    font-size: .81rem; font-weight: 700; color: var(--text-2);
    transition: background .15s, color .15s;
}
.segment:hover { color: var(--text); background: var(--surface-3); }
.segment.is-active { background: var(--surface-3); color: var(--accent); }
.segment.is-active em { opacity: .8; }
.segment.is-disabled { color: var(--text-3); cursor: default; }
.segment em { font-style: normal; font-size: .7rem; opacity: .7; }

.video-frame {
    position: relative; aspect-ratio: 16/9; width: 100%;
    background: #000; border-radius: var(--r-lg); overflow: hidden;
    border: 1px solid var(--border);
}
.video-frame iframe { width: 100%; height: 100%; border: 0; display: block; }
.video-frame.is-loading::after {
    content: ''; position: absolute; inset: 0; z-index: 2;
    background: repeating-linear-gradient(90deg, transparent, transparent 40%, rgba(255, 255, 255, .07) 50%, transparent 60%, transparent);
    background-size: 220% 100%; animation: shimmer 1.1s linear infinite;
}
@keyframes shimmer { to { background-position: -220% 0 } }
.video-empty {
    position: absolute; inset: 0; display: grid; place-content: center; justify-items: center;
    gap: 10px; color: var(--text-3); font-size: 2rem;
}
.video-empty p { font-size: .85rem; color: var(--text-2); }
.player-hint { margin-top: 10px; font-size: .78rem; color: var(--text-2); text-align: center; }

.notice {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 12px 15px; border-radius: var(--r-md);
    font-size: .83rem; font-weight: 600; margin-bottom: 14px;
}
.notice-warn { background: rgba(251, 191, 36, .12); color: var(--warn); border: 1px solid rgba(251, 191, 36, .22); }

/* -------------------------------------------------------- 19. Episodios */
.ep-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(248px, 1fr)); gap: 10px; align-items: stretch; }
.ep {
    display: flex; align-items: center; gap: 12px; text-align: left; width: 100%; min-height: 62px;
    padding: 11px 14px; border-radius: var(--r-md);
    background: var(--surface-2); border: 1px solid var(--border); color: var(--text);
    transition: background .16s, border-color .16s, transform .16s;
}
.ep:hover:not(:disabled) { background: var(--surface-3); border-color: var(--border-2); transform: translateY(-2px); }
.ep.is-active { background: var(--accent-tint); border-color: rgba(30, 144, 255, .38); }
.ep:disabled { opacity: .42; cursor: not-allowed; }
.ep-num {
    width: 34px; height: 34px; flex: none; display: grid; place-items: center; border-radius: 10px;
    background: var(--surface-3); border: 1px solid var(--border);
    font-size: .82rem; font-weight: 800; color: var(--text-2);
}
.ep:hover:not(:disabled) .ep-num { color: var(--accent); border-color: var(--border-2); }
.ep.is-active .ep-num { background: var(--accent-solid); color: #fff; border-color: transparent; }
.ep-body { flex: 1; min-width: 0; }
.ep-title { display: block; font-size: .83rem; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ep-sub { display: block; font-size: .72rem; color: var(--text-2); }
.ep-icon { color: var(--text-2); font-size: .9rem; flex: none; }
.ep:hover:not(:disabled) .ep-icon, .ep.is-active .ep-icon { color: var(--accent); }

/* -------------------------------------- 20. Vacíos, avisos y pie de página */
.empty {
    display: grid; justify-items: center; gap: 10px; text-align: center;
    padding: 56px 24px;
    background: var(--surface); border: 1px dashed var(--border-2); border-radius: var(--r-xl);
}
.empty > i { font-size: 2.4rem; color: var(--text-3); }
.empty h1, .empty h3 { font-size: 1.2rem; font-weight: 800; }
.empty p { color: var(--text-2); font-size: .9rem; max-width: 52ch; }
.empty-actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-top: 8px; }
.empty-page { margin-top: 40px; }

.reanudar-aviso {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    background: var(--accent-tint); border: 1px solid rgba(30, 144, 255, .26);
    border-radius: var(--r-md); padding: 11px 14px; margin-bottom: 13px;
    font-size: .86rem; font-weight: 600; color: var(--accent);
}
.reanudar-aviso span:first-child { flex: 1; min-width: 190px; display: flex; align-items: center; gap: 9px; }
.reanudar-aviso strong { font-weight: 800; }

/* Aviso de «siguiente capítulo»: sobre el vídeo, abajo a la derecha. */
.siguiente-aviso {
    position: absolute; right: 14px; bottom: 14px; z-index: 6;
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    background: rgba(8, 8, 12, .92); color: var(--text);
    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    border: 1px solid var(--border-2); border-radius: var(--r-md);
    padding: 11px 13px; max-width: calc(100% - 28px);
    box-shadow: var(--sh-3); animation: slide .25s var(--ease);
}
.siguiente-aviso strong { display: block; font-size: .74rem; color: var(--text-2); font-weight: 700; }
.siguiente-aviso span { font-size: .86rem; font-weight: 700; }
.siguiente-aviso .btn-ghost { background: rgba(255, 255, 255, .12); color: var(--text); border-color: transparent; }
.siguiente-aviso .btn-ghost:hover { background: rgba(255, 255, 255, .2); color: var(--text); }
.siguiente-aviso em { font-style: normal; color: var(--text-2); }

.sitefoot {
    display: flex; flex-direction: column; align-items: center; gap: 14px;
    padding: 48px 24px 40px; margin-top: 40px;
    border-top: 1px solid var(--border);
    text-align: center;
}
.sitefoot-brand, .sitefoot > strong {
    font-size: 1rem; font-weight: 800;
    text-transform: uppercase; letter-spacing: .26em; padding-left: .26em;
    color: var(--text);
}
.sitefoot-links {
    display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
    gap: 0; font-size: .82rem; color: var(--text-2);
}
.sitefoot-links a {
    display: inline-flex; align-items: center; min-height: 40px; padding: 0 16px;
    color: var(--text-2); font-weight: 600; transition: color .15s;
}
.sitefoot-links a:hover { color: var(--text); }
/* Las barras verticales van en CSS: en el HTML serían texto que el lector de
   pantalla leería como «barra» entre cada enlace. */
.sitefoot-links a + a { position: relative; }
.sitefoot-links a + a::before {
    content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
    width: 1px; height: 12px; background: var(--border-2);
}
.sitefoot small, .sitefoot p { font-size: .76rem; color: var(--text-3); }
.footer { text-align: center; padding: 26px 0 8px; color: var(--text-2); font-size: .82rem; }

/* --------------------------------------------------- 21. Barra inferior */
.tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 200;
    justify-content: space-around; align-items: stretch;
    background: rgba(8, 8, 12, .94);
    backdrop-filter: saturate(180%) blur(20px); -webkit-backdrop-filter: saturate(180%) blur(20px);
    border-top: 1px solid var(--border);
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom, 0px));
    -webkit-user-select: none; user-select: none;
}
.tab {
    flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    min-height: 48px; padding: 5px 2px;
    color: var(--text-2); font-size: .69rem; font-weight: 700;
    touch-action: manipulation;
}
.tab-ico {
    width: 42px; height: 28px; display: grid; place-items: center;
    border-radius: var(--r-pill); font-size: .95rem;
    transition: background .18s var(--ease), color .18s, transform .12s;
}
.tab-txt { line-height: 1.2; }
.tab.is-active { color: var(--accent); }
.tab.is-active .tab-ico { background: var(--accent-tint); }
.tab:active .tab-ico { transform: scale(.88); }

/* ------------------------------------------------------- 22. Responsive */
@media (max-width: 1200px) {
    .panel-grid { grid-template-columns: 1fr; }
    .popular-prev { left: 4px; }
    .popular-next { right: 4px; }
}

/* Por debajo de 900 px el rail de iconos deja de caber junto al contenido:
   se oculta y la navegación pasa a la barra superior (o a la inferior). */
@media (max-width: 900px) {
    :root { --gap: 16px; }
    .railnav { display: none; }
    body:has(.railnav) { padding-left: 0; }
    .topnav { padding: 10px 16px; }
    .topnav-links { gap: 0; overflow-x: auto; scrollbar-width: none; }
    .topnav-links::-webkit-scrollbar { display: none; }
    .topnav-brand { letter-spacing: .16em; font-size: .95rem; }
}

@media (max-width: 1024px) {
    .shell:has(> .sidebar) { grid-template-columns: 1fr; }
    .sidebar {
        position: fixed; top: 0; left: 0; height: 100dvh; width: 286px; max-width: 84vw;
        border-radius: 0 var(--r-xl) var(--r-xl) 0; box-shadow: var(--sh-3);
        transform: translateX(-102%); transition: transform .3s var(--ease); z-index: 100;
    }
    .sidebar.is-open { transform: none; }
    .topbar-menu { display: grid; }
    .badge-text-full, .pill-live { display: none; }
}

/* =========================================================================
   MÓVIL — se comporta como una app: portada a pantalla completa, pestañas
   abajo y la búsqueda como hoja deslizante. Sin menú lateral ni rail.
   ========================================================================= */
@media (max-width: 720px) {
    :root { --gap: 12px; --header-h: 54px; }

    body {
        padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px));
        overscroll-behavior-y: none;
    }
    .shell { padding: 10px 12px 0; gap: 14px; }
    .main { gap: 18px; position: relative; }

    /* --- barra superior: los enlaces estorban, quedan marca y usuario --- */
    .topnav { padding: 8px 12px; gap: 10px; }
    .topnav-links { display: none; }
    .topnav-brand { flex: 1; text-align: left; font-size: .9rem; letter-spacing: .14em; }
    .topnav-user { flex: none; }

    /* --- controles flotantes sobre la portada (barra antigua) --- */
    .topbar {
        position: absolute; top: 0; left: 0; right: 0; z-index: 50;
        min-height: 0; padding: calc(6px + env(safe-area-inset-top, 0px)) 14px 6px;
        gap: 10px; border: 0; border-radius: 0;
        background: transparent;
        /* Sin backdrop-filter: crearía un bloque contenedor y la hoja de
           búsqueda, que es hija suya, dejaría de ocupar la pantalla entera. */
        backdrop-filter: none; -webkit-backdrop-filter: none;
    }
    .topbar-menu, .pill-live, .topbar-brand { display: none; }
    .topbar-actions { gap: 9px; margin-left: auto; }
    .topbar-buscar { display: grid; }
    .topbar .icon-btn, .topbar .avatar {
        width: 40px; height: 40px; border: 0;
        background: rgba(8, 8, 12, .62); color: var(--text);
        backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    }
    .topbar .avatar { background: var(--accent-solid); color: #fff; }

    /* --- portada a pantalla completa --- */
    .hero {
        min-height: 92vh; min-height: 92dvh;
        padding: 24px 18px 34px;
        align-items: flex-end; justify-content: center;
        text-align: center;
    }
    /* Misma especificidad que la regla de escritorio para poder anularla. */
    .shell > .hero, .main > .hero,
    .shell > .hero-carousel, .main > .hero-carousel { margin: -10px -12px 0; }
    .hero-body { align-items: center; text-align: center; max-width: 100%; gap: 12px; }
    .hero-title { font-size: clamp(1.9rem, 9vw, 2.6rem); }
    .hero-text { display: none; }
    .hero-sub { justify-content: center; font-size: .82rem; }
    .hero-stars { justify-content: center; }
    .hero-actions, .hero-cta { width: 100%; justify-content: center; gap: 10px; }
    .hero-actions .btn, .btn-watch, .btn-trailer, .btn-play { flex: 1 1 0; min-width: 0; }
    .hero .pills { justify-content: center; gap: 6px; }
    .hero .pill:nth-child(n+5) { display: none; }
    .hero-shade {
        background: linear-gradient(to top, var(--bg) 4%, rgba(8, 8, 12, .78) 34%, rgba(8, 8, 12, .16) 72%, rgba(8, 8, 12, .35) 100%);
    }
    /* El margen negativo lo lleva el carrusel; sus diapositivas no deben
       repetirlo (la ficha, que no va en carrusel, sí lo conserva). */
    .hero-carousel .hero { margin: 0; }
    .hero-dots { bottom: 8px; }
    .hero-poster, .hero-poster img, .hero-poster .card-img-empty {
        width: 100%; height: auto; border-radius: var(--r-md);
    }

    /* --- ficha: botón de volver flotante en lugar de las migas --- */
    .crumbs { display: none; }
    .back-fab {
        display: grid; place-items: center; position: absolute;
        top: calc(6px + env(safe-area-inset-top, 0px)); left: 14px; z-index: 60;
        width: 40px; height: 40px; border-radius: 50%;
        background: rgba(8, 8, 12, .62); color: var(--text);
        backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
        border: 1px solid var(--border-2);
    }
    .view-detail .hero-text {
        display: -webkit-box; font-size: .82rem; text-align: center; -webkit-line-clamp: 3;
    }

    /* --- hoja de búsqueda a pantalla completa (se abre con :target) --- */
    .search-sheet {
        display: block; position: fixed; inset: 0; z-index: 300;
        background: var(--bg); padding: calc(10px + env(safe-area-inset-top, 0px)) 12px 12px;
        transform: translateY(100%); visibility: hidden;
        transition: transform .28s var(--ease), visibility .28s;
        overflow-y: auto; overscroll-behavior: contain;
    }
    .search-sheet:target, .search-sheet.is-open { transform: none; visibility: visible; }
    .sheet-bar { display: flex; align-items: center; gap: 10px; }
    .sheet-back {
        display: grid; place-items: center; width: 40px; height: 40px; flex: none;
        border-radius: var(--r-md); background: var(--surface-2);
        border: 1px solid var(--border); color: var(--text-2);
    }
    .search { flex: 1; }
    .search-input { padding: 12px 44px 12px 40px; font-size: 1rem; }
    .search-kbd { display: none; }
    .search-clear { right: 12px; }
    .search-suggest {
        position: static; margin-top: 12px; max-height: none;
        box-shadow: none; background: transparent; border: 0; padding: 0;
    }
    .suggest-item { background: var(--surface); border: 1px solid var(--border); margin-bottom: 8px; padding: 10px 12px; }
    .suggest-item img { width: 40px; height: 58px; }

    /* --- rejilla y carruseles: dos por fila --- */
    /* Con arte apaisado tres por fila dejan miniaturas de 111x62 px en un
       móvil de 375: ilegibles. Dos dan 171x96, que es lo que enseña la app. */
    .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 9px; }
    .card-title { font-size: .78rem; }
    .card-meta { font-size: .69rem; gap: 6px; }
    /* Sin ratón no hay hover: el play sobra y el corazón se ve siempre. */
    .card-play { display: none; }
    .card-fav { opacity: 1; transform: none; }
    .card-fav::before { width: 28px; height: 28px; }
    .card:active .card-art { transform: scale(.96); }
    .card-meta .cm-eye { display: none; }   /* tres datos caben; cuatro no */

    .rail-track { gap: 9px; margin: 0 -12px; padding: 4px 12px; }
    /* Apaisadas: 190 px dejan ver una y media larga, que es el trozo que
       invita a deslizar sin que la miniatura se quede en una tira. */
    .rail-track > .card { flex-basis: 190px; }
    .rail-track .card-info { display: none; }
    .rail .section-head { margin-bottom: 10px; }

    /* En el móvil no caben seis: se enseñan tres y pico, y ese trozo de la
       cuarta es justamente lo que invita a deslizar. */
    .popular-track {
        --pop-gap: 10px; --pop-visibles: 1.8;
        margin: 0 -12px; padding: 16px 12px 14px;
    }

    /* --- banner --- */
    .banner { min-height: 300px; padding: 20px 16px; border-radius: var(--r-md); }
    .banner-text { -webkit-line-clamp: 2; font-size: .84rem; }
    .banner-actions { width: 100%; }
    .banner-actions .btn-watch, .banner-actions .btn-list { flex: 1 1 0; }

    /* --- filtros --- */
    .filters { padding: 11px; border-radius: var(--r-lg); gap: 10px; }
    .filter-types { margin: 0 -11px; padding: 0 11px 2px; }
    .chiprow { margin: 0 -12px; padding: 2px 12px 8px; }
    .chip { padding: 9px 14px; font-size: .8rem; }
    .select { max-width: 145px; }
    .toggle span:last-child { font-size: .78rem; }
    .panel-actions .btn { flex: 1; }

    /* --- secciones --- */
    .section-title { font-size: 1rem; }
    .section-title > i { width: 27px; height: 27px; font-size: .72rem; }
    .section-count { font-size: .72rem; }
    .tabsrow { margin: 0 -12px 16px; padding: 0 12px; }

    /* --- ficha --- */
    .player-card, .episodes { padding: 13px; border-radius: var(--r-lg); }
    .player-head { gap: 10px; }
    .segmented { width: 100%; overflow-x: auto; scrollbar-width: none; }
    .segmented::-webkit-scrollbar { display: none; }
    .ep-grid { grid-template-columns: 1fr; }
    .ep { min-height: 58px; }
    .siguiente-aviso { left: 10px; right: 10px; bottom: 10px; justify-content: space-between; }
    .reanudar-aviso .btn { flex: 1; }

    /* --- paginación y pie --- */
    .pager-word { display: none; }
    .pager-btn { min-width: 40px; height: 40px; }
    .btn-lg { padding: 12px 18px; font-size: .88rem; }
    .showmore { min-height: 48px; margin: 20px 0 4px; }
    .sitefoot { padding: 32px 16px 28px; margin-top: 28px; gap: 10px; }
    .sitefoot-links { font-size: .78rem; }
    .sitefoot-links a { padding: 0 12px; }
    .footer { padding: 18px 0 6px; font-size: .74rem; }

    .tabbar { display: flex; }
}

/* Por debajo de 340 px se mantienen las dos columnas —una sola dejaría una
   página kilométrica— pero se quita el hueco horizontal y se estrecha la
   bandeja: son los 20 px que faltan para que la miniatura siga leyéndose. */
@media (max-width: 340px) {
    .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 6px; }
    .rail-track > .card { flex-basis: 160px; }
    .popular-track { --pop-visibles: 1.5; }
}

/* Pantallas grandes: el hero no debe comerse toda la altura disponible. */
@media (min-width: 1600px) {
    .hero { min-height: 620px; }
}

/* Los usuarios que piden más contraste reciben bordes sólidos en vez de
   blancos translúcidos, que sobre negro casi desaparecen. */
@media (prefers-contrast: more) {
    :root {
        --border:   rgba(255, 255, 255, .22);
        --border-2: rgba(255, 255, 255, .38);
        --text-2:   #C6CAD8;
        --text-3:   #A9AEC0;
    }
}

@media print {
    .railnav, .topnav, .topbar, .sidebar, .filters, .pager,
    .rail-nav, .popular-nav, .hero-nav, .player-card, .tabbar { display: none !important; }
    body { background: #fff; color: #000; padding-left: 0; }
    .shell { grid-template-columns: 1fr; }
}

/* ------------------------------------------------- 22b. Escritorio: un solo menú
   El cajón lateral y el raíl de iconos son la misma navegación: en pantallas
   anchas sólo debe verse el raíl. Sin esto salían los dos, el cajón de 264 px
   empujando el contenido y el raíl encima. */
@media (min-width: 901px) {
    .sidebar { display: none; }
    .shell:has(> .sidebar) { grid-template-columns: minmax(0, 1fr); }
}

/* ------------------------------------- 22c. Filtros en modo reducido (portada)
   Sin filas visibles, la caja se quedaría como un rectángulo vacío entre los
   géneros y la rejilla. Cuando el panel se abre recupera su marco. */
.filters-min { background: none; border: 0; padding: 0; margin-bottom: 0; gap: 0; }
.filters-min .panel { border-top: 0; padding-top: 0; }
.filters-min:not(:has(.panel[hidden])) {
    background: var(--surface); border: 1px solid var(--border);
    padding: 14px; margin-bottom: 22px;
}
/* El bloque de orden ocupa las dos columnas del panel: es una fila, no una
   columna de casillas. */
.panel-ancho { grid-column: 1 / -1; }
.panel-ancho .filter-tools { flex-wrap: wrap; }

/* =========================================================================
   23. Televisor (Google TV / Android TV) y animaciones tipo app nativa
   Se activa cuando tv.js detecta un mando (clase .tv en <html>). A tres metros
   de distancia cambian tres cosas: el foco debe verse desde el sofá, los bordes
   de la pantalla se recortan, y todo texto pequeño deja de leerse.
   ========================================================================= */
:root { --tv-safe: 0px; }

/* El foco tiene que verse desde el sofá, a tres metros: filo blanco grueso y
   bien separado. En un televisor el foco no es un adorno, es el cursor. */
.tv :focus,
.tv .card:focus,
.tv .watch-frame:focus,
.tv .eps-fila:focus {
    outline: 4px solid #fff;
    outline-offset: 4px;
    border-radius: var(--r-md);
}
/* El marco del vídeo es un control más con mando: se enfoca y la cruceta pasa
   a manejar el reproductor. Sin marca no se sabría que lo tiene. */
.tv .watch-frame { outline-offset: -4px; }
/* En las tarjetas el foco además las levanta, como en las apps de televisor:
   el borde solo no basta para saber dónde estás de un vistazo. */
/* El resalte del foco vive entero en el bloque 29; aquí sólo queda la capa,
   para que la tarjeta señalada pase por encima de sus vecinas. */
.tv .card:focus { z-index: 20; }
.tv .card:focus .card-title { color: #fff; }

.tv .btn-watch:focus, .tv .btn-trailer:focus,
.tv .chip:focus, .tv .tabsrow a:focus {
    outline: 3px solid #fff; outline-offset: 3px; transform: scale(1.05);
}

/* Margen de seguridad: los televisores recortan los bordes de la imagen. */
.tv .shell    { padding-left: calc(var(--gap) + var(--tv-safe)); padding-right: calc(var(--gap) + var(--tv-safe)); }
.tv .sitefoot { padding-bottom: calc(28px + var(--tv-safe)); }
.tv .topnav   { padding-top: calc(18px + var(--tv-safe)); }

/* A tres metros, todo un punto más grande. */
.tv { font-size: 18px; }
.tv .card-title { font-size: .92rem; }
.tv .card-meta, .tv .cm-year, .tv .cm-rate { font-size: .8rem; }
.tv .section-title { font-size: 1.35rem; }
.tv .hero-text { font-size: 1rem; -webkit-line-clamp: 2; }
.tv .grid { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 26px 18px; }

/* El puntero no existe: lo que dependía de :hover pasa a verse siempre. */
.tv .card-fav { opacity: 1; transform: none; }
.tv .rail-nav { opacity: 1; }
/* …y el cursor se esconde, que en un televisor sólo estorba. */
.tv, .tv * { cursor: none; }

/* -------------------------------------------------- peso para el aparato
 * Un Chromecast con Google TV tiene una fracción de la potencia de un móvil
 * de gama media. Los desenfoques a pantalla completa y las transparencias con
 * recomposición son justo lo que no aguanta: con 60 carteles en pantalla la
 * interfaz se arrastra. Se apagan y se sustituyen por opacidad, que sale
 * prácticamente gratis.
 */
.tv .card-fondo,
.tv .portal-fondo,
.tv .modal-arte-fondo,
.tv .modal-sim-fondo { filter: none; opacity: .35; transform: scale(1.15); }

.tv .eps-panel,
.tv .topnav,
.tv .searchbar-compacta input,
.tv .rail-nav {
    -webkit-backdrop-filter: none; backdrop-filter: none;
}
.tv .eps-panel { background: rgba(8, 8, 12, .96); }

/* La tarjeta ampliada al pasar el ratón no tiene sentido con mando —no hay
   «pasar por encima»— y además obligaría a componer una capa más. */
.tv .portal { display: none !important; }

/* Sombras grandes y difusas: cada una es una pasada de desenfoque. Con foco en
   una tarjeta basta el filo blanco. */
.tv .card-art, .tv .card:hover .card-art { box-shadow: none; }

/* La barra inferior no pinta nada con mando: se navega con la cruceta. */
.tv .tabbar { display: none; }
.tv body { padding-bottom: 0; }

/* Con mando, el panel de capítulos y el modal son la única forma de elegir:
   se les da más cuerpo para que se lean desde lejos. */
.tv .eps-nombre { font-size: 1.05rem; }
.tv .eps-num { font-size: 1.1rem; }
.tv .eps-fila { padding: 16px 14px; }
.tv .modal { width: min(1100px, 92vw); }
.tv .modal-titulo { font-size: 2rem; }

/* Animaciones de entrada, al estilo de una app nativa: las secciones aparecen
   con un desplazamiento corto en lugar de saltar de golpe. */
@media (prefers-reduced-motion: no-preference) {
    /* «backwards» y no «both»: al terminar, la animación deja de imponer sus
       valores. Con «both» el opacity:1 final seguía ganando y bloqueaba el
       fundido de salida del héroe al cambiar de título. */
    .hero-body > * { animation: entrar .5s var(--ease) backwards; }
    .rail, .popular, .catalog, .banner, .player-card, .episodes {
        animation: entrar .5s var(--ease) both;
    }
    .hero-body > *:nth-child(1) { animation-delay: .04s; }
    .hero-body > *:nth-child(2) { animation-delay: .10s; }
    .hero-body > *:nth-child(3) { animation-delay: .16s; }
    .hero-body > *:nth-child(4) { animation-delay: .22s; }
    .hero-body > *:nth-child(5) { animation-delay: .28s; }
    .rail:nth-of-type(2) { animation-delay: .06s; }
    .rail:nth-of-type(3) { animation-delay: .12s; }
}
@keyframes entrar {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: none; }
}

/* =========================================================================
   24. Página de ver — el vídeo es la página
   El reproductor ocupa la parte de arriba a sangre y los datos van encima.
   Al empezar a reproducir pasa a ocupar la pantalla entera (html.viendo), que
   es como se comporta cualquier aplicación de televisión.
   ========================================================================= */
.watch {
    position: relative; isolation: isolate;
    aspect-ratio: 16/9; max-height: 78vh; width: auto;
    background: #000 center/cover no-repeat;
    border-radius: 0; overflow: hidden;
}
/* A sangre, igual que el héroe de la portada. */
/* A sangre por los lados. Arriba nace pegado a la barra: el hueco de 70 px lo
   pone .shell y el vídeo empieza justo ahí. */
.main > .watch, .shell > .watch {
    margin-left: calc(var(--gap) * -1);
    margin-right: calc(var(--gap) * -1);
    margin-top: 0;
}
/* En la página de ver, la ruta de migas se queda sólo para lectores de
   pantalla y buscadores: en el clon el vídeo empieza bajo la barra y no hay
   nada entre medias. */
.main:has(.watch) .crumbs {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.watch-frame { position: absolute; inset: 0; }
.watch-frame iframe { width: 100%; height: 100%; border: 0; display: block; background: #000; }

/* Velo por la izquierda y por abajo: sostiene el texto sin apagar la imagen. */
.watch-veil {
    position: absolute; inset: 0; z-index: 2; pointer-events: none;
    background:
        linear-gradient(to right, rgba(0, 0, 0, .88) 0%, rgba(0, 0, 0, .62) 32%, rgba(0, 0, 0, .08) 58%, transparent 74%),
        linear-gradient(to top, rgba(0, 0, 0, .78) 0%, transparent 42%);
    transition: opacity .45s var(--ease);
}

.watch-info {
    position: absolute; z-index: 3;
    left: clamp(18px, 4vw, 56px); bottom: clamp(22px, 6vh, 64px);
    width: min(46%, 560px); min-width: 0;
    display: flex; flex-direction: column; align-items: flex-start; gap: 12px;
    /* Clave: la capa NO intercepta el ratón, para que el reproductor de dentro
       del iframe siga respondiendo. Sólo sus botones lo reciben. */
    pointer-events: none;
    transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.watch-info button, .watch-info a { pointer-events: auto; }

/* QR de apoyo, encima del rótulo de la ficha. En un lado, pequeño y sin
   tapar nada: dentro del reproductor obligaba a mirarlo antes de ver nada. */
.watch-apoyo {
    display: inline-grid; justify-items: center; gap: 6px;
    padding: 10px; border-radius: 10px;
    background: rgba(0, 0, 0, .45);
    border: 1px solid rgba(255, 255, 255, .14);
}
.watch-apoyo-t {
    font-size: .6rem; font-weight: 800; letter-spacing: .18em;
    color: rgba(255, 255, 255, .7);
}
.watch-apoyo-qr {
    width: 104px; height: 104px; display: block;
    border-radius: 6px; background: #fff; padding: 6px;
    /* El QR es un mapa de bits: al escalarlo, el suavizado emborrona los
       módulos y el móvil deja de leerlo. */
    image-rendering: pixelated;
}
@media (max-width: 720px) { .watch-apoyo-qr { width: 84px; height: 84px; } }

.watch-eyebrow {
    font-size: .72rem; font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
    color: rgba(255, 255, 255, .72);
}
.watch-title {
    font-size: clamp(1.7rem, 4vw, 3.1rem); font-weight: 800; line-height: 1.04;
    letter-spacing: -.02em; color: #fff;
    text-shadow: 0 3px 22px rgba(0, 0, 0, .8);
}
.watch-meta { font-size: .84rem; font-weight: 600; color: rgba(255, 255, 255, .74); }
.watch-text {
    font-size: .88rem; line-height: 1.55; color: rgba(255, 255, 255, .8);
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

/* Avance guardado, al estilo «121 de 130 min». */
.watch-progreso { display: flex; align-items: center; gap: 12px; width: 100%; max-width: 420px; }
.watch-progreso-linea {
    flex: 1; height: 3px; border-radius: 99px;
    background: rgba(255, 255, 255, .3); overflow: hidden;
}
.watch-progreso-linea i { display: block; height: 100%; width: 0; background: var(--hot); border-radius: 99px; }
.watch-progreso-txt { font-size: .78rem; font-weight: 600; color: rgba(255, 255, 255, .78); white-space: nowrap; }

.watch-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.watch-icon {
    width: 44px; height: 44px; border-radius: 50%;
    background: rgba(255, 255, 255, .16); border: 1px solid rgba(255, 255, 255, .28); color: #fff;
}
.watch-icon:hover { background: rgba(255, 255, 255, .28); }

/* Tarjeta del capítulo siguiente. */
.watch-next { margin-top: 4px; }
.watch-next-rotulo { font-size: .74rem; font-weight: 700; color: rgba(255, 255, 255, .66); margin-bottom: 7px; }
.watch-next-caja { display: flex; gap: 12px; align-items: center; }
.watch-next-art { width: 64px; height: 40px; object-fit: cover; border-radius: 6px; flex: none; }
.watch-next-titulo { font-size: .84rem; font-weight: 700; color: #fff; margin-bottom: 5px; }
.watch-next-titulo span { opacity: .45; margin: 0 4px; font-weight: 400; }
.watch-next-btn {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: .78rem; font-weight: 700; color: rgba(255, 255, 255, .82);
    background: none; border: 0; padding: 4px 0; cursor: pointer;
}
.watch-next-btn:hover { color: #fff; }
.watch-next-btn i { font-size: .7em; }

/* Volver / reportar: escondidos hasta que se entra a pantalla completa. */
.watch-top {
    position: absolute; inset: 0 0 auto; z-index: 5;
    display: flex; justify-content: space-between;
    padding: clamp(14px, 2.4vw, 30px);
    opacity: 0; pointer-events: none; transition: opacity .3s var(--ease);
}
.watch-top-btn {
    width: 46px; height: 46px; border-radius: 50%;
    display: grid; place-items: center; font-size: 1.15rem;
    color: #fff; background: rgba(0, 0, 0, .38); border: 0; cursor: pointer;
    transition: background .18s, transform .18s;
}
.watch-top-btn:hover { background: rgba(0, 0, 0, .66); transform: scale(1.06); }

/* ------------------------------------------------- modo pantalla completa */
html.viendo, html.viendo body { overflow: hidden; }
html.viendo .watch {
    position: fixed; inset: 0; z-index: 90;
    margin: 0; max-height: none; aspect-ratio: auto;
    background: #000;
    animation: entraPantalla .34s var(--ease);
}
@keyframes entraPantalla {
    from { opacity: .4; transform: scale(.96); }
    to   { opacity: 1; transform: none; }
}
/* Con el vídeo a pantalla completa sobran los textos: es el vídeo y punto. */
html.viendo .watch-info { opacity: 0; transform: translateY(14px); pointer-events: none; }
html.viendo .watch-veil { opacity: 0; }
html.viendo .watch-top { opacity: 1; pointer-events: auto; }
/* Los controles del propio vídeo se esconden solos; cuando eso pasa, también
   se va la barra de arriba, para no dejar botones flotando sobre la imagen. */
html.viendo.quieto .watch-top { opacity: 0; pointer-events: none; }
html.viendo.quieto .watch { cursor: none; }

/* La capa de información también se retira al empezar a reproducir, aunque no
   se haya entrado a pantalla completa. Nada de devolverla al pasar el ratón:
   mientras se reproduce, encima del vídeo sólo va la barra del reproductor. */
.watch.is-playing .watch-info { opacity: 0; transform: translateY(14px); }
.watch.is-playing .watch-veil { opacity: 0; }

/* Tira de servidores bajo el vídeo. */
.watch-bar {
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
    padding: 16px 0 4px; margin-bottom: 6px;
}
.watch-bar .segmented { flex: 1 1 auto; min-width: 0; }
.watch-bar .player-hint { margin: 0; font-size: .8rem; color: var(--text-2); }
.watch-detalle { margin-bottom: 26px; }

@media (max-width: 900px) {
    .watch { max-height: none; }
    .watch-info { width: min(78%, 480px); }
    .watch-text { -webkit-line-clamp: 2; }
}
@media (max-width: 720px) {
    /* En el móvil el texto va debajo del vídeo, no encima: sobre una pantalla
       de 16:9 en vertical no cabe nada legible. */
    .watch { aspect-ratio: 16/9; }
    .watch-info { position: static; width: 100%; padding: 14px 0 0; pointer-events: auto; }
    .watch-veil { background: linear-gradient(to top, rgba(0, 0, 0, .55), transparent 46%); }
    .watch.is-playing .watch-info { opacity: 1; transform: none; }
    .watch-title { font-size: 1.35rem; text-shadow: none; color: var(--text); }
    .watch-eyebrow, .watch-meta, .watch-text { color: var(--text-2); }
}
@media (prefers-reduced-motion: reduce) {
    html.viendo .watch { animation: none; }
    .watch-info, .watch-veil, .watch-top { transition: none; }
}

/* =========================================================================
   25. Panel de capítulos sobre el vídeo
   Entra por la derecha sin parar lo que se está viendo: se elige el siguiente
   capítulo mientras sigue sonando el actual. El que suena se despliega con su
   miniatura y el rótulo «Reproduciendo»; el resto son una línea.
   ========================================================================= */
.eps-panel {
    position: absolute; z-index: 6;
    top: 0; right: 0; bottom: 0;
    width: min(46%, 560px);
    display: flex; flex-direction: column;
    padding: clamp(16px, 2.4vw, 30px) clamp(14px, 2vw, 26px) 96px;
    background: linear-gradient(to left, rgba(0, 0, 0, .88) 0%, rgba(0, 0, 0, .78) 70%, rgba(0, 0, 0, .34) 100%);
    -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
    animation: epsEntra .3s var(--ease);
}
.eps-panel[hidden] { display: none; }
@keyframes epsEntra {
    from { opacity: 0; transform: translateX(38px); }
    to   { opacity: 1; transform: none; }
}

.eps-head { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; flex: none; }
.eps-back {
    width: 40px; height: 40px; border-radius: 50%; flex: none;
    display: grid; place-items: center; font-size: 1.05rem;
    color: #fff; background: none; border: 0; cursor: pointer;
    transition: background .18s;
}
.eps-back:hover { background: rgba(255, 255, 255, .14); }
.eps-head-titulo { font-size: 1.32rem; font-weight: 800; color: #fff; letter-spacing: -.01em; }

.eps-temporadas { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; flex: none; }
.eps-temporada {
    min-height: 34px; padding: 0 14px; border-radius: var(--r-pill);
    font-size: .8rem; font-weight: 700; cursor: pointer;
    color: rgba(255, 255, 255, .74);
    background: rgba(255, 255, 255, .1); border: 1px solid transparent;
}
.eps-temporada:hover { background: rgba(255, 255, 255, .2); color: #fff; }
.eps-temporada.is-active { background: #fff; color: #000; }

.eps-lista { flex: 1; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; }
.eps-lista::-webkit-scrollbar { width: 5px; }
.eps-lista::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .26); border-radius: 99px; }

/* Cada fila es una rejilla: número + nombre a la izquierda y la línea de lo
   visto a la derecha. La miniatura y el pie sólo se despliegan en la que está
   sonando, y ocupan las filas de abajo. */
.eps-fila {
    display: grid;
    grid-template-columns: 30px minmax(0, 1fr) 84px;
    grid-template-areas: 'num nombre linea';
    align-items: center; gap: 4px 10px;
    width: 100%; padding: 13px 12px; text-align: left;
    background: none; border: 1px solid transparent; border-radius: 8px;
    color: rgba(255, 255, 255, .82); cursor: pointer;
    transition: background .16s, border-color .16s;
}
.eps-fila:hover:not(:disabled) { background: rgba(255, 255, 255, .08); }
.eps-fila:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.eps-fila.is-muerta { opacity: .38; cursor: not-allowed; }

.eps-num    { grid-area: num; font-size: 1rem; font-weight: 700; color: rgba(255, 255, 255, .62); }
.eps-nombre { grid-area: nombre; font-size: .95rem; font-weight: 700; color: #fff; }
.eps-linea  {
    grid-area: linea; height: 2px; border-radius: 99px;
    background: rgba(255, 255, 255, .34); overflow: hidden;
}
.eps-linea i { display: block; height: 100%; width: 0; background: var(--hot); }

/* Plegados mientras el capítulo no sea el que suena. */
.eps-tarjeta, .eps-pie { display: none; }

.eps-fila.is-sonando {
    border-color: rgba(255, 255, 255, .9);
    background: rgba(255, 255, 255, .06);
    grid-template-areas:
        'num     nombre  linea'
        'tarjeta tarjeta tarjeta'
        'pie     pie     pie';
    padding: 15px 14px 16px;
}
.eps-fila.is-sonando .eps-tarjeta {
    grid-area: tarjeta; display: block; position: relative;
    margin-top: 10px; border-radius: 6px; overflow: hidden;
    aspect-ratio: 16/9; max-width: 220px; background: var(--surface-2);
}
.eps-fila.is-sonando .eps-tarjeta img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Mientras el flujo se abre, el rótulo dice la verdad: «Cargando…». Ponerlo ya
   en «Reproduciendo» mientras seguía viéndose el capítulo anterior hacía pensar
   que el clic no había funcionado. */
.eps-fila.is-cargando .eps-sonando span { display: none; }
.eps-fila.is-cargando .eps-sonando::after { content: 'Cargando…'; }
.eps-fila.is-cargando .eps-sonando i {
    animation: girarEps .9s linear infinite;
}
@keyframes girarEps { to { transform: rotate(360deg); } }

.eps-sonando {
    position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 8px;
    background: rgba(0, 0, 0, .48);
    font-size: .82rem; font-weight: 700; color: #fff;
}
.eps-fila.is-sonando .eps-pie {
    grid-area: pie; display: block; margin-top: 9px;
    font-size: .78rem; color: rgba(255, 255, 255, .6);
}

@media (max-width: 900px) { .eps-panel { width: min(70%, 460px); } }
@media (max-width: 720px) {
    /* En vertical no cabe media pantalla al lado del vídeo: entra desde abajo. */
    .eps-panel {
        position: fixed; inset: auto 0 0; top: 34%;
        width: 100%; border-radius: 18px 18px 0 0; padding-bottom: 24px;
        background: rgba(8, 8, 12, .97);
        animation-name: epsEntraAbajo;
    }
    @keyframes epsEntraAbajo {
        from { opacity: 0; transform: translateY(40px); }
        to   { opacity: 1; transform: none; }
    }
}
@media (prefers-reduced-motion: reduce) { .eps-panel { animation: none; } }
/* Flechas de carrusel: en la referencia están siempre, no sólo al acercar el
   ratón, y montadas sobre el borde de la fila. */
.rail-nav {
    opacity: 1;
    background: rgba(10, 10, 14, .72);
    border-color: rgba(255, 255, 255, .16);
    box-shadow: 0 6px 20px rgba(0, 0, 0, .5);
}
.rail-nav:hover { background: var(--hot); border-color: transparent; transform: translateY(-50%) scale(1.08); }
.rail-prev { left: -18px; }
.rail-next { right: -18px; }

/* =========================================================================
   27. Tarjeta ampliada al pasar el ratón (el «mini-portal» de Netflix)
   Portado del clon que hay en clonetemplate/ (VideoCardPortal.tsx): mismo
   ancho (x1.5 de la tarjeta), mismo desplazamiento, misma ampliación desde el
   lado que corresponde y el mismo 16:9 del original —antes era cuadrado, que
   era el apaño de cuando la tarjeta era un cartel vertical—.
   Los títulos sin apaisado no se recortan: se rellenan con su propio cartel
   desenfocado, igual que en la sección 14.
   ========================================================================= */
.portal {
    position: absolute; z-index: 60;
    border-radius: 8px; overflow: hidden;
    background: #181818;
    box-shadow: 0 18px 48px rgba(0, 0, 0, .78);
    animation: portalAbre .26s cubic-bezier(.2, .7, .2, 1);
    transform-origin: center center;
}
.portal[hidden] { display: none; }
.portal-desde-izq { transform-origin: left center; }
.portal-desde-der { transform-origin: right center; }
@keyframes portalAbre {
    from { opacity: 0; transform: scale(.72); }
    to   { opacity: 1; transform: none; }
}

.portal-art {
    position: relative; display: block; aspect-ratio: 16/9;
    overflow: hidden; background: var(--surface-2);
}
/* Las dos imágenes se apilan (fondo desenfocado + cartel entero), así que van
   las dos absolutas: en flujo se pondrían una debajo de otra. */
.portal-art img {
    position: absolute; inset: 0; display: block;
    width: 100%; height: 100%; object-fit: cover; object-position: center;
}
/* Sin apaisado el cartel se enseña completo y el hueco lo tapa su propia
   copia ampliada y desenfocada; el scale evita el halo claro del borde. */
.portal-art[data-sin-arte="1"] img { object-fit: contain; }
.portal-art[data-sin-arte="1"] .portal-fondo {
    object-fit: cover;
    filter: blur(18px) brightness(.55);
    transform: scale(1.15);
}
.portal-sombra {
    position: absolute; inset: 0;
    background: linear-gradient(to top, rgba(0, 0, 0, .92) 4%, transparent 46%);
}
/* Como en el clon: el título vive sobre el arte, abajo a la izquierda, y no
   pasa del 80 % del ancho para no chocar con nada que se pinte a la derecha. */
.portal-titulo {
    position: absolute; left: 16px; right: 16px; bottom: 12px;
    max-width: 80%;
    font-size: 1.05rem; font-weight: 700; line-height: 1.3; color: #fff;
    text-shadow: 0 2px 8px rgba(0, 0, 0, .7);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

.portal-cuerpo { padding: 14px 16px 16px; display: flex; flex-direction: column; gap: 10px; }
.portal-botones { display: flex; align-items: center; gap: 8px; }
/* El play del clon es un PlayCircleIcon de 40 px sin caja: un disco blanco
   macizo a la izquierda, más grande que los redondos que lo acompañan. */
.portal-play {
    width: 40px; height: 40px; border-radius: 50%; flex: none;
    display: grid; place-items: center; font-size: .82rem;
    background: #fff; color: #000;
    transition: transform .16s, background .16s;
}
.portal-play:hover { transform: scale(1.08); background: rgba(255, 255, 255, .82); }
.portal-btn {
    width: 34px; height: 34px; border-radius: 50%; flex: none;
    display: grid; place-items: center; font-size: .8rem; cursor: pointer;
    color: #fff; background: rgba(42, 42, 42, .8);
    border: 2px solid rgba(255, 255, 255, .5);
    transition: border-color .16s, background .16s, transform .16s;
}
.portal-btn:hover { border-color: #fff; background: rgba(70, 70, 70, .9); transform: scale(1.06); }
/* La flecha de «más información» se va al extremo derecho, como el original. */
.portal-mas { margin-left: auto; }
.portal-play:focus-visible, .portal-btn:focus-visible {
    outline: 2px solid #fff; outline-offset: 3px;
}

.portal-datos {
    display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
    font-size: .8rem; font-weight: 600; color: rgba(255, 255, 255, .88);
}
/* En el clon el primer dato de la fila va en verde (el «% de coincidencia»).
   Aquí el primero es la nota real, así que se queda con el ámbar de estrella
   —inventar un porcentaje sería fingir un dato que el catálogo no tiene—. */
.portal-nota { color: var(--star); display: inline-flex; align-items: center; gap: 4px; }
.portal-cal {
    font-size: .64rem; font-weight: 800; letter-spacing: .04em;
    padding: 1px 5px; border-radius: 3px;
    border: 1px solid rgba(255, 255, 255, .42); color: rgba(255, 255, 255, .82);
}
/* Géneros: el texto ya llega separado por « · » desde card.php, así que aquí
   sólo hace falta el gris apagado y que no crezca más de dos líneas. */
.portal-gen {
    font-size: .78rem; color: var(--text-2); line-height: 1.45;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
    .portal { animation: none; }
    .portal-play:hover, .portal-btn:hover { transform: none; }
}

/* =========================================================================
   28. Modal de detalle
   Réplica del DetailModal.tsx del clon: una hoja de 850 px centrada sobre un
   velo negro, con el arte apaisado arriba, el título y los botones encima del
   arte, los datos y la sinopsis debajo a dos columnas, y las recomendaciones
   al final. Lo pinta assets/js/modal.js.
   ========================================================================= */
.modal-velo {
    position: fixed; inset: 0; z-index: 200;
    /* 70 % y no más: el catálogo del fondo se sigue intuyendo, que es lo que
       hace que el modal se lea como una capa y no como otra página. */
    background: rgba(0, 0, 0, .7);
    display: flex; justify-content: center;
    /* align-items:flex-start en vez de center: centrado, un modal más alto que
       la ventana se recorta por arriba y el aspa deja de alcanzarse. */
    align-items: flex-start;
    padding: 4vh 16px;
    overflow-y: auto; overscroll-behavior: contain;
    animation: modalVelo .2s ease;
}
.modal-velo[hidden] { display: none; }
@keyframes modalVelo { from { opacity: 0; } to { opacity: 1; } }

.modal {
    position: relative;
    width: min(850px, 100%);
    max-height: 90vh; overflow-y: auto; overscroll-behavior: contain;
    border-radius: var(--r-lg);
    background: var(--surface);
    box-shadow: 0 32px 90px rgba(0, 0, 0, .85);
    /* Se abre creciendo desde su centro, como el Dialog del clon. */
    animation: modalAbre .26s var(--ease);
    transform-origin: center center;
    scrollbar-width: thin; scrollbar-color: var(--surface-3) transparent;
}
@keyframes modalAbre {
    from { opacity: 0; transform: scale(.88); }
    to   { opacity: 1; transform: none; }
}
.modal::-webkit-scrollbar { width: 8px; }
.modal::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 4px; }

/* El aspa flota sobre el arte, así que lleva fondo propio: sobre una imagen
   clara un icono blanco a pelo desaparece. */
.modal-cerrar {
    position: absolute; top: 15px; right: 15px; z-index: 3;
    width: 40px; height: 40px; border-radius: 50%; flex: none;
    display: grid; place-items: center;
    background: var(--surface); color: #fff; font-size: 1rem; cursor: pointer;
    transition: background .16s;
}
.modal-cerrar:hover { background: var(--hot-deep); }

/* ---- Arte ---- */
.modal-arte {
    position: relative; aspect-ratio: 16/9;
    background: var(--surface-2); overflow: hidden;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
}
.modal-arte img {
    position: absolute; inset: 0; display: block;
    width: 100%; height: 100%; object-fit: cover; object-position: center;
}
/* Mismo recurso que en las tarjetas y en el mini-portal: sin apaisado, el
   cartel entero encima de una copia suya ampliada y desenfocada. Aquí la caja
   es mucho mayor, así que el desenfoque sube a 28 px para que no se llegue a
   reconocer la imagen del fondo.
   El degradado queda debajo por si el título no trae ninguna imagen: entonces
   no hay copia que desenfocar y sin él el hueco sería un rectángulo plano. */
.modal-arte[data-sin-arte="1"] {
    background:
        radial-gradient(120% 90% at 50% 40%, #232323 0%, #121212 100%);
}
.modal-arte[data-sin-arte="1"] img { object-fit: contain; z-index: 1; }
.modal-arte[data-sin-arte="1"] .modal-arte-fondo {
    z-index: 0; object-fit: cover;
    filter: blur(28px) brightness(.5);
    transform: scale(1.18);
}
/* Los dos degradados del clon: uno lateral desde la izquierda para que el
   título tenga sobre qué apoyarse y otro hacia arriba desde el borde inferior,
   que es el que funde el arte con el cuerpo del modal. */
.modal-arte-sombra {
    position: absolute; inset: 0; z-index: 1;
    background:
        linear-gradient(77deg, rgba(0, 0, 0, .6), transparent 85%),
        linear-gradient(180deg, transparent 0, rgba(24, 24, 24, .35) 55%, var(--surface) 96%);
}

.modal-titulo {
    position: absolute; left: 0; right: 0; bottom: 78px; z-index: 2;
    padding: 0 48px; margin: 0;
    font-size: clamp(1.6rem, 3.2vw, 2.2rem); font-weight: 700; line-height: 1.15;
    color: #fff; text-shadow: 0 2px 12px rgba(0, 0, 0, .6);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* La fila de botones es hermana del arte, no hija: se sube con un margen
   negativo hasta apoyarse sobre el último tramo de la imagen, que a esa altura
   el degradado ya ha fundido con el fondo del modal. Es la posición que ocupa
   en el clon, y hacerlo así —y no con position:absolute— deja que el bloque
   empuje al de abajo cuando los botones se parten en dos líneas. */
.modal-acciones {
    position: relative; z-index: 3;
    margin-top: -62px; padding: 0 48px;
    display: flex; align-items: center; flex-wrap: wrap; gap: 12px;
}
/* Botón principal del clon: relleno blanco, texto negro, sin mayúsculas. */
.modal-play {
    display: inline-flex; align-items: center; gap: 8px;
    height: 44px; padding: 0 24px; border-radius: var(--r-sm);
    background: var(--btn); color: var(--btn-texto);
    font-size: 1.05rem; font-weight: 700; white-space: nowrap; cursor: pointer;
    transition: background .16s;
}
.modal-play:hover { background: rgba(255, 255, 255, .75); }
.modal-play i { font-size: 1.15rem; }
.modal-btn {
    width: 42px; height: 42px; border-radius: 50%; flex: none;
    display: grid; place-items: center; font-size: .95rem; cursor: pointer;
    color: #fff; background: rgba(42, 42, 42, .6);
    border: 2px solid rgba(255, 255, 255, .5);
    transition: border-color .16s, background .16s, transform .16s;
}
.modal-btn:hover { border-color: #fff; background: rgba(70, 70, 70, .9); transform: scale(1.06); }
/* El último control se va al extremo derecho: en el clon hay un separador
   elástico justo antes del altavoz. */
.modal-acciones > :last-child { margin-left: auto; }

/* ---- Cuerpo ---- */
/* Los datos cuelgan directamente del modal (no del cuerpo), así que el margen
   lateral de 48 px lo pone este bloque por su cuenta. */
.modal-datos {
    display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
    margin: 0; padding: 20px 48px 0;
    font-size: .9rem; font-weight: 600; color: var(--text);
}
.modal-nota { color: var(--star); display: inline-flex; align-items: center; gap: 5px; }
.modal-cal {
    font-size: .7rem; font-weight: 800; letter-spacing: .04em;
    padding: 2px 6px; border-radius: 3px;
    border: 1px solid rgba(255, 255, 255, .42); color: var(--text-2);
}

/* Dos columnas asimétricas como el Grid md={8}/md={4} del clon: la sinopsis
   manda y la ficha (géneros, idiomas) queda de apoyo a la derecha. */
.modal-cuerpo {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 14px 40px; align-items: start;
    padding: 14px 48px 28px;
}
.modal-sinopsis {
    grid-column: 1; margin: 0;
    font-size: .95rem; line-height: 1.55; color: var(--text);
}
/* 1 / -1 y no un span fijo: la ficha ocupa la derecha entera aunque el cuerpo
   acabe trayendo más bloques a la izquierda. */
.modal-ficha {
    grid-column: 2; grid-row: 1 / -1; margin: 0;
    font-size: .85rem; line-height: 1.6; color: var(--text-3);
}
.modal-ficha p { margin: 0 0 8px; }
.modal-ficha p:last-child { margin-bottom: 0; }
/* Los rótulos («Géneros:», «Disponible en:») se distinguen del valor por
   color, que es como los separa el clon: mismo tamaño, distinto gris. */
.modal-ficha strong, .modal-ficha b { color: var(--text-2); font-weight: 500; }

/* ---- Recomendaciones ---- */
/* Las tarjetas cuelgan de la propia <section>, sin lista intermedia: la
   rejilla va aquí y el rótulo ocupa la fila entera. */
.modal-similares {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 16px; padding: 0 48px 32px;
}
.modal-similares > h3, .modal-similares > h2 {
    grid-column: 1 / -1;
    margin: 0; font-size: 1.35rem; font-weight: 700; color: var(--text);
}
.modal-sim {
    display: flex; flex-direction: column;
    border-radius: var(--r-md); overflow: hidden;
    background: var(--surface-2);
    transition: background .16s;
}
.modal-sim:hover { background: var(--surface-3); }
/* Es un <span>: sin display:block no habría caja que proporcionar. */
.modal-sim-arte {
    display: block; position: relative; aspect-ratio: 16/9;
    background: var(--surface-3); overflow: hidden;
}
.modal-sim-arte img {
    position: absolute; inset: 0; display: block;
    width: 100%; height: 100%; object-fit: cover;
}
/* Mismo criterio que arriba: el cartel entero y el hueco relleno. */
.modal-sim-arte[data-sin-arte="1"] {
    background: radial-gradient(120% 90% at 50% 40%, #262626 0%, #151515 100%);
}
.modal-sim-arte[data-sin-arte="1"] img { object-fit: contain; z-index: 1; }
.modal-sim-arte[data-sin-arte="1"] .modal-sim-fondo {
    z-index: 0; object-fit: cover;
    filter: blur(14px) brightness(.55); transform: scale(1.15);
}
/* El título va dentro de la línea de datos, en un <strong>: se le da la fila
   entera para que los datos queden debajo y no a su lado. */
.modal-sim-datos {
    display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px;
    margin: 0; padding: 12px 14px 0;
    font-size: .78rem; font-weight: 600; color: var(--text-2);
}
.modal-sim-datos > strong {
    flex-basis: 100%;
    font-size: .92rem; font-weight: 700; color: var(--text);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.modal-sim-texto {
    display: -webkit-box; margin: 0; padding: 8px 14px 14px;
    font-size: .8rem; line-height: 1.5; color: var(--text-3);
    -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}

/* ---- Espera y aviso ---- */
/* El mismo bloque sirve para «Cargando…» y para el aviso de error, que se
   distingue por traer el botón de reintentar. */
.modal-cargando {
    display: grid; place-items: center; gap: 14px;
    min-height: 220px; padding: 40px; margin: 0;
    color: var(--text-2); font-size: .95rem; text-align: center;
}
/* La rueda sólo mientras se espera: girando junto a un «no se pudo cargar»
   diría que sigue intentándolo, y no es verdad. */
.modal-cargando:not(:has(button))::before {
    content: ''; width: 34px; height: 34px; border-radius: 50%;
    border: 3px solid var(--surface-3); border-top-color: var(--hot);
    animation: modalGira .9s linear infinite;
}
/* El botón de reintentar no trae clase propia: se le da el aspecto del
   secundario del clon. */
.modal-cargando button {
    height: 40px; padding: 0 20px; border-radius: var(--r-sm);
    background: var(--btn-2); color: #fff;
    font-size: .9rem; font-weight: 700; cursor: pointer;
    transition: background .16s;
}
.modal-cargando button:hover { background: var(--btn-2-hover); }
.modal-cargando button:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
@keyframes modalGira { to { transform: rotate(1turn); } }

/* Foco visible en todo lo pulsable del modal: el aspa y los redondos van sobre
   la imagen, donde un anillo del color de acento no se distingue. */
.modal-cerrar:focus-visible,
.modal-play:focus-visible,
.modal-btn:focus-visible,
.modal-sim:focus-visible {
    outline: 2px solid #fff; outline-offset: 3px;
}

@media (max-width: 900px) {
    .modal-titulo { bottom: 72px; padding: 0 28px; }
    .modal-acciones { padding: 0 28px; margin-top: -58px; }
    .modal-datos { padding: 18px 28px 0; }
    .modal-cuerpo { grid-template-columns: minmax(0, 1fr); padding: 12px 28px 24px; gap: 12px; }
    /* A una columna la ficha vuelve al flujo normal: mantenerla en la columna
       2 la dejaría fuera de la rejilla. */
    .modal-ficha { grid-column: 1; grid-row: auto; }
    .modal-similares { padding: 0 28px 26px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
    .modal-velo { padding: 0; align-items: stretch; }
    /* En el móvil ocupa la ventana entera: un cuadro flotante con 12 px de aire
       alrededor no aporta nada y roba altura útil. */
    .modal { width: 100%; max-height: 100dvh; border-radius: 0; }
    .modal-arte { border-radius: 0; }
    .modal-cerrar { width: 34px; height: 34px; top: 10px; right: 10px; font-size: .85rem; }
    .modal-titulo { bottom: 62px; padding: 0 18px; }
    .modal-acciones { padding: 0 18px; margin-top: -52px; gap: 9px; }
    .modal-play { height: 40px; padding: 0 18px; font-size: .95rem; }
    .modal-btn { width: 36px; height: 36px; }
    .modal-datos { padding: 16px 18px 0; font-size: .82rem; }
    .modal-cuerpo { padding: 12px 18px 22px; }
    .modal-similares { padding: 0 18px 22px; grid-template-columns: minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) {
    .modal, .modal-velo { animation: none; }
    .modal-btn:hover { transform: none; }
    /* La espera se queda quieta pero sigue siendo visible: sin animación el
       borde de color basta para que no parezca un hueco vacío. */
    .modal-cargando::before { animation: none; }
}

/* =========================================================================
   29. Televisor: dónde está el mando
   A tres metros, un filo de 4 px no basta. Aquí el elemento señalado CRECE,
   se rodea de un halo blanco y lo demás se apaga: la mirada va sola, que es
   justo lo que se pierde en un salón cuando hay cinco filas en pantalla.
   ========================================================================= */

/* --- la tarjeta señalada --- */
.tv .card:focus {
    outline: none;                 /* el aro lo dibuja la propia carátula */
    z-index: 20;
}
.tv .card:focus .card-art {
    transform: scale(1.14);
    box-shadow:
        0 0 0 4px #fff,
        0 0 0 10px rgba(0, 0, 0, .55),
        0 26px 60px rgba(0, 0, 0, .85);
    transition: transform .16s ease-out, box-shadow .16s ease-out;
}
/* El título del señalado, más grande y en blanco: a esa distancia el pie de
   la tarjeta es lo único que se lee. */
.tv .card:focus .card-title {
    color: #fff; font-size: 1.05rem; font-weight: 700;
    white-space: normal;
}
.tv .card:focus .card-meta { color: rgba(255, 255, 255, .78); }

/* Lo demás de la fila se apaga. Sin esto, sesenta carátulas del mismo tamaño
   compiten con la señalada y no se distingue cuál es. */
.tv .rail-track:has(:focus) > .card:not(:focus) .card-art,
.tv .grid:has(:focus) > .card:not(:focus) .card-art { opacity: .45; }
.tv .rail-track > .card .card-art,
.tv .grid > .card .card-art { transition: opacity .16s ease-out; }

/* --- botones y píldoras --- */
.tv .btn-watch:focus,
.tv .btn-trailer:focus,
.tv .btn-list:focus,
.tv .chip:focus,
.tv .tabsrow a:focus,
.tv .icon-btn:focus,
.tv .section-more:focus {
    outline: 4px solid #fff;
    outline-offset: 4px;
    transform: scale(1.06);
    box-shadow: 0 0 0 10px rgba(0, 0, 0, .5);
}

/* --- filas del panel de capítulos --- */
.tv .eps-fila:focus {
    outline: none;
    background: #fff;
    box-shadow: 0 0 0 4px #fff, 0 0 0 10px rgba(0, 0, 0, .5);
}
.tv .eps-fila:focus .eps-nombre,
.tv .eps-fila:focus .eps-num,
.tv .eps-fila:focus .eps-pie { color: #000; }
.tv .eps-fila:focus .eps-linea { background: rgba(0, 0, 0, .3); }

/* --- el marco del vídeo --- */
.tv .watch-frame:focus {
    outline: 4px solid #fff;
    outline-offset: -4px;
}
/* Con el vídeo señalado se recuerda qué hace la cruceta. Aparece sólo cuando
   tiene el foco y no tapa nada: es una ayuda, no un cartel permanente. */
.tv .watch-frame:focus::after {
    content: '◀ −10 s   ·   OK reproducir o pausar   ·   +10 s ▶';
    position: absolute; left: 50%; bottom: 22px; transform: translateX(-50%);
    padding: 10px 20px; border-radius: 999px;
    background: rgba(0, 0, 0, .78); color: #fff;
    font-size: .92rem; font-weight: 600; white-space: nowrap;
    pointer-events: none;
}

/* --- en qué sección está --- */
.tv .tv-seccion > .section-head .section-title,
.tv .tv-seccion > .section-title {
    color: #fff;
}
/* Una barra roja a la izquierda del rótulo marca la fila activa: se ve de un
   vistazo aunque la tarjeta señalada esté al otro extremo de la pantalla. */
.tv .tv-seccion > .section-head .section-title::before,
.tv .tv-seccion > .section-title::before {
    content: ''; display: inline-block; flex: none;
    width: 5px; height: 1.1em; margin-right: 10px; border-radius: 3px;
    background: var(--hot);
}

@media (prefers-reduced-motion: reduce) {
    .tv .card:focus .card-art,
    .tv .btn-watch:focus { transform: none; }
}

/* Desplazamiento sin animar con mando. Dos motivos: en un Chromecast animar
   una página con sesenta carátulas cuesta fotogramas que no sobran, y mientras
   dura la animación las posiciones están a medio camino, así que el cálculo de
   «qué hay debajo» de la siguiente pulsación se hace sobre datos falsos. */
.tv, .tv * { scroll-behavior: auto !important; }

/* En el bloque de televisor se usa :focus y no :focus-visible a propósito.
   :focus-visible depende de una heurística del navegador —«¿ha llegado el foco
   por teclado?»— que los navegadores de televisor aplican mal o directamente no
   implementan, y el resultado era un foco invisible. Con mando no hay ratón, así
   que todo foco es de mando y todo foco debe verse. */
