/* ============================================================================
   SOMOS TRUFAS — LOS COMPONENTES COMUNES
   ============================================================================

   Lo que se ve igual en la web (somostrufas.org) y en el panel
   (admin.somostrufas.org): el aro del bisel, el antetítulo, los botones, las
   píldoras, la caja biselada, el menú de la cuenta, la aparición al bajar y,
   desde el 17 oct 2026, los controles de formulario (casillas, interruptores,
   deslizadores, campos…: ver «LOS CONTROLES DE FORMULARIO» al final).
   Separado de base.css el 28 sep 2026 para que los dos sitios lean EL MISMO
   archivo y no dos copias que se van separando (el panel tenía las suyas).

   EL ORDEN DE LAS TRES HOJAS: marca.css (tokens y fuentes) → este →
   base.css o panel.css (la maqueta de cada sitio, que puede retocar lo de
   aquí porque se carga después).

   CÓMO LLEGA AL PANEL: NO lo lee de somostrufas.org. Cada vez que Cloudflare
   publica el panel (producción o una preview), `scripts/comun-panel.mjs`
   copia este archivo, marca.css, colocar.js y las fuentes a
   panel/assets/comun/ (el paso `build` de panel/wrangler.jsonc). Así cada
   rama se prueba con su versión y las fuentes cargan desde el propio panel.
   ⚠ Tocar algo aquí cambia LOS DOS sitios: se mira en los dos.

   Lo que NO va aquí: la barra, el hero, las tarjetas de evento, las tablas
   del panel… todo lo que solo existe en un sitio.
   ========================================================================== */

/* ---------- EL ANTETÍTULO ---------- */
.eyebrow{
  font-family:'Poppins',sans-serif;
  font-size:var(--tipo-antetitulo);
  font-weight:600;
  letter-spacing:.22em;
  text-transform:uppercase;
  color:var(--yellow);
}

/* ---------- EL FILO DEL BISEL ----------
   `clip-path` recorta TODO lo que pinta el elemento, el borde incluido, y el
   borde se dibuja sobre el rectángulo: los dos chaflanes se llevaban su trozo
   por delante y el contorno se quedaba con dos huecos. Esto lo repone con un
   aro que SÍ tiene la forma del bisel. El cómo, el porqué y la geometría —que
   no es «lo mismo menos 1px»— están escritos junto a `--filo` en marca.css.

   Y de paso arregla el foco, que era el mismo fallo con otra cara: el
   `:focus-visible` de aquí arriba va por FUERA (outline-offset:3px), o sea que
   en cualquier cosa biselada caía entero fuera del recorte y no se veía nada.
   Ningún botón del sitio enseñaba dónde estaba el teclado. Ahora el anillo es
   el mismo aro, en amarillo y a 2px, por dentro.

   EL `::after` SE DECLARA EN TODOS LOS `.btn` Y TODAS LAS `.pill`, no solo en
   los que llevan filo: en los macizos (.btn-primary, .pill-live) nace
   transparente y solo aparece al enfocar. Un pseudo transparente no cuesta
   nada y evita tener dos listas de selectores que mantener a la par.

   ⚠ El `@supports` NO es decorativo: sin él, un navegador que no entienda el
   `fill-rule` dejaría el `clip-path` en `none` y el pseudo taparía el
   elemento con un rectángulo macizo. Con él se degrada a lo de antes. */
/* ⚠ `--filo-color` VA FUERA DEL `@supports`, y esto no es colocación: la
   reserva `box-shadow` de cada regla lo lee como
   `var(--filo-borde, var(--filo-color))`. Declarado dentro, un navegador sin
   `evenodd` se quedaría sin la variable, el `var()` no resolvería y el
   `box-shadow` entero se caería — la reserva desaparecería justo en el único
   navegador que la necesita. Pasó, y se vio en los botones de la barra. */
.btn-ghost,.pill-soon,.pill-done,.nav-toggle{--filo-color:var(--line)}
/* Los macizos no llevan filo propio: sin esto heredan el `--filo-color` de la
   `.caja` donde caen (marrón) y `.btn::after` pinta un aro oscuro sobre el
   amarillo. El foco lo vuelve a poner más abajo (--sobre-amarillo). */
.btn-primary,.btn-live,.pill-live,.pill-open{--filo-color:transparent}

@supports (clip-path: polygon(evenodd, 0 0, 1px 1px, 0 1px)){
  /* UNA VEZ POR DOCUMENTO: apaga todas las reservas `box-shadow`/`border` del
     sitio, las de esta hoja y las de los <style> de cada página. */
  :root{--filo-borde:transparent}
  .btn,.pill,.nav-toggle{position:relative}
  .btn::after,.pill::after,.nav-toggle::after{
    content:'';position:absolute;inset:0;pointer-events:none;
    clip-path:var(--filo-sm);background:var(--filo-color,transparent);
  }
  /* La píldora es una etiqueta: su corte es el de 5px (--bevel-xs). */
  .pill::after{clip-path:var(--filo-xs)}

  /* Las etiquetas: sin `border`, el pseudo ya es la caja de borde. */
  .bv-tag::after,.bv-chip::after{content:'';position:absolute;inset:0;pointer-events:none;
    clip-path:var(--filo-xs);background:var(--filo-color,transparent)}

  .btn:focus-visible,.nav-toggle:focus-visible{outline:none;--filo-color:var(--yellow)}
  .btn:focus-visible::after,
  .nav-toggle:focus-visible::after{clip-path:var(--filo-foco-sm)}
  /* Sobre los amarillos, el anillo amarillo no se veía: amarillo sobre
     amarillo. Va en la tinta oscura, la misma del texto del botón. */
  .btn-primary:focus-visible,.btn-live:focus-visible{--filo-color:var(--sobre-amarillo)}
}

/* ---------- LAS ETIQUETAS · un tamaño, tres niveles ----------
   Sistema de diseño (26 sep 2026). Todas a --tipo-etiqueta y en CHIP: bisel
   pequeño y el aro --filo-sm completo (el `::after`, en el `@supports` de más
   abajo; el `box-shadow` es la reserva de quien no entienda `evenodd`). La
   importancia la da el estilo, NUNCA el tamaño:
     · principal  — relleno: la región (su color), «En vivo», la ronda
     · normal     — contorno amarillo al 45 % y texto amarillo: juego, nivel, cupos
     · secundaria — contorno --line y texto --texto-3 (`.menor`): edición, borrador
   Con el mismo patrón van los tags de los cuadros (.cd-*), el estado de un
   jugador (.jug-st), la pastilla de la Escalera (.pf-n-tag) y la del campeón.
   Antes había seis tamaños (9,3–12,8px) y dos formas, recta y biselada. */
.bv-tags{list-style:none;margin:0 0 .9rem;padding:0;display:flex;flex-wrap:wrap;gap:.35rem}
.bv-tag,.bv-chip{position:relative;display:inline-flex;align-items:center;gap:.4em;
  padding:calc(var(--pill-pad-y) + .08rem) var(--pill-pad-x);white-space:nowrap;
  font-family:'Poppins',sans-serif;font-size:var(--tipo-etiqueta);font-weight:600;line-height:1.2;
  letter-spacing:.14em;text-transform:uppercase;
  color:var(--yellow);--filo-color:rgba(255,198,33,.45);clip-path:var(--bevel-xs);
  box-shadow:inset 0 0 0 1px var(--filo-borde, var(--filo-color))}
.bv-tag.menor,.bv-chip.menor,.bv-chip.borrador{color:var(--texto-3);--filo-color:var(--line)}
.bv-tag-ico{width:1.25em;height:1.25em;flex:none;fill:currentColor;display:block}
/* La región: relleno de su color y el texto «hueco», en el color del fondo.
   Se distingue también sin ver el color: es la única con relleno de la fila. */
.bv-tag.region{background:var(--tag, var(--yellow));--filo-color:var(--tag, var(--yellow));color:var(--ink)}

/* ---------- BOTONES ---------- */
/* UNA SOLA LÍNEA Y EL TEXTO CENTRADO (16 oct 2026, CEO): un botón nunca se
   parte en dos renglones (dos botones de una fila salían de alturas
   distintas). Si no cabe, se acorta el texto o se apila con .acciones. */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.55rem;
  white-space:nowrap;
  font-family:'Poppins',sans-serif;font-size:var(--tipo-control);font-weight:600;
  letter-spacing:.08em;text-transform:uppercase;
  padding:var(--btn-pad-y) var(--btn-pad-x);
  clip-path:var(--bevel-sm);
  transition:transform .15s ease, background .15s ease, color .15s ease;
  cursor:pointer;border:none;
}
.btn-primary{background:var(--yellow);color:var(--sobre-amarillo)}
.btn-primary:hover{transform:translateY(-2px);background:var(--yellow-alto)}
.btn-ghost{background:rgba(242,232,220,.07);color:var(--texto-1);box-shadow:inset 0 0 0 1px var(--filo-borde, var(--filo-color))}
.btn-ghost:hover{background:rgba(242,232,220,.13)}
/* MEDIDAS (16 oct 2026, COO): `.btn` 39 px y `.btn-sm` 32 px, el suelo táctil. Salen de
   los tokens `--btn-*` y `--pill-*` de marca.css, no de números aquí. */
.btn-sm{padding:.35rem var(--btn-sm-pad-x);min-height:var(--btn-sm-alto);font-size:var(--tipo-rotulo);
  clip-path:var(--bevel-compacto)}   /* 32 px de alto → el escalón de 31–36 px: 7 px */
@supports (clip-path: polygon(evenodd, 0 0, 1px 1px, 0 1px)){
  .btn-sm::after{clip-path:var(--filo-compacto)}
  .btn-sm:focus-visible::after{clip-path:var(--filo-foco-compacto)}
}

/* ---------- EL MENÚ DE PÁGINAS (.nav-paginas) ----------
   Los enlaces de página de una barra: Comunidad · Esports · Media kit en la
   web, Administración · Bot de Discord en el panel. En mayúsculas a
   `--tipo-control`, en --texto-3, y la página en la que estás en --texto-1
   con la raya amarilla abajo (`aria-current="page"`). Dónde va en cada
   barra lo decide cada sitio (base.css / panel.css). */
.nav-paginas{display:flex;align-items:center;gap:1.75rem;align-self:stretch}
.nav-paginas .nav-pagina{
  display:inline-flex;align-items:center;align-self:stretch;
  font-size:var(--tipo-control);font-weight:500;letter-spacing:.1em;text-transform:uppercase;
  color:var(--texto-3);transition:color .15s;white-space:nowrap;
}
.nav-paginas .nav-pagina:hover{color:var(--texto-1)}
.nav-paginas .nav-pagina[aria-current="page"]{color:var(--texto-1);box-shadow:inset 0 -2px 0 var(--yellow)}

/* ---------- LAS PÍLDORAS (etiquetas) ---------- */
.pill{
  /* Una etiqueta de 10–12 px nunca es Dharma (el corte, CEO, 21 oct 2026), aunque
     la lleve dentro una cifra que sí lo es (`.tarjeta-cuenta` del panel). */
  font-family:var(--fuente-texto);
  font-size:var(--tipo-etiqueta);font-weight:600;letter-spacing:.16em;text-transform:uppercase;
  padding:var(--pill-pad-y) var(--pill-pad-x);line-height:1.5;
  clip-path:var(--bevel-xs);white-space:nowrap;
  /* Con icono: centrado y con su aire (CEO, 21 oct 2026: «iconos no
     centrados o muy pegados al texto»). Vale para toda píldora. */
  display:inline-flex;align-items:center;gap:.6em;
}
.pill > .icono{width:1.4em;height:1.4em;vertical-align:0}
/* LA JERARQUÍA DE LAS CUATRO PÍLDORAS, que es lo único que ordena la parrilla
   de un vistazo: en vivo → abierto → próximo → finalizado, de más a menos.

   Antes la llevaba el matiz —rojo, amarillo, contorno, contorno apagado— y hoy
   la lleva el PESO, que es lo que sobrevive a quitar un color: amarillo macizo,
   marrón macizo, contorno claro, contorno apagado. En vivo y abierto son los
   dos que compiten, y por eso son los dos rellenos; lo que los separa es cuál
   de los dos colores de la marca los rellena, que a este tamaño se distingue
   antes que cualquier borde. */
.pill-live{background:var(--yellow);color:var(--sobre-amarillo)}
.pill-open{background:var(--brown);color:var(--texto-1)}
.pill-soon{background:rgba(242,232,220,.1);color:var(--texto-1);box-shadow:inset 0 0 0 1px var(--filo-borde, var(--filo-color))}
.pill-done{background:transparent;color:var(--texto-3);box-shadow:inset 0 0 0 1px var(--filo-borde, var(--filo-color))}

/* LOS OTROS DOS NIVELES DE ETIQUETA de la skill (28 sep 2026, del panel):
   la NORMAL, contorno amarillo al 45 % y texto amarillo (juego, cupos, lo
   nuevo); y la de AVISO, en la gama gris (error, sin verificar). */
.pill-normal,.pill-aviso{box-shadow:inset 0 0 0 1px var(--filo-borde, var(--filo-color))}
.pill-normal{background:transparent;color:var(--yellow);--filo-color:rgba(255,198,33,.45)}
.pill-aviso{background:var(--gris-1);color:var(--gris-3);--filo-color:var(--gris-2)}

/* LAS ETIQUETAS DE NIVEL Y DE PLAN (de base.css, 23 oct 2026): Bronze, Silver
   y Gold del media kit y de los formatos, y PLAN FREE (plata) y PLAN PREMIUM
   (oro) de los límites del Dashboard (U.limitePremium). La de oro va dentro de
   .oro-aura, que deja asomar la nebulosa 2-3 px: el clip-path de la píldora se
   la comería. Muestrario, «Color y ambiente 2» y «Formularios 6». */
.pill-bronze{background:var(--brown);color:var(--texto-1)}
.pill-silver{background:linear-gradient(160deg,var(--gris-4),var(--gris-3) 42%,var(--gris-4) 58%,var(--gris-3));color:var(--sobre-amarillo)}
.pill-gold{position:relative;overflow:hidden;isolation:isolate;
  background:linear-gradient(160deg,var(--yellow-alto),var(--yellow) 55%,var(--yellow-bajo));color:var(--sobre-amarillo)}
.pill-gold::before{content:'';position:absolute;inset:-60%;z-index:-1;pointer-events:none;
  background:radial-gradient(40% 40% at 30% 35%, rgba(255,246,223,.8), transparent 70%),
             radial-gradient(35% 45% at 72% 65%, rgba(255,246,223,.6), transparent 70%);
  filter:blur(3px);transform-origin:45% 55%}
.pill-gold::after{content:'';position:absolute;inset:-20% -120%;pointer-events:none;clip-path:none;
  background:linear-gradient(100deg,transparent 44%, rgba(255,255,255,.85) 50%, transparent 56%);transform:translateX(-60%)}
.oro-aura{position:relative;display:inline-flex;isolation:isolate}
.oro-aura::before{content:'';position:absolute;inset:-2px -3px;z-index:-1;pointer-events:none;
  background:radial-gradient(60% 70% at 30% 40%, rgba(255,198,33,.75), transparent 70%),
             radial-gradient(55% 65% at 75% 65%, rgba(255,213,88,.6), transparent 70%);
  filter:blur(3px);opacity:.75}
@media (prefers-reduced-motion: no-preference){
  .pill-gold::before{animation:nebulosa-giro 6s linear infinite, nebulosa-respira 2.4s ease-in-out infinite alternate}
  .pill-gold::after{animation:nivel-barrido 4s ease-in-out infinite}
  .oro-aura::before{animation:nivel-aura 2.4s ease-in-out infinite alternate}
}
@keyframes nebulosa-giro{from{rotate:0deg} to{rotate:360deg}}
@keyframes nebulosa-respira{from{scale:.94} to{scale:1.14}}
@keyframes nivel-barrido{0%,62%{transform:translateX(-60%)} 88%,100%{transform:translateX(60%)}}
@keyframes nivel-aura{from{opacity:.45;scale:.98} to{opacity:.85;scale:1.02}}

/* ---------- EL SELLO DE UNA OFERTA (30 sep 2026) ----------
   Cada oferta dice de un vistazo QUIÉN la respalda, con tres sellos que se
   ordenan por PESO y no por matiz (la misma idea que las cuatro píldoras):

     Oferta oficial           .pill.pill-live    + .sello  amarillo macizo + ojo
     Oferta de Confianza      .pill.pill-normal  + .sello  contorno amarillo + palomita
     Oferta sin verificar     .pill.pill-aviso   + .sello  gris, sin marca (el defecto)

   LA OFICIAL NO LLEVA AUTOR: es de la casa. Las de terceros (Confianza y sin
   verificar) llevan debajo al autor —su usuario de Discord, con el logo de
   Discord— y un «?» que abre el aviso de que la oferta no es de Trufas
   (assets/ayuda.js). El autor puede llevar, junto al nombre, la marca de su
   verificación: el ojo de la cicatriz si es staff, la palomita amarilla si es
   de Confianza y nada si no. Manda la de más arriba.
   Las marcas son símbolos: el significado lo lleva el texto (aria-label). */
.sello{display:inline-flex;align-items:center;gap:.45rem}
.sello svg{height:1.45em;width:auto;flex:none}
.publica{position:relative;display:inline-flex;align-items:center;gap:.5rem;flex-wrap:wrap;
  font-size:var(--tipo-descripcion);color:var(--texto-2);line-height:1.4}
.publica b{font-weight:500;color:var(--texto-1)}
.ico-discord{width:1.3em;height:1.3em;fill:currentColor;flex:none;color:var(--texto-2)}
.marca-trufas,.marca-confianza{display:inline-flex;align-items:center;flex:none;color:var(--yellow)}
.marca-trufas svg{height:1.3em;width:auto}
.marca-confianza svg{height:1.05em;width:auto}

/* EL «?» DE AYUDA (CEO, 21 oct 2026: se abre al pasar el cursor; con el dedo,
   un toque; assets/ayuda.js): una píldora que abre un globo con la explicación.
   Es un botón (aria-expanded/aria-controls); Escape y tocar fuera lo cierran.
   El globo es una .caja, colgada del contenedor que lo rodea (en las ofertas
   de terceros, el .publica). */
.ayuda-boton{border:0;cursor:pointer;font-family:inherit;letter-spacing:0;padding-inline:.5rem;
  display:inline-flex;align-items:center;justify-content:center;min-width:1.5rem;min-height:1.5rem}  /* 24: el mínimo táctil de WCAG 2.2 */
.ayuda-boton:hover,.ayuda-boton[aria-expanded="true"]{background:var(--yellow);color:var(--sobre-amarillo)}
.ayuda-boton:focus-visible{outline:2px solid var(--yellow);outline-offset:3px}
.ayuda-globo{position:absolute;z-index:5;top:calc(100% + .5rem);left:0;width:min(22rem,calc(100vw - 3rem));
  padding:var(--esp-rejilla);font-size:var(--tipo-leyenda);color:var(--texto-2);line-height:1.55}
.ayuda-globo[hidden]{display:none}
/* Abierto en la capa de arriba (ayuda.js): sin el borde, el relleno ni el
   scroll que el navegador pone a un popover; el fondo y la letra, los suyos. */
.ayuda-globo[popover]{border:0;overflow:visible;height:auto}
.ayuda-globo[popover]:not(.caja){background:var(--surface)}

/* El aviso de que se sale del espacio oficial: va antes del enlace que lleva
   a ofertas de terceros (Empleos → «Ver tablero completo»), con el mismo
   texto que el «?». Una caja, no un modal: se lee y se sigue. */
.aviso-salida{display:flex;align-items:center;gap:var(--esp-rejilla);padding:var(--esp-rejilla);
  font-size:var(--tipo-leyenda);color:var(--texto-2);line-height:1.5}
.aviso-salida>*{min-width:0}
.aviso-salida>.pill{flex:none}

/* ---------- LA CAJA BISELADA (.caja) ----------
   Una caja opaca de más de 60 px de alto: tarjeta, panel, ficha, aviso,
   menú. CAPA DOBLE, como la `.card` de siempre pero sin envoltorio:

     · el FONDO del elemento es el color del contorno (`--filo-color`),
     · un `::before` recortado con el mismo bisel 1 px por dentro pone el
       relleno (`--caja-fondo`). Al estar metido 1 px en cada eje, su
       diagonal queda a 1,4 px de la de fuera: el chaflán sale con raya.

   POR QUÉ NO EL ARO `--filo` (28 sep 2026): el aro va recortado DENTRO de
   un elemento que ya está recortado, y en una caja que cae en medio píxel
   (una rejilla de `1fr`, una pantalla a 1× o 1,25×) los dos bordes
   suavizados se multiplican: medido, los cantos bajaban a 55 de 74. Y
   depende de `polygon(evenodd…)`; el navegador que no lo entiende cae a la
   reserva, que deja los chaflanes sin raya. La capa doble no depende de nada
   y midió 74 en los cuatro cantos y los dos chaflanes.

   El `clip-path` ya crea su propio contexto de apilamiento, así que el
   relleno con `z-index:-1` queda entre el fondo y el contenido.

   Estados: se cambian `--filo-color` y `--caja-fondo`, nada más. El foco
   lleva el relleno a `inset:2px` (ver cada sitio). El aro `--filo` se queda
   para lo pequeño o translúcido (botones, píldoras, chips), donde no hay
   relleno opaco que poner encima. */
.caja,.cuenta-menu{
  position:relative;clip-path:var(--bevel);
  --filo-color:var(--line);--caja-fondo:var(--surface);
  background:var(--filo-color);
}
.caja::before,.cuenta-menu::before{
  content:'';position:absolute;inset:1px;z-index:-1;pointer-events:none;
  clip-path:var(--bevel);background:var(--caja-fondo);
}
.cuenta-menu{--caja-fondo:var(--surface-2)}

/* UNA .caja NUNCA LLEVA OVERFLOW PROPIO: EL SCROLL VA EN UN HIJO (`.caja-scroll`).
   El `::before` que pinta la superficie es `position:absolute` y mide solo la
   caja visible; en un contenedor con scroll, un absoluto se desplaza CON el
   contenido, así que al bajar o ir de lado la superficie se va y asoma el
   color del filo (marrón claro) por detrás. Pasó en /muestra, en el
   calendario de campo, en la hoja de un evento y en la tabla de XP del
   dashboard (18 oct 2026), y antes en Minimapa, Cápsulas y Automatizaciones.

   LA RECETA: la `.caja` queda con `overflow:visible` (quien la recorta es su
   `clip-path`) y lleva dentro UN hijo `.caja-scroll`, que es el que se
   desplaza, con la barra de la marca (la común de arriba, sin hacer nada) y
   el relleno. El tope de alto o ancho se pone en ese hijo
   (`.mi-caja > .caja-scroll{max-height:…}`), nunca en la caja, y lo que debe
   quedarse quieto (un ✕, una cabecera fija) va como hermano suyo. Si la caja
   es hija de una rejilla o de un flex, lleva `min-width:0`: antes el scroll
   era suyo y la contenía; ahora el contenido ancho empujaría a la rejilla.
   El borde transparente de 1 px lo deja dentro del filo (ni la barra ni el
   contenido desplazado pisan el contorno) y, a diferencia de un margen, no
   se colapsa con el de la caja cuando esta no lleva relleno.

   POR QUÉ ASÍ Y NO UN `background` EN EL ELEMENTO: el elemento ES el filo
   (su fondo pinta `--filo-color`); con scroll propio habría que pintar el
   relleno con `background-attachment:local` y dibujar el filo con otra cosa
   (borde o `box-shadow`), que el `clip-path` se come en los chaflanes
   (regla de CLAUDE.md: el contorno biselado va siempre completo). Un hijo
   funciona igual en Chromium, Firefox y Safari y no toca la receta. */
.caja-scroll{
  border:1px solid transparent;min-width:0;min-height:0;
  overflow:auto;overscroll-behavior:contain;
}

/* ---------- EL BOTÓN DE DISCORD (assets/cuenta.js) ----------
   Invitación y login en un solo botón, en el hueco del icono de siempre: el
   logo ▾ sin sesión, el avatar ▾ con ella. El menú lleva las acciones. */
.cuenta-sustituido{display:none!important}
.cuenta{position:relative;display:flex;align-items:center;flex:none}
/* La altura cae a 37px, la de un .btn-sm, donde la barra no define --btn-h
   (en /esports/ salía de 22px, más bajo que «Inscribirse»). */
.cuenta-boton{gap:.3rem;padding:0 .7rem 0 .85rem;cursor:pointer;height:var(--btn-h, 37px);
  clip-path:var(--bevel-sm)}   /* 37 px de alto: el escalón de 37–60, aunque lleve .btn-sm */
@supports (clip-path: polygon(evenodd, 0 0, 1px 1px, 0 1px)){
  .cuenta-boton::after{clip-path:var(--filo-sm)}
  .cuenta-boton:focus-visible::after{clip-path:var(--filo-foco-sm)}
}
.cuenta-boton svg:not(.cuenta-chevron){width:22px;height:22px;fill:currentColor;flex:none;display:block}
.cuenta-chevron{width:16px;height:16px;flex:none;opacity:.7;transition:transform .2s ease}
.cuenta-boton[aria-expanded="true"] .cuenta-chevron{transform:rotate(180deg)}
.cuenta-avatar{width:26px;height:26px;border-radius:50%;display:block;flex:none;background:var(--surface-2);object-fit:cover}
/* EL MENÚ ES UNA CAJA BISELADA (28 sep 2026), con la capa doble de `.caja`
   (ver arriba) y SIN SOMBRA: la llevaba, y la skill diseno-trufas no admite
   sombras. El relleno lateral de 1 px es para que el fondo de un ítem al
   pasar el cursor no tape el contorno. */
.cuenta-menu{
  position:absolute;top:calc(100% + .5rem);right:0;min-width:220px;z-index:80;
  padding:.35rem 1px;
}
.cuenta-menu[hidden]{display:none}
/* EN ESTRECHO EL MENÚ SE ALINEA CON LA BARRA, NO CON EL BOTÓN. Colgado del
   botón se salía por la izquierda donde el botón no queda pegado al borde
   (el media kit a 360px, con «PDF» y la hamburguesa a su derecha). Así cae
   siempre bajo la barra, a 16px del borde derecho. */
@media (max-width:620px){
  .nav-in{position:relative}
  .cuenta{position:static}
  .cuenta-menu{right:16px;top:calc(100% - .35rem)}
}
.cuenta-nombre{
  padding:.55rem 1rem .65rem;margin:0 0 .3rem;font-size:var(--tipo-descripcion);font-weight:600;color:var(--texto-1);
  border-bottom:1px solid var(--line);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* Un ítem puede ser <a> (enlace) o <button> (acción, como «Cerrar sesión»
   en el panel): el botón se desnuda para que los dos se vean igual. */
.cuenta-item{
  display:flex;justify-content:space-between;align-items:center;gap:1rem;white-space:nowrap;
  padding:.65rem 1rem;font-size:var(--tipo-descripcion);color:var(--texto-3);
  width:100%;text-align:left;font-family:inherit;font-weight:400;
  background:transparent;border:0;cursor:pointer;
}
.cuenta-item.es-principal{color:var(--yellow);font-weight:600}
.cuenta-item.es-externo::after{content:'↗';font-size:var(--tipo-control);opacity:.8}
.cuenta-item:hover,.cuenta-item:focus-visible{color:var(--texto-1);background:var(--surface-2);outline:none}
.cuenta-item.es-principal:hover,.cuenta-item.es-principal:focus-visible{color:var(--yellow-alto)}
/* UNA OPCIÓN QUE TODAVÍA NO FUNCIONA (28 sep 2026; hoy ninguna del menú): se
   enseña para que se sepa que va a existir, pero apagada. Es un <a> SIN
   href y con aria-disabled: no se enfoca ni se pulsa. La opacidad aquí es un
   ESTADO, no un nivel de texto: `--opacidad-apagado` de marca.css (CEO, 21 oct 2026). La
   descripción puede partirse en dos líneas: el resto del menú no. */
.cuenta-item.es-inactivo{
  flex-direction:column;align-items:flex-start;gap:.15rem;
  white-space:normal;opacity:var(--opacidad-apagado);cursor:not-allowed;
}
.cuenta-item.es-inactivo:hover{color:var(--texto-3);background:transparent}
.cuenta-item-desc{font-size:var(--tipo-leyenda);line-height:1.4}
/* «SALIR DE TODOS LOS DISPOSITIVOS» ARMADO (sesión única, 20 oct 2026): el
   primer clic lo deja esperando el segundo, en amarillo, que es lo que se
   espera que se pulse ahora. Vuelve solo a los 5 s. Igual en los tres sitios. */
.cuenta-item.es-confirmar,.cuenta-item.es-confirmar:hover,.cuenta-item.es-confirmar:focus-visible{color:var(--yellow);font-weight:600}
@media (prefers-reduced-motion: reduce){ .cuenta-chevron{transition:none} }
/* En estrecho, la flecha fuera y el mismo relleno que .btn-icon: el botón
   ocupa exactamente el hueco del icono al que sustituye. Con la flecha, la
   barra de la portada se pasaba 14px a 360. */
@media (max-width:640px){
  .cuenta-chevron{display:none}
  .cuenta-boton{padding:0 .78rem}
}

/* ============================================================
   APARICIÓN AL BAJAR — DESVANECIDO + COLOCACIÓN (26 sep 2026)
   ------------------------------------------------------------
   UNA SOLA VEZ PARA TODO EL SITIO. Hasta hoy cada página llevaba la
   suya (el home y esports un `surgir` de 10px, el media kit un `subir`
   de 26px desde opacidad 0), y la misma entrada se sentía distinta al
   cambiar de página. Los valores son los tokens `--mov-*` de marca.css
   y las reglas de uso, la skill diseno-trufas.

   DOS EFECTOS QUE SE SUMAN, en dos propiedades distintas para que no
   se pisen:
     1 · DESVANECIDO (`opacity`) — lo conduce el scroll con
         animation-timeline:view(): de .35 a 1 en los primeros 160px.
     2 · COLOCACIÓN (`translate`) — cuando el bloque ya está un poco
         dentro de la pantalla, assets/colocar.js le pone `.colocado` y
         sube 20px con un rebote leve. En `translate` y NO en `transform`
         para no pisar el `transform` del hover de las tarjetas.

   REGLA DE ORO, LA MISMA DE SIEMPRE: EL CONTENIDO SIEMPRE ESTÁ VISIBLE.
   El desplazamiento solo existe bajo `html.colocar`, que pone el script;
   si el script no llega, no hay nada desplazado. Con menos movimiento
   pedido, ni lo uno ni lo otro.
   ============================================================ */
@supports (animation-timeline: view()){
 @media (prefers-reduced-motion: no-preference){
  @keyframes aparecer{from{opacity:.35} to{opacity:1}}
  .reveal{
    animation:aparecer linear both;
    animation-timeline:view();
    animation-range:entry 0px entry var(--mov-tramo, 160px);
  }
 }
}
@media (prefers-reduced-motion: no-preference){
  .colocar .reveal{
    translate:0 var(--mov-desde, 1.25rem);
    transition:translate var(--mov-colocar, .6s) var(--mov-rebote, ease-out);
    /* En una rejilla, cada hermano lleva su `--i` y entra detrás del
       anterior. Sin `--i`, sin retraso. */
    transition-delay:calc(var(--i, 0) * var(--mov-escalon, 80ms));
  }
  .colocar .reveal.colocado{translate:0 0}
  /* Lo que se repinta ya a la vista (una lista que llega de la base, el
     cambio de pestaña de esports) se coloca SIN salto: saltaría con cada
     repintado, y eso es un parpadeo, no una entrada. */
  .colocar .reveal.colocado-quieto{transition:none}
}
/* Donde no hay animation-timeline (Safari, Firefox), el desvanecido
   viaja con el salto para no perderse. */
@supports not (animation-timeline: view()){
 @media (prefers-reduced-motion: no-preference){
  .colocar .reveal{opacity:.35;transition-property:translate,opacity}
  .colocar .reveal.colocado{opacity:1}
 }
}
/* En papel, todo en su sitio. */
@media print{
  .reveal{animation:none!important;opacity:1!important;translate:none!important}
}

/* ============================================================
   LA ETIQUETA — el tooltip propio (16 oct 2026)
   ------------------------------------------------------------
   La pinta y la coloca assets/etiqueta.js (un solo globo por página,
   `role="tooltip"`); el porqué y el marcado (`data-etiqueta`,
   `-tono`, `-lado`, `-cuando`) están en su cabecera. Aquí solo el
   aspecto, con las reglas de la skill diseno-trufas:
     · Mide menos de 30 px de alto: bisel de 5 (`--bevel-xs`) y su
       aro `--filo-xs` en un `::after`, NUNCA un `border` con el
       `clip-path`. Si el texto pasa a dos líneas, el script le pone
       `.es-alta` y sube al escalón de 9.
     · Oscura de serie: relleno `--surface-2`, texto `--texto-1` y el
       aro amarillo al 45 % (el de la etiqueta «Normal»): sobre `--ink`
       y sobre una caja se separa sin sombra.
     · Amarilla (`data-etiqueta-tono="amarillo"`) para el menú
       plegado: es el nombre de un sitio al que se va, o sea lo que se
       pulsa. Maciza, sin aro, tinta `--sobre-amarillo`.
     · Entra con 3 px de recorrido desde el lado del elemento y
       un fundido de 140 ms; con menos movimiento, solo el fundido.
   ============================================================ */
/* Medida fija, 12 px (COO, 19 oct 2026): con --tipo-leyenda medía 12 en el
   panel y 11 en la web y el bot (escala compacta). La etiqueta es la misma
   pieza en los tres sitios: se lee igual en todos. */
.etiqueta{
  position:fixed;left:0;top:0;z-index:1100;pointer-events:none;
  max-width:min(18rem, calc(100vw - 16px));
  padding:.35rem .6rem .4rem;
  font-family:'Poppins',system-ui,sans-serif;font-size:var(--tipo-descripcion);font-weight:500;line-height:1.35;
  letter-spacing:.01em;text-transform:none;white-space:normal;text-align:left;
  color:var(--texto-1);background:var(--surface-2);
  clip-path:var(--bevel-xs);--filo-color:rgba(255,198,33,.45);
  box-shadow:inset 0 0 0 1px var(--filo-borde, var(--filo-color));
  opacity:0;translate:0 3px;
  transition:opacity .14s ease, translate .18s var(--mov-rebote, ease-out);
}
.etiqueta[hidden]{display:none}
.etiqueta[data-lado="abajo"]{translate:0 -3px}
.etiqueta[data-lado="derecha"]{translate:-3px 0}
.etiqueta[data-lado="izquierda"]{translate:3px 0}
.etiqueta.visible{opacity:1;translate:0 0}
.etiqueta.es-alta{clip-path:var(--bevel-sm);padding:.5rem .75rem}
.etiqueta-amarilla{
  background:var(--yellow);color:var(--sobre-amarillo);font-weight:600;--filo-color:transparent;
}
@supports (clip-path: polygon(evenodd, 0 0, 1px 1px, 0 1px)){
  .etiqueta::after{content:'';position:absolute;inset:0;pointer-events:none;clip-path:var(--filo-xs);background:var(--filo-color)}
  .etiqueta.es-alta::after{clip-path:var(--filo-sm)}
}
/* En el lienzo escalado (`pantallas`) el <body> lleva zoom: la etiqueta se
   lo deshace, como el lateral, y se lee siempre a su tamaño real. */
@media screen and (min-width:960px){
  html.pantallas .etiqueta{zoom:calc(1 / var(--u, 1))}
}
@media (prefers-reduced-motion: reduce){
  .etiqueta,.etiqueta[data-lado]{translate:none;transition:opacity .1s linear}
}
@media print{ .etiqueta{display:none!important} }

/* ============================================================
   LAS BARRAS DE DESPLAZAMIENTO — de la marca, en todo (16 oct 2026)
   ------------------------------------------------------------
   Pedido por el CEO: EN REPOSO, APAGADAS; AL USARLAS, SE ENCIENDEN.
   Una barra que se lee es ruido; la que se está usando tiene que
   decir «aquí estás» con el amarillo y un brillo, no solo cambiando
   de color. Hasta hoy el menú lateral hacía lo contrario (saturada en
   reposo, apagada al cogerla): ese es el error que no se repite.

   VAN AQUÍ Y NO EN marca.css: marca.css son tokens y fuentes, nada de
   piezas; esto es una pieza que se ve igual en la web, el panel y el
   dashboard del bot, que es justo lo que vive en este archivo (y lo
   que copian comun-panel.mjs y comun-bot.mjs).

   VALE PARA TODO: la página (`:root`) y cualquier zona con scroll
   propio (`*`). Una zona que esconde su barra a propósito (pestañas y
   carriles que se deslizan de lado) lo sigue haciendo: su
   `.clase::-webkit-scrollbar{display:none}` gana por especificidad.

   TRES ESTADOS (Chrome, Edge, Safari):
     · reposo      un hilo de 2 px de ámbar hondo al 55 %, en una calle de 10.
     · encendida   al pasar el cursor por la zona, o mientras se
                   desplaza (`[data-desplazando]`, lo pone
                   assets/barras.js ~0,9 s): núcleo amarillo de 4 px y
                   un halo que se apaga hacia los lados — el brillo.
                   La PÁGINA no se enciende con el cursor encima (el
                   cursor siempre está encima): solo al desplazarla o
                   al tocar su barra.
     · cogida      al pasar por el pulgar, el núcleo sube a
                   `--yellow-alto`; al arrastrarlo, se pone al rojo
                   blanco (crema en el centro).
   El brillo es un degradado dentro del pulgar porque un `box-shadow`
   no sale de la calle de la barra. Sin esquinas redondeadas.

   SOLO CON RATÓN (`hover:hover` y `pointer:fine`). En un móvil la
   barra del sistema ya es la buena: flota, no come ancho y se
   esconde sola.

   FIREFOX solo entiende `scrollbar-color`: hilo apagado en reposo y
   amarillo al pasar o desplazar, sin brillo. Va dentro de
   `@supports not selector(::-webkit-scrollbar)`, porque en Chrome
   121+ poner `scrollbar-color` APAGA los `::-webkit-scrollbar`.
   ============================================================ */
@media (hover:hover) and (pointer:fine){
  :root::-webkit-scrollbar,*::-webkit-scrollbar{width:10px;height:10px;background:transparent}
  :root::-webkit-scrollbar-track,*::-webkit-scrollbar-track,
  :root::-webkit-scrollbar-corner,*::-webkit-scrollbar-corner{background:transparent}
  /* Reposo: el hilo. */
  *::-webkit-scrollbar-thumb:vertical{
    background:linear-gradient(90deg, transparent 4px, color-mix(in srgb, var(--yellow-hondo) 55%, transparent) 4px 6px, transparent 6px)}
  *::-webkit-scrollbar-thumb:horizontal{
    background:linear-gradient(180deg, transparent 4px, color-mix(in srgb, var(--yellow-hondo) 55%, transparent) 4px 6px, transparent 6px)}
  /* Encendida: la zona bajo el cursor (nunca la página entera) o la que se desplaza. */
  :not(:root):hover::-webkit-scrollbar-thumb:vertical,
  [data-desplazando]::-webkit-scrollbar-thumb:vertical,
  *::-webkit-scrollbar-thumb:vertical:hover{
    background:linear-gradient(90deg, rgba(255,198,33,0), rgba(255,198,33,.3) 22%, var(--yellow) 32% 68%, rgba(255,198,33,.3) 78%, rgba(255,198,33,0))}
  :not(:root):hover::-webkit-scrollbar-thumb:horizontal,
  [data-desplazando]::-webkit-scrollbar-thumb:horizontal,
  *::-webkit-scrollbar-thumb:horizontal:hover{
    background:linear-gradient(180deg, rgba(255,198,33,0), rgba(255,198,33,.3) 22%, var(--yellow) 32% 68%, rgba(255,198,33,.3) 78%, rgba(255,198,33,0))}
  /* Cogida: el núcleo, más encendido. */
  *::-webkit-scrollbar-thumb:vertical:hover{
    background:linear-gradient(90deg, rgba(255,198,33,0), rgba(255,198,33,.4) 20%, var(--yellow-alto) 34% 66%, rgba(255,198,33,.4) 80%, rgba(255,198,33,0))}
  *::-webkit-scrollbar-thumb:horizontal:hover{
    background:linear-gradient(180deg, rgba(255,198,33,0), rgba(255,198,33,.4) 20%, var(--yellow-alto) 34% 66%, rgba(255,198,33,.4) 80%, rgba(255,198,33,0))}
  *::-webkit-scrollbar-thumb:vertical:active{
    background:linear-gradient(90deg, rgba(255,198,33,.1), rgba(255,198,33,.55) 22%, var(--yellow-alto) 34%, var(--texto-1) 45% 55%, var(--yellow-alto) 66%, rgba(255,198,33,.55) 78%, rgba(255,198,33,.1))}
  *::-webkit-scrollbar-thumb:horizontal:active{
    background:linear-gradient(180deg, rgba(255,198,33,.1), rgba(255,198,33,.55) 22%, var(--yellow-alto) 34%, var(--texto-1) 45% 55%, var(--yellow-alto) 66%, rgba(255,198,33,.55) 78%, rgba(255,198,33,.1))}
}
@supports not selector(::-webkit-scrollbar){
  @media (hover:hover) and (pointer:fine){
    *{scrollbar-width:thin;scrollbar-color:color-mix(in srgb, var(--yellow-hondo) 55%, transparent) transparent}
    :not(:root):hover,[data-desplazando]{scrollbar-color:var(--yellow) transparent}
  }
}

/* ============================================================
   EL FONDO DE LA MARCA (16 oct 2026, CEO; rehecho por el COO el mismo día)
   assets/fondo.js
   ============================================================
   Elementos de Trufas (mascota, Trufacoin, trofeo, espadas) a los LATERALES
   de la página, a distintos tamaños y giros, a lo largo de todo el
   documento. fondo.js los coloca en px (left/top/width/height) sin que se
   toquen; aquí solo cómo se pinta cada pieza (--giro, --espejo, --op, --par).
   VA AQUÍ Y NO EN SU HOJA porque la llevan los tres sitios (web, panel y
   dashboard), que ya copian este archivo al publicarse, y porque la capa
   tiene que tener su estilo en el primer pintado (sin él, las imágenes se
   verían un instante a tamaño natural).
   · VA CON EL DOCUMENTO, NO FIJA: `position:absolute` desde lo alto, y el
     alto se lo pone fondo.js (el del <body>). Las piezas se desplazan con
     el contenido.
   · La capa no recibe nada (pointer-events:none, aria-hidden) y va detrás
     de todo (z-index:-1 con el <body> aislado).
   · Las piezas asoman desde fuera del borde: `clip` (y no solo `hidden`)
     las recorta SIN hacer de la capa un contenedor de desplazamiento, así
     que nunca hay scroll lateral (visto en /paquetes/ y /media-kit/).
   · NADA DE DESENFOQUE (COO, 16 oct 2026): todo con la opacidad, ≤ .11 las
     piezas y .07 la mascota. --texto-3 sigue por encima de 4,5:1 encima.
   · Con prefers-reduced-motion no hay parallax.
   Demo en /muestra, «Color y ambiente 5». */
body:has(> .fondo-marca){isolation:isolate}
.fondo-marca{
  position:absolute;top:0;left:var(--fondo-izq, 0px);right:0;height:100%;z-index:-1;
  overflow:hidden;overflow:clip;contain:layout paint style;
  pointer-events:none;user-select:none;
}
.fondo-marca.fondo-en-caja{inset:0;height:auto;z-index:0}
.fondo-pieza{
  position:absolute;display:block;
  color:var(--yellow);opacity:min(var(--op, .08), .11);
  translate:0 calc(var(--fondo-y, 0px) * var(--par, 0));
  rotate:var(--giro, 0deg);scale:var(--espejo, 1) 1;
}
.fondo-pieza img,.fondo-pieza svg{display:block;width:100%;height:100%;object-fit:contain}
/* LA PRIMERA PIEZA, SIEMPRE LA MISMA (CEO, 16 oct 2026): la mascota grande
   arriba a la derecha, con las medidas del .hero-mascot de antes (base.css),
   nítida. fondo.js la coloca y las demás piezas la esquivan. */
.fondo-ancla{
  position:absolute;display:block;aspect-ratio:360 / 368;
  opacity:.07;filter:grayscale(.2);
}
.fondo-ancla img{display:block;width:100%;height:100%;object-fit:contain}
.fondo-parallax .fondo-pieza{will-change:translate}
@media (prefers-reduced-motion: reduce){ .fondo-pieza{translate:none} }
@media print{ .fondo-marca{display:none} }

/* ============================================================
   EL ESTADO CENTRADO (16 oct 2026, CEO) · .estado-centro
   ============================================================
   Todo mensaje que ocupa el sitio de una pantalla —cargando, vacío, error,
   sin acceso, «Vuelve a entrar»— va CENTRADO EN LOS DOS EJES del área libre
   (lo que queda bajo la barra y al lado del lateral), nunca pegado arriba.
   El área la pone quien lo usa con --estado-alto (de serie, 60 % de la
   pantalla); dentro de una caja, .en-caja (12rem). Lo usa la pantalla de
   carga. Demo en /muestra, «Estados 2». */
.estado-centro{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;gap:var(--esp-3, .75rem);
  min-height:var(--estado-alto, 60dvh);padding:var(--esp-caja) 1rem;
  flex:1 1 auto;width:100%;box-sizing:border-box;
}
.estado-centro[hidden],.acciones[hidden]{display:none}
.estado-centro.en-caja{--estado-alto:12rem;padding:var(--esp-rejilla)}
/* Dentro de un estado, si el área es estrecha, los botones van apilados al
   mismo ancho (la principal arriba), no en dos filas de anchos distintos. */
.estado-centro{container-type:inline-size}
@container (max-width:30rem){
  .estado-centro > .acciones{flex-direction:column;align-items:stretch;width:100%;max-width:22rem}
  .estado-centro > .acciones > .btn{width:100%}
  .estado-centro > .acciones > .btn-primary{order:-1}
}
.estado-titulo{margin:0;font-family:var(--fuente-subtitulo);font-weight:700;font-size:var(--tipo-subtitulo);
  line-height:1;letter-spacing:calc(.01em + var(--tracking-subtitulo));text-transform:uppercase;color:var(--texto-1)}
/* El titular recibe el foco por código (tras un fallo, para el lector de pantalla):
   no es un control, así que sin aro. */
.estado-titulo[tabindex="-1"]:focus{outline:none}
.estado-texto{margin:0;max-width:44ch;font-size:var(--tipo-cuerpo);color:var(--texto-2);line-height:1.55}
.estado-pie{margin:0;max-width:44ch;font-size:var(--tipo-descripcion);color:var(--texto-3);line-height:1.55}

/* ============================================================
   LAS ACCIONES: BOTONES PAREJOS (16 oct 2026, CEO) · .acciones
   ============================================================
   En una misma fila, todos los botones con LA MISMA ALTURA y UNA SOLA LÍNEA
   de texto. Si no caben: primero se acorta el texto; si aun así no caben,
   se apilan a ancho completo (en ≤520 px, siempre; antes, con .apilar).
   Nunca uno en una línea y otro en dos. Demo en /muestra, «Componentes 3». */
.acciones{display:flex;flex-wrap:wrap;align-items:stretch;justify-content:center;gap:.75rem}
.acciones.a-la-izquierda{justify-content:flex-start}
.acciones > .btn{white-space:nowrap;justify-content:center;flex:0 0 auto}
.acciones.apilar{flex-direction:column;align-items:stretch;width:100%;max-width:22rem}
.acciones.apilar > .btn{width:100%}
.acciones.apilar > .btn-primary{order:-1}       /* apiladas, la principal arriba */
/* Las filas de botones reales de la web (cada página escribe la suya). En
   portales-comunidad.css `.pc-acciones` pone `align-items:center` después de
   esta hoja: por eso el ancho completo va también en el hijo. */
@media (max-width:520px){
  .acciones,.hero-actions,.pc-acciones,.es-acciones,.em-acciones,.cierre-acc,.lg-contacto,.cm-acciones{
    flex-direction:column;align-items:stretch;width:100%}
  .acciones > .btn,.hero-actions > .btn,.pc-acciones > .btn,.es-acciones > .btn,.em-acciones > .btn,
  .cierre-acc > .btn,.lg-contacto > .btn,.cm-acciones > .btn{width:100%}
  .acciones > .btn-primary,.hero-actions > .btn-primary,.pc-acciones > .btn-primary,.es-acciones > .btn-primary,
  .em-acciones > .btn-primary,.cierre-acc > .btn-primary,.lg-contacto > .btn-primary,.cm-acciones > .btn-primary{order:-1}
}

/* ============================================================
   LA PANTALLA DE CARGA (16 oct 2026, CEO; variantes 21 oct 2026) · assets/carga.js
   ============================================================
   Un dibujo en una caja cuadrada de --moneda (5 rem; 1,5 en la mini) y su
   texto debajo. El dibujo es una VARIANTE (carga.js, VARIANTES): la de serie
   es la Trufacoin en 3D de CSS (preserve-3d: dos caras y un canto de láminas),
   que le encanta al CEO y no se toca; las otras son alternativas. Todas del
   mismo tamaño y del mismo ciclo (--carga-ciclo), y la pose de reposo es la
   del CSS de abajo: la animación solo la mueve. Así, con prefers-reduced-motion
   o en error, basta con quitar la animación.
   --carga-fase (la pone carga.js) es el retraso negativo de un reloj común:
   una carga nueva sigue donde iba la anterior y el giro no se reinicia. Va en
   cada `animation:` como segundo tiempo, porque el shorthand lo pondría a 0.
   Estados en data-estado: cargando · tarda (ciclo más lento, y ofrece
   salida) · error (quieto, en gris, y sale el botón) · aviso (quieto, en
   color: lo que no es un fallo pero pide algo). Sin three.js: una carga no
   puede esperar a 680 KB de librería. Demo y comparación en /muestra,
   «Estados 1». */
.carga{--moneda:5rem;--grueso:.4rem;--carga-ciclo:2.2s;--carga-trazo:44}
.carga-pantalla{position:fixed;inset:0;z-index:90;background:var(--ink);--estado-alto:100dvh}
.carga-moneda{position:relative;width:var(--moneda);height:var(--moneda);margin-bottom:var(--esp-4, 1rem);flex:none}
.carga-moneda img,.carga-moneda svg{display:block;width:100%;height:100%;object-fit:contain;-webkit-user-drag:none}
/* El contenedor de cada variante y sus capas ocupan la caja entera. */
.carga-moneda > span,.cv-capa{position:absolute;inset:0;display:block}

/* (moneda) LA TRUFACOIN EN 3D, DE SERIE: dos caras y un canto de láminas
   apiladas en Z, del amarillo bajo al hondo (se ven de lado); gira y sube un
   poco a mitad de vuelta. */
.cv-moneda{transform-style:preserve-3d;perspective:24rem}
.carga-giro{position:absolute;inset:0;transform-style:preserve-3d;
  animation:carga-giro var(--carga-ciclo) var(--carga-fase,0s) cubic-bezier(.45,.05,.55,.95) infinite}
.carga-cara,.carga-canto{position:absolute;inset:0;border-radius:50%;backface-visibility:hidden}
.carga-cara{transform:translateZ(calc(var(--grueso) / 2))}
.carga-dorso{transform:rotateY(180deg) translateZ(calc(var(--grueso) / 2))}
.carga-canto{backface-visibility:visible;background:var(--yellow-bajo);inset:3%;
  transform:translateZ(calc(var(--grueso) * (var(--k) / 6 - .5)))}
.carga-canto:nth-child(odd){background:var(--yellow-hondo)}
@keyframes carga-giro{
  0%{transform:rotateY(0) translateY(0)}
  50%{transform:rotateY(180deg) translateY(-6%)}
  100%{transform:rotateY(360deg) translateY(0)}
}

/* (guino) LA MASCOTA QUE GUIÑA: isotipo-guino.svg en línea. Se agacha, da un
   saltito, cae y, ya quieta, guiña el ojo sin cicatriz. La sombra es un halo
   amarillo (sobre --ink una negra no se vería) que se encoge al subir. */
.cv-guino .guino-cuerpo{fill:var(--yellow)}
.cv-guino .guino-ojo{transform-box:fill-box;transform-origin:50% 55%;animation:cv-guino var(--carga-ciclo) var(--carga-fase,0s) infinite}
.cv-guino .cv-cuerpo{transform-origin:50% 100%;animation:cv-bote var(--carga-ciclo) var(--carga-fase,0s) infinite}
.cv-guino .cv-sombra{inset:auto 18% -12% 18%;height:9%;border-radius:50%;
  background:radial-gradient(closest-side,color-mix(in srgb,var(--yellow) 34%,transparent),transparent);
  animation:cv-sombra-bote var(--carga-ciclo) var(--carga-fase,0s) infinite}
@keyframes cv-bote{
  0%{transform:translateY(0) scale(1,1)}
  12%{transform:translateY(0) scale(1.07,.92);animation-timing-function:cubic-bezier(.2,.7,.4,1)}
  32%{transform:translateY(-14%) scale(.97,1.04);animation-timing-function:cubic-bezier(.6,0,.8,.4)}
  48%{transform:translateY(0) scale(1.05,.95)}
  58%,100%{transform:translateY(0) scale(1,1)}
}
@keyframes cv-sombra-bote{0%,48%,100%{transform:scaleX(1);opacity:1} 12%{transform:scaleX(1.1)} 32%{transform:scaleX(.6);opacity:.45}}
@keyframes cv-guino{0%,68%,86%,100%{transform:scaleY(1)} 74%,79%{transform:scaleY(.06)}}

/* (plata) LA MONEDA DE PLATA QUE SE BALANCEA: moneda-plata.svg oscila como
   un péndulo corto y un brillo le cruza la cara (máscara con la propia
   moneda: --cv-img, que pone carga.js). */
.cv-plata .cv-oscila{transform-origin:50% 8%;animation:cv-oscila var(--carga-ciclo) var(--carga-fase,0s) ease-in-out infinite}
.cv-plata .cv-brillo{-webkit-mask:var(--cv-img) center / contain no-repeat;mask:var(--cv-img) center / contain no-repeat;
  background:linear-gradient(115deg,transparent 38%,color-mix(in srgb,var(--cream) 85%,transparent) 50%,transparent 62%) no-repeat;
  background-size:300% 100%;background-position:120% 0;mix-blend-mode:screen;
  animation:cv-brillo var(--carga-ciclo) var(--carga-fase,0s) infinite}
@keyframes cv-oscila{0%,100%{transform:rotate(-9deg)} 50%{transform:rotate(9deg)}}
@keyframes cv-brillo{0%,8%{background-position:120% 0} 46%,100%{background-position:-20% 0}}

/* (trazo) LA MASCOTA QUE SE DIBUJA: isotipo.svg en línea; un trazo amarillo
   la recorre, se rellena, se queda y se apaga para volver a empezar. */
.cv-trazo path{fill:var(--yellow);fill-opacity:1;stroke:var(--yellow);stroke-width:var(--carga-trazo);stroke-linejoin:round;
  stroke-dasharray:1 1;stroke-dashoffset:0;animation:cv-trazo var(--carga-ciclo) var(--carga-fase,0s) infinite}
@keyframes cv-trazo{
  0%{stroke-dashoffset:1;fill-opacity:0;opacity:1;animation-timing-function:cubic-bezier(.45,.05,.55,.95)}
  52%{stroke-dashoffset:0;fill-opacity:0}
  66%{fill-opacity:1}
  86%{stroke-dashoffset:0;fill-opacity:1;opacity:1}
  100%{stroke-dashoffset:0;fill-opacity:1;opacity:0}
}

.carga-texto{margin:0;font-size:var(--tipo-control);font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--texto-2)}
.carga-texto::after{content:'';display:inline-block;width:1.2em;text-align:left;animation:carga-puntos 1.2s steps(4) infinite}
.carga .acciones{margin-top:var(--esp-4, 1rem)}
.carga[data-estado="tarda"]{--carga-ciclo:3.4s}
/* En error y en aviso, todo quieto en su pose de reposo. */
.carga[data-estado="error"] .carga-moneda *,.carga[data-estado="aviso"] .carga-moneda *{animation:none}
.carga[data-estado="error"] .carga-giro{transform:rotateY(-24deg) rotateX(8deg)}
.carga[data-estado="error"] .carga-moneda{filter:grayscale(1);opacity:.55}
.carga[data-estado="error"] .carga-texto::after,.carga[data-estado="aviso"] .carga-texto::after,.carga[data-estado="tarda"] .carga-texto::after{content:none;animation:none}
.carga[data-estado="error"] .carga-texto,.carga[data-estado="aviso"] .carga-texto{display:none}
.carga.saliendo{opacity:0;transition:opacity .3s ease}
/* La versión de una fila, para lo pequeño («Buscando…» dentro de una lista). */
.carga-mini{display:inline-flex;align-items:center;gap:.6rem;--moneda:1.5rem;--grueso:.15rem;--carga-trazo:90}
.carga-mini .carga-moneda{margin:0}
.carga-mini .cv-sombra{display:none}
.carga-mini .carga-texto{letter-spacing:.1em}
@keyframes carga-puntos{0%{content:''}25%{content:'.'}50%{content:'..'}75%{content:'...'}}
@media (prefers-reduced-motion: reduce){
  .carga .carga-moneda *,.carga-texto::after{animation:none!important}
  .carga-texto::after{content:'…'}
}

/* ============================================================
   LOS CONTROLES DE FORMULARIO (17 oct 2026, COO) · uno solo, para los tres sitios
   ============================================================
   Todo lo que el navegador dibuja por su cuenta —casillas, interruptores,
   deslizadores, números, buscadores, archivos, colores, campos de texto— sale
   con la marca, una vez, aquí. Web, panel y dashboard leen este archivo
   (el panel y el dashboard, copiado: scripts/comun-panel.mjs y comun-bot.mjs),
   así que un control nuevo nace ya tematizado y no hace falta escribir nada.
   Demo con todos sus estados en /muestra, «Controles».

   CÓMO SE CONVIVE CON LO QUE YA TENÍA ESTILO. Todo lo de abajo va dentro de
   `:where()`, o sea con especificidad CERO: cualquier clase de una página
   (`.f input`, `.em-entrada`, `.control input`, `.campo input`…) lo gana sin
   pelear. Es la receta de partida de lo que no tiene ninguna, y lo único que
   ya no se escribe a mano es lo que el navegador dibujaba: el spinner del
   número, la X del buscador, el botón del archivo, la casilla.

   LA FORMA DE LA CASILLA (escalón de 20 px → `--bevel-xs`, 5 px). Hace de
   `clip-path` y por tanto se come su propio borde: el contorno es una CAPA
   DOBLE como `.caja` —el fondo del <input> es el filo, el `::before` el
   relleno un grueso hacia dentro (corte − 0,59 × grueso) y el `::after` el
   tic—. Todo en la rejilla de 1 celda del propio input: sin posiciones
   absolutas. El FOCO es el mismo aro a 2 px en amarillo, con el interior
   oscuro (marcada o no): un `outline` caería fuera del recorte y no se vería.
   El radio es redondo a propósito: es lo único del sitio que no es chaflán, y
   por eso se distingue de la casilla sin leer nada. */
:root{color-scheme:dark;accent-color:var(--yellow)}

/* ---------- Campos de texto (la receta de partida) ----------
   El relleno interior es `--esp-2` (arriba y abajo) y `--esp-3` (a los lados):
   8 × 12 px, el mismo que `.campo textarea` del panel. Vale para el texto y
   para el placeholder (18 oct 2026, COO: en el editor de bloques del dashboard
   salían pegados al borde porque el `*{padding:0}` de su hoja le ganaba a esta
   receta, que va en `:where()`). Una hoja que resetee el relleno de todo
   (`*{padding:0}`) tiene que dejar fuera estos campos; ver `dashboard.css`.
   `--esp-*` los definen el panel y el dashboard; en la web, el valor de reserva. */
:where(input:not([type]),input[type=text],input[type=email],input[type=url],input[type=tel],
  input[type=password],input[type=search],input[type=number],input[type=date],
  input[type=datetime-local],input[type=time],input[type=month],input[type=week],textarea){
  font-family:'Poppins',sans-serif;font-size:var(--tipo-descripcion);font-weight:400;line-height:1.4;
  color:var(--texto-1);caret-color:var(--yellow);background-color:var(--ink);
  border:1px solid var(--line);border-radius:0;padding:var(--esp-2,.5rem) var(--esp-3,.75rem);min-width:0;max-width:100%;
  transition:border-color .15s ease,background-color .15s ease;
}
:where(textarea){min-height:6rem;line-height:1.55;resize:vertical}
:where(input:not([type]),input[type=text],input[type=email],input[type=url],input[type=tel],
  input[type=password],input[type=search],input[type=number],input[type=date],
  input[type=datetime-local],input[type=time],input[type=month],input[type=week],textarea):hover{
  border-color:var(--texto-3)}
:where(input:not([type]),input[type=text],input[type=email],input[type=url],input[type=tel],
  input[type=password],input[type=search],input[type=number],input[type=date],
  input[type=datetime-local],input[type=time],input[type=month],input[type=week],textarea):focus-visible{
  outline:none;border-color:var(--yellow)}
:where(input:not([type]),input[type=text],input[type=email],input[type=url],input[type=tel],
  input[type=password],input[type=search],input[type=number],input[type=date],
  input[type=datetime-local],input[type=time],input[type=month],input[type=week],textarea):disabled{
  opacity:.5;cursor:not-allowed}
/* El anillo `outline` global de la hoja de la página (`:focus-visible`) se
   apaga aquí: el campo ya enseña el foco con el borde amarillo, y los dos
   juntos salían como un marco doble. */
input:is(:not([type]),[type=text],[type=email],[type=url],[type=tel],[type=password],[type=search],
  [type=number],[type=date],[type=datetime-local],[type=time],[type=month],[type=week]):focus-visible,
textarea:focus-visible{outline:none}
/* El error no es un color: el amarillo es de lo que se pulsa. Gris y, en la
   página, el texto que lo explica (misma regla que `.f.mal`). */
:where(input,textarea)[aria-invalid="true"]{border-color:var(--gris-3)}
:where(input,textarea)::placeholder{color:var(--texto-3);opacity:1}
/* El fondo amarillento del autocompletado: se queda en la tinta de la marca y
   el texto en crema. El `transition` larguísimo es el truco que evita que el
   navegador pinte su color; el `box-shadow` inset es la reserva de Safari. */
:where(input,textarea,select):-webkit-autofill,
:where(input,textarea,select):-webkit-autofill:hover,
:where(input,textarea,select):-webkit-autofill:focus{
  -webkit-text-fill-color:var(--texto-1);caret-color:var(--yellow);
  -webkit-box-shadow:0 0 0 100rem var(--ink) inset;
  transition:background-color 600000s 0s,color 600000s 0s;
}
:where(input,textarea,select):autofill{background-color:var(--ink);color:var(--texto-1)}

/* ---------- El buscador: sin lupa ni X del navegador ----------
   La X de borrar se dibuja con dos degradados (sin imagen: la CSP del panel y
   del dashboard no deja más que lo suyo), gris y amarilla al pasar. Firefox no
   pinta ninguna: no hay nada que quitar. */
:where(input[type=search]){-webkit-appearance:none;appearance:none}
input[type=search]::-webkit-search-decoration,
input[type=search]::-webkit-search-results-button,
input[type=search]::-webkit-search-results-decoration{-webkit-appearance:none;display:none}
input[type=search]::-webkit-search-cancel-button{
  -webkit-appearance:none;appearance:none;flex:none;cursor:pointer;
  width:.875rem;height:.875rem;margin:0 0 0 .5rem;
  background:
    linear-gradient(45deg,transparent calc(50% - 1px),var(--texto-3) calc(50% - 1px),var(--texto-3) calc(50% + 1px),transparent calc(50% + 1px)),
    linear-gradient(-45deg,transparent calc(50% - 1px),var(--texto-3) calc(50% - 1px),var(--texto-3) calc(50% + 1px),transparent calc(50% + 1px));
}
input[type=search]::-webkit-search-cancel-button:hover{
  background:
    linear-gradient(45deg,transparent calc(50% - 1px),var(--yellow) calc(50% - 1px),var(--yellow) calc(50% + 1px),transparent calc(50% + 1px)),
    linear-gradient(-45deg,transparent calc(50% - 1px),var(--yellow) calc(50% - 1px),var(--yellow) calc(50% + 1px),transparent calc(50% + 1px));
}

/* ---------- El número: sin las flechas del navegador ----------
   Las teclas ↑ ↓ y la rueda siguen valiendo. Donde el sitio ya pinta su − / +
   (`.control-paso` del dashboard) es lo único que se ve. */
input[type=number]{-moz-appearance:textfield;appearance:textfield}
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;appearance:none;margin:0}

/* ---------- Casilla y radio ---------- */
:where(input[type=checkbox],input[type=radio]){
  --c-filo:var(--gris-2);--c-fondo:var(--ink);--c-marca:var(--sobre-amarillo);
  -webkit-appearance:none;appearance:none;flex:none;
  position:relative;display:inline-grid;grid-template:100% / 100%;vertical-align:middle;
  inline-size:1.25rem;block-size:1.25rem;margin:0;padding:0;border:0;cursor:pointer;
}
/* La casilla: filo → relleno → tic, en una celda. */
:where(input[type=checkbox]){
  background:var(--c-filo);clip-path:var(--bevel-xs);
  transition:background .15s ease;
}
:where(input[type=checkbox])::before{
  content:'';grid-area:1 / 1;place-self:center;
  inline-size:calc(100% - 2px);block-size:calc(100% - 2px);
  --c:4.41px;clip-path:polygon(0 0,calc(100% - var(--c)) 0,100% var(--c),100% 100%,var(--c) 100%,0 calc(100% - var(--c)));
  background:var(--c-fondo);transition:background .15s ease;
}
:where(input[type=checkbox])::after{
  content:'';grid-area:1 / 1;place-self:center;
  inline-size:.7rem;block-size:.7rem;background:var(--c-marca);
  clip-path:polygon(14% 44%,0 60%,40% 100%,100% 22%,86% 8%,40% 70%);
  transform:scale(0);transition:transform .18s var(--mov-rebote,cubic-bezier(.34,1.56,.64,1)),background .15s ease;
}
:where(input[type=checkbox]):checked::after{transform:scale(1)}
/* A medias (las filas que marcan «todo»): una barra en vez del tic. */
:where(input[type=checkbox]):indeterminate::after{
  clip-path:polygon(0 38%,100% 38%,100% 62%,0 62%);transform:scale(1)}
:where(input[type=checkbox],input[type=radio]):hover,
label:hover>:where(input[type=checkbox],input[type=radio]){--c-filo:var(--texto-3)}
:where(input[type=checkbox]):checked,
:where(input[type=checkbox]):indeterminate,
:where(input[type=radio]):checked{--c-filo:var(--yellow);--c-fondo:var(--yellow)}
:where(input[type=checkbox]):checked:hover,
:where(input[type=checkbox]):indeterminate:hover,
:where(input[type=radio]):checked:hover,
label:hover>:where(input[type=checkbox]:checked,input[type=checkbox]:indeterminate,input[type=radio]:checked){
  --c-filo:var(--yellow-alto);--c-fondo:var(--yellow-alto)}
/* El foco: aro de 2 px, interior oscuro, tic amarillo. */
:where(input[type=checkbox]):focus-visible{--c-filo:var(--yellow);--c-fondo:var(--ink);--c-marca:var(--yellow);outline:none}
:where(input[type=checkbox]):focus-visible::before{
  inline-size:calc(100% - 4px);block-size:calc(100% - 4px);--c:3.82px}
:where(input[type=checkbox]):disabled,:where(input[type=radio]):disabled{opacity:.45;cursor:not-allowed}

/* El radio: redondo, con su punto. Sin recorte, así que el filo es un
   `box-shadow` inset y el foco el mismo a 2 px. */
:where(input[type=radio]){
  border-radius:50%;background:var(--c-fondo);
  box-shadow:inset 0 0 0 1px var(--c-filo);
  transition:box-shadow .15s ease,background .15s ease;
}
:where(input[type=radio])::before{
  content:'';grid-area:1 / 1;place-self:center;inline-size:.5rem;block-size:.5rem;border-radius:50%;
  background:var(--c-marca);transform:scale(0);
  transition:transform .18s var(--mov-rebote,cubic-bezier(.34,1.56,.64,1));
}
:where(input[type=radio]):checked::before{transform:scale(1)}
:where(input[type=radio]):focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--yellow);--c-filo:var(--yellow);--c-fondo:var(--ink);--c-marca:var(--yellow)}

/* ---------- El interruptor: <input type="checkbox" role="switch"> ----------
   Las medidas y la forma del `.interruptor` del dashboard (44 × 24, chaflán
   de etiqueta, perilla cuadrada que salta con el rebote): un solo interruptor
   en los tres sitios. El off es la superficie 2; el on, amarillo. */
:where(input[type=checkbox][role=switch]){
  --c-fondo:var(--surface-2);--c-marca:var(--texto-3);
  inline-size:2.75rem;block-size:1.5rem;
}
:where(input[type=checkbox][role=switch])::before{inline-size:calc(100% - 2px);block-size:calc(100% - 2px)}
:where(input[type=checkbox][role=switch])::after{
  inline-size:1rem;block-size:1rem;place-self:center start;margin-inline-start:.25rem;
  clip-path:var(--bevel-perilla);   /* los chaflanes de su caja, a escala (COO, 28 oct 2026) */
  transform:none;transition:transform .32s var(--mov-rebote,cubic-bezier(.34,1.56,.64,1)),background .2s ease;
}
:where(input[type=checkbox][role=switch]):checked::after{transform:translateX(1.25rem)}
:where(input[type=checkbox][role=switch]):checked{--c-marca:var(--sobre-amarillo)}
:where(input[type=checkbox][role=switch]):focus-visible{--c-marca:var(--texto-3)}
:where(input[type=checkbox][role=switch]):focus-visible:checked{--c-marca:var(--yellow)}
:where(input[type=checkbox][role=switch]):focus-visible::before{inline-size:calc(100% - 4px);block-size:calc(100% - 4px)}

/* ---------- El deslizador ----------
   La caja del <input> mide 24 px (se agarra bien con el dedo) y la pista 4.
   El relleno lo pone `--lleno` (un %), que escribe quien lo mueve —ui.js del
   dashboard—; en Firefox `::-moz-range-progress` lo hace solo. Sin `--lleno`
   queda la pista lisa. La perilla es el chaflán de etiqueta; con el teclado
   crece y lleva un punto oscuro: el aro de 2 px del `.deslizador` (dashboard)
   es un extra, no lo único que dice dónde está el foco. */
:where(input[type=range]){
  -webkit-appearance:none;appearance:none;width:100%;height:1.5rem;margin:0;padding:0;
  background:transparent;border:0;cursor:pointer;
}
input[type=range]::-webkit-slider-runnable-track{
  height:4px;
  background:linear-gradient(to right,var(--yellow) var(--lleno,0%),var(--line) var(--lleno,0%));
}
input[type=range]::-moz-range-track{height:4px;background:var(--line)}
input[type=range]::-moz-range-progress{height:4px;background:var(--yellow)}
input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;width:1rem;height:1rem;margin-top:calc(2px - .5rem);border:0;
  background:var(--yellow);clip-path:var(--bevel-xs);
  transition:transform .2s var(--mov-rebote,cubic-bezier(.34,1.56,.64,1));
}
input[type=range]::-moz-range-thumb{
  width:1rem;height:1rem;border:0;border-radius:0;background:var(--yellow);clip-path:var(--bevel-xs);
}
input[type=range]:hover::-webkit-slider-thumb{background:var(--yellow-alto)}
input[type=range]:hover::-moz-range-thumb{background:var(--yellow-alto)}
input[type=range]:active::-webkit-slider-thumb{transform:scale(1.25)}
input[type=range]:focus-visible{outline:none}
input[type=range]:focus-visible::-webkit-slider-thumb{
  transform:scale(1.3);background:radial-gradient(circle,var(--sobre-amarillo) 0 2px,var(--yellow) 2.5px)}
input[type=range]:focus-visible::-moz-range-thumb{
  transform:scale(1.3);background:radial-gradient(circle,var(--sobre-amarillo) 0 2px,var(--yellow) 2.5px)}
input[type=range]:disabled{opacity:.5;cursor:not-allowed}
input[type=range]:disabled::-webkit-slider-thumb{background:var(--texto-3)}
input[type=range]:disabled::-moz-range-thumb{background:var(--texto-3)}

/* ---------- El archivo: el botón es un `.btn-sm` fantasma ----------
   El chaflán se come el borde, así que el botón va sin filo (relleno nada
   más); con el teclado se vuelve amarillo macizo, como el botón principal. */
:where(input[type=file]){
  font-family:'Poppins',sans-serif;font-size:var(--tipo-descripcion);color:var(--texto-3);
  max-width:100%;cursor:pointer;
}
input[type=file]::file-selector-button{
  font-family:'Poppins',sans-serif;font-size:var(--tipo-rotulo);font-weight:600;
  letter-spacing:.08em;text-transform:uppercase;white-space:nowrap;
  min-height:var(--btn-sm-alto,2rem);padding:.35rem var(--btn-sm-pad-x,.85rem);margin-inline-end:.75rem;
  color:var(--texto-1);background:rgba(242,232,220,.07);border:0;cursor:pointer;
  clip-path:var(--bevel-compacto);transition:background .15s ease,color .15s ease;
}
input[type=file]:hover::file-selector-button{background:rgba(242,232,220,.13)}
input[type=file]:focus-visible{outline:none}
input[type=file]:focus-visible::file-selector-button{background:var(--yellow);color:var(--sobre-amarillo)}
input[type=file]:disabled{opacity:.5;cursor:not-allowed}
input[type=file]:disabled::file-selector-button{cursor:not-allowed}

/* ---------- El color: una muestra biselada ----------
   Un marco de 2 px (el fondo del <input>) y la muestra recortada con el
   mismo chaflán, un grueso hacia dentro. */
:where(input[type=color]){
  -webkit-appearance:none;appearance:none;
  inline-size:var(--alto-control,2.5rem);block-size:var(--alto-control,2.5rem);padding:2px;border:0;
  background:var(--line);clip-path:var(--bevel-sm);cursor:pointer;transition:background .15s ease;
}
input[type=color]::-webkit-color-swatch-wrapper{padding:0}
/* Dos reglas y no una lista: un navegador descarta la regla entera si no
   entiende uno de los pseudoelementos de la lista (Chrome con -moz-). */
input[type=color]::-webkit-color-swatch{
  border:0;--c:7.82px;
  clip-path:polygon(0 0,calc(100% - var(--c)) 0,100% var(--c),100% 100%,var(--c) 100%,0 calc(100% - var(--c)));
}
input[type=color]::-moz-color-swatch{
  border:0;--c:7.82px;
  clip-path:polygon(0 0,calc(100% - var(--c)) 0,100% var(--c),100% 100%,var(--c) 100%,0 calc(100% - var(--c)));
}
input[type=color]:hover{background:var(--texto-3)}
input[type=color]:focus-visible{outline:none;background:var(--texto-1)}   /* crema: el amarillo se perdería en una muestra amarilla */
input[type=color]:disabled{opacity:.5;cursor:not-allowed}

@media (prefers-reduced-motion: reduce){
  input[type=checkbox],input[type=checkbox]::before,input[type=checkbox]::after,
  input[type=radio],input[type=radio]::before,
  input[type=file]::file-selector-button{transition:none}
  input[type=range]::-webkit-slider-thumb{transition:none}
}

/* ============================================================
   LOS ICONOS (17 oct 2026, COO) · assets/iconos.js
   Un solo set para la web, el panel y el dashboard: todos salen de
   assets/iconos/<id>.svg (catálogo y reglas en /muestra/iconos). El trazo
   (1,8, redondo, currentColor) lo lleva cada <svg>; aquí, solo el tamaño
   de serie, que sigue al texto. Un sitio que quiera otro lo pone con su
   clase, nunca cambiando el grosor: los trazos son los mismos en todo
   tamaño.
   ============================================================ */
.icono{width:1.25em;height:1.25em;flex:none;display:inline-block;vertical-align:-.25em;overflow:visible}

/* ============================================================
   MENOS TEXTO, MÁS INTERFAZ (19 oct 2026, COO) · muestrario «Inicio 3»
   ============================================================
   Tres piezas para cumplirlo sin escribir CSS en cada módulo:
   · .btn-icono  un botón de SOLO icono (cuadrado, el alto del .btn-sm). El
     nombre va en aria-label y en la etiqueta propia (data-etiqueta): nunca
     un icono mudo.
   · .campo-s/-m/-l/-xl  el ancho máximo de un campo según el dato que
     lleva (tokens --campo-* de marca.css). Nunca a todo el ancho.
   · .campos  una rejilla que pone los campos en columnas cuando cabe, y
     uno por fila en el móvil. */
.btn-icono{padding:0;inline-size:var(--btn-sm-alto);min-block-size:var(--btn-sm-alto);gap:0}
.btn-icono .icono{width:1.15rem;height:1.15rem;vertical-align:0}
.campo-s{max-inline-size:var(--campo-s)}
.campo-m{max-inline-size:var(--campo-m)}
.campo-l{max-inline-size:var(--campo-l)}
.campo-xl{max-inline-size:var(--campo-xl)}
.campos{display:grid;gap:var(--esp-rejilla);align-items:start;
  grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--campo-m)),1fr))}
.campos > .ancho-completo{grid-column:1 / -1}

/* LOS AJUSTES CORTOS, EN FILA O EN REJILLA (COO, 28 oct 2026; plan
   «Rediseño del Dashboard»). Un ajuste corto (un número, un interruptor, un
   rol) no ocupa una fila entera de formulario:
   · .fila-ajuste   la etiqueta a la izquierda y su control a la derecha, en
     una línea (en el móvil, si no cabe, el control baja). El control mide lo
     suyo (--campo-*), nunca el resto de la fila.
   · .ajustes-rejilla  dos o tres columnas de ajustes cortos cuando caben
     (cada una del ancho de un campo m), una en el móvil.
   El contenido de lectura no pasa de --ancho-lectura. Muestrario,
   «Formularios 15». */
.fila-ajuste{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:var(--esp-2, .5rem) var(--esp-rejilla);min-width:0}
.fila-ajuste > :first-child{flex:1 1 12rem;min-width:0}
.fila-ajuste > :last-child:not(:first-child){flex:0 1 auto;min-width:0;max-inline-size:100%}
.ajustes-rejilla{display:grid;gap:var(--esp-4, 1rem) var(--esp-rejilla);align-items:start;
  grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--campo-m)),1fr))}
.ajustes-rejilla > .ancho-completo{grid-column:1 / -1}
@media (min-width:1200px){ .ajustes-rejilla.de-3{grid-template-columns:repeat(3,minmax(0,1fr))} }

/* ============================================================
   LA ALERTA ENCENDIDA (COO, 28 oct 2026) · .alerta
   ============================================================
   Revierte «el error en gris» (marca.css, EL REPARTO). Recuadro compacto
   (una línea si cabe), oscuro, con el FILO LATERAL amarillo que brilla hacia
   dentro, el icono y el texto encendidos. Nunca relleno amarillo: eso es el
   botón (se pulsa); esto se lee. Tres intensidades:
     .alerta                  error: filo y texto amarillos con halo y un
                              latido al aparecer (sin él con movimiento
                              reducido)
     .alerta.es-importante    filo amarillo apagado, texto crema, sin brillo
     .alerta.es-info          filo marrón claro, texto de apoyo
   El bisel es el de su alto (37–60 px, --bevel-sm): el filo lateral es un
   `::after` dentro del recorte, así sigue el chaflán de abajo. Se usa con un
   icono (`.alerta-ico`) y el texto; en el Dashboard la misma receta pinta
   .nota-aviso, .aviso-error, los toasts y el error de un campo. Muestrario,
   «Componentes 20» y «Estados 5». */
.alerta{
  position:relative;display:flex;align-items:flex-start;gap:var(--esp-3, .75rem);min-width:0;
  padding:.6rem .9rem .6rem 1.05rem;clip-path:var(--bevel-sm);
  background:var(--alerta-velo),var(--alerta-fondo);box-shadow:var(--alerta-brillo);
  font-size:var(--tipo-descripcion);font-weight:500;line-height:1.45;color:var(--alerta-texto);text-shadow:var(--alerta-halo);
}
.alerta::after{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;pointer-events:none;
  background:var(--alerta-filo);box-shadow:0 0 10px 1px rgba(255,198,33,.65)}
.alerta > *{min-width:0}
.alerta .alerta-ico,.alerta > .ico:first-child,.alerta > .icono:first-child{flex:none;width:1.15rem;height:1.15rem;margin-top:.12em;color:inherit;
  filter:drop-shadow(0 0 4px rgba(255,198,33,.7))}
.alerta b,.alerta strong{font-weight:600;color:inherit}
.alerta.es-importante,.alerta.es-info{background:var(--capa-2);box-shadow:none;text-shadow:none;color:var(--texto-1)}
.alerta.es-importante::after{background:var(--alerta-filo-importante);box-shadow:none}
.alerta.es-importante .alerta-ico,.alerta.es-importante > .ico:first-child,.alerta.es-importante > .icono:first-child{color:var(--alerta-filo-importante);filter:none}
.alerta.es-info{background:var(--capa-1);color:var(--texto-2)}
.alerta.es-info::after{background:var(--alerta-filo-info);box-shadow:none}
.alerta.es-info .alerta-ico,.alerta.es-info > .ico:first-child,.alerta.es-info > .icono:first-child{color:var(--alerta-filo-info);filter:none}
@media (prefers-reduced-motion: no-preference){
  .alerta:not(.es-importante):not(.es-info){animation:alerta-latido 1.1s ease-out 1}
}
@keyframes alerta-latido{
  0%{box-shadow:inset 18px 0 30px -10px rgba(255,198,33,.9);filter:brightness(1.25)}
  100%{box-shadow:var(--alerta-brillo);filter:none}
}

/* ============================================================
   EL PUNTO DE ESTADO (COO, 28 oct 2026) · .punto-estado
   ============================================================
   Siempre REDONDO, nunca un rombo, y el mismo en todo: parpadea lo abierto
   (lo que ocurre ahora), relleno lo que espera una acción, hueco lo
   programado, hueco discontinuo el borrador, crema lo terminado y apagado lo
   anulado. El estado lo dice también el texto de al lado: el punto no va
   solo. En el Dashboard se pintan igual .sor-punto, .ev-punto,
   .estado-punto y .guardar-punto. Muestrario, «Componentes 21». */
.punto-estado{flex:none;display:inline-block;width:.6rem;height:.6rem;border-radius:50%;background:var(--yellow);vertical-align:.05em}
.punto-estado.es-hueco{background:none;box-shadow:inset 0 0 0 1.5px var(--yellow)}
.punto-estado.es-borrador{background:none;border:1.5px dashed var(--yellow-bajo)}
.punto-estado.es-crema{background:var(--cream)}
.punto-estado.es-apagado{background:var(--texto-3);opacity:.6}
@media (prefers-reduced-motion: no-preference){
  .punto-estado.es-vivo{animation:punto-parpadea 1.2s ease-in-out infinite alternate}
}
@keyframes punto-parpadea{from{opacity:1;box-shadow:0 0 6px rgba(255,198,33,.8)} to{opacity:.35;box-shadow:none}}

/* LAS TEXTURAS, COMO CLASE (COO, 28 oct 2026): la capa de encima del color de
   la caja, con los tokens --tex-* de marca.css. Para el muestrario y para lo
   que no tenga ya su regla; en el Dashboard cada pieza la lleva puesta. */
.tex-luz{background-image:var(--tex-luz)}
.tex-peligro{background-image:var(--tex-peligro)}

/* El globo del «?» es una .caja, y .caja (más arriba) lo devolvía al flujo
   con position:relative: esto lo deja flotando, en todos los sitios. */
.caja.ayuda-globo{position:absolute}

/* ============================================================================
   LA CAMPANA DE LA BANDEJA (S3, CEO, 20 oct 2026) · .campana-cab, .campana-n
   ============================================================================
   El número de mensajes sin leer (assets/campana.js) en Administración y el
   Dashboard; la web tiene el suyo en assets/marco.css (.marco-campana-*) y
   pinta igual. Dos usos:
     · .campana-cab  un botón de solo icono en la cabecera, junto a la cuenta,
       para cuando el lateral no está a la vista (móvil, pantallas sin lateral).
       Sin caja ni chaflán a propósito: el contador se sale de la esquina del
       icono y un clip-path se lo comería (CLAUDE.md, «el contorno biselado»).
     · .campana-n    el contador, amarillo y macizo: el único dato que llama, y
       solo cuando hay algo. Va sobre el icono (.campana-ico, o .lat-ico en el
       lateral) para que se lea igual entero y plegado.
   ========================================================================== */
.campana-cab{position:relative;display:inline-flex;align-items:center;justify-content:center;flex:none;
  inline-size:2.5rem;block-size:2.5rem;padding:0;border:0;background:none;color:var(--texto-2);cursor:pointer;
  text-decoration:none;-webkit-tap-highlight-color:transparent;transition:color .15s ease}
.campana-cab:hover,.campana-cab[aria-current="page"]{color:var(--yellow)}
.campana-cab.con-avisos{color:var(--texto-1)}
.campana-cab.con-avisos:hover,.campana-cab.con-avisos[aria-current="page"]{color:var(--yellow)}
.campana-cab:focus-visible{outline:2px solid var(--yellow);outline-offset:-2px}
.campana-cab[hidden]{display:none}
.campana-ico{position:relative;display:flex;inline-size:1.375rem;block-size:1.375rem}
.campana-ico svg{inline-size:100%;block-size:100%}
.campana-n{position:absolute;left:calc(100% - .55rem);top:-.4rem;min-inline-size:1rem;block-size:1rem;padding:0 .25rem;
  display:flex;align-items:center;justify-content:center;
  font-family:inherit;font-size:var(--tipo-etiqueta);font-weight:700;line-height:1;letter-spacing:0;
  color:var(--sobre-amarillo);background:var(--yellow);clip-path:var(--bevel-xs);pointer-events:none}
.campana-n[hidden]{display:none}

/* ============================================================================
   EL BOTÓN DE COMENTARIOS Y BUGS, FLOTANTE (CEO, 23 oct 2026) · .fbk-flota
   ============================================================================
   Solo el icono del bug, fijo ABAJO A LA DERECHA, en la web y en el Dashboard
   (Administración no lo lleva). Lo crea assets/campana.js (TRUFAS_CAMPANA.
   feedback) y abre el formulario de assets/feedback.js. Es hermano del índice
   y del flotante de estado (beta/staff): mismo alto (--flotante-alto, 38),
   mismo cristal oscuro, mismo bisel pequeño y mismo aro, y la misma altura
   del suelo: 16 + lo que suba el aviso de idioma o el dock (--hueco-flotantes
   en la web; en el Dashboard, que no lleva esos dos flotantes, lo que ocupa
   el dock: --dock-h sin su aire de arriba ni la zona segura, que ya suma el
   `bottom`). Con él a la vista el <html> lleva `con-fbk-flota` y el índice (base.css) se corre
   a su izquierda. z 60 como ellos: bajo la barra de guardar (80), el panel
   lateral de Sorteos (92) y el propio formulario (125). La barra «guardar» del
   Dashboard (abajo y a todo el ancho en móvil) lo levanta encima de ella.
   Muestrario, «Componentes 12» y «Maquetación 11».
   ========================================================================== */
.fbk-flota{
  position:fixed;right:16px;z-index:60;
  bottom:calc(16px + max(var(--hueco-flotantes, 0px), var(--dock-h, 0px) - var(--dock-margen, 0px) - env(safe-area-inset-bottom, 0px)) + var(--fbk-sube, 0px) + env(safe-area-inset-bottom, 0px));
  display:flex;align-items:center;justify-content:center;
  inline-size:var(--flotante-alto);block-size:var(--flotante-alto);padding:0;border:none;cursor:pointer;
  color:var(--texto-1);background:rgba(23,17,13,.78);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  clip-path:var(--bevel-sm);--filo-color:var(--yellow-bajo);
  box-shadow:inset 0 0 0 1px var(--filo-borde, var(--filo-color));
  -webkit-tap-highlight-color:transparent;
  transition:bottom .25s ease, color .15s ease;
}
.fbk-flota[hidden]{display:none}
.fbk-flota-ico{inline-size:1.125rem;block-size:1.125rem;display:block}
.fbk-flota:hover,.fbk-flota[aria-expanded="true"]{--filo-color:var(--yellow);color:var(--yellow)}
.fbk-flota:focus-visible{outline:2px solid var(--yellow);outline-offset:2px}
@supports (clip-path: polygon(evenodd, 0 0, 1px 1px, 0 1px)){
  .fbk-flota::after{content:'';position:absolute;inset:0;pointer-events:none;clip-path:var(--filo-sm);background:var(--filo-color)}
  .fbk-flota:focus-visible{outline:none}
  .fbk-flota:focus-visible::after{clip-path:var(--filo-foco-sm);--filo-color:var(--yellow)}
}
/* La barra de guardar del Dashboard: donde ocupa el ancho del bug (móvil), él
   sube encima de ella (su alto y 8 px de aire). */
@media (max-width:959.98px){
  html:has(.guardar:not([hidden])) .fbk-flota{--fbk-sube:calc(var(--guardar-alto, 3.5rem) + .5rem)}
}
@media print{ .fbk-flota{display:none} }

@keyframes campana-pulso{0%{transform:scale(1)}40%{transform:scale(.82) rotate(-8deg)}100%{transform:scale(1)}}
@media (prefers-reduced-motion:no-preference){
  .campana-n.salta{animation:campana-pulso .38s var(--mov-rebote)}
}

/* ============================================================================
   LA CIFRA EN EL MENÚ DE LA CUENTA · .mc-cifra (21 oct 2026; antes en marco.css)
   «Bandeja» lleva el número de no leídos a la derecha, en la web,
   Administración y el Dashboard (como en el home: CEO, 21 oct 2026).
   ========================================================================== */
.mc-cifra{min-width:1.1rem;height:1.1rem;padding:0 .3rem;display:inline-flex;align-items:center;justify-content:center;
  font-size:var(--tipo-etiqueta);font-weight:700;line-height:1;color:var(--sobre-amarillo);background:var(--yellow);clip-path:var(--bevel-xs)}
.mc-cifra[hidden]{display:none}
.cuenta-item-bandeja{display:flex;align-items:center;justify-content:space-between;gap:.5rem}

/* ============================================================================
   LOS FILTROS · .fl-grupo, .fl-chips, .fl-chip (muestrario «Formularios 3»,
   variante C aprobada por el CEO, 21 oct 2026)
   Con 5 opciones o menos, chips pequeños a la vista; con más, el desplegable
   múltiple de marca. Varias a la vez dentro de un filtro («o»), ninguna =
   «Todos» (que se enciende solo), y un segundo clic quita la opción. Con solo
   DOS opciones, elegir la otra CAMBIA (sumarlas sería «Todos» y el filtro se
   reiniciaría: así fallaba la bandeja). Cada chip es un botón con
   aria-pressed; el grupo, role="group" con su rótulo. Primer uso: el filtro
   Todos / Oficiales / Otros de la bandeja (assets/bandeja.js).
   ========================================================================== */
.fl-grupo{display:flex;align-items:center;gap:.5rem;min-width:0;max-width:100%}
.fl-rotulo{flex:none;font-size:var(--tipo-rotulo);font-weight:600;letter-spacing:.18em;text-transform:uppercase;color:var(--texto-3)}
.fl-chips{display:flex;flex-wrap:wrap;gap:.25rem;min-width:0}
.fl-chip{position:relative;display:inline-flex;align-items:center;flex:none;height:1.625rem;padding:0 .5rem;margin:0;border:0;cursor:pointer;
  font:inherit;font-size:var(--tipo-leyenda);font-weight:500;line-height:1;white-space:nowrap;color:var(--texto-2);
  background:var(--velo-1,rgba(242,232,220,.045));clip-path:var(--bevel-xs);--filo-color:var(--line);
  box-shadow:inset 0 0 0 1px var(--filo-borde, var(--filo-color));transition:color .15s ease, background .15s ease}
.fl-chip:hover{color:var(--texto-1);--filo-color:var(--texto-3)}
.fl-chip[aria-pressed="true"]{color:var(--texto-1);background:var(--velo-vivo,rgba(255,198,33,.10));--filo-color:var(--yellow)}
.fl-chip:focus-visible{outline:none;--filo-color:var(--yellow)}
@supports (clip-path: polygon(evenodd, 0 0, 1px 1px, 0 1px)){
  .fl-chip{box-shadow:none}
  .fl-chip::after{content:'';position:absolute;inset:0;pointer-events:none;clip-path:var(--filo-xs);background:var(--filo-color)}
  .fl-chip:focus-visible::after{clip-path:var(--filo-foco-xs)}
}
@media (prefers-reduced-motion: reduce){ .fl-chip{transition:none} }
/* En el móvil: un renglón por filtro, y la fila se desliza (sin barra). */
@media (max-width:620px){
  .fl-grupo{flex:1 1 100%}
  .fl-chips{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none}
  .fl-chips::-webkit-scrollbar{display:none}
}

/* ============================================================================
   LAS FILAS QUE SE DESLIZAN · .desliza, [data-deslizar] (COO, 27 oct 2026;
   muestrario «Componentes 18»)
   Toda fila horizontal (pestañas, chips, filtros, rieles) que NO cabe se
   desliza con el dedo, arrastrando con el ratón desde una zona vacía y con
   el teclado (sin la rueda: COO, 27 oct 2026), y se desvanece por el borde donde hay más. Lo monta solo
   assets/deslizar.js (la clase `.desliza` y los avisos `data-mas-izq` /
   `data-mas-der` los pone él); aquí vive solo el aspecto. Una fila nueva
   se apunta con `data-deslizar`, que además le da overflow-x:auto.
   ============================================================================ */
[data-deslizar]{overflow-x:auto;scrollbar-width:none;flex-wrap:nowrap}
[data-deslizar]::-webkit-scrollbar{display:none}
.desliza{--desliza-fade:2.5rem;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;scroll-padding-inline:var(--desliza-fade)}
.desliza[data-mas-der]{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - var(--desliza-fade)),transparent);mask-image:linear-gradient(to right,#000 calc(100% - var(--desliza-fade)),transparent)}
.desliza[data-mas-izq]{-webkit-mask-image:linear-gradient(to left,#000 calc(100% - var(--desliza-fade)),transparent);mask-image:linear-gradient(to left,#000 calc(100% - var(--desliza-fade)),transparent)}
.desliza[data-mas-izq][data-mas-der]{-webkit-mask-image:linear-gradient(to right,transparent,#000 var(--desliza-fade),#000 calc(100% - var(--desliza-fade)),transparent);mask-image:linear-gradient(to right,transparent,#000 var(--desliza-fade),#000 calc(100% - var(--desliza-fade)),transparent)}
.desliza[data-desliza-hay]{cursor:grab}
.desliza[data-desliza-hay] :is(a,button,label,summary,[role="tab"],[role="button"],[role="link"],[role="option"],[role="radio"]){cursor:pointer}
/* Con scroll-snap, el imán se suelta mientras el ratón la mueve. */
.desliza.desliza-libre,.desliza.desliza-arrastrando{scroll-snap-type:none!important;scroll-behavior:auto}
.desliza.desliza-arrastrando,.desliza.desliza-arrastrando *{cursor:grabbing!important;user-select:none;-webkit-user-select:none}
@media (prefers-reduced-motion: reduce){ .desliza{scroll-behavior:auto} }

/* ============================================================================
   NADA INTERACTIVO SE SELECCIONA NI MUESTRA CURSOR DE TEXTO (CEO, 29 oct 2026;
   muestrario «Componentes 24»)
   «En ningún switch o elemento interactivo visual debería poderse poner el
   cursor ni sombrear.» En un interruptor, botón, pestaña, chip, casilla,
   opción de un desplegable, fila o tarjeta que se pulsa, dock o riel: su texto
   no se resalta (doble clic, arrastrar, Ctrl+A) y no sale la rayita de escribir
   (la navegación con cursor del navegador, F7) ni el cursor de texto: manda la
   mano. Se vio en el Dashboard: el «ENCENDIDO» junto al interruptor de un
   módulo se podía seleccionar. Hasta hoy la regla vivía solo en `base.css`, que
   carga la web; Administración y el Dashboard no la cargan, y por eso se
   escapaba allí. Ahora está aquí, en lo común, y la heredan los tres sitios.
   · Todo va en `:where()`: especificidad 0, así que una pieza que de verdad
     necesite otra cosa (el cuadro que se vuelve campo, `cursor:text`) lo dice
     con su propia clase y gana. Una clase nueva que se pulsa y no es `button`,
     `a` ni un `role` se APUNTA EN LA LISTA DE ABAJO: ahí está el único sitio.
   · Quedan fuera, a propósito, los campos donde se escribe (`input` de texto,
     `textarea`, `[contenteditable]`: siguen seleccionables y con su cursor) y
     el texto corrido: un enlace dentro de un párrafo se sigue pudiendo
     seleccionar y copiar (solo se apuntan los enlaces con aspecto de botón).
   ============================================================================ */
:where(
  button, summary, label:has(input[type=checkbox], input[type=radio], [role="switch"], .interruptor),
  [role="button"], [role="switch"], [role="tab"], [role="option"], [role="menuitem"],
  [role="menuitemcheckbox"], [role="menuitemradio"], [role="checkbox"], [role="radio"], [role="treeitem"],
  :not(a)[role="link"],
  input[type=checkbox], input[type=radio], input[type=range], input[type=color], input[type=file],
  input[type=button], input[type=submit], input[type=reset],
  a.btn, a[class*="btn-"], a.pill, a.chip, a.pestana, a.segmento, a[class$="-boton"], a[class*="-boton "],
  /* Un enlace CON CLASE es una pieza (tarjeta, fila, menú), no texto corrido; los de texto se llaman «enlace». */
  a[class]:not([class*="enlace"],[class*="link"]),
  nav a, .lat-fila, .lat-dock a, .marco-dock a, .marco-entrada,
  /* Interruptores y lo que va pegado a ellos (su «Encendido» / «Apagado» y su título). */
  .interruptor, .mod-interruptor, .fila-si, .of-fila-interruptor, .cmp-fila-interruptor,
  .blq-interruptor, .cmp-interruptor, .of-interruptor, .fb-interruptor,
  /* Botones, chips, pestañas y segmentados. */
  .btn, .btn-icon, .btn-icono, .btn-menu, .boton-icono, .boton-descartar, .grupo-boton, .tira-boton, .dia-boton,
  .ayuda-boton, .cuenta-boton, .cuenta-item, .campana-cab, .fbk-flota, .fbk-cerrar, .eg-btn, .nav-toggle,
  .chip, .chip-boton, .chip-juego, .chip-x, .fl-chip, .fase-chip, .pill, .blq-chip, .pr-chip-x, .evt-chip-quitar,
  .pestana, .segmento, .ficha-mod, .pf-seg, .bj-tab, .cm-tab, .fm-tab, .pc-tab, .fm-escalon,
  .cc-boton, .cc-flecha, .cc-titulo-btn, .cc-celda, .cc-op, .cal-filtro, .cal-dia, .cal-item, .cal-tarjeta,
  .pe-filtro, .pe-plegar, .pe-cerrar, .pe-flecha, .np-grupo,
  .control-paso, .enlace-quitar, .aviso-cerrar, .aviso-accion, .franja-salir, .buzon-salir, .buzon-item-x,
  .lapiz, .chk, .tar-check, .ti-casilla, .as-chk,
  .mc-boton, .marco-apoyo-btn, .mxl-apoyo-btn, .mx-emoji-boton, .mx-nombre-btn, .mx-subir-boton, .mx-accion,
  .heroe-editar, .heroe-nombre-btn, .sor-accion, .sor-cerrar, .sor-cajon-boton, .sor-riel-boton, .sor-vivo-abrir,
  .ev-cab-boton, .ev-accion, .ev-riel-boton, .blq-anadir, .blq-accion, .blq-mini, .blq-acc-mini, .blq-barra-boton,
  .blq-barra-color, .blq-sep-margen, .blq-emoji-cuadro, .blq-menu-item, .blq-sug-op, .obq-anadir, .obq-mini, .obq-mini-btn,
  .tarjeta-nueva-boton, .crm-eliminar, .cmp-quitar, .cap-modo-aviso-x, .pb-color-btn, .pc-cifra-btn, .mm-resultado,
  /* Opciones de desplegables, menús, selectores y dock / riel / lateral. */
  .dp-boton, .dp-op, .se-op, .vr-sug-op, .as-opcion, .cm-opcion, .obq-op, .acc-opcion, .permisos-opcion, .carp-opcion,
  .au-menu-item, .bva-menu-item, .lat-plegar, .lat-titulo-b, .lat-dock-item, .lat-hoja-cerrar,
  .marco-plegar, .marco-titulo-b, .marco-dock-item, .marco-hoja-cerrar, .mxl-plegar, .carp-plegar,
  /* Filas y tarjetas que se pulsan (la fila ES el botón). */
  .es-pulsable, .est-r-in, .lat-cab-pag, .atajo, .club-abre, .msj-abre, .acc-abre, .al-abre, .cfg-abre, .mis-abre, .mk-art-pulsable, .sor-fila-abrir,
  .bj-fila, .bj-sel, .bj-selbar-todo, .ar-selbar-todo, .aud-fila-boton, .aud-fila-pulsable, .aud-barra-pulsable,
  .aud-casilla, .cpa-fila-boton, .fb-chip-abrir, .md-sujeto, .md-persona-fila, .tk-elegir-fila, .prm-g-cab, .pz-grupo-cab,
  .mk-mas-t, .evt-plegado-t, .sa-detalles-cab, .tk-ticket-cab, .ar-item-cab, .acc-quien, .acc-t-quien, .acc-c,
  .filter, .bq-solo, .bq-limpiar, .bq-mas-b, .fm-t-tramo, .mc-mini-saldo, .op-vista, .obq-tipo, .obq-muestra, .obq-fmt,
  .of-acepto, .of-reportar, .of-motivo, .of-fila, .pb-chat-slash, .pb-cmd, .pb-emoji, .pb-tema-bola, .pb-servidor, .sf-vitrina,
  .ti-equipo-b, .ti-celda-b, .ti-corona, .mxl-yo, .mx-ctl, .mx-fila-abrir, .mx-muestra, .mx-riel-boton, .mx-pr-fila, .mx-pr-chip,
  .aud-proximo, .bva-miga, .bva-nombre, .bva-sel, .bva-flot-b, .bva-marca-b, .bva-mover-fila, .bva-previa-pedir, .bva-cupo,
  .bva-cab-todo, .cmp-fila, .cmp-resultado, .cmp-idioma, .cmp-srv, .mm-vecino, .trn-cuenta, .trn-resumen, .hueco,
  .sor-dc-boton, .blq-muestra, .blq-img-vista, .idioma, .tar-fila, .tar-cifra, .pr-fila, .pr-resultado-b, .pr-admin-l,
  .mision, .cuenta-tarjeta, .trato-tarjeta, .actividad-cuenta, .au-nodo, .au-plantilla, .sr-tipo,
  .pz-banner, .pz-foto, .pz-tema, .club-color, .tipo-color, .ed-tipo, .alm-sel-pieza, .entrada-moneda, .canal-estado
){
  -webkit-user-select:none;user-select:none;caret-color:transparent;
}
/* La mano, solo a lo que es un control por su etiqueta o su `role` (`button`,
   `summary`, `[role=tab]`…): una clase de la lista de arriba que es solo una
   etiqueta informativa (un `.chip` que no se pulsa) no estrena un cursor que
   prometa un clic; las que se pulsan ya declaran el suyo. */
:where(
  button, summary, label:has(input[type=checkbox], input[type=radio], [role="switch"], .interruptor),
  [role="button"], [role="switch"], [role="tab"], [role="option"], [role="menuitem"],
  [role="menuitemcheckbox"], [role="menuitemradio"], [role="checkbox"], [role="radio"], [role="treeitem"],
  :not(a)[role="link"],
  input[type=checkbox], input[type=radio], input[type=range], input[type=color], input[type=file],
  input[type=button], input[type=submit], input[type=reset]
){cursor:pointer}
/* Apagado: la mano se va (`default`, no `not-allowed`: base.css, «Fantasma
   apagado»). Va con la especificidad de un botón para ganarle a la clase de
   una pieza que repita `cursor:pointer`; lo que declare `not-allowed` con más
   peso (`.cuenta-item.es-inactivo`) se queda como está. */
button:disabled, :where([role="switch"],[role="tab"],[role="option"],[role="menuitem"],[role="checkbox"],[role="radio"],[role="button"])[aria-disabled="true"]{cursor:default}
/* Los campos donde se escribe siguen siendo de escribir: seleccionables y con su
   cursor, aunque vivan dentro de un control (un campo dentro de una fila que se
   despliega). Van después y, como los dos son `:where()`, aquí gana el último. */
:where(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=button],[type=submit],[type=reset],[type=image]),
  textarea,[contenteditable]:not([contenteditable="false"])){
  -webkit-user-select:text;user-select:text;
}
:where([contenteditable]:not([contenteditable="false"])){caret-color:auto}
