/* ============================================================
   portada.css — El armazón de layouts/portada, y los tokens de toda la casa

   Sistema propio y autónomo: no depende de ninguna otra hoja. Define los
   tokens —--bg, --sup, --borde, --tx, --ac, --r, --ease y las tres
   familias— sobre los que se apoyan notes.css, ludoteca.css y config.css,
   que sólo agregan lo suyo, y también resources/react/tema.ts, que los mapea
   al contrato --base-* del design system. Tocar la paleta de acá se ve en
   las quince secciones Blade y en las tres de React a la vez.

   El nombre quedó de cuando esta hoja vestía la portada. **Ya no lo hace**:
   desde que la portada y sus cuatro subportadas son React, lo que queda acá
   es el armazón del layout —la banda, la barra, las migas, la cabecera— más
   la página de sección en proceso, que todavía usan Spotify y YouTube. Las
   familias de la portada (pz-hero, pz-rejilla, pz-tarjeta, pz-ficha,
   pz-noticias, pz-destacado, pz-titular, pz-hitos) se podaron el 2026-09-11,
   535 líneas, después de comprobar por grep que no las nombraba ni una vista
   ni un .tsx. Viven ahora en Emotion, dentro de resources/react/{inicio,comunes}.

   Con la ludoteca migrada, hub.css se retiró y estilos.css quedó acotado al
   libreto de Sleeping Gods; el acceso salió a acceso.css al adoptar este
   sistema.

   ── Sobre la estética ──────────────────────────────────────────────────
   El lenguaje es el de la landing TCP de appExtranet: fondo casi negro
   teñido con el tono del acento, bloques de esquina casi recta delimitados
   por hairlines en vez de superficies que contrastan y micro-etiquetas en
   versalitas. De ese lenguaje NO sobrevivieron las versales en los títulos:
   se probaron y se descartaron, y los títulos volvieron a la caja normal y a
   Plus Jakarta Sans, que es lo que había antes.

   Tampoco se trajo la atmósfera —grano de film, marco HUD de esquinas,
   línea de barrido—: funciona en una página que se mira una vez y estorba
   en pantallas de trabajo.
   ============================================================ */

:root {
  /* Casi negro con una pizca del tono del acento, igual que el fondo verdoso
     de la landing que sirve de modelo. Un navy neutro apagaba el cian. */
  --bg: #070b0e;
  --sup: #0e1419;
  --sup-2: #141c22;
  --borde: #1e2930;
  --borde-2: #2c3b45;
  --tx: #e8eef1;
  --tx-2: #8b9aa3;
  --tx-3: #5c6a73;
  --ac: #3ad6e6;
  /* El verde de "esto salió bien" —el punto de guardado de Notes, los avisos
     de config—. Era un verde marino #46b17b que contra el azul de antes se
     distinguía solo; a 60° del cian se confundía con el acento en un punto de
     6 px. Este corte es verde franco y no deja dudas. */
  --bien: #5fc46b;
  /* Tinta sobre el acento —el relleno de .ui-button--primary—. En oscuro el
     acento es claro y pide texto oscuro; en claro es al revés. Antes esto
     estaba clavado en ui.css y el botón primario del tema claro salía con
     texto casi negro sobre azul oscuro. */
  --ac-tinta: #04191d;
  /* El verde de Spotify. Es lo único de la paleta que no se eligió aquí: es de
     ellos y va tal cual, igual en los dos temas. Está a un paso de --bien
     —#5fc46b— y por eso el glifo que lo lleva es además el único relleno: sin
     esa diferencia de tratamiento, un glifo verde en la rejilla se leería como
     un estado y no como una marca. */
  --spotify: #1db954;
  /* El rojo de YouTube, con el mismo trato que el verde de arriba: es de ellos
     y va tal cual en los dos temas. El puro #ff0000 vibra feo contra el casi
     negro del fondo, así que se usa el de su interfaz oscura, que es el mismo
     rojo apenas bajado de luminancia y es lo que la propia YouTube pinta sobre
     fondo negro. */
  --youtube: #f0322e;

  /* Las tres familias del sistema, una por papel. --fuente-t es para títulos y
     nombres de bloque; --fuente-m para todo lo que va en versalitas: migas,
     estados, contadores, etiquetas de campo.

     Inter no opina: es la más legible para texto de aplicación y desaparece,
     que es lo que se le pide al papel de fondo.

     Los títulos volvieron a Plus Jakarta Sans, que era la familia única del
     sistema anterior. Ya no van en versales, así que no hace falta una
     condensada: lo condensado servía para que un bloque de mayúsculas no se
     comiera el ancho de la tarjeta, y ese problema desapareció con las
     versales. En caja normal Plus Jakarta pide tracking NEGATIVO —es lo que
     tenía antes—, al revés que cualquiera de las que se probaron en versales.

     Antes de ésta se pasó por Saira Condensed, Chakra Petch, Plex y Oswald.
     Oswald se descartó por la minúscula: los dos títulos que llevan texto del
     usuario —el nombre de un juego, el de una nota— van en caja normal, y una
     letra de señalética los hace leer como afiche en vez de como el nombre de
     un registro. Es la prueba que hay que hacerle a cualquier reemplazo. */
  --fuente: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  --fuente-t: 'Plus Jakarta Sans', 'Inter', system-ui, sans-serif;
  --fuente-m: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --r: 3px;
  --ease: cubic-bezier(.23, 1, .32, 1);

  /* El pulgar de las barras de desplazamiento. Apunta a --borde-2 y no a un
     valor propio: una barra es un borde que se mueve, y con el mismo tono se
     apoya en el sistema en vez de abrir un color más. Está como token aparte
     para poder subirle el peso sin tocar los bordes de verdad. */
  --barra: var(--borde-2);
}

:root[data-tema="claro"] {
  --bg: #f4f7f8;
  --sup: #fff;
  --sup-2: #fbfdfd;
  --borde: #dde5e8;
  --borde-2: #c3d0d5;
  --tx: #0d1518;
  --tx-2: #55646b;
  --tx-3: #8695a0;
  /* El cian brillante sobre blanco da 1.9:1 e ilegible. Este corte llega a
     5:1 contra --bg y sigue leyéndose de la misma familia. */
  --ac: #0e7490;
  --ac-tinta: #fff;
  --bien: #2f7d3f;
}

* { box-sizing: border-box; }

/* ============================================================
   Las barras de desplazamiento, para toda la aplicación.

   Esta hoja la carga layouts/portada.blade.php, así que lo de acá vale para
   las secciones que siguen en Blade y para las de React por igual. Hasta el
   2026-09-15 no existía: la barra nativa de Windows —gris casi blanca, con
   sus dos flechas, 15 px— partía en dos cada columna sobre el casi negro del
   tema oscuro. Cinco sitios se lo habían arreglado por su cuenta con estas
   mismas dos líneas —Spotify, Contactos y Notas—; el resto, y la ventana
   entera, se quedaban con la del sistema.

   ── Por qué las dos recetas, y en este orden ──────────────────────────
   No se pisan: en cada navegador manda una sola.

   Desde Chromium 121 las propiedades estándar GANAN y las reglas
   ::-webkit-scrollbar se ignoran por completo. O sea que en Chrome, Edge,
   Firefox y Safari 18.2+ la barra la decide `thin` y mide 10 px —medido, no
   supuesto—. Las reglas webkit de abajo son el respaldo para Chromium viejo y
   Safari anterior, donde la estándar no existe y si no quedaría la nativa.

   ⚠️ Por eso no se puede bajar de 10 px sin romper algo: pedir 8 con webkit
   sólo funciona si se quita `scrollbar-width`, y entonces Firefox vuelve a la
   nativa de 15. Diez es lo más fino que se puede pedir sin dejar a nadie
   afuera.

   `scrollbar-color` hereda, así que en :root alcanza para todo el documento.
   `scrollbar-width` NO hereda: por eso va en el universal.

   El universal tiene especificidad 0, así que cualquier regla con clase le
   gana: nfl.css sigue escondiendo la suya con `scrollbar-width: none` y este
   bloque no la toca.
   ============================================================ */

:root { scrollbar-color: var(--barra) transparent; }

* { scrollbar-width: thin; }

::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  border-radius: 999px;
  /* El borde transparente con background-clip es lo que mete el pulgar hacia
     adentro: sin él toca los dos bordes del canal y se lee como una columna
     más, no como algo que se agarra. */
  border: 2px solid transparent;
  background: var(--barra);
  background-clip: padding-box;
}
/* La esquina donde se cruzan las dos barras: sin esto queda un cuadrado del
   gris del sistema, que es justo lo que este bloque viene a sacar. */
::-webkit-scrollbar-corner { background: transparent; }

body.portada {
  margin: 0;
  background: var(--bg);
  color: var(--tx);
  font: 400 15px/1.62 var(--fuente);
  -webkit-font-smoothing: antialiased;
}

/* Único gesto atmosférico que sobrevive —y es de esta casa, no de la landing:
   un halo del acento detrás de la cabecera. Fijo y sin capturar el puntero. */
body.portada::before {
  content: "";
  position: fixed;
  inset: 0 0 auto;
  height: 520px;
  pointer-events: none;
  background: radial-gradient(760px 320px at 50% -8%, rgba(58, 214, 230, .10), transparent 70%);
}
:root[data-tema="claro"] body.portada::before {
  background: radial-gradient(760px 320px at 50% -8%, rgba(14, 116, 144, .08), transparent 70%);
}

/* ---------- La banda de la portada ----------
   Sólo en la portada —la clase la pone inicio.blade—; el resto de las
   pantallas se queda con el halo de arriba. La imagen entra por --pz-fondo,
   que la propia vista define en un <style> del <head>: es de cada usuario y
   cambia con la sesión, así que no puede vivir clavada en esta hoja.

   Es una sola capa con tres fondos apilados —el de arriba es el primero de la
   lista—: el velado diagonal, el que la funde con el fondo abajo, y la imagen.
   Van juntos y no en tres elementos porque este pseudo-elemento ya existe y el
   ::after de body queda POR ENCIMA del contenido, no detrás.

   El velado no es parejo: carga en la izquierda, que es donde van el logo y el
   título, y afloja en el 62 % para dejar respirar la parte luminosa. Con un
   velado plano hay que subirlo tanto para que el texto se lea que la imagen ya
   no se ve. */
body.portada.hero::before {
  height: clamp(360px, 40vw, 470px);
  background-image:
    /* Refuerzo a la altura de la barra: el fondo lo elige el usuario y no hay
       forma de saber qué le toca detrás a los iconos. Con esto la barra se lee
       contra cualquier imagen sin tener que velar la banda entera. */
    linear-gradient(to bottom, rgba(7, 11, 14, .62) 0, transparent 96px),
    linear-gradient(100deg, rgba(7, 11, 14, .90) 0%, rgba(7, 11, 14, .66) 38%, rgba(7, 11, 14, .28) 62%, rgba(7, 11, 14, .72) 100%),
    linear-gradient(to bottom, transparent 42%, var(--bg) 97%),
    var(--pz-fondo, none);
  background-size: auto, auto, auto, cover;
  /* El encuadre corrido a la izquierda empuja la parte luminosa hacia el 60 %
     del ancho, que es donde el velado afloja. Centrada, la zona brillante caía
     detrás del título y había que taparla. */
  background-position: center, center, center, 32% 56%;
  background-repeat: no-repeat;
}
/* En claro no hay imagen: una foto casi negra debajo de una interfaz clara se
   ve rota, y aclararla lo suficiente la deja en un gris sucio. Vuelve el halo
   de siempre, tal cual estaba. */
:root[data-tema="claro"] body.portada.hero::before {
  height: 520px;
  background-image: radial-gradient(760px 320px at 50% -8%, rgba(14, 116, 144, .08), transparent 70%);
}

/* Sobre la imagen la barra no vela: velar sobre una foto la convierte en una
   franja gris pegada arriba. El hairline pasa a ser un blanco tenue, que es lo
   único que se ve contra una imagen y contra el fondo liso a la vez. */
body.portada.hero .pz-barra {
  background: transparent;
  backdrop-filter: none;
  border-bottom-color: rgba(255, 255, 255, .12);
}
:root[data-tema="claro"] body.portada.hero .pz-barra {
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  backdrop-filter: blur(14px) saturate(1.3);
  border-bottom-color: var(--borde);
}

/* En la portada la barra se queda con el logo y los botones. Lo que se va es la
   palabra «Extranet» y la ruta: las dice el hero, tres centímetros más abajo y
   en grande, y repetirlas arriba era escribir «Extranet / Portada» dos veces en
   la misma pantalla. El logo se queda porque es la marca, no una etiqueta.
   Se ocultan por CSS y no sacándolas de la plantilla porque la barra es la
   misma en todas las secciones, y ahí sí hacen falta: son el camino de vuelta.
   El hairline también se va —la banda ya separa— y la barra queda flotando. */
/* La marca entera y la ruta se van: las dos las dice el hero, tres centímetros
   más abajo. Se va el enlace completo y no sólo su texto —ocultar la palabra y
   dejar el glifo, que es aria-hidden, deja un enlace sin nombre, y un enlace
   que no se puede nombrar no se puede usar a ciegas—. Perder el atajo a la
   portada no cuesta nada acá: la portada es esta pantalla. */
body.portada.hero .pz-marca,
body.portada.hero .pz-migas { display: none; }
body.portada.hero .pz-barra { border-bottom-color: transparent; }
:root[data-tema="claro"] body.portada.hero .pz-barra { border-bottom-color: var(--borde); }

.pz {
  /* El margen lateral pasa a token: la barra lo necesita en negativo para
     sangrar de borde a borde cuando queda pegada arriba. */
  --pz-pad: clamp(18px, 4vw, 32px);
  position: relative;
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 var(--pz-pad) 96px;
}

/* ---------- Barra ---------- */
/* La barra queda pegada arriba: es donde viven el tema y la salida, y en móvil
   la portada mide tres pantallas de alto. Sangra a los lados con el margen en
   negativo para que el velado tape el contenido hasta el borde. */
.pz-barra {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 14px;
  height: 66px;
  margin: 0 calc(-1 * var(--pz-pad));
  padding: 0 var(--pz-pad);
  border-bottom: 1px solid var(--borde);
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  backdrop-filter: blur(14px) saturate(1.3);
}
/* Sin backdrop-filter el velado no vela: ahí el fondo va opaco. */
@supports not (backdrop-filter: blur(1px)) {
  .pz-barra { background: var(--bg); }
}

.pz-marca {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--fuente-t);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -.015em;
  text-decoration: none;
  color: inherit;
  flex: none;
}
.pz-marca-glifo {
  display: grid;
  place-items: center;
  width: 27px;
  height: 27px;
  border: 1.6px solid var(--ac);
  border-radius: 2px;
  color: var(--ac);
  flex: none;
}
.pz-marca-glifo svg { display: block; width: 15px; height: 15px; }
/* Con logo propio, igual que en el hero: sin recuadro y sin recorte. */
.pz-marca-glifo--propio { border: 0; }
.pz-marca-glifo--propio img { display: block; width: 100%; height: 100%; object-fit: contain; }

/* Las migas van en versalitas de mono: es lo que las separa de la marca, que
   está al lado y en la letra de títulos. El contraste lo hacen la familia y el
   tracking, no el cuerpo. */
.pz-migas {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: var(--fuente-m);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--tx-3);
  overflow: hidden;
  white-space: nowrap;

  /* Centrar no es alinear. La barra centra por caja y las migas quedan
     geométricamente en el medio, pero 3,5 px por encima de la baseline de la
     marca: al lado de «Extranet» se leen flotando. Lo que haría falta
     —align-self: baseline— no sirve acá: .pz-marca es un flex container cuyo
     primer ítem es el glifo, un grid con un SVG, y el navegador le sintetiza la
     baseline en su borde inferior; pedirla pega el bloque entero contra el
     techo de la barra. Así que el desplazamiento va explícito, y va en transform
     y no en padding porque con align-items: center el padding se recentra y baja
     sólo la mitad —y porque así no toca el ancho del que dependen el overflow y
     el ellipsis de los enlaces que React inyecta acá por portal—.
     El cálculo daba .32em —los 3,5 px que igualan las dos baselines—, pero a ojo
     queda mejor 1 px más arriba: las versalitas de mono no tienen descendentes y
     apoyadas exactamente en la línea se leen bajas. Van .23em, en em para que el
     desplazamiento siga al cuerpo si alguna vez cambia. */
  transform: translateY(.23em);
}
.pz-migas a { color: var(--tx-2); text-decoration: none; transition: color .18s ease; }
.pz-migas a:hover { color: var(--ac); }
.pz-migas [aria-current] { color: var(--tx-2); }

.pz-acciones { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.pz-acciones form { display: flex; margin: 0; }
.pz-icono {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--borde);
  border-radius: var(--r);
  background: transparent;
  color: var(--tx-2);
  font-size: 14px;
  cursor: pointer;
  transition: border-color .18s ease, color .18s ease, transform .14s var(--ease);
}
.pz-icono:hover { border-color: var(--borde-2); color: var(--tx); }
.pz-icono:active { transform: scale(.96); }
.pz-icono:focus-visible { outline: 2px solid var(--ac); outline-offset: 2px; }
/* Config es un enlace y sus vecinos son <button>: sin esto llega con subrayado
   y con el color de enlace del navegador. El engranaje además tiene menos
   cuerpo óptico que ◑ y ⏻ al mismo tamaño, y 1,5 px lo emparejan; medido
   ampliando la barra, no a ojo. */
a.pz-icono { font-size: 15.5px; text-decoration: none; }
/* Estando dentro, el engranaje se queda encendido: es la única pista de en
   qué sección estás cuando las migas se ocultan en móvil. */
.pz-icono[aria-current] { border-color: color-mix(in srgb, var(--ac) 45%, var(--borde)); color: var(--ac); }

/* ---------- Cabecera ---------- */
.pz-cabecera { padding: clamp(30px, 6vw, 62px) 0 clamp(24px, 3.4vw, 38px); }

/* El sobretítulo deja el punto y pasa a ser el eyebrow del sistema: versalitas
   con tracking largo, precedidas de un guion del acento. El punto se retiró
   porque a este cuerpo y con este tracking quedaba pegado a la primera letra;
   el guion cumple la misma función de anclaje y respira. */
.pz-kicker {
  display: inline-block;
  position: relative;
  margin: 0 0 15px;
  padding-left: 38px;
  font-family: var(--fuente-m);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--ac);
}
.pz-kicker::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 28px;
  height: 1px;
  background: currentColor;
  transform: translateY(-50%);
}

.pz-cabecera h1 {
  margin: 0;
  font-family: var(--fuente-t);
  font-size: clamp(32px, 4.8vw, 46px);
  font-weight: 700;
  letter-spacing: -.025em;
  line-height: 1.06;
  text-wrap: balance;
}
.pz-lema {
  margin: 14px 0 0;
  max-width: 52ch;
  color: var(--tx-2);
  font-size: 15.5px;
  text-wrap: pretty;
}

/* ---------- Glifos de marca ---------- */

/* El glifo de Spotify no toma el acento como los otros doce: es una marca
   ajena y va en su verde. El verde vive aquí y no en el SVG porque el mismo
   glifo se pinta en la cabecera de la sección y en las migas. (En la portada,
   que hoy es React, los glifos llevan su color en el propio SVG.)

   --glifo-hueco es el fondo contra el que se recortan las ondas. Por defecto
   es --sup; donde el glifo caiga sobre otra superficie, se redefine ahí y las
   ondas acompañan sin tocar el marcado. */
.gl-disco { fill: var(--spotify); stroke: none; }
.gl-onda {
  fill: none;
  stroke: var(--glifo-hueco, var(--sup));
  /* Decrecen de fuera hacia dentro, como en el original. A 30 px el trazo más
     fino queda en 1,75 px reales: por debajo de eso la onda de adentro se
     empasta contra el disco. */
  stroke-linecap: round;
}
.gl-onda--a { stroke-width: 4.2; }
.gl-onda--b { stroke-width: 3.4; }
.gl-onda--c { stroke-width: 2.8; }

/* El de YouTube, con el mismo criterio y el mismo --glifo-hueco. El triángulo
   se pinta del color del fondo en vez de calarse: a los tamaños en que se usa
   —30 y 34 px— no hay diferencia visible, y un calado real obligaría a
   resolver la caja y el play como una sola forma con fill-rule evenodd. */
.gl-yt-caja { fill: var(--youtube); stroke: none; }
.gl-yt-play { fill: var(--glifo-hueco, var(--sup)); stroke: none; }

/* ---------- Página de sección en proceso ---------- */
.pz-taller { max-width: 620px; padding-top: clamp(30px, 5vw, 52px); }
/* Aquí el glifo cae sobre el fondo de la página y no sobre una tarjeta: las
   ondas de Spotify tienen que recortarse contra --bg o se ven como tres rayas
   del color de una superficie que en esta pantalla no existe. */
.pz-taller-glifo { display: block; margin-bottom: 22px; color: var(--ac); --glifo-hueco: var(--bg); }
.pz-taller-glifo svg { display: block; width: 40px; height: 40px; }

/* El botón de una cabecera de sección. Va suelto y no en el cuerpo del texto,
   así que necesita su propio aire arriba. */
.pz-acciones-taller { margin: 28px 0 0; }

.pz-volver {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-top: 34px;
  padding: 11px 18px;
  border: 1px solid var(--borde);
  border-radius: var(--r);
  color: var(--tx-2);
  font-family: var(--fuente-m);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
  transition: border-color .18s ease, color .18s ease, transform .14s var(--ease);
}
.pz-volver:hover { border-color: var(--borde-2); color: var(--tx); }
.pz-volver:active { transform: scale(.98); }
.pz-volver:focus-visible { outline: 2px solid var(--ac); outline-offset: 2px; }

/* ---------- Pantallas pequeñas ---------- */
@media (max-width: 620px) {
  .pz-migas { display: none; }

  /* Los botones crecen: en el teléfono la barra es lo que se toca. El ALTO de
     la barra no se toca —Notes calcula su armazón con \`100dvh - 67px\` y ese
     token vive en notes.css—, así que bajarla acá le dejaría la aplicación 9 px
     larga y con scroll de página. */
  .pz-icono { width: 40px; height: 40px; }
  .pz-marca { font-size: 17px; }
}

/* ---------- Accesibilidad ---------- */
@media (prefers-reduced-motion: reduce) {
  .pz-icono,
  .pz-volver { transition: none; }
}
