@charset "UTF-8";
/* Generado por SA-Diseñador · framework.css
   Tema de referencia: Claro · Everforest · 02 ago 12:01
   Los componentes viven bajo .ui — ponla en el <body> o en el
   contenedor que envuelva tu aplicación. Ni un color propio:
   todo sale de las variables de theme.css. */
/* ===============================================================
   framework.css — la capa de componentes.

   Contiene todas las clases ui-* y las reglas de los elementos que
   viven dentro de un contenedor con class="ui". No trae ni un color
   propio: todo sale de las variables que define theme.css.

   Uso:
     <link rel="stylesheet" href="theme.css">      <- los tokens
     <link rel="stylesheet" href="framework.css">  <- los componentes
     <body class="ui"> ... </body>

   Los valores por defecto de abajo van en :where(.ui) para que el
   framework no se rompa si falta el tema.

   OJO: no basta con que tengan especificidad cero. Este bloque casa con
   el <body class="ui"> y el :root de theme.css casa con el <html>: son
   elementos distintos, así que NUNCA compiten y la especificidad no
   arbitra nada. Lo que decide es la herencia, y lo declarado en el
   <body> gana a lo que le llega heredado del <html>. Por eso theme.css
   declara sus tokens en «:root, .ui» y no sólo en «:root»; si alguien
   recorta ese selector, el tema deja de verse y todo sale con los
   valores grises de aquí abajo.
   =============================================================== */

:where(.ui) {
  --bg: #10141a;
  --surface: #171c24;
  --surface-2: #1e2530;
  --surface-3: #27303c;
  --line: #2a323d;
  --line-strong: #3a4553;
  --ink: #e8edf3;
  --ink-dim: #96a2b2;
  --ink-faint: #5e6b7d;
  --accent: #8a97a8;
  --accent-strong: #aab6c6;
  --accent-ink: #10141a;
  --ok: #4c9a68;
  --warn: #d99a2b;
  --danger: #cf5850;
  --info: #5b8db0;
  --font-display: 'Barlow Condensed', 'Arial Narrow', sans-serif;
  --font-body: 'Barlow', 'Segoe UI', system-ui, sans-serif;
  --font-mono: 'IBM Plex Mono', 'Consolas', monospace;
  --fs-base: 14px;
  --fs-title-lg: 20px;
  --fs-title: 15px;
  --fs-body: 14px;
  --fs-label: 11px;
  --fs-mono: 12px;
  --fs-stat: 26px;
  --fs-table: 13px;
  --fs-badge: 11px;
  --lh-body: 1.45;
  --lh-tight: 1.15;
  --ls-title: 0.05em;
  --heading-weight: 600;
  --heading-transform: uppercase;
  --radius: 2px;
  --border-width: 1px;
  --cols: 2;
  --gap: 16px;
  --panel-pad: 14px;
  --para-space: 10px;
  --topbar-bg: var(--surface);
  --topbar-accent: var(--accent);
  --panel-bg: var(--surface);
  --panel-border: var(--line);
  --panel-border-width: var(--border-width);
  --panel-radius: var(--radius-lg);
  --panel-tick: var(--accent);
  --btn-radius: var(--radius-sm);
  --btn-border-width: var(--border-width);
  --btn-primary-bg: var(--accent);
  --btn-primary-ink: var(--accent-ink);
  --btn-primary-border: var(--accent);
  --btn-bg: var(--surface-2);
  --btn-ink: var(--ink);
  --btn-border: var(--line-strong);
  --input-bg: var(--bg);
  --input-border: var(--line-strong);
  --input-border-width: var(--border-width);
  --input-radius: var(--radius-sm);
  --input-focus: var(--accent);
  --badge-radius: var(--radius-pill);
  --stat-accent: var(--accent);
  --focus-width: 2px;
  --shadow: none;
  --overlay: #000000;
  --overlay-alpha: 0.62;
  --alert-tint: 0.12;
  --progress-h: 6px;
  --scroll-size: 10px;
  --link: var(--accent);
  --link-hover: var(--accent-strong);
  --focus-ring: var(--accent);
  --nav-bg: var(--surface);
  --nav-ink: var(--ink-dim);
  --nav-active-bg: var(--surface-3);
  --nav-active-ink: var(--accent);
  --nav-radius: var(--radius-sm);
  --tab-ink: var(--ink-dim);
  --tab-active-ink: var(--ink);
  --tab-indicator: var(--accent);
  --alert-radius: var(--radius-md);
  --control-accent: var(--accent);
  --control-bg: var(--surface-3);
  --control-radius: var(--radius-xs);
  --menu-bg: var(--surface-2);
  --menu-ink: var(--ink);
  --menu-active-bg: var(--surface-3);
  --menu-radius: var(--radius-md);
  --tooltip-bg: var(--ink);
  --tooltip-ink: var(--bg);
  --tooltip-radius: var(--radius-sm);
  --dialog-bg: var(--surface);
  --dialog-border: var(--line-strong);
  --dialog-radius: var(--radius-lg);
  --progress-track: var(--surface-3);
  --progress-fill: var(--accent);
  --page-active-bg: var(--accent);
  --page-active-ink: var(--accent-ink);
  --page-radius: var(--radius-sm);
  --chip-bg: var(--surface-2);
  --chip-ink: var(--ink-dim);
  --chip-radius: var(--radius-pill);
  --avatar-bg: var(--accent);
  --avatar-ink: var(--accent-ink);
  --avatar-radius: var(--radius-pill);
  --scroll-track: var(--surface);
  --scroll-thumb: var(--line-strong);
  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-pill: 999px;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --content-pad: 24px;
  --topbar-h: 52px;
  --fw-normal: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;
  --fw-black: 800;
  --fw-title-lg: var(--fw-bold);
  --fw-title: var(--heading-weight);
  --fw-body: var(--fw-normal);
  --fw-label: var(--fw-medium);
  --fw-stat: var(--fw-semibold);
  --fw-table-head: var(--heading-weight);
  --fw-table: var(--fw-normal);
  --fw-btn: var(--fw-semibold);
  --fw-nav: var(--fw-medium);
  --fw-badge: var(--fw-medium);
  --fw-mono: var(--fw-normal);
  --ls-caps: 0.05em;
  --btn-h: 34px;
  --input-h: 36px;
  --row-h: 36px;
  --focus-offset: 2px;
  --shadow-strength: 0.5;
  --tint-border-alpha: 0.4;
  --blur-chrome: 0px;
  --chrome-alpha: 1;
  --dur-fast: 150ms;
  --dur-base: 250ms;
  --dur-slow: 320ms;
  /* Curvas de movimiento: movimiento.css las consume; estos son los respaldos de fábrica. */
  --ease-standard: cubic-bezier(0.2, 0, 0.2, 1);
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
  --ease-emphasis: cubic-bezier(0.25, 0.1, 0.25, 1);
  --anim-enter-dur: 400ms;
  --anim-stagger: 45ms;
  --hover-lift: 2px;
  --tab-indicator-h: 2px;
  --nav-active-bar-w: 3px;
  --page-mesh: none;
  --gradient-brand: none;
  --z-sticky: 100;
  --z-drawer: 200;
  --z-dropdown: 300;
  --z-modal: 400;
  --z-toast: 500;
  --z-tooltip: 600;
  --bp-sm: 640px;
  --bp-md: 768px;
  --bp-lg: 1024px;
  --bp-xl: 1280px;
  --dash-cols: 4;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, calc(var(--shadow-strength) * 0.5));
  --shadow-md: 0 6px 18px rgba(0, 0, 0, calc(var(--shadow-strength) * 0.7));
  --shadow-lg: 0 16px 42px rgba(0, 0, 0, calc(var(--shadow-strength) * 1));
  --accent-soft: color-mix(in srgb, var(--accent) calc(var(--alert-tint) * 100%), var(--surface));
  --ok-soft: color-mix(in srgb, var(--ok) calc(var(--alert-tint) * 100%), var(--surface));
  --warn-soft: color-mix(in srgb, var(--warn) calc(var(--alert-tint) * 100%), var(--surface));
  --danger-soft: color-mix(in srgb, var(--danger) calc(var(--alert-tint) * 100%), var(--surface));
  --info-soft: color-mix(in srgb, var(--info) calc(var(--alert-tint) * 100%), var(--surface));
  --surface-inset: var(--bg);
  --ink-strong: var(--ink);
  --kind: todo;
  --layout: topbar;
  --nav-w: 224px;
  --nav-w-min: 56px;
  --content-max: 1440px;
  --density: 1;
  --map-style: auto;
  --map-land: var(--bg);
  --map-water: var(--surface-2);
  --map-road: var(--line-strong);
  --map-building: var(--surface-3);
  --map-label: var(--ink-dim);
  --map-marker-stroke: var(--bg);
  --map-popup-bg: var(--surface);
  --map-popup-ink: var(--ink);
  --map-popup-border: var(--line-strong);
  --map-ctrl-bg: var(--surface);
  --map-ctrl-ink: var(--ink);
}

.ui {
  
  
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

  
  background: var(--page-mesh), var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  padding: 18px;
  min-height: 100%;
}

.ui * { box-sizing: border-box; }

/* El atributo hidden tiene que ganar siempre. El runtime abre y cierra
   capas con él (diálogo, cajón, menú, paneles de pestaña), y aquí hay
   clases que fijan display —.ui-shell-nav es flex, .ui-menu es block—
   que sin esto lo anularían y la capa se quedaría abierta. */
.ui [hidden] { display: none !important; }

/* Los hijos directos de una columna flexible también deben poder encoger */
.ui :where(.ui-setting-text, .ui-nav-user-text, .ui-profile-stats div,
  .ui-card, .ui-feature, .ui-price) > * { min-width: 0; }

/* Las pestañas se desplazan, como en cualquier sistema real */
.ui-tabs { overflow-x: auto; scrollbar-width: none; }

.ui-tabs::-webkit-scrollbar { display: none; }

.ui-tab { flex: none; }

/* La ficha clave/valor no puede empujar su columna */
.ui-kv { grid-template-columns: minmax(0, auto) minmax(0, 1fr); }

.ui-kv dt, .ui-kv dd { overflow-wrap: anywhere; }

/* El valor del KPI es lo más grande del tema: con 4 columnas estrechas
   rompía la tarjeta. Que parta antes de desbordar. */
.ui .ui-stat-value, .ui-stat-label, .ui-dash-big { overflow-wrap: anywhere; }

/* El campo con addon: el input debe poder encogerse dentro del grupo */
.ui-input-group { min-width: 0; }

/* width:auto es la clave: el 100% de la regla general de los campos, sumado
   al addon, siempre sobraba del grupo. */
.ui .ui-input-group > input { width: auto; min-width: 0; flex: 1; }

/* La etiqueta del KPI va en versalitas con tracking: en una columna
   estrecha era lo que rompía la tarjeta. */
.ui .ui-stat-label, .ui .ui-stat { overflow-wrap: anywhere; }

/* Tipografía base */
.ui h1, .ui h2, .ui h3, .ui h4 {
  font-family: var(--font-display);
  font-weight: var(--heading-weight);
  text-transform: var(--heading-transform);
  letter-spacing: var(--ls-title);
  /* Mismo motivo que en las cifras grandes: --lh-tight puede bajar a 0.9
     y las fuentes de display tienen la caja del glifo más alta que eso,
     así que el titular se salía por arriba y por abajo. */
  line-height: max(var(--lh-tight), 1.2);
  padding-block: 0.04em;
  color: var(--ink);
  margin: 0;
}

.ui .mono, .ui .num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: var(--fw-mono);
  font-variant-numeric: tabular-nums;
}

/* ─── Barra superior ─────────────────────────────────────────── */
.ui-topbar {
  display: flex;
  align-items: center;
  gap: 16px;
  background: var(--topbar-bg);
  border-bottom: var(--border-width) solid var(--line);
  padding: 0 16px;
  /* Mínimo y no fijo: la marca y el subtítulo crecen con el tema y
     desbordaban la barra por abajo. */
  min-height: 52px;
  flex-wrap: wrap;
  position: relative;
  border-radius: var(--panel-radius) var(--panel-radius) 0 0;
}

.ui-topbar::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: var(--topbar-accent);
}

.ui-wordmark {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-title-lg);
  font-weight: var(--fw-title-lg);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
}

.ui-sigla { color: var(--topbar-accent); }

.ui-subtitle {
  font-size: var(--fs-label);
  color: var(--ink-dim);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  border-left: var(--border-width) solid var(--line-strong);
  padding-left: 16px;
}

.ui-topbar-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  color: var(--ink-dim);
}

.ui-stat {
  border-left: 3px solid var(--line-strong);
  padding: 6px 14px;
  background: var(--panel-bg);
  border-top: var(--panel-border-width) solid var(--panel-border);
  border-right: var(--panel-border-width) solid var(--panel-border);
  border-bottom: var(--panel-border-width) solid var(--panel-border);
  border-radius: var(--panel-radius);
}

.ui-stat.primary { border-left-color: var(--stat-accent); }

/* Toque de marca en el KPI primario: un velo del degradado al 8%, solo
   en tarjetas (en ruled y flat no hay caja que teñir). Con
   --gradient-brand: none el velo no pinta nada y todo sigue igual. */
.ui[data-panel="card"] .ui-stat.primary { position: relative; }

.ui[data-panel="card"] .ui-stat.primary::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--gradient-brand);
  opacity: 0.08;
  pointer-events: none;
}

/* Con .ui delante para ganar a «.ui .num»: el valor del KPI lleva
   las dos clases y el peso de los datos mono le pisaba el suyo. */
.ui .ui-stat-value {
  font-family: var(--font-mono);
  font-size: var(--fs-stat);
  font-weight: var(--fw-stat);
  /* La cifra se salía del KPI en los 37 temas: la caja de la línea la
     fija --lh-tight (1.15 por defecto) pero los glifos de estas fuentes
     miden ~1.22 em de alto, así que sobresalían por arriba y por abajo.
     El mínimo de 1.25 deja sitio al glifo sin aflojar los temas que ya
     venían con más aire. */
  line-height: max(var(--lh-tight), 1.25);
  /* Y un pelo de aire en em para las fuentes de caja más alta: escala
     con el tamaño, así vale igual a 18px que a 96px. */
  padding-block: 0.06em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.ui-stat-label {
  font-size: var(--fs-label);
  font-weight: var(--fw-label);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-dim);
}

/* ─── Panel ──────────────────────────────────────────────────── */
.ui-panel {
  /* Columna flexible y no bloque: cuando la rejilla estira un panel a
     la altura de su vecino (align stretch), el pie de tabla puede bajar
     al borde con margin-top:auto en vez de dejar ~100px de tarjeta
     vacía bajo la paginación. En un panel a su altura natural no cambia
     nada: los hijos apilan igual que en bloque. */
  display: flex;
  flex-direction: column;
  background: var(--panel-bg);
  border: var(--panel-border-width) solid var(--panel-border);
  border-radius: var(--panel-radius);
  box-shadow: var(--shadow-sm);
}

.ui-panel-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 10px 14px;
  border-bottom: var(--panel-border-width) solid var(--panel-border);
}

.ui-panel-title {
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: var(--fw-title);
  text-transform: var(--heading-transform);
  letter-spacing: var(--ls-title);
  color: var(--ink);
}

.ui-panel-title::before {
  content: '';
  display: inline-block;
  width: 8px; height: 8px;
  background: var(--panel-tick);
  margin-right: 8px;
}

.ui-panel-meta {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  color: var(--ink-faint);
}

.ui-panel-body { padding: calc(var(--panel-pad) * var(--density)); }

/* ─── Botones ────────────────────────────────────────────────── */
.ui-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: var(--fw-btn);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  min-height: calc(var(--btn-h) * var(--density));
  padding: 0 calc(18px * var(--density));
  border-radius: var(--btn-radius);
  border: var(--btn-border-width) solid var(--btn-border);
  background: var(--btn-bg);
  color: var(--btn-ink);
  cursor: pointer;
  /* Todo el feedback del botón cuelga del token: si el tema o el usuario
     ponen --dur-fast a 0, el botón queda quieto sin tocar nada más. */
  transition: background-color var(--dur-fast) ease, border-color var(--dur-fast) ease,
    color var(--dur-fast) ease, box-shadow var(--dur-fast) ease,
    transform var(--dur-fast) ease, filter var(--dur-fast) ease;
}

.ui-btn:hover { background: var(--surface-3); border-color: var(--ink-faint); }

/* Press físico: 1px de hundimiento se siente sin mover el layout
   (transform no dispara reflow; un padding o un margin sí). */
.ui-btn:active { transform: translateY(1px); }

.ui-btn-primary {
  background: var(--btn-primary-bg);
  border-color: var(--btn-primary-border);
  color: var(--btn-primary-ink);
}

/* Si el tema define degradado de marca, el botón primario lo usa */
.ui:not([style*="--gradient-brand: none"]) .ui-btn-primary { background-image: var(--gradient-brand); }

.ui-btn-primary:hover { filter: brightness(1.08); }

.ui-btn-danger {
  background: transparent;
  border-color: var(--danger);
  color: var(--danger);
}

/* Todos los campos de texto libres, no solo text/number: el login usa
   email y password y el filtro de tablas usa search; sin ellos aquí,
   salían con el estilo nativo del navegador (caja blanca cruda) en
   mitad de un tema oscuro. */
.ui input[type="text"],
.ui input[type="email"],
.ui input[type="password"],
.ui input[type="search"],
.ui input[type="tel"],
.ui input[type="url"],
.ui input[type="date"],
.ui input[type="number"],
.ui textarea,
.ui select {
  background: var(--input-bg);
  border: var(--input-border-width) solid var(--input-border);
  border-radius: var(--input-radius);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--fs-base);
  min-height: calc(var(--input-h) * var(--density));
  padding: 0 12px;
  width: 100%;
  resize: vertical;
  /* El anillo de foco existe desde el reposo pero transparente: así el
     foco es un fundido de borde y anillo, no un parpadeo. outline no
     ocupa sitio, de modo que en reposo no cambia nada. */
  outline: var(--focus-width) solid transparent;
  outline-offset: 1px;
  transition: border-color var(--dur-fast) ease, outline-color var(--dur-fast) ease,
    background-color var(--dur-fast) ease;
}

.ui input:focus, .ui select:focus, .ui textarea:focus {
  outline: var(--focus-width) solid var(--input-focus);
  outline-offset: 1px;
  border-color: var(--input-focus);
}

.ui input:disabled, .ui select:disabled, .ui textarea:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.ui input[type="range"] {
  accent-color: var(--control-accent);
  width: 100%;
  padding: 0;
  /* El navegador le pone margin:2px por su cuenta y, sumado al 100% de
     ancho, el control se salía 4px del campo. */
  margin: 0;
}

.ui-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-mono);
  font-size: var(--fs-badge);
  font-weight: var(--fw-badge);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 3px 9px;
  border-radius: var(--badge-radius);
  border: var(--border-width) solid;
}

/* Sin el cuadrito de color de antes: el borde y el texto ya iban del
   color del estado, así que la misma información se daba tres veces.
   Dos señales bastan y la etiqueta deja de parecer recargada. */

.ui-badge-ok     { color: var(--ok);     border-color: var(--ok); }

.ui-badge-warn   { color: var(--warn);   border-color: var(--warn); }

.ui-badge-danger { color: var(--danger); border-color: var(--danger); }

.ui-badge-info   { color: var(--info);   border-color: var(--info); }

/* ─── Tabla ──────────────────────────────────────────────────── */
/* Envoltorio con desplazamiento: una tabla nunca debe romper su panel */
.ui-table-wrap { width: 100%; overflow-x: auto; }

.ui-table { width: 100%; min-width: 320px; border-collapse: collapse; font-size: var(--fs-table); }

.ui-table th {
  font-family: var(--font-display);
  font-weight: var(--fw-table-head);
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-dim);
  text-align: left;
  padding: calc(8px * var(--density)) 12px;
  border-bottom: 2px solid var(--line-strong);
}

.ui-table td {
  font-weight: var(--fw-table);
  height: calc(var(--row-h) * var(--density));
  padding: 0 12px;
  border-bottom: var(--border-width) solid var(--panel-border);
  color: var(--ink);
}

.ui-table td.num { text-align: right; }

/* El fondo del hover entra en fundido; también suaviza is-selected */
.ui-table tbody tr { transition: background-color var(--dur-fast) ease; }

.ui-table tbody tr:hover { background: var(--surface-2); }

/* ─── Separador ──────────────────────────────────────────────── */
.ui-divider {
  border: 0;
  border-top: var(--border-width) solid var(--line);
  position: relative;
  margin: 16px 0;
}

.ui-divider::after {
  content: '';
  position: absolute;
  left: 0; top: -3px;
  width: 24px; height: 5px;
  background: var(--accent);
}

/* Controles y popup: réplica de los .mapboxgl-ctrl / .mapboxgl-popup */
.ui-map-ctrl {
  position: absolute;
  top: 12px; right: 12px;
  display: flex;
  flex-direction: column;
  border-radius: var(--panel-radius);
  overflow: hidden;
  box-shadow: var(--shadow);
}

.ui-map-ctrl button {
  width: 29px; height: 29px;
  display: grid;
  place-items: center;
  background: var(--map-ctrl-bg);
  color: var(--map-ctrl-ink);
  border: var(--border-width) solid var(--line);
  border-bottom: 0;
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}

.ui-map-ctrl button:last-child { border-bottom: var(--border-width) solid var(--line); }

.ui-map-ctrl button:hover { background: var(--surface-3); }

.ui-map-popup {
  position: absolute;
  left: 50%; top: 26px;
  transform: translateX(-50%);
  width: 230px;
  background: var(--map-popup-bg);
  color: var(--map-popup-ink);
  border: var(--border-width) solid var(--map-popup-border);
  border-radius: var(--panel-radius);
  box-shadow: var(--shadow);
  padding: 9px 11px;
}

.ui-map-popup-head {
  font-family: var(--font-display);
  font-size: var(--fs-label);
  font-weight: var(--heading-weight);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--map-popup-ink);
  margin-bottom: 5px;
  padding-right: 14px;
}

.ui-map-popup-body {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  font-size: var(--fs-label);
  color: var(--ink-dim);
}

.ui-map-popup-close {
  position: absolute;
  top: 2px; right: 4px;
  background: none;
  border: 0;
  color: var(--ink-faint);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}

.ui-map-popup-tip {
  position: absolute;
  top: 100%; left: 50%;
  transform: translateX(-50%);
  border: 7px solid transparent;
  border-top-color: var(--map-popup-bg);
}

/* ═══════════════════════════════════════════════════════════════
   Componentes de interfaz web — cada uno con sus propias variables
   (heredan del token global hasta que se fijan desde el editor).
   ═══════════════════════════════════════════════════════════════ */

/* ─── Shell del sistema (layout seleccionable) ───────────────
   La variante la fija --layout; el lienzo la refleja en el atributo
   data-layout de .ui para poder reorganizar la caja.          */
/* El armazón OCUPA LA PÁGINA. En el lienzo del editor es una maqueta de
   340 px dentro de una tarjeta, pero eso es cosa del editor y vive en
   canvas.css: aquí no puede haber una altura fija o la aplicación del
   usuario saldría recortada. */
.ui-shell {
  position: relative;
  display: flex;
  min-height: 100vh;
  /* Mesh delante del color, como en la raíz .ui: si el armazón pintara
     solo --bg opaco, la atmósfera del tema jamás se vería en las vistas
     de aplicación (con --page-mesh: none no cambia nada). */
  background: var(--page-mesh), var(--bg);
}

/* Con fondo animado en marcha, el lienzo tiene que VERSE. fondo.js lo
   cuelga como primer hijo del anfitrión .ui (el body exportado o el
   preview del editor), pero el armazón y la mitad del formulario de
   acceso pintaban --bg opaco a toda área y lo tapaban por completo:
   la aurora o las ondas de serie de un tema no llegaban nunca al
   usuario. Cuando el lienzo existe, estas capas se apartan: el fondo
   y el mesh ya los pinta el anfitrión debajo del lienzo (regla .ui),
   así que aquí no se duplica nada. Solo hijos directos: las maquetas
   del catálogo viven dentro de tarjetas y no deben volverse de cristal. */
.ui:has(> [data-ui-fondo]) > .ui-shell,
.ui:has(> [data-ui-fondo]) > .ui-auth .ui-auth-main {
  background: none;
}

.ui-shell-nav {
  display: flex;
  flex-direction: column;
  width: var(--nav-w);
  flex: none;
  background: var(--nav-bg);
  border-right: var(--border-width) solid var(--line);
  /* El colapso NO anima width: animar una medida reflowa todo el
     contenido en cada frame, justo lo que la regla de movimiento
     prohíbe. El ancho salta seco y la sensación de transición la
     pone el fundido de las etiquetas al reaparecer (ui-nav-label,
     solo opacity/transform, en la sección de Movimiento). */
}

.ui-shell-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  /* Con altura fija y overflow:hidden, una marca larga o una tipografía
     grande quedaba cortada a media letra (hasta 24px). Ahora la caja
     crece y el nombre parte de línea: no se pierde texto. */
  min-height: 52px;
  padding: var(--space-2) 12px;
  flex: none;
  border-bottom: var(--border-width) solid var(--line);
}

.ui-shell-logo {
  /* Medida mínima, no fija: la inicial hereda el tamaño de letra del
     tema y con las tipografías grandes se salía del cuadro hasta 26px.
     Con min-* la marca crece con la letra en vez de recortarla. */
  min-width: 28px; min-height: 28px;
  padding: 0.1em 4px;
  flex: none;
  display: grid;
  place-items: center;
  line-height: 1.2;
  background: var(--topbar-accent);
  color: var(--accent-ink);
  border-radius: var(--nav-radius);
  font-family: var(--font-display);
  font-weight: 700;
}

.ui-shell-name {
  font-family: var(--font-display);
  font-size: var(--fs-title);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  min-width: 0;
  overflow-wrap: anywhere;
}

.ui-shell-name b { color: var(--topbar-accent); }

/* El menú se desplaza en vez de recortarse: con overflow:hidden se
   comía hasta 92px de entradas —literalmente destinos que no había
   forma de ver— en cuanto la tipografía o la densidad crecían.
   min-height:0 es lo que permite encoger dentro del flex del armazón. */
.ui-shell-side {
  flex: 1;
  min-height: 0;
  padding: 8px;
  overflow-y: auto;
  overflow-x: hidden;
  background: none;
}

/* Etiqueta de sección del menú: versalitas con su propio tracking */
.ui-nav-label {
  padding: var(--space-3) 12px var(--space-1);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--ink-faint);
  white-space: nowrap;
}

/* Tarjeta de usuario al pie del menú */
.ui-nav-user {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
  padding: var(--space-3) 12px;
  border-top: var(--border-width) solid var(--line);
  overflow: hidden;
}

.ui-nav-user-text { display: flex; flex-direction: column; line-height: 1.25; white-space: nowrap; }

.ui-nav-user-text b { font-size: var(--fs-label); color: var(--ink); font-weight: var(--fw-semibold); }

.ui-nav-user-text span { font-size: var(--fs-label); color: var(--ink-faint); }

/* Indicador «en vivo», reloj, toggle de tema y avatares apilados */
.ui-live {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 9px;
  border-radius: var(--radius-pill);
  background: var(--ok-soft);
  color: var(--ok);
  font-family: var(--font-mono);
  font-size: var(--fs-badge);
  letter-spacing: var(--ls-caps);
}

.ui-live-dot {
  width: 7px; height: 7px;
  border-radius: var(--radius-pill);
  background: var(--ok);
  animation: ui-pulse 1.8s ease-in-out infinite;
}

@keyframes ui-pulse { 50% { opacity: 0.25; } }

.ui-clock { letter-spacing: 1px; }

.ui-theme-toggle {
  width: 28px; height: 28px;
  display: grid; place-items: center;
  background: none;
  border: var(--border-width) solid var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--ink-dim);
  cursor: pointer;
}

.ui-theme-toggle:hover { color: var(--ink); border-color: var(--ink-faint); }

.ui-avatars { display: inline-flex; }

/* El solape se come sólo el relleno, nunca las iniciales: la ficha que
   se pone encima tapaba la última letra de la anterior. */
.ui-avatars .ui-avatar { margin-left: -4px; box-shadow: 0 0 0 1.5px var(--topbar-bg); }

.ui-avatars .ui-avatar:first-child { margin-left: 0; }

.ui-avatar.is-muted { background: var(--surface-3); color: var(--ink-dim); }

.ui[data-layout="compact"] .ui-nav-label,
.ui[data-layout="compact"] .ui-nav-user-text { display: none; }

.ui[data-layout="compact"] .ui-nav-user { justify-content: center; padding-left: 0; padding-right: 0; }

.ui-side-text { white-space: nowrap; overflow: hidden; }

.ui-shell-collapse {
  height: 34px;
  flex: none;
  background: none;
  border: 0;
  border-top: var(--border-width) solid var(--line);
  color: var(--ink-faint);
  font-size: 16px;
  cursor: pointer;
}

.ui-shell-veil {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--overlay);
  opacity: var(--overlay-alpha);
}

.ui-shell-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

/* Barra translúcida: con --blur-chrome a 0 se comporta como sólida */
.ui-shell-top {
  display: flex;
  align-items: center;
  gap: 12px;
  height: var(--topbar-h);
  flex: none;
  padding: 0 14px;
  background: color-mix(in srgb, var(--topbar-bg) calc(var(--chrome-alpha) * 100%), transparent);
  backdrop-filter: blur(var(--blur-chrome)) saturate(160%);
  -webkit-backdrop-filter: blur(var(--blur-chrome)) saturate(160%);
  border-bottom: var(--border-width) solid var(--line);
}

.ui-shell-title {
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: var(--heading-weight);
  text-transform: var(--heading-transform);
  letter-spacing: var(--ls-title);
  color: var(--ink);
}

.ui-shell-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  color: var(--ink-dim);
}

.ui-burger {
  width: 32px; height: 28px;
  display: grid;
  align-content: center;
  gap: 4px;
  padding: 0 6px;
  background: none;
  border: var(--btn-border-width) solid var(--btn-border);
  border-radius: var(--btn-radius);
  cursor: pointer;
}

.ui-burger span { display: block; height: 2px; background: var(--ink); }

.ui-shell-body {
  flex: 1;
  overflow: auto;
  padding: calc(var(--panel-pad) * var(--density));
  max-width: var(--content-max);
  width: 100%;
  /* Centrada: pegada a la izquierda, un --content-max menor que la
     pantalla dejaba una franja muerta enorme a la derecha. */
  margin-inline: auto;
}

.ui-shell-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--gap);
  margin-bottom: var(--gap);
}

/* Variantes de layout */
.ui[data-layout="topbar"] .ui-shell-nav,
.ui[data-layout="topbar"] .ui-burger,
.ui[data-layout="sidebar"] .ui-burger,
.ui[data-layout="compact"] .ui-burger { display: none; }

.ui[data-layout="compact"] .ui-shell-nav { width: var(--nav-w-min); }

.ui[data-layout="compact"] .ui-side-text,
.ui[data-layout="compact"] .ui-shell-name,
.ui[data-layout="compact"] .ui-shell-side .ui-chip { display: none; }

.ui[data-layout="compact"] .ui-side-item { justify-content: center; padding-left: 0; padding-right: 0; }

.ui[data-layout="hamburger"] .ui-shell-nav {
  position: absolute;
  top: 0; bottom: 0; left: 0;
  z-index: 3;
  box-shadow: var(--shadow);
}

.ui[data-layout="hamburger"] .ui-shell-veil { display: block; }

.ui[data-layout="hamburger"] .ui-shell-collapse { display: none; }

/* ═══════════════════════════════════════════════════════════════
   Tratamiento de superficie — data-panel
   ───────────────────────────────────────────────────────────────
   Esta es la decisión ESTRUCTURAL del tema, y la que hace que dos
   temas puedan ser propuestas distintas en vez del mismo sistema
   repintado. Mientras todo el contenido viva dentro de una tarjeta,
   lo único que puede cambiar entre temas es el color.

   · card  — tarjeta: fondo, borde y sombra. Lo de siempre.
   · ruled — sin caja: un filete separa bloques. Denso, de datos.
   · flat  — sin nada: la jerarquía la llevan el espacio y la
             tipografía, que es como trabajan los sistemas que se
             ven bien. Exige aire, así que el tema que lo use tiene
             que subir --gap y --space-*.
   ═══════════════════════════════════════════════════════════════ */

/* ── Filete ─────────────────────────────────────────────────── */
.ui[data-panel="ruled"] :where(.ui-panel, .ui-stat) {
  background: none;
  border: 0;
  border-top: var(--border-width) solid var(--line);
  border-radius: 0;
  box-shadow: none;
}

.ui[data-panel="ruled"] .ui-panel-head {
  padding-left: 0;
  padding-right: 0;
  border-bottom: 0;
}

.ui[data-panel="ruled"] .ui-panel-body { padding-left: 0; padding-right: 0; }

.ui[data-panel="ruled"] .ui-stat { padding: var(--space-2) 0 0; }

/* Las filas mandan sobre las cajas: filete arriba y nada más */
.ui[data-panel="ruled"] .ui-table td { border-bottom: var(--border-width) solid var(--line); }

.ui[data-panel="ruled"] :where(.ui-card, .ui-col, .ui-feature, .ui-price, .ui-dash-card) {
  background: none;
  border: 0;
  border-top: var(--border-width) solid var(--line);
  border-radius: 0;
  box-shadow: none;
}

/* ── Sin caja ───────────────────────────────────────────────── */
.ui[data-panel="flat"] :where(.ui-panel, .ui-stat, .ui-card, .ui-col,
  .ui-feature, .ui-price, .ui-dash-card, .ui-settings) {
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.ui[data-panel="flat"] :where(.ui-panel-head, .ui-panel-body,
  .ui-table-foot, .ui-toolbar) {
  padding-left: 0;
  padding-right: 0;
  border-bottom: 0;
  border-top: 0;
}

.ui[data-panel="flat"] .ui-panel-head {
  /* El título deja de ser la barra de una caja y pasa a ser un rótulo:
     es lo que sostiene la jerarquía cuando no hay marco que la marque. */
  padding-bottom: var(--space-2);
  margin-bottom: var(--space-2);
}

.ui[data-panel="flat"] .ui-stat { padding: 0; }

/* Sin marco, dos paneles seguidos se pegan: el aire los separa */
.ui[data-panel="flat"] .ui-panel + .ui-panel { margin-top: var(--space-6); }

/* ...pero solo en flujo: dentro de una rejilla ese margen escalonaba la
   fila (la primera tarjeta quedaba más alta que sus hermanas). Ahí el
   aire ya lo pone el gap de la rejilla. */
.ui[data-panel="flat"] [style*="display:grid"] > .ui-panel + .ui-panel { margin-top: 0; }

.ui[data-panel="flat"] .ui-table th { border-bottom: var(--border-width) solid var(--line); }

.ui[data-panel="flat"] .ui-table td { border-bottom: 0; }

/* El menú lateral tampoco es una superficie: sólo una columna de texto */
.ui[data-panel="flat"] :where(.ui-side, .ui-shell-nav, .ui-shell-top) {
  background: none;
  border: 0;
}

/* El acordeón cierra página a menudo y sin caja se leía como dos líneas
   de texto suelto en un cuadrante vacío (~500×300px de hueco en los
   temas sin marco). En ruled entra al sistema de filetes: raya ARRIBA,
   como los paneles, y no abajo. */
.ui[data-panel="ruled"] .ui-accordion {
  border-bottom: 0;
  border-top: var(--border-width) solid var(--line);
}

/* En flat, una lámina de --surface le da cuerpo de sección diseñada;
   el padding lateral despega el texto del borde de la lámina (el resto
   del tema flat no lo necesita porque no tiene cajas). */
.ui[data-panel="flat"] .ui-accordion {
  border-bottom: 0;
  background: var(--surface);
  border-radius: var(--radius-md);
  padding: 0 var(--space-3);
}

.ui[data-panel="flat"] .ui-accordion + .ui-accordion { margin-top: var(--space-2); }

/* ─── Enlaces y migas ────────────────────────────────────────── */
.ui-link {
  color: var(--link);
  text-decoration: none;
  border-bottom: var(--border-width) solid transparent;
}

.ui-link:hover { color: var(--link-hover); border-bottom-color: currentColor; }

.ui-breadcrumb {
  display: flex;
  gap: 8px;
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-faint);
  margin-bottom: 10px;
}

.ui-breadcrumb a { color: var(--link); text-decoration: none; }

.ui-breadcrumb a:hover { color: var(--link-hover); }

.ui-breadcrumb .is-current { color: var(--ink); }

/* ─── Navegación lateral ─────────────────────────────────────── */
.ui-side {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px;
  background: var(--nav-bg);
  border-radius: var(--panel-radius);
}

.ui-side-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: calc(9px * var(--density)) 12px;
  border-radius: var(--nav-radius);
  color: var(--nav-ink);
  text-decoration: none;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: var(--fw-nav);
  text-transform: var(--heading-transform);
  letter-spacing: var(--ls-title);
}

.ui-side-item:hover { background: var(--surface-2); }

.ui-side-item.active { background: var(--nav-active-bg); color: var(--nav-active-ink); }

.ui-side-item.is-disabled { opacity: 0.4; }

.ui-side-dot { width: 6px; height: 6px; background: currentColor; opacity: 0.5; flex: none; }

.ui-side-item.active .ui-side-dot { opacity: 1; }

.ui-side-item .ui-chip { margin-left: auto; }

/* ─── Pestañas ───────────────────────────────────────────────── */
.ui-tabs {
  display: flex;
  gap: 2px;
  padding: 0 8px;
  border-bottom: var(--panel-border-width) solid var(--panel-border);
}

.ui-tab {
  background: none;
  border: 0;
  border-bottom: var(--tab-indicator-h) solid transparent;
  margin-bottom: calc(-1 * var(--panel-border-width));
  padding: 10px 12px;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: var(--heading-weight);
  text-transform: var(--heading-transform);
  letter-spacing: var(--ls-title);
  color: var(--tab-ink);
  cursor: pointer;
}

.ui-tab:hover { color: var(--tab-active-ink); }

.ui-tab.active { color: var(--tab-active-ink); border-bottom-color: var(--tab-indicator); }

.ui-tab.is-disabled { opacity: 0.4; }

.ui-alert {
  --alert-color: var(--info);
  color: var(--ink);
  background: var(--panel-bg);
  background: color-mix(in srgb, var(--alert-color) calc(var(--alert-tint) * 100%), var(--panel-bg));
  border: var(--border-width) solid var(--alert-color);
  border-radius: var(--alert-radius);
  padding: 10px 14px;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.ui-alert strong {
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--alert-color);
  margin-right: 8px;
}

.ui-alert-ok     { --alert-color: var(--ok); }

.ui-alert-warn   { --alert-color: var(--warn); }

.ui-alert-danger { --alert-color: var(--danger); }

.ui-alert-info   { --alert-color: var(--info); }

.ui-check, .ui-switch {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-body);
  color: var(--ink);
  cursor: pointer;
}

.ui-check.is-disabled { opacity: 0.45; cursor: not-allowed; }

.ui input[type="checkbox"],
.ui input[type="radio"] {
  -webkit-appearance: none;
  appearance: none;
  width: 16px; height: 16px;
  flex: none;
  margin: 0;
  display: grid;
  place-items: center;
  background: var(--control-bg);
  border: var(--border-width) solid var(--line-strong);
  border-radius: var(--control-radius);
  cursor: pointer;
  transition: background-color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}

.ui input[type="radio"] { border-radius: 50%; }

.ui input[type="checkbox"]:checked {
  background: var(--control-accent);
  border-color: var(--control-accent);
}

/* La palomita y el punto del radio existen SIEMPRE, pero invisibles:
   al marcar solo cambian opacity y transform, que son lo único que se
   anima barato. Si la marca naciera al marcar (content condicionado a
   :checked, como antes) aparecería a saltos, sin transición posible. */
.ui input[type="checkbox"]::after {
  content: '';
  width: 9px; height: 5px;
  border-left: 2px solid var(--accent-ink);
  border-bottom: 2px solid var(--accent-ink);
  transform: rotate(-45deg) translate(0, -1px) scale(0.4);
  opacity: 0;
  transition: transform var(--dur-fast) ease, opacity var(--dur-fast) ease;
}

.ui input[type="checkbox"]:checked::after {
  transform: rotate(-45deg) translate(0, -1px);
  opacity: 1;
}

.ui input[type="radio"]:checked { border-color: var(--control-accent); }

.ui input[type="radio"]::after {
  content: '';
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--control-accent);
  transform: scale(0.4);
  opacity: 0;
  transition: transform var(--dur-fast) ease, opacity var(--dur-fast) ease;
}

.ui input[type="radio"]:checked::after { transform: scale(1); opacity: 1; }

.ui input[type="checkbox"]:focus-visible,
.ui input[type="radio"]:focus-visible {
  outline: var(--focus-width) solid var(--focus-ring);
  outline-offset: 2px;
}

.ui-switch input { position: absolute; opacity: 0; pointer-events: none; }

.ui-switch-track {
  position: relative;
  width: 38px; height: 20px;
  flex: none;
  border-radius: 999px;
  background: var(--control-bg);
  border: var(--border-width) solid var(--line-strong);
  transition: background-color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}

.ui-switch-track::after {
  content: '';
  position: absolute;
  top: 50%; left: 2px;
  transform: translate(0, -50%);
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--ink-dim);
  /* La bolita viaja con transform y no con left: el navegador la mueve
     en composición sin recalcular layout en cada fotograma. El destino
     (18px) es el mismo left:20px de antes menos el arranque de 2px. */
  transition: transform var(--dur-fast) ease, background-color var(--dur-fast) ease;
}

.ui-switch input:checked + .ui-switch-track {
  background: var(--control-accent);
  border-color: var(--control-accent);
}

.ui-switch input:checked + .ui-switch-track::after { transform: translate(18px, -50%); background: var(--accent-ink); }

/* ─── Estados de botón ───────────────────────────────────────── */
.ui-btn.is-hover { background: var(--surface-3); border-color: var(--ink-faint); }

.ui-btn-primary.is-hover {
  background: var(--btn-primary-bg);
  border-color: var(--btn-primary-border);
  filter: brightness(1.08);
}

.ui-btn.is-focus { outline: var(--focus-width) solid var(--focus-ring); outline-offset: 2px; }

.ui-btn:disabled { opacity: 0.45; cursor: not-allowed; }

.ui-btn-ghost { background: transparent; color: var(--ink-dim); }

/* ─── Menú desplegable ───────────────────────────────────────── */
.ui-menu {
  max-width: 300px;
  padding: var(--space-1);
  background: var(--menu-bg);
  border: var(--panel-border-width) solid var(--panel-border);
  border-radius: var(--menu-radius);
  box-shadow: var(--shadow-md);
}

.ui-menu-item {
  padding: 8px 10px;
  border-radius: var(--menu-radius);
  color: var(--menu-ink);
  font-size: var(--fs-body);
  cursor: pointer;
}

.ui-menu-item:hover, .ui-menu-item.is-active { background: var(--menu-active-bg); }

.ui-menu-item.is-danger { color: var(--danger); }

.ui-menu-sep { height: var(--border-width); background: var(--line); margin: 5px 0; }

/* ─── Tooltip ────────────────────────────────────────────────── */
.ui-tooltip {
  position: relative;
  display: inline-block;
  margin-bottom: 16px;
  padding: 6px 10px;
  background: var(--tooltip-bg);
  color: var(--tooltip-ink);
  border-radius: var(--tooltip-radius);
  font-size: var(--fs-label);
  box-shadow: var(--shadow);
}

.ui-tooltip::after {
  content: '';
  position: absolute;
  top: 100%; left: 18px;
  border: 6px solid transparent;
  border-top-color: var(--tooltip-bg);
}

.ui-chip {
  display: inline-flex;
  align-items: center;
  font-weight: var(--fw-badge);
  background: var(--chip-bg);
  color: var(--chip-ink);
  border-radius: var(--chip-radius);
  padding: 2px 9px;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
}

.ui-chip.is-on { background: var(--accent); color: var(--accent-ink); }

.ui-avatar {
  /* Medida mínima, no fija: dos iniciales a 12px con tracking miden casi
     los 30px, y al solaparse en pila el siguiente avatar le comía las
     letras al anterior. Con min-width y relleno, la ficha crece. */
  min-width: 30px; height: 30px;
  padding: 0 5px;
  flex: none;
  /* inline-grid, no grid: como caja de bloque, dentro de una celda de
     tabla se estiraba al ancho completo (losa de acento de 150 px).
     En .ui-avatars da igual: los hijos flex ignoran el nivel inline. */
  display: inline-grid;
  place-items: center;
  background: var(--avatar-bg);
  color: var(--avatar-ink);
  border-radius: var(--avatar-radius);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.04em;
}

.ui-avatar.is-muted { background: var(--surface-3); color: var(--ink-dim); }

/* En una tabla el responsable es metadato, no acción: con el acento
   macizo repetido en cada fila competía con el botón primario y los
   badges. En tono de chip, el acento recupera su intención. */
.ui-table .ui-avatar { background: var(--chip-bg); color: var(--chip-ink); }

.ui-meta { font-size: var(--fs-label); color: var(--ink-faint); }

.ui-progress {
  height: var(--progress-h);
  background: var(--progress-track);
  border-radius: 999px;
  overflow: hidden;
  margin-bottom: 14px;
}

/* Degradado de marca delante del relleno, como ya hace la barra de las
   diapositivas: con --gradient-brand: none no cambia nada. */
.ui-progress > span { display: block; height: 100%; background: var(--gradient-brand), var(--progress-fill); }

.ui-progress-warn > span { background: var(--warn); }

.ui-pager { display: flex; gap: 6px; flex-wrap: wrap; }

.ui-page {
  min-width: 30px; height: 30px;
  padding: 0 8px;
  background: var(--btn-bg);
  color: var(--btn-ink);
  border: var(--btn-border-width) solid var(--btn-border);
  border-radius: var(--page-radius);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  cursor: pointer;
}

.ui-page:hover { background: var(--surface-3); }

.ui-page.is-active {
  background: var(--page-active-bg);
  border-color: var(--page-active-bg);
  color: var(--page-active-ink);
}

/* ─── Área con desplazamiento ────────────────────────────────── */
.ui-scrollbox {
  max-height: 156px;
  overflow-y: auto;
  padding-right: 8px;
  scrollbar-width: thin;
  scrollbar-color: var(--scroll-thumb) var(--scroll-track);
}

.ui-scrollbox::-webkit-scrollbar { width: var(--scroll-size); }

.ui-scrollbox::-webkit-scrollbar-track { background: var(--scroll-track); }

.ui-scrollbox::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border-radius: 999px; }

.ui-log {
  padding: 6px 0;
  font-size: var(--fs-table);
  color: var(--ink-dim);
  border-bottom: var(--border-width) solid var(--panel-border);
}

.ui-log .mono { color: var(--ink-faint); margin-right: 8px; }

.ui-dialog {
  position: relative;
  width: min(440px, 100%);
  background: var(--dialog-bg);
  border: var(--panel-border-width) solid var(--dialog-border);
  border-radius: var(--dialog-radius);
  box-shadow: var(--shadow-lg);
}

.ui-dialog-head {
  padding: 12px 16px;
  border-bottom: var(--panel-border-width) solid var(--dialog-border);
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: var(--heading-weight);
  text-transform: var(--heading-transform);
  letter-spacing: var(--ls-title);
  color: var(--ink);
}

.ui-dialog-body { padding: var(--panel-pad); }

.ui-dialog-foot {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  padding: 12px 16px;
  border-top: var(--panel-border-width) solid var(--dialog-border);
}

/* ─── Formulario: etiqueta, obligatorio, ayuda y validación ──── */

/* Campo completo: la etiqueta encima y el control debajo. Es la unidad
   con la que se montan los formularios; .ui-form los pone en rejilla. */
.ui-field { min-width: 0; margin-bottom: var(--space-3); }

.ui-field > label {
  display: block;
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--ink-dim);
  margin-bottom: var(--space-1);
}

.ui-field > input,
.ui-field > select,
.ui-field > textarea { width: 100%; }

.ui-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--gap);
}

.ui-label {
  display: block;
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--ink-dim);
  margin-bottom: var(--space-1);
}

.ui-req { color: var(--danger); }

.ui-field-hint, .ui-field-error, .ui-field-ok {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--fs-label);
  color: var(--ink-faint);
}

.ui-field-error { color: var(--danger); }

.ui-field-ok { color: var(--ok); }

.ui input.is-invalid { border-color: var(--danger); background: var(--danger-soft); }

.ui input.is-valid { border-color: var(--ok); }

/* Campo con addon o botón interior */
.ui-input-group { display: flex; align-items: stretch; }

.ui-input-group > input { border-radius: 0; }

.ui-input-group > :first-child { border-top-left-radius: var(--input-radius); border-bottom-left-radius: var(--input-radius); }

.ui-input-group > :last-child { border-top-right-radius: var(--input-radius); border-bottom-right-radius: var(--input-radius); }

.ui-addon, .ui-addon-btn {
  display: grid;
  place-items: center;
  min-height: calc(var(--input-h) * var(--density));
  padding: 0 var(--space-3);
  background: var(--surface-inset);
  border: var(--input-border-width) solid var(--input-border);
  color: var(--ink-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  white-space: nowrap;
}

.ui-addon { border-right: 0; }

.ui-addon-btn { border-left: 0; cursor: pointer; }

.ui-addon-btn:hover { background: var(--surface-3); color: var(--ink); }

/* ─── Buscador ───────────────────────────────────────────────── */
.ui-search { position: relative; flex: 1; min-width: 180px; }

.ui-search-icon {
  position: absolute;
  left: var(--space-3); top: 50%;
  transform: translateY(-50%);
  color: var(--ink-faint);
  font-size: 15px;
  pointer-events: none;
}

.ui .ui-search input { padding-left: calc(var(--space-3) * 2 + 8px); }

.ui-search-sm { max-width: 220px; }

/* ─── Control segmentado ─────────────────────────────────────── */
.ui-segmented {
  display: inline-flex;
  padding: 2px;
  gap: 2px;
  background: var(--surface-inset);
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius-sm);
}

.ui-seg {
  padding: 0 var(--space-3);
  min-height: calc(var(--btn-h) * var(--density) - 6px);
  background: none;
  border: 0;
  border-radius: calc(var(--radius-sm) - 2px);
  color: var(--ink-dim);
  font-family: var(--font-body);
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  cursor: pointer;
}

.ui-seg.is-on { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-sm); }

/* ─── Botón a ancho completo ─────────────────────────────────── */
.ui-btn-block { display: flex; width: 100%; justify-content: center; margin-top: var(--space-3); }

/* ─── Avisos flotantes ───────────────────────────────────────── */
.ui-toasts { display: flex; flex-direction: column; gap: var(--space-2); }

.ui-toast {
  position: relative;
  padding: var(--space-3) var(--space-4);
  padding-left: calc(var(--space-4) + 4px);
  background: var(--menu-bg);
  border: var(--border-width) solid var(--line);
  border-left: 4px solid var(--ink-faint);
  border-radius: var(--menu-radius);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-body);
  color: var(--ink);
}

.ui-toast strong { margin-right: var(--space-2); font-weight: var(--fw-semibold); }

.ui-toast-ok { border-left-color: var(--ok); }

.ui-toast-ok strong { color: var(--ok); }

.ui-toast-danger { border-left-color: var(--danger); }

.ui-toast-danger strong { color: var(--danger); }

/* ─── Cargando: spinner, anillo y esqueleto ──────────────────── */
.ui-spinner {
  width: 22px; height: 22px;
  flex: none;
  border: 2.5px solid var(--line-strong);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: ui-spin 0.8s linear infinite;
}

@keyframes ui-spin { to { transform: rotate(360deg); } }

.ui-ring { position: relative; width: 46px; height: 46px; flex: none; display: grid; place-items: center; }

.ui-ring svg { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); }

.ui-ring circle { fill: none; stroke-width: 4; }

.ui-ring-track { stroke: var(--progress-track); }

.ui-ring-fill {
  stroke: var(--progress-fill);
  stroke-linecap: round;
  stroke-dasharray: 100.5;
  stroke-dashoffset: calc(100.5 - (100.5 * var(--val) / 100));
}

.ui-ring .mono { font-size: 9px; color: var(--ink-dim); }

.ui-skeleton-group { display: flex; flex-direction: column; gap: var(--space-2); }

.ui-skeleton {
  display: block;
  height: 10px;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--surface-3) 25%, var(--surface-2) 50%, var(--surface-3) 75%);
  background-size: 240% 100%;
  animation: ui-shimmer 1.4s ease-in-out infinite;
}

@keyframes ui-shimmer { to { background-position: -240% 0; } }

/* ─── Estado vacío ───────────────────────────────────────────── */
.ui-empty { text-align: center; padding: var(--space-5) var(--space-4); }

.ui-empty-icon {
  width: 46px; height: 46px;
  margin: 0 auto var(--space-3);
  display: grid; place-items: center;
  border-radius: var(--radius-pill);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 22px;
}

.ui-empty-title {
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: var(--heading-weight);
  color: var(--ink-strong);
  margin-bottom: var(--space-1);
}

.ui-empty-text { font-size: var(--fs-body); color: var(--ink-dim); margin: 0 0 var(--space-4); }

/* ─── Tabla de trabajo ───────────────────────────────────────── */
.ui-toolbar {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  padding: var(--space-3) var(--panel-pad);
  border-bottom: var(--panel-border-width) solid var(--panel-border);
}

.ui-table-work { width: 100%; }

.ui-table-work th.is-sorted { color: var(--accent); }

.ui-sort { font-size: 8px; margin-left: 3px; }

.ui-th-check, .ui-table-work td:first-child { width: 34px; text-align: center; }

.ui-th-act, .ui-td-act { width: 36px; text-align: right; }

.ui-table-work tbody tr.is-selected { background: var(--accent-soft); }

.ui-row-menu {
  width: 24px; height: 24px;
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--ink-dim);
  cursor: pointer;
  line-height: 1;
}

.ui-row-menu:hover { background: var(--surface-3); color: var(--ink); }

/* width:auto es obligatorio: el min-width de .ui-avatar le ganaría al
   width de aquí y la ficha pequeña saldría rectangular. El tracking a
   cero deja sitio a dos iniciales sin que el solape se las coma. */
.ui-avatar-sm {
  min-width: 24px; width: auto; height: 24px;
  padding: 0 4px;
  font-size: 9px;
  letter-spacing: 0;
}

.ui-table-foot {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-3) var(--panel-pad);
  border-top: var(--panel-border-width) solid var(--panel-border);
  /* Dentro del panel-columna, el pie cae al borde inferior cuando la
     rejilla estira la tarjeta; fuera de un flex, auto vale 0 y no pasa
     nada. Vale para los tres tratamientos por lo mismo. */
  margin-top: auto;
}

.ui-table-foot .ui-pager { margin-left: auto; }

.ui-meta { font-size: var(--fs-label); color: var(--ink-faint); }

/* ─── Ficha clave/valor y pasos ──────────────────────────────── */
.ui-kv { display: grid; grid-template-columns: auto 1fr; gap: var(--space-2) var(--space-4); margin: 0; }

.ui-kv dt {
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--ink-faint);
}

.ui-kv dd { margin: 0; font-size: var(--fs-body); color: var(--ink); }

.ui-stepper { display: flex; flex-wrap: wrap; gap: var(--space-4); }

.ui-step {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-label);
  color: var(--ink-faint);
}

.ui-step-dot {
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: var(--radius-pill);
  border: var(--border-width) solid var(--line-strong);
  font-family: var(--font-mono);
  font-size: 10px;
}

.ui-step.is-done { color: var(--ok); }

.ui-step.is-done .ui-step-dot { border-color: var(--ok); background: var(--ok-soft); color: var(--ok); }

.ui-step.is-current { color: var(--ink); }

.ui-step.is-current .ui-step-dot { border-color: var(--accent); background: var(--accent); color: var(--accent-ink); }

/* ─── Línea de tiempo ────────────────────────────────────────── */
.ui-timeline { list-style: none; margin: 0 0 var(--space-2); padding: 0 0 0 var(--space-4); border-left: var(--border-width) solid var(--line); }

.ui-tl-item {
  position: relative;
  padding: 0 0 var(--space-3) var(--space-3);
  font-size: var(--fs-body);
  color: var(--ink-dim);
}

.ui-tl-item::before {
  content: '';
  position: absolute;
  left: calc(-1 * var(--space-3) - 4px); top: 6px;
  width: 9px; height: 9px;
  border-radius: var(--radius-pill);
  background: var(--info);
  box-shadow: 0 0 0 3px var(--surface);
}

.ui-tl-item .mono { color: var(--ink-faint); margin-right: var(--space-2); }

.ui-tl-ok::before { background: var(--ok); }

.ui-tl-warn::before { background: var(--warn); }

.ui-tl-danger::before { background: var(--danger); }

/* ─── Acordeón ───────────────────────────────────────────────── */
.ui-accordion { border-bottom: var(--border-width) solid var(--line); }

.ui-accordion > summary {
  list-style: none;
  cursor: pointer;
  padding: var(--space-3) 0;
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.ui-accordion > summary::-webkit-details-marker { display: none; }

.ui-accordion > summary::before {
  content: '+';
  color: var(--accent);
  font-family: var(--font-mono);
}

.ui-accordion[open] > summary::before { content: '−'; }

/* La respuesta cuelga de su pregunta: sangrada hasta pasar el signo +,
   con medida de lectura y un tono por debajo. Sin esto salía a sangre
   izquierda y a todo el ancho, como un párrafo perdido entre filetes. */
.ui-accordion > p {
  margin: 0 0 var(--space-3);
  padding-left: calc(var(--space-2) + 1ch);
  max-width: 70ch;
  font-size: var(--fs-body);
  color: var(--ink-dim);
}

/* ─── Pantalla de acceso, sin armazón ────────────────────────── */
/* La página de acceso LLENA su contenedor, como el armazón: con la
   altura mínima fija de antes, login y logout flotaban cortos dejando
   medio lienzo vacío debajo (también en la página exportada). */
.ui-auth {
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: 100%;
  border: var(--border-width) solid var(--line);
  border-radius: var(--panel-radius);
  overflow: hidden;
}

/* Exportada, la pantalla de acceso es LA ventana: sin marco de tarjeta
   y a toda la altura. El selector de hijo directo no toca el lienzo
   del editor, donde .ui-auth vive dentro de #preview/#pagePreview. */
body.ui > .ui-auth { min-height: 100vh; border: 0; border-radius: 0; }

/* El panel de marca no es una losa de acento: recibe las capas de luz
   del tema —mesh y degradado de marca— con el acento de respaldo, el
   mismo patrón que .ui-cover. El MESH va delante a propósito: los
   degradados de marca son opacos y, detrás de ellos, los glows y el
   grano del mesh no se veían nunca (media pantalla quedaba como
   degradado liso de dos tonos). Con los tokens en none no cambia nada
   y la composición (marca arriba, reclamo-cartel abajo) sigue sola. */
.ui-auth-aside {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-5);
  padding: var(--space-6) var(--space-5);
  background: var(--page-mesh), var(--gradient-brand), var(--accent);
  color: var(--accent-ink);
}

.ui-auth-brand { display: flex; align-items: center; gap: var(--space-2); font-family: var(--font-display); font-size: var(--fs-title); }

/* Sobre el aside, la ficha del logo se invertía en fantasma: pintaba
   acento sobre el propio acento del fondo (violeta sobre violeta en
   Consola, blanco sobre blanco en Alto contraste) y la marca quedaba
   como texto suelto sin ancla. Invertida —la tinta del acento como
   placa y el acento como letra— el contraste es exactamente el de la
   pareja original, en los tres tratamientos y en claro y oscuro. */
.ui-auth-aside .ui-shell-logo { background: var(--accent-ink); color: var(--accent); }

/* El reclamo es el titular-cartel del aside: tipografía de display en
   grande, con lo que cada tema le imprime su carácter (serif editorial,
   mono densa, palo rotunda). Antes era una frase en cuerpo de texto
   perdida al pie de media pantalla. */
.ui-auth-claim {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(20px, 2.6vw, calc(var(--fs-title-lg) * 1.5));
  font-weight: var(--fw-bold);
  /* Como el resto de titulares de display: por debajo de 1.2 los glifos
     se salen de la caja. */
  line-height: max(var(--lh-tight), 1.2);
  padding-block: 0.06em;
  letter-spacing: var(--ls-title);
  opacity: 1;
  max-width: 22ch;
}

/* Todo lo que vive dentro del panel de marca hereda su tinta: los tonos
   de texto del tema (ink-faint, ink-dim) están pensados para el fondo
   del tema, no para el acento, y encima de este podrian no contrastar. */
.ui-auth-aside .ui-kv dt,
.ui-auth-aside .ui-kv dd,
.ui-auth-aside .ui-meta { color: inherit; }

.ui-auth-aside .ui-kv dt, .ui-auth-aside .ui-meta { opacity: 0.72; }

/* La mitad del formulario también deja pasar la atmósfera del tema */
.ui-auth-main { display: grid; place-items: center; padding: var(--space-5); background: var(--page-mesh), var(--bg); }

.ui-auth-card {
  width: 100%;
  /* 400px, no 300: con la tarjeta capada, el correo del ui-kv rompía en
     dos líneas (comprobado: a 380 aún partía la última letra con los
     cuerpos mono de Pliego) y el conjunto quedaba enano en una columna
     de 700px. */
  max-width: 400px;
  padding: var(--space-5);
  background: var(--panel-bg);
  border: var(--panel-border-width) solid var(--panel-border);
  border-radius: var(--panel-radius);
  /* Dos declaraciones a propósito. La tarjeta es el punto focal de la
     página y suma la sombra DE FIRMA del tema (--shadow, que en varios
     temas trae resplandor de color) a la elevación normal: sin ella,
     en los temas flat la tarjeta no tenía ningún momento. Si --shadow
     vale 'none', la lista entera se invalida en tiempo de cómputo y
     box-shadow cae a su valor inicial (none): exactamente lo que esos
     temas piden, y para eso la primera línea queda como red visible
     en herramientas. */
  box-shadow: var(--shadow-md);
  box-shadow: var(--shadow-md), var(--shadow);
}

.ui-auth-title {
  font-family: var(--font-display);
  /* Cuerpo de titular grande: con --fs-title el "Entrar" pesaba menos
     que el logotipo que tiene encima y nada mandaba en la tarjeta. */
  font-size: var(--fs-title-lg);
  font-weight: var(--heading-weight);
  text-transform: var(--heading-transform);
  letter-spacing: var(--ls-title);
  color: var(--ink-strong);
  /* Corto: el subtítulo va pegado como segunda línea del punto focal;
     el aire grande lo pone él por debajo. */
  margin-bottom: var(--space-1);
}

.ui-or {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-3) 0;
  color: var(--ink-faint);
  font-size: var(--fs-label);
}

.ui-or::before, .ui-or::after {
  content: '';
  flex: 1;
  height: var(--border-width);
  background: var(--line);
}

/* Login completo: logo, error, olvidé la contraseña, recordarme, SSO y legal */
.ui-auth-logo { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-4); }

.ui-auth-logo-text { font-family: var(--font-display); font-size: var(--fs-title); color: var(--ink); }

.ui-auth-logo-text b { color: var(--accent); }

/* Sin margen negativo: el par título/subtítulo respira (el hueco corto
   lo da el título) y el margen inferior separa el bloque de los campos. */
.ui-auth-sub { margin: 0 0 var(--space-4); font-size: var(--fs-body); color: var(--ink-dim); }

.ui-auth-error { margin-bottom: var(--space-4); font-size: var(--fs-label); }

.ui-label-row { display: flex; align-items: baseline; gap: var(--space-2); }

.ui-auth-forgot { margin-left: auto; font-size: var(--fs-label); }

.ui-auth-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-3) 0;
}

.ui-auth-row .ui-meta { margin-left: auto; }

.ui-auth-sso { display: flex; flex-direction: column; gap: var(--space-2); }

.ui-auth-sso .ui-btn-block { margin-top: 0; }

.ui-sso-mark { color: var(--accent); margin-right: var(--space-2); }

.ui-auth-legal {
  margin: var(--space-4) 0 0;
  font-size: var(--fs-label);
  line-height: var(--lh-body);
  color: var(--ink-faint);
  text-align: center;
}

/* ─── Lista de ajustes ───────────────────────────────────────── */
.ui-settings { display: flex; flex-direction: column; }

.ui-setting {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--panel-pad);
  border-bottom: var(--panel-border-width) solid var(--panel-border);
}

.ui-setting:last-child { border-bottom: 0; }

.ui-setting-text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }

.ui-setting-text b { font-size: var(--fs-body); font-weight: var(--fw-semibold); color: var(--ink); }

.ui-setting-text span { font-size: var(--fs-label); color: var(--ink-faint); }

.ui-setting > select, .ui-setting > .ui-btn { width: auto; flex: none; }

/* ─── Carga de archivos ──────────────────────────────────────── */
.ui-dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-5) var(--space-4);
  margin-bottom: var(--space-4);
  background: var(--surface-inset);
  border: 2px dashed var(--line-strong);
  border-radius: var(--radius-md);
  color: var(--ink-dim);
  text-align: center;
}

.ui-dropzone-icon { font-size: 24px; color: var(--accent); }

.ui-dropzone b { color: var(--ink); font-size: var(--fs-body); }

/* ─── Submenú anidado ───────────────────────────────────────── */
.ui-side-nested { padding: 0; background: none; }

.ui-subnav { display: flex; flex-direction: column; margin-left: var(--space-4); border-left: var(--border-width) solid var(--line); }

.ui-subnav-item {
  padding: var(--space-2) var(--space-3);
  font-size: var(--fs-label);
  color: var(--nav-ink);
  text-decoration: none;
  border-left: var(--nav-active-bar-w) solid transparent;
  margin-left: calc(-1 * var(--border-width));
}

.ui-subnav-item:hover { color: var(--ink); }

.ui-subnav-item.is-on { color: var(--nav-active-ink); border-left-color: var(--nav-active-ink); }

/* ─── Tablero ────────────────────────────────────────────────── */
.ui-board { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gap); }

.ui-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--surface-inset);
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius-md);
}

.ui-col-head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--ink-dim);
  margin-bottom: var(--space-1);
}

.ui-col-head .ui-chip { margin-left: auto; }

.ui-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
  padding: var(--space-3);
  background: var(--panel-bg);
  border: var(--panel-border-width) solid var(--panel-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
}

.ui-card b { font-size: var(--fs-body); color: var(--ink); font-weight: var(--fw-medium); }

.ui-card.is-dragging { box-shadow: var(--shadow-lg); transform: rotate(-1.5deg); border-color: var(--accent); }

/* ─── Perfil ─────────────────────────────────────────────────── */
.ui-profile { overflow: hidden; }

.ui-cover { height: 76px; background: var(--gradient-brand), var(--accent); }

/* Cuatro portadas idénticas en fila delatan plantilla y multiplican el
   acento (la banda de Ponentes era una losa cuádruple del mismo
   degradado). Una luz radial en una esquina DISTINTA por tarjeta —dos
   amaneceres blancos y una caída oscura— rompe los clones sin tocar la
   paleta ni pedir tokens nuevos. Va por :nth-child para funcionar en
   cualquier rejilla, en claro y oscuro y en los tres data-panel. */
.ui-profile:nth-child(3n+1) .ui-cover {
  background: radial-gradient(120% 150% at 12% -20%, rgba(255,255,255,0.25), transparent 55%), var(--gradient-brand), var(--accent);
}

.ui-profile:nth-child(3n+2) .ui-cover {
  background: radial-gradient(120% 150% at 85% -20%, rgba(255,255,255,0.25), transparent 55%), var(--gradient-brand), var(--accent);
}

.ui-profile:nth-child(3n) .ui-cover {
  background: radial-gradient(120% 150% at 50% 120%, rgba(0,0,0,0.18), transparent 55%), var(--gradient-brand), var(--accent);
}

.ui-profile-body { padding: 0 var(--panel-pad) var(--panel-pad); }

.ui-avatar-lg {
  width: 56px; height: 56px;
  font-size: 18px;
  margin-top: -28px;
  box-shadow: 0 0 0 3px var(--panel-bg);
}

.ui-profile-name {
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: var(--heading-weight);
  color: var(--ink-strong);
  margin-top: var(--space-2);
}

.ui-profile-stats { display: flex; gap: var(--space-5); margin-top: var(--space-4); }

.ui-profile-stats div { display: flex; flex-direction: column; }

.ui-profile-stats b { font-family: var(--font-mono); font-size: var(--fs-title); color: var(--ink); }

.ui-profile-stats span { font-size: var(--fs-label); color: var(--ink-faint); }

/* ─── KPI con tendencia y punto de notificación ──────────────── */
.ui-stat-spark { display: flex; align-items: center; gap: var(--space-4); }

.ui-spark { width: 110px; height: 34px; flex: none; }

/* Dentro del KPI, la tendencia ocupa el ancho sobrante del panel en vez
   de quedarse en un sello de 110px con un hueco muerto al lado: el SVG
   lleva viewBox y preserveAspectRatio="none", así que estira limpio. */
.ui-stat-spark .ui-spark { flex: 1; width: auto; min-width: 110px; }

.ui-spark polyline { fill: none; stroke: var(--accent); stroke-width: 2; }

.ui-trend { font-family: var(--font-mono); font-size: var(--fs-badge); margin-left: var(--space-2); }

.ui-trend.is-up { color: var(--ok); }

/* flex:none para que no lo encoja la fila que lo contiene: el icono se
   salía del botón porque la caja se comprimía por debajo de su glifo.
   El min-width lo deja cuadrado, a la misma altura que los demás. */
.ui-icon-btn {
  position: relative;
  flex: none;
  min-width: calc(var(--btn-h) * var(--density));
  padding: 0 var(--space-3);
  justify-content: center;
}

.ui-dot-note {
  position: absolute;
  top: -3px; right: -3px;
  width: 9px; height: 9px;
  border-radius: var(--radius-pill);
  background: var(--danger);
  box-shadow: 0 0 0 2px var(--panel-bg);
}

/* ─── Bloques de página pública ──────────────────────────────── */
/* El héroe abre la página: un halo del acento (rebajado por --accent-soft,
   que cada tema recalcula) le da un momento visual propio sin tocar el
   contraste del texto, en card/ruled/flat y en claro y oscuro. */
.ui-hero {
  padding: calc(var(--space-6) * 1.5) var(--panel-pad) var(--space-6);
  text-align: center;
  background: radial-gradient(760px 340px at 50% -120px, var(--accent-soft), transparent 70%);
}

.ui-hero-title {
  font-family: var(--font-display);
  font-size: clamp(22px, 3.4vw, calc(var(--fs-title-lg) * 1.5));
  font-weight: var(--fw-bold);
  /* Igual que el resto de titulares grandes: por debajo de 1.2 los
     glifos de las fuentes de display se salen de la caja. */
  line-height: max(var(--lh-tight), 1.2);
  padding-block: 0.06em;
  letter-spacing: var(--ls-title);
  color: var(--ink-strong);
  margin: var(--space-3) 0 var(--space-2);
}

.ui-hero-text { font-size: var(--fs-body); color: var(--ink-dim); margin: 0 0 var(--space-4); }

.ui-logos {
  display: flex;
  justify-content: center;
  gap: var(--space-6);
  flex-wrap: wrap;
  padding: var(--space-4);
  border-top: var(--panel-border-width) solid var(--panel-border);
  border-bottom: var(--panel-border-width) solid var(--panel-border);
  font-family: var(--font-display);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-caps);
  color: var(--ink-faint);
}

/* Aire vertical propio: tres columnas de texto pegadas a sus vecinos
   leían como relleno, no como sección. */
.ui-features { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gap); padding: var(--space-5) var(--panel-pad); }

.ui-feature { display: flex; flex-direction: column; gap: var(--space-1); }

.ui-feature-icon {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  margin-bottom: var(--space-1);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 16px;
}

.ui-feature b { font-size: var(--fs-body); color: var(--ink); }

.ui-price {
  margin: 0 var(--panel-pad) var(--panel-pad);
  padding: var(--space-4);
  background: var(--surface-inset);
  border: var(--border-width) solid var(--line);
  border-radius: var(--radius-md);
  max-width: 280px;
}

.ui-price-head {
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--ink-faint);
}

.ui-price-amount { font-family: var(--font-mono); font-size: 30px; color: var(--ink-strong); }

.ui-price-amount span { font-size: var(--fs-label); color: var(--ink-faint); }

.ui-price-list { list-style: none; margin: var(--space-3) 0; padding: 0; }

.ui-price-list li { font-size: var(--fs-body); color: var(--ink-dim); padding: var(--space-1) 0; }

.ui-price-list li::before { content: '✓'; color: var(--ok); margin-right: var(--space-2); }

/* El plan recomendado (el del centro) manda: sin esto las tres columnas
   pesaban igual en la decisión más importante de la página. */
.ui-price:nth-of-type(2) { border-color: var(--accent); box-shadow: var(--shadow); }

/* Con filetes no hay marco que resaltar: lo marca el filete superior */
.ui[data-panel="ruled"] .ui-price:nth-of-type(2) { border-top: 3px solid var(--accent); }

.ui-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  /* El cierre de la página pide más aire que una barra cualquiera */
  padding: var(--space-5) var(--panel-pad);
  background: var(--accent-soft);
  border-top: var(--panel-border-width) solid var(--panel-border);
}

/* Titular de cierre en cuerpo grande: es la última llamada, no un rótulo */
.ui-cta b { font-family: var(--font-display); font-size: var(--fs-title-lg); color: var(--ink-strong); }

.ui-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  padding: var(--space-4) var(--panel-pad);
  border-top: var(--panel-border-width) solid var(--panel-border);
  font-size: var(--fs-label);
  color: var(--ink-faint);
}

/* ─── Capas: cajón, velo y barra de acciones ─────────────────── */
.ui-stage {
  position: relative;
  height: 240px;
  overflow: hidden;
  background: var(--bg);
  border: var(--border-width) solid var(--line);
  border-radius: var(--panel-radius);
}

.ui-stage-veil { position: absolute; inset: 0; z-index: var(--z-drawer); background: var(--overlay); opacity: var(--overlay-alpha); }

.ui-drawer {
  position: absolute;
  top: 0; right: 0; bottom: 0;
  z-index: calc(var(--z-drawer) + 1);
  width: 62%;
  background: var(--dialog-bg);
  border-left: var(--panel-border-width) solid var(--dialog-border);
  box-shadow: var(--shadow-lg);
}

.ui-drawer-head {
  display: flex;
  align-items: center;
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--panel-border-width) solid var(--dialog-border);
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: var(--heading-weight);
  text-transform: var(--heading-transform);
  letter-spacing: var(--ls-title);
  color: var(--ink);
}

.ui-drawer-head .ui-row-menu { margin-left: auto; }

.ui-drawer-body { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-4); }

.ui-actionbar {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
  border-top: var(--border-width) solid var(--line);
  box-shadow: var(--shadow-md);
}

.ui-actionbar .ui-btn:first-of-type { margin-left: auto; }

/* ─── Página de error ────────────────────────────────────────── */
.ui-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  /* Altura fija no: con tipografías grandes el contenido no cabía y se
     salía por abajo. Que crezca lo que necesite a partir de 240. */
  min-height: 240px;
  padding: var(--space-4);
  text-align: center;
  background: var(--page-mesh), var(--bg);
  border: var(--border-width) solid var(--line);
  border-radius: var(--panel-radius);
}

.ui-error-code {
  font-family: var(--font-display);
  font-size: clamp(48px, 9vw, 92px);
  font-weight: var(--fw-bold);
  /* Mismo caso que la cifra del KPI, pero a 92px se notaba mucho más:
     con line-height 1 el «404» se salía hasta 15px de su caja. */
  line-height: 1.2;
  padding-block: 0.06em;
  letter-spacing: var(--ls-title);
  color: var(--accent);
}

.ui-error-title { font-size: var(--fs-title); font-weight: var(--fw-semibold); color: var(--ink-strong); }

.ui-error-text { margin: 0 0 var(--space-3); font-size: var(--fs-body); color: var(--ink-dim); max-width: 32ch; }

/* ─── Mega-menú ──────────────────────────────────────────────── */
.ui-megamenu {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-4);
  padding: var(--space-4);
  background: var(--menu-bg);
  border-radius: var(--menu-radius);
  box-shadow: var(--shadow-md);
}

.ui-mega-item {
  display: block;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  color: var(--menu-ink);
  text-decoration: none;
  font-size: var(--fs-body);
}

.ui-mega-item:hover { background: var(--menu-active-bg); }

.ui-mega-promo {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3);
  background: var(--accent-soft);
  border-radius: var(--radius-sm);
}

.ui-mega-promo b { color: var(--accent); font-size: var(--fs-body); }

/* ─── Tablero componible ─────────────────────────────────────── */
.ui-dash {
  display: grid;
  grid-template-columns: repeat(var(--dash-cols), minmax(0, 1fr));
  gap: var(--gap);
  align-items: start;
}

.ui-dash-card {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--panel-bg);
  border: var(--panel-border-width) solid var(--panel-border);
  border-radius: var(--panel-radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.ui-dash-head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--panel-pad);
  border-bottom: var(--panel-border-width) solid var(--panel-border);
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: var(--heading-weight);
  text-transform: var(--heading-transform);
  letter-spacing: var(--ls-title);
  color: var(--ink);
}

.ui-dash-body { flex: 1; padding: var(--panel-pad); }

.ui-dash-card.is-tall .ui-dash-body { min-height: 190px; }

.ui-dash-fig { display: flex; align-items: flex-end; gap: 6px; height: 100%; min-height: 62px; }

.ui-dash-fig i { flex: 1; background: var(--accent); opacity: 0.55; border-radius: var(--radius-sm) var(--radius-sm) 0 0; }

.ui-dash-big { font-family: var(--font-mono); font-size: var(--fs-stat); color: var(--ink-strong); line-height: max(var(--lh-tight), 1.25); padding-block: 0.06em; }

/* Modo composición: mango, controles y hueco de destino */
body.is-composing .ui-dash-card { cursor: grab; outline: 1px dashed var(--line-strong); outline-offset: 2px; }

body.is-composing .ui-dash-card.is-drag { opacity: 0.35; }

body.is-composing .ui-dash-card.is-over { outline: 2px solid var(--accent); outline-offset: 3px; }

.ui-dash-tools { display: none; gap: 3px; margin-left: auto; }

body.is-composing .ui-dash-tools { display: inline-flex; }

.ui-dash-tool {
  width: 22px; height: 22px;
  display: grid; place-items: center;
  background: var(--surface-inset);
  border: var(--border-width) solid var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--ink-dim);
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
}

.ui-dash-tool:hover { color: var(--ink); border-color: var(--accent); }

.ui-dash-span {
  font-family: var(--font-mono);
  font-size: var(--fs-badge);
  color: var(--ink-faint);
  padding: 0 2px;
}

/* ─── Modo presentación ──────────────────────────────────────── */
.ui-slide {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 260px;
  overflow: hidden;
  background: var(--page-mesh), var(--surface);
  border: var(--panel-border-width) solid var(--panel-border);
  border-radius: var(--panel-radius);
}

.ui-slide-progress { position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--progress-track); }

.ui-slide-progress > span { display: block; height: 100%; background: var(--gradient-brand), var(--progress-fill); }

/* Marcas de esquina del HUD */
.ui-hud { position: absolute; width: 14px; height: 14px; border: 2px solid var(--accent); opacity: 0.55; }

.ui-hud-tl { top: 12px; left: 12px; border-right: 0; border-bottom: 0; }

.ui-hud-tr { top: 12px; right: 12px; border-left: 0; border-bottom: 0; }

.ui-hud-bl { bottom: 40px; left: 12px; border-right: 0; border-top: 0; }

.ui-hud-br { bottom: 40px; right: 12px; border-left: 0; border-top: 0; }

.ui-slide-body { flex: 1; display: flex; flex-direction: column; justify-content: center; padding: var(--space-6) var(--space-5); }

.ui-slide-eyebrow {
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--accent);
  margin-bottom: var(--space-2);
}

.ui-slide-title {
  font-family: var(--font-display);
  font-size: clamp(20px, 2.6vw, calc(var(--fs-title-lg) * 1.35));
  font-weight: var(--fw-bold);
  line-height: max(var(--lh-tight), 1.2);
  padding-block: 0.06em;
  letter-spacing: var(--ls-title);
  color: var(--ink-strong);
}

.ui-slide-text { margin: var(--space-2) 0 0; font-size: var(--fs-body); color: var(--ink-dim); }

.ui-slide-foot {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  border-top: var(--panel-border-width) solid var(--panel-border);
}

.ui-dots { display: inline-flex; gap: 5px; }

.ui-dots i { width: 6px; height: 6px; border-radius: var(--radius-pill); background: var(--line-strong); }

.ui-dots i.is-on { background: var(--accent); }

.ui-keys { margin-left: auto; display: inline-flex; gap: 4px; }

.ui-kbd {
  font-family: var(--font-mono);
  font-size: var(--fs-badge);
  color: var(--ink-dim);
  background: var(--surface-inset);
  border: var(--border-width) solid var(--line-strong);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm);
  padding: 1px 6px;
}

/* ─── Diagrama de flujo ──────────────────────────────────────── */
.ui-flow { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-3); }

.ui-node {
  padding: var(--space-2) var(--space-3);
  background: var(--surface-inset);
  border: var(--border-width) solid var(--line-strong);
  border-radius: var(--radius-sm);
  font-size: var(--fs-label);
  color: var(--ink);
  white-space: nowrap;
}

.ui-node.is-active { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }

.ui-node-ok { border-color: var(--ok); background: var(--ok-soft); color: var(--ok); }

.ui-node-warn { border-color: var(--warn); background: var(--warn-soft); color: var(--warn); }

/* Flecha dibujada con CSS: línea + punta */
.ui-arrow { position: relative; flex: 1; min-width: 28px; height: var(--border-width); background: var(--line-strong); }

.ui-arrow::after {
  content: '';
  position: absolute;
  right: 0; top: 50%;
  transform: translateY(-50%) rotate(45deg);
  width: 6px; height: 6px;
  border-top: 2px solid var(--line-strong);
  border-right: 2px solid var(--line-strong);
}

.ui-arrow-back::after { right: auto; left: 0; transform: translateY(-50%) rotate(-135deg); }

/* ═══════════════════════════════════════════════════════════════
   Piezas de producto — medios, social y mercados.

   El catálogo ya demuestra el sistema en paneles y formularios;
   estas piezas lo llevan a los géneros que faltaban: la parrilla
   de vídeos, el muro social y la mesa de mercados. Nada trae color
   propio ni fotografía: las miniaturas se SIMULAN con degradados
   de los tokens, así el mismo fragmento cambia de piel entera al
   cambiar de tema en vez de arrastrar una foto ajena a todos.
   ═══════════════════════════════════════════════════════════════ */

/* ─── Barra de filtros ───────────────────────────────────────── */
/* Fila que se desplaza en horizontal sin barra visible, como las
   pestañas: los filtros que no caben asoman por la derecha y se
   arrastran. Nunca se apilan: apilados dejarían de leerse como una
   cabecera de filtros y robarían dos o tres filas a la parrilla. */
.ui-chipbar {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  scrollbar-width: none;
  margin-bottom: var(--gap);
}

.ui-chipbar::-webkit-scrollbar { display: none; }

/* flex:none + nowrap: un chip jamás se parte ni se encoge; antes que
   deformarse, la fila desplaza. Algo más de cuerpo que el chip de
   tabla: aquí es un control que se pulsa, no una etiqueta. */
.ui-chipbar .ui-chip {
  flex: none;
  white-space: nowrap;
  cursor: pointer;
  padding: 4px 12px;
  /* En el chipbar los chips son <button> y conservaban el borde outset
     del navegador: un anillo gris que ningún token podía quitar. */
  border: 0;
}

/* ─── Parrilla de medios ─────────────────────────────────────── */
.ui-media-grid, .ui-media-grid-v {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--gap);
  margin-bottom: var(--gap);
}

/* La variante vertical cabe más veces por fila: su miniatura 9/16
   ya es alta de sobra. */
.ui-media-grid-v { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }

/* La tarjeta de medios NO es una caja: el contenedor es transparente
   y la forma la pone la miniatura. Así funciona idéntica en card,
   ruled y flat, porque no hay marco que quitar. */
.ui-media {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

/* La miniatura simulada: degradado de marca sobre --surface-3.
   position:relative ancla la duración y las estadísticas;
   overflow:hidden recorta la escala del hover al radio. */
.ui-thumb {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--gradient-brand), var(--surface-3);
}

.ui-thumb-v { aspect-ratio: 9 / 16; }

/* Escrima: velo oscuro en la base de la miniatura. Sobre los tintes
   claros, las estadísticas y la duración se leían con esfuerzo; el velo
   las asienta y en los temas oscuros ni se nota. OJO al orden de
   pintado: ::after se genera como último hijo y taparía los rótulos,
   así que ellos suben a z-index 1. */
.ui-thumb::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 44%;
  background: linear-gradient(transparent, rgba(0, 0, 0, 0.38));
  pointer-events: none;
}

.ui-thumb-time, .ui-thumb-stats { z-index: 1; }

/* Duración u hora: píldora oscura FIJA, sin tokens a propósito, como
   el rótulo de un reproductor: tiene que leerse sobre cualquier tinte
   y tanto en claro como en oscuro. */
.ui-thumb-time {
  position: absolute;
  right: 8px; bottom: 8px;
  padding: 1px 6px;
  border-radius: var(--radius-sm);
  background: rgba(0, 0, 0, 0.72);
  color: #fff;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  line-height: 1.6;
}

/* Cifra superpuesta a la miniatura: blanco con sombra de texto, la
   receta clásica para flotar texto sobre imagen sin meterlo en caja. */
.ui-thumb-stats {
  position: absolute;
  left: 8px; bottom: 8px;
  color: #fff;
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: 0.02em;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
}

/* Avatar + columna de texto bajo la miniatura */
.ui-media-body {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  min-width: 0;
}

.ui-media-body > :not(.ui-avatar) { min-width: 0; }

/* Dos líneas y tijera: un título largo no descuadra la parrilla */
.ui-media-title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  font-size: var(--fs-body);
  font-weight: var(--fw-title);
  line-height: 1.35;
  color: var(--ink);
}

.ui-media-body .ui-meta { display: block; margin-top: 2px; }

/* El hover escala la miniatura, no la tarjeta: es la señal de «esto
   se reproduce». Bajo media query positiva a propósito: la regla
   general de movimiento reducido solo anula duraciones, y aquí ni
   siquiera debe quedar el salto seco de escala. */
@media (prefers-reduced-motion: no-preference) {
  .ui-thumb { transition: transform var(--dur-base) ease; }

  .ui-media:hover .ui-thumb { transform: scale(1.02); }
}

/* ─── Muro social ────────────────────────────────────────────── */
/* Columna central acotada: un muro a todo el ancho del monitor no
   existe en ningún producto real. */
.ui-feed {
  max-width: 620px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  min-width: 0;
}

/* La publicación SÍ es superficie: viste los tokens del panel y las
   variantes ruled/flat de abajo la desvisten igual que a un panel. */
.ui-post {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4) var(--space-4);
  background: var(--panel-bg);
  border: var(--panel-border-width) solid var(--panel-border);
  border-radius: var(--panel-radius);
  box-shadow: var(--shadow-sm);
  min-width: 0;
}

.ui-post-head { display: flex; align-items: center; gap: var(--space-2); }

.ui-post-head b { color: var(--ink); font-size: var(--fs-body); }

.ui-post-head .ui-row-menu { margin-left: auto; }

/* La imagen de la publicación: retrato 4/5 clásico y el mismo sistema
   de tintes que .ui-thumb (las clases .ui-thumb-b/-c/-d de abajo
   también la pintan). El radio es de la imagen, no de la caja: en
   ruled y flat sobrevive aunque la tarjeta pierda el marco. */
.ui-post-media {
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--gradient-brand), var(--surface-3);
}

/* Acciones: botones fantasma, glifo + contador. En mono, como todos
   los numeritos del sistema. */
.ui-actions { display: flex; align-items: center; gap: var(--space-1); }

.ui-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  background: none;
  border: 0;
  border-radius: var(--radius-pill);
  color: var(--ink-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  line-height: 1;
  cursor: pointer;
  transition: color var(--dur-fast) ease, background-color var(--dur-fast) ease;
}

.ui-action:hover { background: var(--surface-3); color: var(--ink); }

/* El marcador va solo, a la derecha, como en cualquier muro */
.ui-actions .ui-action:last-child { margin-left: auto; }

.ui-post-text {
  margin: 0;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--ink-dim);
  overflow-wrap: anywhere;
}

.ui-post-text b { color: var(--ink); margin-right: 4px; }

/* Los tratamientos sin caja desvisten la publicación como al panel:
   filete arriba en ruled, nada en flat (ahí separa el aire del gap
   del muro). */
.ui[data-panel="ruled"] .ui-post {
  background: none;
  border: 0;
  border-top: var(--border-width) solid var(--line);
  border-radius: 0;
  box-shadow: none;
  padding-left: 0;
  padding-right: 0;
}

.ui[data-panel="flat"] .ui-post {
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
}

/* ─── Tintes de miniatura ────────────────────────────────────── */
/* Cuatro pieles para que la parrilla no cante a plantilla: la base
   lleva el degradado de marca y estas tres mezclan un color funcional
   a baja alfa sobre --surface-3 (dos lavados diagonales: uno fuerte
   que da el tono y otro suave a contraluz que da profundidad).
   Después de .ui-post-media a propósito: misma especificidad y aquí
   gana la última regla, igual que en las correcciones del final. */
.ui-thumb-b {
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--info) 45%, transparent), transparent 70%),
    linear-gradient(315deg, color-mix(in srgb, var(--info) 18%, transparent), transparent 55%),
    var(--surface-3);
}

.ui-thumb-c {
  background:
    linear-gradient(150deg, color-mix(in srgb, var(--ok) 40%, transparent), transparent 68%),
    linear-gradient(330deg, color-mix(in srgb, var(--ok) 16%, transparent), transparent 55%),
    var(--surface-3);
}

.ui-thumb-d {
  background:
    linear-gradient(120deg, color-mix(in srgb, var(--warn) 38%, transparent), transparent 66%),
    linear-gradient(300deg, color-mix(in srgb, var(--warn) 15%, transparent), transparent 55%),
    var(--surface-3);
}

/* ─── Sugerencias ────────────────────────────────────────────── */
.ui-suggest { display: flex; flex-direction: column; gap: var(--space-3); }

.ui-suggest-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
}

/* La columna del medio (nombre + meta) es el único hijo flexible:
   el avatar y el enlace de seguir no se tocan. */
.ui-suggest-item > :not(.ui-avatar):not(.ui-link) {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow-wrap: anywhere;
}

.ui-suggest-item b { color: var(--ink); font-size: var(--fs-body); }

.ui-suggest-item .ui-link {
  margin-left: auto;
  flex: none;
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
}

/* ─── Cinta de cotizaciones ──────────────────────────────────── */
.ui-tickerbar {
  display: flex;
  overflow-x: auto;
  scrollbar-width: none;
  border-bottom: var(--border-width) solid var(--line);
  margin-bottom: var(--gap);
}

.ui-tickerbar::-webkit-scrollbar { display: none; }

/* Cada instrumento es una columnita que no se encoge; el activo marca
   su borde inferior pisando la línea de la cinta, como las pestañas.
   El reseteo (appearance/background/border/font) es obligatorio: en la
   página es un <button> y sin él quedarían el fondo buttonface claro y
   el borde outset del navegador, ilegibles en los temas oscuros. El
   border:0 va ANTES del border-bottom para no pisar el subrayado. */
.ui-ticker {
  appearance: none;
  background: none;
  border: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2) var(--space-4);
  border-bottom: 2px solid transparent;
  margin-bottom: calc(-1 * var(--border-width));
  cursor: pointer;
}

.ui-ticker.is-on, .ui-ticker.is-active, .ui-ticker.active { border-bottom-color: var(--accent); }

.ui-ticker-sym {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--ink-dim);
}

.ui-ticker-price {
  font-family: var(--font-mono);
  font-size: var(--fs-title);
  font-weight: var(--fw-stat);
  line-height: var(--lh-tight);
  color: var(--ink);
}

/* Subida y bajada con el glifo puesto desde el CSS: el HTML solo dice
   is-up o is-down y el color y la flecha llegan siempre juntos (una
   flecha verde de bajada no puede existir ni por descuido). */
.ui-delta { font-family: var(--font-mono); font-size: var(--fs-label); }

.ui-delta.is-up { color: var(--ok); }

.ui-delta.is-down { color: var(--danger); }

.ui-delta.is-up::before { content: '\25B2\00A0'; font-size: 0.8em; }

.ui-delta.is-down::before { content: '\25BC\00A0'; font-size: 0.8em; }

/* ─── Gráfica seria ──────────────────────────────────────────── */
/* Clases para VESTIR un SVG que traen las páginas: el dibujo (los
   puntos de la serie) es contenido, pero color, grosor y letra son
   del tema, así la misma gráfica cambia de piel con cada preset. */
.ui-chart { display: block; width: 100%; height: auto; }

.ui-chart-grid { stroke: var(--line); stroke-width: 1; }

.ui-chart-axis {
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  fill: var(--ink-faint);
}

.ui-chart-line, .ui-chart-line-2 {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.ui-chart-line-2 { stroke: var(--info); }

/* El área bajo la línea, a la alfa justa para teñir sin tapar la
   rejilla que tiene debajo. */
.ui-chart-area { fill: var(--accent); opacity: 0.12; stroke: none; }

.ui-chart-bar { fill: var(--info); }

.ui-chart-bar.is-down { fill: var(--danger); opacity: 0.75; }

.ui-chart-legend {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-top: var(--space-2);
  font-size: var(--fs-label);
  color: var(--ink-dim);
}

.ui-chart-legend span { display: inline-flex; align-items: center; gap: 6px; }

.ui-chart-legend i {
  display: inline-block;
  width: 8px; height: 8px;
  flex: none;
  border-radius: var(--radius-pill);
  background: var(--accent);
}

.ui-chart-legend i.is-info { background: var(--info); }

.ui-chart-legend i.is-ok { background: var(--ok); }

.ui-chart-legend i.is-danger { background: var(--danger); }

/* ─── Botón flotante ─────────────────────────────────────────── */
/* Vive en la esquina inferior derecha de su contenedor posicionado
   (el armazón ya es position:relative: dentro de una página con
   armazón cae en la esquina del contenido sin más ayuda). Píldora
   siempre y sombra media: flota, no descansa. */
.ui-fab {
  position: absolute;
  right: var(--space-5);
  bottom: var(--space-5);
  z-index: var(--z-sticky);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: calc(var(--btn-h) * var(--density));
  padding: 0 calc(18px * var(--density));
  background: var(--btn-primary-bg);
  color: var(--btn-primary-ink);
  border: 0;
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-md);
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: var(--fw-btn);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  cursor: pointer;
}

/* Mismo trato que el botón primario: degradado de marca si lo hay */
.ui:not([style*="--gradient-brand: none"]) .ui-fab { background-image: var(--gradient-brand); }

.ui-fab:hover { filter: brightness(1.08); }

/* ═══════════════════════════════════════════════════════════════
   Movimiento — un solo lenguaje para todo el sistema.

   Dos velocidades y nada más: --dur-fast para el feedback pequeño
   (color, borde, fondo) y --dur-base para lo estructural (elevación,
   colapso, capas). SIEMPRE a través de los tokens: quien ponga las
   duraciones a 0 en el editor obtiene un sistema quieto, y el tema
   exportado hereda esa decisión sin tocar ninguna regla. Solo se
   animan transform, opacity, color, fondo, borde y sombra: nada que
   dispare layout (width, height, top, left quedan fuera adrede).
   ═══════════════════════════════════════════════════════════════ */

/* Feedback pequeño: enlaces, migas, chips, pestañas, items de menú y
   de navegación, páginas del paginador y botoncillos auxiliares. Una
   sola regla —con :where para no sumar especificidad— para que el
   lenguaje sea idéntico en todo el sistema y no por componente. */
.ui :where(.ui-link, .ui-breadcrumb a, .ui-chip, .ui-tab, .ui-menu-item,
  .ui-mega-item, .ui-side-item, .ui-subnav-item, .ui-page, .ui-seg,
  .ui-addon-btn, .ui-row-menu, .ui-theme-toggle, .ui-dash-tool,
  .ui-map-ctrl button, .ui-shell-collapse, .ui-node) {
  transition: color var(--dur-fast) ease, background-color var(--dur-fast) ease,
    border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}

/* Elevación al pasar, SOLO en el tratamiento de tarjeta: en ruled y
   flat no hay caja que levantar y la sombra delataría un marco que el
   tema decidió no tener. La tarjeta en vuelo del tablero (is-dragging)
   se excluye para no pisar su giro de arrastre. */
.ui[data-panel="card"] :where(.ui-panel, .ui-card:not(.is-dragging), .ui-dash-card) {
  transition: transform var(--dur-base) ease, box-shadow var(--dur-base) ease;
}

.ui[data-panel="card"] :where(.ui-panel, .ui-card:not(.is-dragging), .ui-dash-card):hover {
  /* La altura del vuelo es decisión del tema: --hover-lift a 0 deja
     las tarjetas clavadas sin tocar ninguna regla. */
  transform: translateY(calc(-1 * var(--hover-lift)));
  box-shadow: var(--shadow-md);
}

/* Entradas de capas. El runtime abre diálogo, menú, cajón y avisos
   quitando [hidden]; al pasar de display:none a visible, la animación
   se dispara sola, sin JS. Cada keyframe declara SOLO el fotograma de
   salida (from): el estado final es el natural del elemento, así
   ningún tema tiene que redeclararlo y el velo termina exactamente en
   su --overlay-alpha. */
.ui :where(.ui-dialog, .ui-menu, .ui-megamenu) { animation: ui-pop var(--dur-base) ease; }

.ui .ui-toast { animation: ui-rise var(--dur-base) ease; }

.ui :where(.ui-shell-veil, .ui-stage-veil) { animation: ui-veil var(--dur-base) ease; }

.ui .ui-drawer { animation: ui-drawer var(--dur-base) ease; }

/* Colapso de la navegación: el ancho salta sin transición (animar una
   medida dispara reflow, prohibido arriba), y el movimiento vive aquí:
   al expandir, las etiquetas pasan de display:none a visibles y la
   entrada se dispara sola, igual que en las capas. */
.ui[data-layout="sidebar"] :where(.ui-side-text, .ui-shell-name) {
  animation: ui-nav-label var(--dur-base) ease;
}

@keyframes ui-pop { from { opacity: 0; transform: scale(0.98); } }

@keyframes ui-nav-label { from { opacity: 0; transform: translateX(-6px); } }

@keyframes ui-rise { from { opacity: 0; transform: translateY(10px); } }

@keyframes ui-veil { from { opacity: 0; } }

@keyframes ui-drawer { from { opacity: 0; transform: translateX(16px); } }

/* ─── Entrada de página (grupo «Movimiento» del panel) ───────────
   El editor elige el gesto con --anim-enter y apply() lo refleja
   como data-anim en el lienzo de página; la exportación lo escribe
   en el <body>. Tres gestos y ninguno más — aparecer, subir,
   escalar — siempre solo con opacity y transform.

   El anfitrión .ui suele tener UN solo hijo (el armazón, o la
   pantalla de acceso), así que además de los hijos directos se
   animan los bloques del cuerpo del armazón: ahí vive lo que se
   percibe como «la página entrando», y el escalonado tiene hermanos
   que escalonar. El armazón queda quieto a propósito: su chrome
   (barra, menú) no debe saltar cada vez que se cambia de vista.
   El lienzo de fondo (data-ui-fondo) tampoco entra: es atmósfera,
   no contenido. data-anim="ninguno" no casa con ninguna regla, y
   el movimiento reducido ya lo apaga el bloque final. */
.ui[data-anim="aparecer"] > :not(.ui-shell):not([data-ui-fondo]),
.ui[data-anim="aparecer"] .ui-shell-body > * {
  animation: ui-enter-aparecer var(--anim-enter-dur) ease both;
}

.ui[data-anim="subir"] > :not(.ui-shell):not([data-ui-fondo]),
.ui[data-anim="subir"] .ui-shell-body > * {
  animation: ui-enter-subir var(--anim-enter-dur) ease both;
}

.ui[data-anim="escalar"] > :not(.ui-shell):not([data-ui-fondo]),
.ui[data-anim="escalar"] .ui-shell-body > * {
  animation: ui-enter-escalar var(--anim-enter-dur) ease both;
}

/* Escalonado: los ocho primeros entran en cascada y del noveno en
   adelante llegan todos con el retardo máximo — nunca ANTES que sus
   hermanos de arriba, que es lo que pasaría con el 0 por defecto.
   Sin animación en marcha, un retardo no hace nada. */
.ui[data-anim] > :nth-child(2), .ui[data-anim] .ui-shell-body > :nth-child(2) { animation-delay: var(--anim-stagger); }

.ui[data-anim] > :nth-child(3), .ui[data-anim] .ui-shell-body > :nth-child(3) { animation-delay: calc(var(--anim-stagger) * 2); }

.ui[data-anim] > :nth-child(4), .ui[data-anim] .ui-shell-body > :nth-child(4) { animation-delay: calc(var(--anim-stagger) * 3); }

.ui[data-anim] > :nth-child(5), .ui[data-anim] .ui-shell-body > :nth-child(5) { animation-delay: calc(var(--anim-stagger) * 4); }

.ui[data-anim] > :nth-child(6), .ui[data-anim] .ui-shell-body > :nth-child(6) { animation-delay: calc(var(--anim-stagger) * 5); }

.ui[data-anim] > :nth-child(7), .ui[data-anim] .ui-shell-body > :nth-child(7) { animation-delay: calc(var(--anim-stagger) * 6); }

.ui[data-anim] > :nth-child(8), .ui[data-anim] .ui-shell-body > :nth-child(8) { animation-delay: calc(var(--anim-stagger) * 7); }

.ui[data-anim] > :nth-child(n+9), .ui[data-anim] .ui-shell-body > :nth-child(n+9) { animation-delay: calc(var(--anim-stagger) * 7); }

@keyframes ui-enter-aparecer { from { opacity: 0; } }

@keyframes ui-enter-subir { from { opacity: 0; transform: translateY(12px); } }

@keyframes ui-enter-escalar { from { opacity: 0; transform: scale(0.98); } }

/* ═══════════════════════════════════════════════════════════════
   Correcciones de desborde, al final a propósito: con la misma
   especificidad gana la última regla, y arriba quedaban anuladas
   por las generales de campos y de KPI.

   Que nada se salga de su caja: un hijo de flex o de grid no baja de
   su tamaño de contenido salvo que se le diga (min-width:0), y con
   tipografías grandes o densidades altas eso rompe el panel.
   ═══════════════════════════════════════════════════════════════ */
.ui :where(.ui-panel, .ui-panel-head, .ui-panel-body, .ui-dash-card, .ui-dash-head,
  .ui-stat, .ui-card, .ui-col, .ui-setting, .ui-setting-text,
  .ui-shell-main, .ui-shell-top, .ui-shell-body, .ui-auth-card, .ui-drawer,
  .ui-slide, .ui-slide-body, .ui-toast, .ui-empty, .ui-feature, .ui-price) { min-width: 0; }

/* Texto largo: parte la palabra antes que romper el contenedor */
.ui :where(.ui-panel-title, .ui-dash-head, .ui-shell-title, .ui-slide-title,
  .ui-hero-title, .ui-auth-title, .ui-empty-title, .ui-profile-name, .ui-setting-text,
  .ui-card b, .ui-toast, .ui-alert, .ui-meta, .ui-empty-text) { overflow-wrap: anywhere; }

/* Filas que si no desbordarían en vez de pasar a la línea siguiente */
.ui :where(.ui-actionbar, .ui-breadcrumb, .ui-profile-stats,
  .ui-shell-actions, .ui-slide-foot, .ui-table-foot, .ui-dash-head, .ui-panel-head,
  .ui-setting, .ui-auth-row, .ui-col-head, .ui-stepper, .ui-flow) { flex-wrap: wrap; }

.ui .ui-input-group > input { width: auto; min-width: 0; flex: 1 1 auto; }

.ui .ui-stat { min-width: 0; overflow-wrap: anywhere; }

.ui .ui-stat-value { overflow-wrap: anywhere; word-break: break-word; }

.ui .ui-stat-label { overflow-wrap: anywhere; }

.ui .ui-shell-grid { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }

/* ─── Respeto real a la preferencia de movimiento reducido ───────
   No basta con acortar: duraciones a cero y keyframes desactivados
   (0.01ms + 1 iteración congela la animación en su estado final sin
   los bugs que algunos navegadores tienen con 0 exacto; también para
   el pulso, el spinner y el shimmer, que son infinitos). Va con
   !important para que ningún tema ni componente pueda reactivarlo. */
@media (prefers-reduced-motion: reduce) {
  .ui, .ui *, .ui *::before, .ui *::after {
    transition-duration: 0ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}
