/* Alumne Flex Liquid Glass — el cristal que no cabe en un token.

   Tres bloques, en este orden:
     A. Receta del cristal (superficies de la interfaz)
     B. Lienzo con aurora: el degradado dinámico de la zona de contenido
     C. Acceso: gotas de color vivas tras una tarjeta de cristal ahumado

   OJO CON EL ORDEN DE CARGA: templates/element/head.php pinta theme.css y este fichero
   ANTES de alumneflex-ui.css. Con la misma especificidad ganaría la capa común, así que
   cada selector lleva `:root` delante para subir un punto.

   TRES REGLAS QUE ESTE FICHERO NO PUEDE ROMPER (y por qué):

   1. `backdrop-filter` NUNCA sobre un contenedor que pueda tener dentro un modal.
      Además de desenfocar, convierte al elemento en bloque contenedor de sus hijos
      `position:fixed` y en contexto de apilamiento: un `.modal` de Bootstrap que viva
      dentro de una tarjeta quedaría recortado por ella y por debajo de su velo (que se
      inyecta en <body>). Muchas plantillas meten modales dentro de `.af-card`.
      Por eso el cristal de las tarjetas va en un `::before` con `z-index:-1`: el
      pseudoelemento se desenfoca, la tarjeta no, y sus hijos siguen tan libres como
      antes. Solo llevan el filtro directo los elementos que YA flotan (modal, menú,
      offcanvas…) o que la capa común ya filtraba (la barra superior).

   2. Nada de `isolation` ni `z-index` en las tarjetas por el mismo motivo: atraparía el
      modal por debajo del velo. El `::before` en negativo cae así al contexto de la raíz,
      por encima de la aurora (-2) y por debajo del contenido. Consecuencia buscada: una
      tarjeta dentro de otra pinta su cristal encima del de la madre, en orden de árbol.

   3. `--surface-card` NO es el cristal (ver tokens/colors.css): es casi opaco para que
      las capas flotantes que no se han revisado se sigan leyendo. El cristal es
      `--glass-bg` y se aplica aquí, selector a selector. */


/* =====================================================================================
   A. RECETA DEL CRISTAL
   ===================================================================================== */

/* --- A.1 Tarjetas y paneles: cristal en el ::before ---------------------------------
   El borde del elemento es el filete de luz del canto; el ::before es la cara (relleno +
   reflejo diagonal + desenfoque) y los brillos interiores. La sombra exterior va en el
   propio elemento: cae fuera de la caja, así que no tapa la cara. */
:root .af-card,
:root .af-panel,
:root .af-empty,
:root .af-recent-overlay {
  position: relative;
  background: transparent;
  border: 1px solid var(--glass-border);
  box-shadow: 0 0 0 1px var(--glass-edge), var(--glass-shadow);
}
:root .af-card::before,
:root .af-panel::before,
:root .af-empty::before,
:root .af-recent-overlay::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  border-radius: inherit;
  background: var(--glass-sheen), var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: inset 0 1px 0 var(--glass-highlight), inset 0 -1px 0 var(--glass-lowlight);
  pointer-events: none;
}
/* El estado vacío conserva su borde discontinuo: es lo que dice «aquí no hay nada». */
:root .af-empty { border-style: dashed; border-color: var(--border-default); }

/* Al pasar por encima, la lámina se levanta: más sombra y un canto más brillante. */
:root .af-card-interactive:hover {
  box-shadow: 0 0 0 1px var(--glass-edge), var(--glass-shadow-lift);
}

/* Panel oscuro (la voz técnica) y portada de bienvenida de los paneles
   (templates/Dashboard/admin|teacher|supervisor.php y element/dashboard/welcome.php).
   Es una versión en miniatura del acceso: telón navy con luz de marca que se mueve por
   dentro, y encima las piezas (cifras, aviso) en cristal ahumado.

   `isolation` y `overflow:hidden` son seguros AQUÍ y solo aquí: contienen las manchas de
   luz dentro del panel, y ninguna de las cuatro plantillas mete un modal ni un
   desplegable en él (verificado). Si algún día lo hiciera, el modal quedaría recortado.

   OJO con las coordenadas: la capa mide un 160 % del panel (inset -30 %), así que un
   punto del panel en X % cae en la capa en (X + 30) / 1,6 %. Las manchas son degradados radiales ya suaves, sin `filter: blur()`: dos capas que se
   mueven solo con `transform`, cada una a su ritmo, así que la GPU las desplaza sin
   repintar. Van ancladas a la derecha y abajo, lejos del título y el texto, que caen
   sobre el navy; aun así el subtítulo se ha calculado sobre el peor caso (una mancha
   naranja justo detrás): 5:1. */
:root .af-panel-ink {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background:
    radial-gradient(110% 90% at 0% 0%, #1A2856 0%, rgba(26,40,86,0) 60%),
    linear-gradient(160deg, #111E48 0%, #050F2B 100%);
  border: 1px solid rgba(255,255,255,.14);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.18), var(--shadow-lg);
}
:root .af-panel-ink::before,
:root .af-panel-ink::after {
  content: "";
  position: absolute; inset: -30%; z-index: -1;
  pointer-events: none;
  will-change: transform;
}
/* Solo dos luces: la idea es que el navy no sea plano, no montar un espectáculo.
   Cálida arriba a la derecha, el naranja de firma. */
:root .af-panel-ink::before {
  background: radial-gradient(30% 36% at 70% 36%, rgba(255,110,48,.55), rgba(255,110,48,0) 70%);
  animation: lg-ink-a calc(var(--dur-blob) * 1.2) var(--ease-liquid) infinite alternate;
}
/* Fría abajo a la izquierda, por debajo de las cifras: el teal de sistema. */
:root .af-panel-ink::after {
  background: radial-gradient(32% 32% at 34% 74%, rgba(18,178,166,.45), rgba(18,178,166,0) 70%);
  animation: lg-ink-b calc(var(--dur-blob) * 1.5) var(--ease-liquid) infinite alternate;
}
@keyframes lg-ink-a {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); }
  50%  { transform: translate3d(-7%, 6%, 0) rotate(-10deg) scale(1.12, .92); }
  100% { transform: translate3d(-3%, -5%, 0) rotate(8deg) scale(.94, 1.1); }
}
@keyframes lg-ink-b {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); }
  50%  { transform: translate3d(8%, -5%, 0) rotate(12deg) scale(1.1, .9); }
  100% { transform: translate3d(-5%, -8%, 0) rotate(-6deg) scale(.92, 1.12); }
}
:root .af-panel-ink .af-muted,
:root .af-hero-sub { color: rgba(255,255,255,.86); }

/* Las cifras: cristal ahumado, la misma receta que la tarjeta del acceso. El brillo que
   pasa se baja con `brightness` para que el blanco se lea aunque la luz de marca cruce
   justo por detrás. Filtro directo: son hojas sin hijos flotantes. */
:root .af-hero-stat {
  position: relative;
  border-radius: var(--radius-card);
  background: linear-gradient(160deg, rgba(255,255,255,.16) 0%, rgba(255,255,255,.04) 60%, rgba(255,255,255,.08) 100%),
              rgba(8,20,56,.30);
  -webkit-backdrop-filter: blur(18px) saturate(160%) brightness(.8);
  backdrop-filter: blur(18px) saturate(160%) brightness(.8);
  border: 1px solid rgba(255,255,255,.24);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.50),
    inset 0 -1px 0 rgba(255,255,255,.08),
    inset 0 16px 32px -20px rgba(255,255,255,.18),
    0 14px 30px -16px rgba(3,8,22,.70);
  transition: var(--transition-surface), border-color var(--dur-base) var(--ease-out);
}
/* Reflejo diagonal de la cara, como en la tarjeta del acceso. */
:root .af-hero-stat::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  border-radius: inherit;
  background: linear-gradient(115deg, rgba(255,255,255,.20) 0%, rgba(255,255,255,0) 32%);
  pointer-events: none;
}
:root .af-hero-stat:hover {
  transform: translateY(-2px);
  border-color: rgba(255,255,255,.40);
}
:root .af-hero-stat-value { font-size: var(--text-2xl); }
:root .af-hero-stat-label { color: rgba(255,255,255,.84); }

/* El aviso de arriba («Revisa el planificador…»): una píldora del mismo cristal. */
:root .af-hero-live {
  background: rgba(255,255,255,.12);
  -webkit-backdrop-filter: blur(12px) saturate(150%);
  backdrop-filter: blur(12px) saturate(150%);
  border: 1px solid rgba(255,255,255,.22);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.30);
}
:root a.af-hero-live:hover { background: rgba(255,255,255,.20); }

/* --- A.2 Superficies que YA flotan: filtro directo ---------------------------------
   Estos elementos se pintan por encima del contenido, no de la aurora: el cristal es más
   denso (--glass-bg-strong) para que el texto de debajo no se lea a través. */
:root .modal-content,
:root .dropdown-menu,
:root .offcanvas,
:root .popover,
:root .toast,
:root .af-gs-panel,
:root .af-config-search-results {
  background: var(--glass-sheen), var(--glass-bg-strong);
  -webkit-backdrop-filter: var(--glass-blur-strong);
  backdrop-filter: var(--glass-blur-strong);
  border: 1px solid var(--glass-border);
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 0 0 1px var(--glass-edge), var(--shadow-xl);
}
:root .modal { --bs-modal-bg: transparent; --bs-modal-border-color: var(--glass-border); }
:root .dropdown-menu { --bs-dropdown-bg: transparent; }
:root .offcanvas { --bs-offcanvas-bg: transparent; }
/* El aviso de «buscando» va pegado arriba del desplegable: con el cristal detrás sería
   transparente y los resultados se verían pasar por debajo. */
:root .af-gs-loading { background: var(--glass-bg-strong); }
/* Velo de los modales: un poco más de desenfoque que el tema base. Es lo que hace que el
   modal se lea como una lámina encima y no como un recorte. */
:root .modal-backdrop { -webkit-backdrop-filter: blur(8px) saturate(120%); backdrop-filter: blur(8px) saturate(120%); }

/* Barras fijadas del teléfono (filtros, acciones en bloque, ficha del catálogo, buscador
   de configuración). Flotan sobre el contenido al bajar: cristal denso con filtro. */
@media (max-width: 767.98px) {
  :root .af-filterbar,
  :root .af-bulkbar,
  :root .af-catalog-bar,
  :root .af-config-search.is-stuck {
    background: var(--glass-bg-strong);
    -webkit-backdrop-filter: var(--glass-blur-strong);
    backdrop-filter: var(--glass-blur-strong);
  }
  /* La barra de filtros es casi siempre un `.af-panel`, y la receta del cristal (A.1) le
     pone `position: relative` con `:root` delante, que gana al `sticky` de la capa común.
     Relativa, su `top: var(--topbar-h)` la BAJA 64 px: hueco encima y la primera tarjeta
     tapada. Se devuelve el `sticky` con el mismo peso. */
  :root .af-filterbar { position: sticky; }
  /* Y en vez de la franja recta de lado a lado de la capa común, una cápsula de cristal
     que flota bajo la barra superior con un respiro, como la barra superior del
     escritorio. Por el respiro se ve pasar el contenido: en este tema es lo buscado
     (en la capa común se leería como un fallo de pintado, aquí es el cristal).
     Una sola cara: la del propio elemento, con el ::before de la receta apagado para
     no sumar dos desenfoques. Abierta, con los filtros desplegados, pasa a tarjeta. */
  :root { --lg-bar-gap: 8px; }
  :root .af-filterbar {
    top: calc(var(--topbar-h) + var(--lg-bar-gap));
    margin-inline: 0;
    max-height: calc(100dvh - var(--topbar-h) - 2 * var(--lg-bar-gap));
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-pill);
    background: var(--glass-sheen), var(--glass-bg-strong);
    box-shadow: inset 0 1px 0 var(--glass-highlight), 0 0 0 1px var(--glass-edge), var(--glass-shadow);
  }
  :root .af-filterbar::before { content: none; }
  :root .af-filterbar .af-panel-body,
  :root form.af-filterbar { padding: 6px 10px; }
  :root .af-filterbar.is-open { border-radius: var(--radius-card); }
  :root .af-filterbar.is-open .af-panel-body,
  :root form.af-filterbar.is-open { padding: var(--space-3) var(--space-4); }
  /* El campo, píldora como los dos botones redondos que lo flanquean. */
  :root .af-filterbar-main-row .form-control { border-radius: var(--radius-pill); }
  /* La barra de acciones en bloque se cuelga debajo: también con su respiro. */
  :root .af-bulkbar { top: calc(var(--topbar-h) + var(--filterbar-h, 0px) + 2 * var(--lg-bar-gap)); }
  /* El panel que solo envuelve un listado apilado deja de ser tarjeta en el teléfono
     (alumneflex-ui.css le quita fondo, borde y sombra): aquí el cristal vive en el
     ::before, que esa regla no alcanza, y quedaba una lámina recta tras las fichas.
     Mismos selectores que la capa común. */
  :root .af-panel:not(:has(> .af-panel-head)):has(> .af-table-wrap > .af-table-stack)::before,
  :root .af-panel:not(:has(> .af-panel-head)):has(> .af-panel-body > .af-table-stack)::before,
  :root .af-panel:not(:has(> .af-panel-head)):has(> .af-table-stack)::before,
  :root .af-panel.af-panel-flush-mobile::before { content: none; }
}

/* --- A.3 Cromo: barra lateral y barra superior como piezas flotantes ----------------
   En vez de pegadas al borde, las dos barras se despegan del lienzo y flotan sobre la
   aurora, como las paletas de una aplicación de escritorio. Solo en escritorio: en el
   teléfono la barra lateral es el offcanvas y la superior necesita todo el ancho. */
@media (min-width: 992px) {
  :root .af-sidebar {
    top: 12px;
    height: calc(100vh - 24px);
    margin: 12px 0 12px 12px;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-shell);
    background: transparent;
    box-shadow: 0 0 0 1px var(--glass-edge), var(--glass-shadow);
  }
  /* La barra lateral es sticky, así que ya es su propio contexto de apilamiento: su
     ::before en negativo se queda dentro de ella, encima de nada. Mismo cristal que
     las tarjetas, un punto más denso para que la navegación mande. */
  :root .af-sidebar::before {
    content: "";
    position: absolute; inset: 0; z-index: -1;
    border-radius: inherit;
    background: var(--glass-sheen), var(--surface-sidebar);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    box-shadow: inset 0 1px 0 var(--glass-highlight), inset 0 -1px 0 var(--glass-lowlight);
    pointer-events: none;
  }
  /* El botón de plegar cuelga del canto de la barra: acompaña el margen de 12 px. */
  :root .af-sidebar-toggle {
    top: 37px;
    left: calc(var(--sidebar-w) - 2px);
    background: var(--glass-bg-strong);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    border-color: var(--glass-border);
    box-shadow: inset 0 1px 0 var(--glass-highlight), var(--shadow-sm);
  }
  :root .af-shell.is-collapsed .af-sidebar-toggle { left: calc(var(--sidebar-w-collapsed) - 2px); }

  /* Barra superior: cápsula flotante. El filtro ya lo ponía la capa común (con
     --blur-glass, que este tema sube), así que aquí solo cambia la forma. */
  :root .af-topbar {
    top: 12px;
    margin: 12px var(--gutter-panel) 0;
    padding: 0 var(--space-4) 0 var(--space-6);
    height: calc(var(--topbar-h) - 8px);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-pill);
    box-shadow: inset 0 1px 0 var(--glass-highlight), 0 0 0 1px var(--glass-edge), var(--glass-shadow);
  }
}
/* En el teléfono, la barra superior sigue de lado a lado pero con su canto de luz. */
@media (max-width: 991.98px) {
  :root .af-topbar {
    border-bottom: 1px solid var(--glass-border);
    box-shadow: inset 0 -1px 0 var(--glass-edge);
  }
}

/* La navegación: el enlace activo es una gota de cristal teñida de naranja, con su
   brillo arriba y un halo cálido. La tinta sigue siendo --text-brand (4,9:1). */
:root .af-nav-link { border-radius: var(--radius-control); }
:root .af-nav-link.active {
  background: linear-gradient(135deg, rgba(255,160,56,.20) 0%, rgba(255,90,45,.14) 100%);
  box-shadow: inset 0 1px 0 var(--glass-highlight), inset 0 0 0 1px rgba(255,90,45,.22),
              0 6px 16px -8px rgba(245,65,31,.45);
}
:root .af-nav-link.active i[data-lucide],
:root .af-nav-link.active svg { color: var(--action-primary); }
:root[data-theme="dark"] .af-nav-link.active {
  background: linear-gradient(135deg, rgba(255,128,52,.26) 0%, rgba(255,90,45,.16) 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14), inset 0 0 0 1px rgba(255,128,52,.30),
              0 8px 20px -8px rgba(255,90,45,.55);
}
:root .af-sidebar-foot { border-top-color: var(--border-subtle); }

/* --- A.4 Botones ----------------------------------------------------------------------
   Píldora completa en todos los botones de texto; los campos conservan 12 px (ver
   tokens/radius.css). El primario es la única pieza de color macizo de la pantalla: el
   degradado de firma del imagotipo con un brillo de cristal en el canto superior. */
:root .btn { --bs-btn-border-radius: var(--radius-pill); }
:root .af-icon-btn { border-radius: var(--radius-pill); }
:root .btn-brand {
  --bs-btn-bg: transparent;
  --bs-btn-border-color: transparent;
  --bs-btn-hover-bg: transparent;
  --bs-btn-hover-border-color: transparent;
  --bs-btn-active-bg: transparent;
  --bs-btn-active-border-color: transparent;
  background-image: var(--gradient-brand);
  background-color: var(--action-primary);
  background-size: 140% 100%;
  background-position: 0% 50%;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.45), inset 0 -1px 0 rgba(112,26,8,.18), var(--shadow-brand);
  transition: var(--transition-control), background-position var(--dur-slow) var(--ease-out);
}
/* Al pasar, el degradado se desliza hacia el lado más intenso: la luz se mueve por
   dentro del cristal en vez de cambiar de color de golpe. */
:root .btn-brand:hover { background-position: 100% 50%; box-shadow: inset 0 1px 0 rgba(255,255,255,.5), inset 0 -1px 0 rgba(112,26,8,.2), var(--shadow-brand); }
:root .btn-brand:active { transform: scale(.97); }
/* La «Marca rápida» de la cuenta reescribe --action-primary: por eso en este tema
   --gradient-brand se construye A PARTIR de --action-primary (tokens/colors.css) y una
   cuenta azul tiene su botón en degradado azul, no en el naranja de Alumne. */

/* Contorno y fantasma: lámina de cristal clara, que sobre la tarjeta se lee como una
   capa encima y no como un agujero. */
:root .btn-outline-brand {
  --bs-btn-bg: rgba(255,255,255,.42);
  --bs-btn-hover-bg: rgba(255,255,255,.72);
  --bs-btn-active-bg: rgba(255,255,255,.72);
  box-shadow: inset 0 1px 0 var(--glass-highlight);
}
:root[data-theme="dark"] .btn-outline-brand {
  --bs-btn-bg: rgba(255,255,255,.04);
  --bs-btn-hover-bg: rgba(255,255,255,.10);
  --bs-btn-active-bg: rgba(255,255,255,.10);
}
:root .btn-ink { box-shadow: inset 0 1px 0 rgba(255,255,255,.18), var(--shadow-sm); }

/* --- A.5 Formularios ------------------------------------------------------------------
   El campo es una lámina más clara que la tarjeta, con brillo interior abajo (la luz que
   entra por el canto superior y rebota). Al enfocarlo se enciende un halo naranja. */
:root .form-control,
:root .form-select {
  background-color: rgba(255,255,255,.70);
  box-shadow: inset 0 1px 2px rgba(8,24,64,.06), 0 1px 0 rgba(255,255,255,.8);
}
:root .form-control:focus,
:root .form-select:focus {
  background-color: rgba(255,255,255,.94);
  box-shadow: var(--ring-focus), inset 0 1px 2px rgba(8,24,64,.04);
}
:root[data-theme="dark"] .form-control,
:root[data-theme="dark"] .form-select {
  background-color: rgba(5,12,34,.42);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.30), 0 1px 0 rgba(255,255,255,.05);
}
:root[data-theme="dark"] .form-control:focus,
:root[data-theme="dark"] .form-select:focus { background-color: rgba(5,12,34,.62); }
/* El texto de un desplegable abierto lo pinta el sistema sobre el fondo del <option>, que
   no hereda el cristal: en oscuro sería texto claro sobre el blanco del navegador. */
:root[data-theme="dark"] .form-select option { background: var(--navy-700); color: var(--text-body); }

/* --- A.6 Tablas, píldoras y badges: tinte SIN desenfoque ---------------------------
   Hay decenas por pantalla: si cada una desenfocara, el navegador tendría que repintar
   la aurora bajo cada fila en cada fotograma. Se tiñen y ya: el cristal lo pone la
   tarjeta que las contiene. */
:root .af-table th { background: rgba(8,24,64,.035); }
:root[data-theme="dark"] .af-table th { background: rgba(255,255,255,.04); }
:root .af-chip { background: rgba(255,255,255,.55); border-color: var(--border-default); }
:root[data-theme="dark"] .af-chip { background: rgba(255,255,255,.05); }
:root .af-icon-box { box-shadow: inset 0 1px 0 rgba(255,255,255,.6); }
:root .progress { --bs-progress-bg: rgba(8,24,64,.08); }
:root[data-theme="dark"] .progress { --bs-progress-bg: rgba(255,255,255,.10); }
:root .progress-bar,
:root .af-recent-bar > span,
:root .af-course-bar > span { background: var(--gradient-brand); }

/* --- A.7 Reserva sin backdrop-filter ---------------------------------------------------
   Sin desenfoque, un relleno al 56 % deja leer lo de detrás. Se vuelve casi opaco. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  :root { --glass-bg: rgba(255,255,255,.90); --glass-bg-strong: rgba(255,255,255,.97); }
  :root[data-theme="dark"] { --glass-bg: rgba(17,30,72,.94); --glass-bg-strong: rgba(12,22,58,.98); }
}


/* =====================================================================================
   B. LIENZO CON AURORA — el degradado dinámico de la zona de contenido
   =====================================================================================
   Solo en las pantallas con el cascarón (.af-shell): el reproductor inmersivo, el SCORM y
   el editor de diplomas tienen su propio telón y no se tocan.

   Dos capas fijas bajo todo (z-index -2), cada una con su deriva y su periodo, para que
   las manchas de color se crucen y se separen en vez de girar como un bloque rígido.
   Solo se anima `transform`: la capa se rasteriza una vez y la mueve la GPU.

   Además, el scroll (donde el navegador sabe atar una animación al desplazamiento) mueve
   la segunda capa con la propiedad `translate`, que es INDEPENDIENTE de `transform`: las
   dos animaciones se suman sin pisarse. */
:root:has(.af-shell) {
  background: var(--gradient-canvas), var(--aurora-base);
  background-attachment: fixed;
}
:root body:has(> .af-shell),
:root .af-shell { background: transparent; }

:root body:has(> .af-shell)::before,
:root body:has(> .af-shell)::after {
  content: "";
  position: fixed; inset: -25%; z-index: -2;
  pointer-events: none;
  will-change: transform;
}
:root body:has(> .af-shell)::before {
  background:
    radial-gradient(34% 38% at 16% 20%, var(--aurora-1), transparent 70%),
    radial-gradient(30% 34% at 84% 14%, var(--aurora-2), transparent 70%),
    radial-gradient(46% 42% at 54% 52%, var(--aurora-5), transparent 72%);
  animation: lg-aurora-a var(--dur-aurora) var(--ease-liquid) infinite alternate;
}
:root body:has(> .af-shell)::after {
  background:
    radial-gradient(36% 40% at 80% 80%, var(--aurora-3), transparent 70%),
    radial-gradient(34% 38% at 18% 84%, var(--aurora-4), transparent 70%);
  animation: lg-aurora-b calc(var(--dur-aurora) * .77) var(--ease-liquid) infinite alternate,
             lg-aurora-scroll linear both;
  animation-timeline: auto, scroll(root);
}
@keyframes lg-aurora-a {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); }
  50%  { transform: translate3d(4%, 3%, 0) rotate(8deg) scale(1.06, .96); }
  100% { transform: translate3d(-3%, 5%, 0) rotate(-6deg) scale(.96, 1.05); }
}
@keyframes lg-aurora-b {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); }
  50%  { transform: translate3d(-5%, -3%, 0) rotate(-10deg) scale(1.08, .95); }
  100% { transform: translate3d(3%, -5%, 0) rotate(6deg) scale(.95, 1.06); }
}
@keyframes lg-aurora-scroll {
  from { translate: 0 0; }
  to   { translate: -6% -14%; }
}
/* Grano: da al cristal textura que desenfocar (sin él, un degradado suave se ve con
   bandas) y quita el aspecto de render. Es una tesela de 160 px de ruido, no una imagen a
   pantalla completa: el navegador la pinta una vez y la repite. */
:root .af-shell::after {
  content: "";
  position: fixed; inset: 0; z-index: -1;
  pointer-events: none;
  opacity: .05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
:root[data-theme="dark"] .af-shell::after { opacity: .07; }


/* =====================================================================================
   C. ACCESO — gotas de color vivas tras una tarjeta de cristal ahumado
   =====================================================================================
   La pantalla sin sesión (login, instalador, recuperación) y también las páginas de error,
   que usan el mismo .af-auth. Va siempre en claro (no hay script de data-theme).

   ESTRUCTURA DE CAPAS (todas fijas, z-index negativo → contexto de la raíz):
     -3  cuatro gotas: body::before/::after y .af-auth::before/::after
     -2  grano
      0  .af-auth-inner con la tarjeta (sin z-index: nada de atrapar el modal)
   Para que las gotas se vean, el telón navy se pinta en <html> y .af-auth se queda
   transparente: con el fondo en .af-auth las gotas quedarían DEBAJO de él.

   CADA GOTA LLEVA DOS MOVIMIENTOS QUE NO SE PISAN:
     · `transform` (animación): deriva, giro y escala desigual. Como la silueta ya es
       irregular, girarla y estirarla la hace cambiar de forma sin animar border-radius,
       que obligaría a repintar y volver a desenfocar la gota en cada fotograma.
     · `translate` (paralaje): sigue al ratón con --pointer-x/-y, que escribe
       alumneflex-shell.js en <html> (de -1 a 1). Cada gota con su amplitud: las lejanas
       se mueven poco y las cercanas mucho, y eso da la profundidad. Sin JS, 0. */
:root:has(.af-auth) {
  background:
    radial-gradient(120% 80% at 50% 115%, #1A2856 0%, rgba(26,40,86,0) 60%),
    radial-gradient(90% 70% at 10% -10%, #111E48 0%, rgba(17,30,72,0) 60%),
    var(--surface-stage);
  background-attachment: fixed;
}
/* <body> también: la capa común le pone --surface-canvas y, con <html> pintado, el fondo
   del body ya no se propaga al lienzo sino que se pinta ENCIMA de las capas negativas. */
:root body:has(.af-auth),
:root .af-auth { background: transparent; }
:root .af-auth-bg { display: none; }

:root body:has(.af-auth)::before,
:root body:has(.af-auth)::after,
:root .af-auth::before,
:root .af-auth::after {
  content: "";
  position: fixed; z-index: -3;
  pointer-events: none;
  filter: blur(56px);
  mix-blend-mode: screen;
  will-change: transform, translate;
  translate: calc(var(--pointer-x, 0) * var(--lg-depth)) calc(var(--pointer-y, 0) * var(--lg-depth));
}
/* Gota 1 — el naranja de firma, arriba a la izquierda. La protagonista. */
:root body:has(.af-auth)::before {
  --lg-depth: 46px;
  width: min(52vw, 620px); aspect-ratio: 1.1;
  left: -6vw; top: -10vh;
  border-radius: 42% 58% 63% 37% / 45% 38% 62% 55%;
  background: radial-gradient(circle at 38% 36%, #FFA038 0%, #FF5A2D 42%, rgba(245,65,31,.55) 62%, rgba(245,65,31,0) 74%);
  animation: lg-blob-1 calc(var(--dur-blob) * 1.1) var(--ease-liquid) infinite alternate;
}
/* Gota 2 — teal, abajo a la derecha: el acento de sistema de Flex. */
:root body:has(.af-auth)::after {
  --lg-depth: 30px;
  width: min(46vw, 560px); aspect-ratio: .95;
  right: -8vw; bottom: -12vh;
  border-radius: 60% 40% 35% 65% / 50% 60% 40% 50%;
  background: radial-gradient(circle at 55% 45%, #2BBBB0 0%, #12B2A6 38%, rgba(10,115,109,.55) 62%, rgba(10,115,109,0) 74%);
  animation: lg-blob-2 calc(var(--dur-blob) * 1.3) var(--ease-liquid) infinite alternate;
}
/* Gota 3 — lila, cruza por detrás de la tarjeta: la luz de la ilustración del tema base. */
:root .af-auth::before {
  --lg-depth: 18px;
  width: min(58vw, 700px); aspect-ratio: 1.35;
  left: 22vw; top: 38vh;
  border-radius: 50% 50% 38% 62% / 62% 40% 60% 38%;
  background: radial-gradient(circle at 50% 50%, #7C6CF0 0%, rgba(78,96,220,.7) 40%, rgba(46,60,107,.4) 62%, rgba(46,60,107,0) 74%);
  animation: lg-blob-3 calc(var(--dur-blob) * 1.55) var(--ease-liquid) infinite alternate;
}
/* Gota 4 — chispa de coral, pequeña y rápida: la que hace que la escena parezca viva. */
:root .af-auth::after {
  --lg-depth: 64px;
  width: min(26vw, 320px); aspect-ratio: 1;
  right: 18vw; top: 6vh;
  border-radius: 38% 62% 56% 44% / 40% 55% 45% 60%;
  background: radial-gradient(circle at 45% 45%, #FF8034 0%, #F5411F 45%, rgba(245,65,31,0) 72%);
  opacity: .85;
  animation: lg-blob-4 calc(var(--dur-blob) * .75) var(--ease-liquid) infinite alternate;
}
@keyframes lg-blob-1 {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg) scale(1, 1); }
  33%  { transform: translate3d(9vw, 6vh, 0) rotate(40deg) scale(1.12, .9); }
  66%  { transform: translate3d(4vw, 14vh, 0) rotate(95deg) scale(.92, 1.1); }
  100% { transform: translate3d(14vw, 4vh, 0) rotate(150deg) scale(1.05, .95); }
}
@keyframes lg-blob-2 {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg) scale(1, 1); }
  50%  { transform: translate3d(-12vw, -8vh, 0) rotate(-70deg) scale(1.1, .88); }
  100% { transform: translate3d(-5vw, -16vh, 0) rotate(-140deg) scale(.9, 1.08); }
}
@keyframes lg-blob-3 {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg) scale(1, 1); }
  50%  { transform: translate3d(-10vw, -6vh, 0) rotate(35deg) scale(1.15, .92); }
  100% { transform: translate3d(6vw, -12vh, 0) rotate(-25deg) scale(.95, 1.12); }
}
@keyframes lg-blob-4 {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); }
  50%  { transform: translate3d(-14vw, 22vh, 0) rotate(120deg) scale(1.3, .8); }
  100% { transform: translate3d(-4vw, 44vh, 0) rotate(260deg) scale(.85, 1.2); }
}
/* Grano sobre las gotas: sin él, el desenfoque de 56 px se ve con bandas en pantallas de
   8 bits y todo parece un render. */
:root .af-auth-inner::before {
  content: "";
  position: fixed; inset: 0; z-index: -2;
  pointer-events: none;
  opacity: .08;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --- La tarjeta: cristal ahumado ---------------------------------------------------
   Filtro directo en la tarjeta: aquí sí se puede, porque el modal «¿Olvidaste la
   contraseña?» (templates/Users/login.php) va FUERA de .af-auth-card, como hermano dentro
   de .af-auth-inner. Ninguna otra plantilla del acceso mete un modal dentro de la tarjeta.

   El cristal es muy translúcido, pero el texto es blanco: la luz que deja pasar se atenúa
   con `brightness(.72)` en el filtro y un velo navy al .42. Contraste calculado sobre el
   punto MÁS CLARO que puede quedar detrás, que no es el centro de una gota sino el cruce
   de la naranja con la lila en modo `screen` (≈#FFBF96), SIN contar el desenfoque, que lo
   rebaja: etiquetas en blanco ≥4,5:1, subtítulo al .92 ≥4,5:1 y el título (30 px) de
   sobra. Si se sube el brillo o se aclara el velo, hay que rehacer esta cuenta. */
:root .af-auth-card {
  position: relative;
  border-radius: var(--radius-shell);
  padding: var(--space-9) var(--space-8) var(--space-8);
  background: linear-gradient(160deg, rgba(255,255,255,.16) 0%, rgba(255,255,255,.05) 55%, rgba(255,255,255,.09) 100%),
              rgba(8,20,56,.42);
  -webkit-backdrop-filter: blur(26px) saturate(160%) brightness(.72);
  backdrop-filter: blur(26px) saturate(160%) brightness(.72);
  border: 1px solid rgba(255,255,255,.26);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.55),
    inset 0 -1px 0 rgba(255,255,255,.10),
    inset 0 0 0 1px rgba(255,255,255,.04),
    inset 0 24px 48px -24px rgba(255,255,255,.14),
    0 40px 90px -24px rgba(3,8,22,.70);
  color: rgba(255,255,255,.92);
}
/* Reflejo diagonal de la cara: se mueve al revés que las gotas, como la luz sobre un
   vidrio cuando lo inclinas. */
:root .af-auth-card::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  border-radius: inherit;
  background: linear-gradient(115deg, rgba(255,255,255,.22) 0%, rgba(255,255,255,0) 30%,
              rgba(255,255,255,0) 68%, rgba(255,255,255,.08) 100%);
  translate: calc(var(--pointer-x, 0) * -6px) calc(var(--pointer-y, 0) * -6px);
  pointer-events: none;
}
/* Filete de luz que recorre el canto, muy despacio. Un conic-gradient enmascarado a un
   anillo de 1 px. El ángulo es una propiedad registrada para poder animarlo; donde
   @property no exista, el anillo se queda quieto, que también está bien. */
@property --lg-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}
:root .af-auth-card::after {
  content: "";
  position: absolute; inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: conic-gradient(from var(--lg-angle),
              rgba(255,255,255,0) 0deg, rgba(255,255,255,0) 200deg,
              rgba(255,160,56,.95) 250deg, rgba(255,255,255,.95) 272deg,
              rgba(18,178,166,.8) 300deg, rgba(255,255,255,0) 340deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  animation: lg-rim 9s linear infinite;
  pointer-events: none;
}
@keyframes lg-rim { to { --lg-angle: 360deg; } }

/* Logotipo: la tarjeta es oscura, así que el logotipo pasa a una silueta blanca. Se hace
   con un filtro y NO sustituyendo la imagen: si la cuenta ha subido su propio logotipo en
   «Marca rápida», AppController::brandingAssets() lo pone en este mismo <img>, y un
   `content:url()` lo cambiaría por el de Alumne Flex. El imagotipo blanco de Alumne Flex
   ya es una silueta de una sola tinta, así que el resultado es idéntico. */
:root .af-auth-logo { filter: brightness(0) invert(1); height: 38px; }

:root .af-auth-card .af-auth-title { color: #FFFFFF; font-size: var(--text-3xl); letter-spacing: var(--tracking-display); }
:root .af-auth-card .af-auth-sub { color: rgba(255,255,255,.92); }
:root .af-auth-card .form-label { color: #FFFFFF; }
:root .af-auth-card .form-check-label { color: rgba(255,255,255,.94); }
:root .af-auth-card .form-text,
:root .af-auth-card .af-muted,
:root .af-auth-card .af-auth-local-note { color: rgba(255,255,255,.88); }
/* Enlaces dentro de la tarjeta («¿Olvidaste la contraseña?»): melocotón claro, que es el
   naranja de marca llevado a luz. Sobre el cristal ahumado da ≥7:1. */
:root .af-auth-card a:not(.btn):not(.af-auth-sso) { color: #FFC7A8; }
:root .af-auth-card a:not(.btn):not(.af-auth-sso):hover { color: #FFFFFF; }

/* Campos: láminas blancas casi opacas encima del cristal ahumado. Se leen igual que en
   cualquier otra pantalla (texto navy sobre blanco) y dan el contraste de capas. */
:root .af-auth-card .form-control {
  background-color: rgba(255,255,255,.90);
  border-color: rgba(255,255,255,.95);
  color: var(--navy-800);
  min-height: var(--control-h-lg);
  box-shadow: inset 0 1px 2px rgba(8,24,64,.08), 0 8px 20px -12px rgba(3,8,22,.5);
}
:root .af-auth-card .form-control:focus {
  background-color: #FFFFFF;
  border-color: #FFFFFF;
  box-shadow: 0 0 0 4px rgba(255,160,56,.45), 0 8px 20px -12px rgba(3,8,22,.5);
}
:root .af-auth-card .form-control::placeholder { color: #6B7394; }
:root .af-auth-card .af-field-icon { color: var(--navy-400); }
:root .af-auth-card .af-password-toggle { color: var(--navy-400); }
:root .af-auth-card .af-password-toggle:hover { background: rgba(8,24,64,.06); color: var(--navy-800); }
:root .af-auth-card .form-check-input {
  background-color: rgba(255,255,255,.18);
  border-color: rgba(255,255,255,.70);
}
:root .af-auth-card .form-check-input:checked {
  background-color: var(--action-primary);
  border-color: var(--action-primary);
}
:root .af-auth-card .btn-brand { height: 52px; }

/* Separador «o» y botones de SSO: cristal sobre cristal. */
:root .af-auth-card .af-auth-sep { color: rgba(255,255,255,.86); }
:root .af-auth-card .af-auth-sep::before,
:root .af-auth-card .af-auth-sep::after { background: rgba(255,255,255,.22); }
:root .af-auth-card .af-auth-sso {
  background: rgba(255,255,255,.12);
  border-color: rgba(255,255,255,.30);
  color: #FFFFFF;
  border-radius: var(--radius-pill);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.30);
}
:root .af-auth-card .af-auth-sso:hover { background: rgba(255,255,255,.20); border-color: rgba(255,255,255,.5); color: #FFFFFF; }
:root .af-auth-card .af-auth-sso:focus-visible { outline-color: #FFC7A8; }
:root .af-auth-card :focus-visible { outline-color: #FFC7A8; }

/* Pasos del instalador y cajas de diagnóstico, dentro de la tarjeta oscura. */
:root .af-auth-card .af-steps,
:root .af-auth-card h2,
:root .af-auth-card h3 { color: #FFFFFF; }

/* Pie: una pastilla de cristal ahumado propia. Sin nada detrás, el blanco de la capa
   común (.5/.38) —y cualquier blanco— se perdía cada vez que el centro de una gota
   naranja pasaba por debajo (blanco sobre #FFA038 da 2,2:1). Con el mismo ahumado que la
   tarjeta el contraste ya no depende de dónde estén las gotas. El pie no contiene ningún
   modal, así que el filtro directo es seguro. */
:root .af-auth-foot {
  width: fit-content; max-width: 100%;
  margin-inline: auto;
  padding: var(--space-4) var(--space-6);
  border-radius: var(--radius-panel);
  background: rgba(8,20,56,.42);
  -webkit-backdrop-filter: blur(20px) saturate(150%) brightness(.72);
  backdrop-filter: blur(20px) saturate(150%) brightness(.72);
  border: 1px solid rgba(255,255,255,.14);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.22);
  color: rgba(255,255,255,.90);
}
:root .af-auth-foot-copy { color: rgba(255,255,255,.84); }
:root .af-auth-foot a { color: #FFFFFF; }

/* Teléfono: gotas más pequeñas y menos desenfoque (el filtro cuesta por píxel), y la
   tarjeta pegada a los bordes con menos relleno. */
@media (max-width: 575.98px) {
  :root body:has(.af-auth)::before,
  :root body:has(.af-auth)::after,
  :root .af-auth::before,
  :root .af-auth::after { filter: blur(40px); }
  :root body:has(.af-auth)::before { width: 90vw; }
  :root body:has(.af-auth)::after { width: 80vw; }
  :root .af-auth::before { width: 100vw; left: 0; }
  :root .af-auth::after { width: 50vw; }
  :root .af-auth-card { padding: var(--space-7) var(--space-6); border-radius: var(--radius-panel); }
}


/* =====================================================================================
   D. PORTADA DE LA FICHA DEL CATÁLOGO (templates/element/catalog/detail_hero.php)
   =====================================================================================
   La capa común (webroot/css/catalog.css) pega la portada al borde superior del área de
   contenido y la funde abajo hacia --surface-canvas OPACO. Con este tema eso falla dos
   veces:
     1. La barra superior flota pero sigue ocupando sitio en el flujo, así que la foto
        empezaba DEBAJO de ella, con una franja de aurora encima.
     2. El fundido a un color macizo termina en un canto recto sobre la aurora, y el
        borde izquierdo de la foto chocaba en seco con la barra lateral.
   La portada sube por detrás de la barra (que es cristal: se ve la foto a través) y en
   vez de fundirse A un color se DESVANECE con una máscara, así que lo que aparece debajo
   es la propia aurora. catalog.css se carga después de este fichero; los selectores
   llevan `:root` y ganan por especificidad. */

/* Lo que ocupa la barra superior en el flujo: su alto más el margen de 12 px con el que
   flota (en escritorio mide --topbar-h − 8 px, ver A.3). En el teléfono va pegada. */
:root { --lg-topbar-space: var(--topbar-h); }
@media (min-width: 992px) { :root { --lg-topbar-space: calc(var(--topbar-h) + 4px); } }

/* Catálogo en modo streaming (0.212.0): sus portadas (slider, cabecera de categoría y
   ficha) suben por detrás de la cápsula de la barra superior, como la portada de la
   ficha antigua de aquí arriba. Solo en escritorio: en el teléfono la barra va de
   lado a lado y es una barra de verdad. El buscador y «Gestionar catálogo» quedan
   flotando justo debajo de la cápsula. Ver 2_UI_DOCS/THEMES.md. */
@media (min-width: 992px) {
  :root {
    --stream-topbar-overlap: var(--lg-topbar-space);
    /* Y empiezan y acaban donde la cápsula, con sus esquinas: separadas del menú
       lateral, que también es una cápsula. */
    --stream-hero-inset: var(--gutter-panel);
    --stream-hero-radius: var(--radius-panel);
  }
}

:root .af-catalog-hero {
  background: transparent;
  min-height: calc(clamp(300px, 46vh, 480px) + var(--lg-topbar-space));
  /* La máscara de la foto y del velo, compartida: opaca arriba, se desvanece hacia el
     pie (donde va el título) y, en el lado de la barra lateral, un fundido corto para
     que no haya canto. */
  --lg-hero-mask:
    linear-gradient(180deg, #000 0%, #000 42%, rgba(0,0,0,.55) 70%, rgba(0,0,0,.18) 88%, transparent 100%),
    linear-gradient(90deg, transparent 0%, #000 7%);
}
:root .af-catalog-hero:first-child {
  margin-top: calc(-1 * (var(--hero-pad-top) + var(--lg-topbar-space)));
}
:root .af-catalog-hero-inner {
  padding-top: calc(var(--space-6) + var(--lg-topbar-space));
}
@media (max-width: 991.98px) {
  :root .af-catalog-hero { min-height: calc(clamp(260px, 40vh, 380px) + var(--lg-topbar-space)); }
}
@media (max-width: 767.98px) {
  :root .af-catalog-hero { min-height: calc(clamp(240px, 62vw, 320px) + var(--lg-topbar-space)); }
  :root .af-catalog-hero-inner { padding-top: calc(var(--space-4) + var(--lg-topbar-space)); }
  /* En el teléfono no hay barra lateral a la izquierda: solo el fundido vertical. */
  :root .af-catalog-hero { --lg-hero-mask: linear-gradient(180deg, #000 0%, #000 42%, rgba(0,0,0,.55) 70%, rgba(0,0,0,.18) 88%, transparent 100%), linear-gradient(#000 0 0); }
}
:root .af-catalog-hero-img,
:root .af-catalog-hero::after {
  -webkit-mask-image: var(--lg-hero-mask);
  -webkit-mask-composite: source-in;
  mask-image: var(--lg-hero-mask);
  mask-composite: intersect;
}
/* El velo: arriba sigue el telón oscuro (las migas son blancas y ahora además pasa la
   barra de cristal por encima); abajo, en vez del lienzo opaco, un lavado del color base
   de la aurora que la máscara se encarga de desvanecer. El resultado: la foto se disuelve
   en el fondo en lugar de acabar en un bloque. */
:root .af-catalog-hero::after {
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--surface-stage) 58%, transparent) 0%,
      color-mix(in srgb, var(--surface-stage) 20%, transparent) 30%,
      transparent 50%),
    linear-gradient(180deg,
      transparent 34%,
      color-mix(in srgb, var(--aurora-base) 45%, transparent) 60%,
      color-mix(in srgb, var(--aurora-base) 80%, transparent) 100%);
}
/* El título y el subtítulo caen sobre la zona desvanecida, donde detrás está la aurora:
   el halo de lectura toma su color base, no el del lienzo liso del tema base. */
:root .af-catalog-hero-title { text-shadow: 0 1px 18px var(--aurora-base), 0 0 2px color-mix(in srgb, var(--aurora-base) 60%, transparent); }
:root .af-catalog-hero-subtitle { text-shadow: 0 1px 12px var(--aurora-base); }

/* --- Tarjetas de material del visor (0.178.0) -----------------------------------------
   Test, entregable, encuesta, enlace, videoconferencia y entrada del calendario se pintan
   en el escenario del reproductor con `.af-matcard`. Aquí el telón no es un halo plano: son
   tres manchas de color (la del tema y las de dos tipos de material) que dan algo que
   desenfocar, y la tarjeta es una lámina de cristal sobre ellas.

   El cristal va en la PROPIA tarjeta y no en un ::before: dentro no hay ningún modal (los
   del intento y del entregable cuelgan de <body>), así que el `backdrop-filter` no atrapa
   nada. Con `--glass-bg-strong` casi opaco, el texto se lee igual que en la tarjeta lisa. */
:root .af-matstage {
  background:
    radial-gradient(55% 48% at 16% 10%, color-mix(in srgb, var(--material-stage-glow, var(--action-primary)) 46%, transparent) 0%, transparent 70%),
    radial-gradient(50% 44% at 88% 90%, color-mix(in srgb, var(--material-practice, var(--action-accent)) 36%, transparent) 0%, transparent 70%),
    radial-gradient(40% 36% at 92% 8%, color-mix(in srgb, var(--material-survey, var(--status-ai-solid)) 28%, transparent) 0%, transparent 70%);
}
:root .af-matcard {
  background: var(--glass-sheen), var(--glass-bg-strong);
  -webkit-backdrop-filter: var(--glass-blur-strong);
  backdrop-filter: var(--glass-blur-strong);
  border: 1px solid var(--glass-border);
  border-top: 4px solid var(--af-mat);
  box-shadow: inset 0 1px 0 var(--glass-highlight), 0 0 0 1px var(--glass-edge), var(--glass-shadow);
}
/* El pie, los recuadros y la banda neutra, translúcidos sobre el cristal en vez de hundidos. */
:root .af-matcard-foot { background: color-mix(in srgb, var(--surface-sunken) 55%, transparent); border-top-color: var(--glass-border); }
:root .af-matcard-tile,
:root .af-matcard-site,
:root .af-matcard-reqs li,
:root .af-matcard-chips li { background: color-mix(in srgb, var(--surface-sunken) 60%, transparent); }
:root .af-matcard-status.is-neutral { background: color-mix(in srgb, var(--surface-sunken) 60%, transparent); }
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  :root .af-matcard { background: var(--surface-card); }
}

/* ---------------------------------------------------------------------------
   Reproductor de cursos (1.2.0)

   Inmersivo: el panel inferior (descripción, foro, clase) y el índice FLOTAN sobre el
   vídeo o el paquete. Con --surface-card al .86 se leía el contenido de detrás a través
   del panel y la escena de la clase quedaba sin anclar: van en sólido, blanco en claro
   y el tono opaco del tema en oscuro, sin desenfoque.

   Clásico, solo en escritorio (en ≤1024 px el índice es un cajón que flota sobre el
   contenido y se queda sólido): el índice no es una tarjeta encima de la aurora, sino
   una columna TRANSPARENTE sobre el mismo fondo, separada por una línea (Guille lo
   prefirió sin velo). Para que se lea en cualquier punto, dentro del índice bajan de
   tono el texto secundario y el naranja del título activo: medido sobre la base con las
   tres manchas que llegan al borde derecho (sola y de dos en dos), en claro y en
   oscuro, todo el texto queda por encima de 4,5:1.
   --------------------------------------------------------------------------- */
:root { --lg-player-solid: #FFFFFF; --lg-side-muted: #4A443E; --lg-side-brand: #8A1F09; }
:root[data-theme="dark"] { --lg-player-solid: #111E48; --lg-side-muted: #CEC8C2; --lg-side-brand: #FFB394; }

:root .af-player-immersive .af-imm-sheet,
:root .af-player-immersive .af-player-side {
  background: var(--lg-player-solid);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

@media (min-width: 1025px) {
  :root .af-player:not(.af-player-immersive) .af-player-side {
    background: transparent;
    border-left: 1px solid var(--border-default);
    box-shadow: none;
    --text-muted: var(--lg-side-muted);
    --text-subtle: var(--lg-side-muted);
    --text-brand: var(--lg-side-brand);
  }
  :root .af-player:not(.af-player-immersive) .af-player-side-head { border-bottom-color: var(--border-default); }
}
