/* ==========================================================================
   Lab4Leads v3 — hoja de estilo única (CRM + sitio público)
   --------------------------------------------------------------------------
   Sin frameworks, sin build. Se sube tal cual por FTP.

   Orden del archivo:
     1. Tokens              6. Tablas            11. Modal
     2. Reset y base        7. Formularios       12. Paginación y pestañas
     3. Utilidades          8. Botones           13. KPI, timeline, vacío
     4. Estructura CRM      9. Badges            14. Sitio público
     5. Tarjetas           10. Alertas           15. Responsive y a11y

   Convención de nombres: bloque `.card`, elemento `.card__title`,
   modificador `.btn--primary`, estado `.is-active`.
   ========================================================================== */

/* ==========================================================================
   1. TOKENS
   --------------------------------------------------------------------------
   Todo el color, el espaciado y la tipografía salen de aquí. El modo oscuro
   NO redefine componentes: solo reasigna estos mismos tokens, de modo que
   añadir un componente no obliga a escribirlo dos veces.
   ========================================================================== */

:root {
  color-scheme: light;

  /* --- Marca: petróleo sobrio, legible sobre blanco y sobre oscuro ------ */
  --brand-50:  #eef7f8;
  --brand-100: #d2ebee;
  --brand-200: #a6d6dd;
  --brand-300: #6dbac5;
  --brand-400: #3d99a6;
  --brand-500: #1f7e8c;
  --brand-600: #166874;
  --brand-700: #12525c;
  --brand-800: #0e3f47;
  --brand-900: #0a2d33;

  /* --- Grises neutros, escalonados para contraste predecible ----------- */
  --gray-0:   #ffffff;
  --gray-25:  #fbfcfd;
  --gray-50:  #f5f7f9;
  --gray-100: #edf1f4;
  --gray-200: #e0e6eb;
  --gray-300: #c9d2da;
  --gray-400: #98a4b0;
  --gray-500: #6a7784;
  --gray-600: #4e5a66;
  --gray-700: #39434d;
  --gray-800: #252d35;
  --gray-900: #161c22;
  --gray-950: #0c1116;

  /* --- Semánticos ------------------------------------------------------ */
  /* Coinciden con LeadStatus::badge(): info, warning, secondary, dark,
     primary, success. `danger` se añade para acciones destructivas. */
  --success:      #1a7a49;
  --success-soft: #e6f4ec;
  --success-line: #a9d9be;

  --warning:      #8a5a00;
  --warning-soft: #fdf3df;
  --warning-line: #ecd19a;

  --danger:       #ad2a20;
  --danger-soft:  #fdeceb;
  --danger-line:  #f0b7b3;

  --info:         #15628f;
  --info-soft:    #e7f1f9;
  --info-line:    #a9cbe4;

  --secondary:      var(--gray-500);
  --secondary-soft: var(--gray-100);
  --secondary-line: var(--gray-300);

  --dark:      var(--gray-800);
  --dark-soft: var(--gray-200);
  --dark-line: var(--gray-400);

  --primary:      var(--brand-600);
  --primary-soft: var(--brand-50);
  --primary-line: var(--brand-200);

  /* --- Roles de superficie y texto ------------------------------------- */
  --bg:            var(--gray-50);
  --surface:       var(--gray-0);
  --surface-2:     var(--gray-25);
  --surface-sunken: var(--gray-100);
  --surface-hover: var(--gray-50);

  --text:          var(--gray-900);
  --text-muted:    var(--gray-600);
  --text-subtle:   var(--gray-500);
  --text-invert:   var(--gray-0);

  --border:        var(--gray-200);
  --border-strong: var(--gray-300);

  --link:       var(--brand-700);
  --link-hover: var(--brand-800);

  --focus: var(--brand-500);

  /* La banda de "modo pruebas" tiene tokens propios porque los semánticos se
     invierten en oscuro: el ámbar pasa a ser claro y el texto blanco quedaría
     ilegible justo en el aviso que más se tiene que leer. */

  /* Halo del foco y del error como valores propios: `color-mix()` no está en
     los navegadores de todos los móviles que usa el equipo comercial, y si la
     declaración se invalida el foco deja de verse. */
  --focus-ring: rgba(31, 126, 140, 0.28);
  --danger-ring: rgba(173, 42, 32, 0.24);

  --primary-hover: var(--brand-700);
  --danger-hover: #8f211a;
  --success-hover: #14603a;

  /* Barra lateral: oscura en ambos modos, así el CRM se lee como una
     herramienta y no como un documento. */
  --sidebar-bg:         var(--brand-900);
  --sidebar-bg-hover:   #123c44;
  --sidebar-bg-active:  var(--brand-700);
  --sidebar-text:       #cfe3e6;
  --sidebar-text-muted: #85a8ad;
  --sidebar-text-active: #ffffff;
  --sidebar-border:     #0d353c;

  /* --- Espaciado (escala de 4px) --------------------------------------- */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.25rem;
  --sp-6: 1.5rem;
  --sp-8: 2rem;
  --sp-10: 2.5rem;
  --sp-12: 3rem;
  --sp-16: 4rem;

  /* --- Radios ---------------------------------------------------------- */
  --radius-sm: 4px;
  --radius:    8px;
  --radius-lg: 12px;
  --radius-xl: 18px;
  --radius-pill: 999px;

  /* --- Sombras --------------------------------------------------------- */
  --shadow-xs: 0 1px 2px rgba(13, 27, 34, 0.06);
  --shadow-sm: 0 1px 3px rgba(13, 27, 34, 0.08), 0 1px 2px rgba(13, 27, 34, 0.04);
  --shadow:    0 4px 12px rgba(13, 27, 34, 0.08);
  --shadow-lg: 0 12px 32px rgba(13, 27, 34, 0.14);

  /* --- Tipografía ------------------------------------------------------ */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
          Arial, "Noto Sans", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
               "Liberation Mono", monospace;

  --fs-xs: 0.75rem;
  --fs-sm: 0.8125rem;
  --fs-base: 0.9375rem;
  --fs-md: 1rem;
  --fs-lg: 1.125rem;
  --fs-xl: 1.375rem;
  --fs-2xl: 1.75rem;
  --fs-3xl: 2.25rem;
  --fs-4xl: 3rem;

  --lh-tight: 1.2;
  --lh: 1.55;

  --fw-normal: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  /* --- Medidas de la estructura ---------------------------------------- */
  --sidebar-w: 258px;
  --sidebar-w-collapsed: 68px;
  --header-h: 60px;
  --content-max: 1400px;
  --prose-max: 68ch;

  --transition: 160ms ease;
  /* El orden importa y se rompe fácil: el fondo oscuro tiene que quedar por
     DEBAJO del panel lateral. Estaba al revés, así que en móvil el backdrop
     se dibujaba sobre el menú y se comía los clics: se veía, pero no se podía
     pulsar nada. */
  --z-header: 30;
  --z-backdrop: 40;
  --z-sidebar: 50;
  --z-modal: 60;
  --z-toast: 70;
}

/* Modo oscuro: solo tokens. */
@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;

    --bg:             var(--gray-950);
    --surface:        #141b21;
    --surface-2:      #182027;
    --surface-sunken: #0f151a;
    --surface-hover:  #1d262e;

    --text:        #e7edf1;
    --text-muted:  #a4b1bc;
    --text-subtle: #7e8b97;
    --text-invert: var(--gray-950);

    --border:        #26313a;
    --border-strong: #35424d;

    --link:       var(--brand-300);
    --link-hover: var(--brand-200);
    --focus:      var(--brand-300);


    --focus-ring: rgba(109, 186, 197, 0.3);
    --danger-ring: rgba(240, 132, 124, 0.28);

    --primary-hover: var(--brand-500);
    --danger-hover: #c9564d;
    --success-hover: #7ed6a6;

    --primary:      var(--brand-400);
    --primary-soft: #10333a;
    --primary-line: #1d5763;

    --success:      #5cc98d;
    --success-soft: #123024;
    --success-line: #1f5a3d;

    --warning:      #e0b465;
    --warning-soft: #33260d;
    --warning-line: #5e4718;

    --danger:       #f0847c;
    --danger-soft:  #371715;
    --danger-line:  #6b2b26;

    --info:         #7ab8e0;
    --info-soft:    #102a3a;
    --info-line:    #1d4a63;

    --secondary:      var(--gray-400);
    --secondary-soft: #1d262e;
    --secondary-line: #35424d;

    --dark:      #cbd5dd;
    --dark-soft: #1d262e;
    --dark-line: #3b4854;

    --sidebar-bg:         #0d1418;
    --sidebar-bg-hover:   #172226;
    --sidebar-bg-active:  var(--brand-700);
    --sidebar-border:     #1c272c;

    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.45);
    --shadow:    0 4px 14px rgba(0, 0, 0, 0.5);
    --shadow-lg: 0 14px 36px rgba(0, 0, 0, 0.6);
  }
}

/* ==========================================================================
   2. RESET Y BASE
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: var(--fw-normal) var(--fs-base) / var(--lh) var(--font);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6 {
  margin: 0 0 var(--sp-3);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-tight);
  color: var(--text);
  text-wrap: balance;
}

h1 { font-size: var(--fs-2xl); }
h2 { font-size: var(--fs-xl); }
h3 { font-size: var(--fs-lg); }
h4 { font-size: var(--fs-md); }
h5, h6 { font-size: var(--fs-base); }

p { margin: 0 0 var(--sp-4); }
p:last-child { margin-bottom: 0; }

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

a:hover { color: var(--link-hover); text-decoration: underline; }

img, svg, video { max-width: 100%; height: auto; display: block; }

ul, ol { margin: 0 0 var(--sp-4); padding-left: var(--sp-5); }

hr {
  margin: var(--sp-6) 0;
  border: 0;
  border-top: 1px solid var(--border);
}

code, kbd, pre, samp { font-family: var(--font-mono); font-size: 0.9em; }

code {
  padding: 0.1em 0.35em;
  background: var(--surface-sunken);
  border-radius: var(--radius-sm);
}

kbd {
  display: inline-block;
  min-width: 1.6em;
  padding: 0.15em 0.4em;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  text-align: center;
  color: var(--text);
}

/* Un único anillo de foco para todo lo interactivo. */
:focus { outline: none; }

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

::selection {
  background: var(--brand-200);
  color: var(--brand-900);
}

/* ==========================================================================
   3. UTILIDADES
   ========================================================================== */

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: -100px;
  left: var(--sp-3);
  z-index: var(--z-toast);
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface);
  color: var(--text);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  font-weight: var(--fw-semibold);
}

.skip-link:focus { top: var(--sp-3); }

.muted { color: var(--text-muted); }
.subtle { color: var(--text-subtle); }
.small { font-size: var(--fs-sm); }
.tiny { font-size: var(--fs-xs); }
.strong { font-weight: var(--fw-semibold); }
.mono { font-family: var(--font-mono); }
.nowrap { white-space: nowrap; }
.truncate { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.text-left { text-align: left; }
.text-center { text-align: center; }
.text-right { text-align: right; }

.text-success { color: var(--success); }
.text-warning { color: var(--warning); }
.text-danger { color: var(--danger); }
.text-info { color: var(--info); }
.text-primary { color: var(--primary); }

.stack > * + * { margin-top: var(--sp-4); }
.stack--tight > * + * { margin-top: var(--sp-2); }
.stack--loose > * + * { margin-top: var(--sp-6); }

.row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
}

.row--between { justify-content: space-between; }
.row--end { justify-content: flex-end; }
.row--middle { align-items: center; }

.grid {
  display: grid;
  gap: var(--sp-4);
}

/* Rejilla auto-ajustable: sin media queries, se adapta al ancho disponible. */
.grid--auto { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }

.divider { height: 1px; background: var(--border); margin: var(--sp-5) 0; }

.prose { max-width: var(--prose-max); }

/* ==========================================================================
   4. ESTRUCTURA DEL CRM
   --------------------------------------------------------------------------
   Móvil primero: la barra lateral es un panel deslizante fuera de pantalla.
   A partir de 1024px pasa a columna fija y puede colapsarse a solo iconos
   (clase `is-collapsed`, que persiste en localStorage desde app.js).
   ========================================================================== */

.app {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* --- Barra lateral ---------------------------------------------------- */

.sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  z-index: var(--z-sidebar);
  width: min(84vw, 300px);
  display: flex;
  flex-direction: column;
  background: var(--sidebar-bg);
  color: var(--sidebar-text);
  border-right: 1px solid var(--sidebar-border);
  transform: translateX(-100%);
  transition: transform var(--transition);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.app.is-sidebar-open .sidebar { transform: translateX(0); }

.sidebar__brand {
  display: flex;
  align-items: center;

  /* Los distintivos de estado bajan a una segunda línea si no caben. Sin el
     wrap, dos distintivos aplastaban el nombre y las letras se solapaban. */
  flex-wrap: wrap;
  row-gap: 0.35rem;
  column-gap: var(--sp-3);
  min-height: var(--header-h);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--sidebar-border);
  color: var(--sidebar-text-active);
  font-weight: var(--fw-bold);
  font-size: var(--fs-md);
  letter-spacing: 0.01em;
}

.sidebar__brand:hover { color: var(--sidebar-text-active); text-decoration: none; }

/* El nombre absorbe el espacio libre; el distintivo se queda a su tamaño. */
/* `0 1 auto`: el nombre puede encogerse, pero no por debajo de lo que mide;
   lo que sobra empuja los distintivos a la línea siguiente. */
.sidebar__name { flex: 0 1 auto; }

/* Modo pruebas, junto al logo.
   Sustituye a la barra de aviso que ocupaba todo el ancho de cada pantalla:
   el estado tiene que verse, pero no gritar todo el día. */
.brand-flag {
  flex: 0 0 auto;
  padding: 0.1rem 0.45rem;
  border-radius: var(--radius-pill);
  /* Ámbar claro literal y no `--warning`: la barra lateral es oscura en los
     dos temas, y el ámbar del tema claro (#8a5a00) sobre ese fondo no se lee. */
  border: 1px solid #b07a2a;
  color: #f0b45c;
  background: rgba(232, 163, 61, 0.12);
  font-size: 0.625rem;
  font-weight: var(--fw-bold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.6;
  white-space: nowrap;
}

/* Marca cuadrada del logo. Se usa en la barra lateral del CRM y en la
   cabecera del sitio público, de ahí el nombre independiente del bloque. */
.brand-mark,
.sidebar__mark {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius);
  background: var(--brand-500);
  color: #fff;
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
}

.sidebar__nav {
  flex: 1 1 auto;
  padding: var(--sp-2) var(--sp-2) var(--sp-6);
}

.sidebar__group + .sidebar__group { margin-top: var(--sp-3); }

.sidebar__group-title {
  margin: 0 0 var(--sp-1);
  padding: 0 var(--sp-3);
  color: var(--sidebar-text-muted);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.sidebar__list { margin: 0; padding: 0; list-style: none; }

.sidebar__link {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 34px;
  padding: var(--sp-1) var(--sp-3);
  border-radius: var(--radius);
  color: var(--sidebar-text);
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  transition: background var(--transition), color var(--transition);
}

.sidebar__link:hover {
  background: var(--sidebar-bg-hover);
  color: var(--sidebar-text-active);
  text-decoration: none;
}

.sidebar__link.is-active {
  background: var(--sidebar-bg-active);
  color: var(--sidebar-text-active);
  font-weight: var(--fw-semibold);
}

.sidebar__link:focus-visible { outline-color: var(--brand-200); }

/* El menú compacto es para ratón. En táctil el panel se toca con el dedo, así
   que ahí se recupera el objetivo de 44px que el escritorio no necesita. */
@media (pointer: coarse) {
  .sidebar__link { min-height: 42px; padding-block: var(--sp-2); }
  .sidebar__group + .sidebar__group { margin-top: var(--sp-4); }
}

.sidebar__icon {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  stroke: currentColor;
  stroke-width: 1.7;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.85;
}

.sidebar__label { flex: 1 1 auto; min-width: 0; }

.sidebar__count {
  flex: 0 0 auto;
  padding: 0.1em 0.5em;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.14);
  color: var(--sidebar-text-active);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
}

/* Fondo oscuro que cubre el contenido mientras el panel está abierto. */
.backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--z-backdrop);
  background: rgba(8, 16, 20, 0.55);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--transition), visibility var(--transition);
}

.app.is-sidebar-open .backdrop { opacity: 1; visibility: visible; }

/* --- Cabecera --------------------------------------------------------- */

.header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--header-h);
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow-xs);
}

/* Título y dato de contexto, en una sola línea cuando caben.
   Es el único título de la pantalla: las vistas ya no pintan el suyo. */
.header__page {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--sp-3);
  row-gap: 0;
}

.header__title {
  margin: 0;
  min-width: 0;
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.header__meta {
  margin: 0;
  min-width: 0;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Acciones de la pantalla. No se encogen: si falta sitio, lo cede el título,
   que es lo que el usuario ya sabe porque acaba de pulsarlo en el menú. */
.header__page-actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

/* Desplegable de opciones ocasionales. `<details>` nativo: sin JavaScript, y
   el teclado lo abre solo. */
.pagemenu { position: relative; flex: 0 0 auto; }
.pagemenu > summary { list-style: none; cursor: pointer; }
.pagemenu > summary::-webkit-details-marker { display: none; }

.pagemenu__panel {
  position: absolute;
  right: 0;
  top: calc(100% + var(--sp-2));
  z-index: var(--z-header);
  min-width: 13rem;
  padding: var(--sp-2);
  display: grid;
  gap: 2px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

.pagemenu__panel a,
.pagemenu__panel button {
  display: block;
  width: 100%;
  padding: var(--sp-2) var(--sp-3);
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--fs-sm);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.pagemenu__panel a:hover,
.pagemenu__panel button:hover { background: var(--surface-hover); color: var(--text); }

.header__actions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-left: auto;
}

.header__user {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-1) var(--sp-2);
  border-radius: var(--radius);
  color: var(--text);
}

.header__user:hover { background: var(--surface-hover); text-decoration: none; }

/* Nombre y rol apilados; el bloque entero desaparece en móvil, donde solo
   queda el avatar. */
.header__user-meta { display: none; line-height: 1.25; }
.header__user-name { display: block; font-size: var(--fs-sm); font-weight: var(--fw-semibold); }
.header__user-role { display: block; font-size: var(--fs-xs); color: var(--text-muted); }

.avatar {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--primary-soft);
  color: var(--primary);
  border: 1px solid var(--primary-line);
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  letter-spacing: 0.02em;
}

.avatar--lg { width: 56px; height: 56px; font-size: var(--fs-md); }

/* Botón hamburguesa / colapsar. */
.icon-btn {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius);
  color: var(--text-muted);
  cursor: pointer;
  transition: background var(--transition), color var(--transition);
}

.icon-btn:hover { background: var(--surface-hover); color: var(--text); }

.icon-btn svg {
  width: 22px;
  height: 22px;
  stroke: currentColor;
  stroke-width: 1.8;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* --- Contenido -------------------------------------------------------- */

.main {
  flex: 1 1 auto;
  width: 100%;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--sp-2) var(--sp-3) var(--sp-10);
}

.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-3);
  margin-bottom: var(--sp-5);
}

.page-head__text { flex: 1 1 260px; min-width: 0; }
.page-head__title { margin: 0; font-size: var(--fs-xl); }
.page-head__sub { margin: var(--sp-1) 0 0; color: var(--text-muted); font-size: var(--fs-sm); }
.page-head__actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-3);
  padding: 0;
  list-style: none;
  font-size: var(--fs-sm);
  color: var(--text-subtle);
}

.breadcrumb li + li::before { content: "/"; margin-right: var(--sp-2); color: var(--border-strong); }


/* Fila que abre su ficha. El cursor y el realce dicen que es pulsable; el
   enlace del nombre sigue siendo el que da el foco de teclado. */
.table__row--link { cursor: pointer; }
.table__row--link:hover { background: var(--surface-hover); }
.table__row--link:focus-within { background: var(--surface-hover); }
/* Zona de alertas flash: aria-live la anuncia; el hueco no reserva espacio. */
.flash-zone { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.flash-zone:empty { display: none; margin: 0; }

/* ==========================================================================
   5. TARJETAS
   ========================================================================== */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
}

/* Las tarjetas de una pantalla son un bloque de trabajo, no piezas sueltas:
   se separan lo justo para distinguirse. */
.card + .card { margin-top: var(--sp-2); }

.card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
}

.card__title {
  margin: 0;
  flex: 1 1 auto;
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
}

.card__sub { margin: var(--sp-1) 0 0; font-size: var(--fs-sm); color: var(--text-muted); font-weight: var(--fw-normal); }

.card__actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-left: auto; }

.card__body { padding: var(--sp-5); }
.card__body--flush { padding: 0; }

.card__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* Lista de pares etiqueta/valor, para la ficha de un lead o cliente. */
/* Ficha de datos: pares etiqueta / valor.
   Se reparte en columnas según el ancho disponible en vez de apilarse
   siempre: una ficha de ocho campos en una sola columna ocupaba una pantalla
   entera y obligaba a hacer scroll para ver algo que cabe de un vistazo. */
.datalist {
  margin: 0;
  display: grid;
  gap: 0;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}

/* La línea inferior separa filas sin añadir espacio: es lo que permite
   apretar el interlineado sin que se lea como un bloque continuo. */
.datalist__row {
  display: grid;
  gap: 0.1rem;
  padding: var(--sp-2) var(--sp-3) var(--sp-2) 0;
  border-bottom: 1px solid var(--border-subtle, var(--border));
  min-width: 0;
}

.datalist__key {
  font-size: 0.7rem;
  font-weight: var(--fw-semibold);
  color: var(--text-subtle);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  line-height: 1.3;
}

.datalist__val {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: 1.35;
  overflow-wrap: anywhere;
}

/* Un valor destacado (un importe, un total) puede pedir más peso. */
.datalist__val--strong { font-weight: var(--fw-semibold); font-size: var(--fs-base); }

/* Las últimas filas de cada columna no llevan línea: en una rejilla no se
   puede saber cuáles son con :last-child, así que se quita en todas y se
   pone arriba, que sí es predecible. */
.datalist__row { border-bottom: 0; border-top: 1px solid var(--border-subtle, var(--border)); }
.datalist__row:first-child { border-top: 0; }

/* Con varias columnas la primera fila de cada una tampoco debe llevar línea
   superior; se resuelve dejándola solo a partir de la segunda fila real. */
@media (min-width: 560px) {
  .datalist { column-gap: var(--sp-5); }
}

/* Copiar al portapapeles, dentro de una fila de datos.

   El icono aparece apagado y se enciende al pasar por encima o al recibir el
   foco: en una ficha con teléfono, otro teléfono y email, tres iconos a pleno
   color compiten con los datos que acompañan. Se mantiene visible siempre —no
   solo en hover— porque en pantalla táctil no hay hover que valga. */
.copybtn,
.iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: text-bottom;
  width: 1.5rem;
  height: 1.5rem;
  margin-left: 0.15rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm, 6px);
  background: transparent;
  color: var(--text-subtle);
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease;
}

.copybtn svg,
.iconbtn svg {
  width: 0.95rem;
  height: 0.95rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.copybtn:hover,
.copybtn:focus-visible,
.iconbtn:hover,
.iconbtn:focus-visible {
  color: var(--primary);
  background: var(--surface-hover);
}

/* Suelto —fuera de una fila de datos— necesita ser un objetivo de dedo. */
.iconbtn { width: 1.85rem; height: 1.85rem; margin: 0; }

/* Variante en línea para fichas estrechas: etiqueta a la izquierda, valor a
   la derecha. Se usa donde la ficha vive en una columna lateral. */
.datalist--inline { grid-template-columns: 1fr; }

.datalist--inline .datalist__row {
  grid-template-columns: minmax(7rem, 38%) 1fr;
  align-items: baseline;
  gap: var(--sp-3);
}

.datalist--inline .datalist__key { padding-top: 0.1rem; }

/* ==========================================================================
   6. TABLAS DE DATOS
   --------------------------------------------------------------------------
   El scroll horizontal vive en `.table-wrap`, nunca en el body: en un móvil
   el listado se desplaza dentro de su caja y la página no baila.
   ========================================================================== */

.table-wrap {
  width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  border-radius: var(--table-radius);
}

/**
 * Radio interior: el de la tarjeta menos su borde.
 *
 * Con el mismo radio que la tarjeta, la curva de dentro y la de fuera no
 * encajan —van desplazadas ese píxel— y se ve un escalón en la esquina.
 */
:root { --table-radius: calc(var(--radius-lg) - 1px); }

/**
 * Un cuerpo a sangre redondea por el lado por el que toca el borde de la
 * tarjeta. Antes redondeaba siempre solo por abajo, así que en una tarjeta sin
 * cabecera la fila de títulos —que lleva fondo propio y va pegajosa— pintaba
 * una esquina cuadrada encima de la esquina redonda de la tarjeta.
 */
.card__body--flush:first-child .table-wrap {
  border-radius: var(--table-radius) var(--table-radius) 0 0;
}

.card__body--flush:last-child .table-wrap {
  border-radius: 0 0 var(--table-radius) var(--table-radius);
}

.card__body--flush:first-child:last-child .table-wrap {
  border-radius: var(--table-radius);
}

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

.table th,
.table td {
  padding: var(--sp-3) var(--sp-4);
  text-align: left;
  vertical-align: middle;
  border-bottom: 1px solid var(--border);
}

.table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  white-space: nowrap;
}

.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover { background: var(--surface-hover); }

.table--striped tbody tr:nth-child(even) { background: var(--surface-2); }
.table--striped tbody tr:hover { background: var(--surface-hover); }

.table__num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.table__actions { text-align: right; white-space: nowrap; }

/* Cabecera ordenable: es un enlace, para que funcione sin JavaScript. */
.table__sort {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  color: inherit;
}

.table__sort:hover { color: var(--link); text-decoration: none; }
.table__sort.is-asc::after { content: "\2191"; }
.table__sort.is-desc::after { content: "\2193"; }

.table-total {
  padding: var(--sp-2) var(--sp-4);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

/* Barra de filtros sobre un listado. */
.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-3);
}

.filters .field { flex: 1 1 170px; min-width: 0; margin: 0; }
.filters__actions { display: flex; gap: var(--sp-2); }

/* ==========================================================================
   7. FORMULARIOS
   ========================================================================== */

.form { display: grid; gap: var(--sp-4); }

/* align-items:start es lo que impide que un campo con ayuda larga estire la
   fila y descuadre los de al lado: cada celda crece hacia abajo por su
   cuenta y los controles siguen alineados arriba. */
.form-grid {
  display: grid;
  gap: var(--sp-4) var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  align-items: start;
}

.form-grid--wide { grid-template-columns: 1fr; }

.fieldset {
  margin: 0;
  padding: 0;
  border: 0;
}

.fieldset__legend {
  padding: 0;
  margin-bottom: var(--sp-3);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
}

.field { display: grid; gap: var(--sp-2); }

.label {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--text);
}

.label__required { color: var(--danger); margin-left: 0.15em; }
.label__optional { color: var(--text-subtle); font-weight: var(--fw-normal); margin-left: 0.35em; font-size: var(--fs-xs); }

.input,
.select,
.textarea {
  width: 100%;
  min-height: 44px;
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  font: inherit;
  font-size: var(--fs-base);
  transition: border-color var(--transition), box-shadow var(--transition);
  /* 16px en móvil evita el zoom automático de iOS al enfocar. */
}

.textarea { min-height: 110px; resize: vertical; line-height: var(--lh); }

.select {
  appearance: none;
  padding-right: var(--sp-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%236a7784' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='M4 6.5 8 10.5 12 6.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-3) center;
  background-size: 16px 16px;
}

.select[multiple] {
  min-height: 140px;
  padding-right: var(--sp-3);
  background-image: none;
}

.input:hover,
.select:hover,
.textarea:hover { border-color: var(--gray-400); }

.input:focus-visible,
.select:focus-visible,
.textarea:focus-visible {
  border-color: var(--focus);
  box-shadow: 0 0 0 3px var(--focus-ring);
  outline: 1px solid var(--focus);
  outline-offset: 0;
}

.input::placeholder,
.textarea::placeholder { color: var(--text-subtle); opacity: 1; }

.input:disabled,
.select:disabled,
.textarea:disabled,
.input[readonly] {
  background: var(--surface-sunken);
  color: var(--text-muted);
  cursor: not-allowed;
}

/* Estado de error: `View::invalidClass()` devuelve ` is-invalid`. */
.is-invalid,
.input.is-invalid,
.select.is-invalid,
.textarea.is-invalid {
  border-color: var(--danger);
  background: var(--danger-soft);
}

.is-invalid:focus-visible {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px var(--danger-ring);
  outline-color: var(--danger);
}

.field-error {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-1);
  color: var(--danger);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
}

.field-error svg {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin-top: 3px;
  stroke: currentColor;
  stroke-width: 2;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* La ayuda es apoyo, no contenido: tamaño menor, interlineado ajustado y
   ancho limitado para que no se estire por toda la columna. */
.field-help {
  color: var(--text-muted);
  font-size: var(--fs-xs);
  line-height: 1.4;
  max-width: 46ch;
  margin-top: calc(var(--sp-1) * -1);
}

/* Casillas y radios: el área pulsable incluye la etiqueta. */
.check {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  min-height: 44px;
  padding: var(--sp-2) 0;
  cursor: pointer;
}

.check__input {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin: 2px 0 0;
  accent-color: var(--primary);
  cursor: pointer;
}

.check__text { font-size: var(--fs-base); line-height: 1.4; }
.check__text small { display: block; color: var(--text-muted); font-size: var(--fs-sm); }

/* En fila y con salto: apilado, seis tipos de evento eran seis líneas de caja
   de filtros para seis palabras. Con dos o tres casillas el resultado es el
   mismo que antes, porque caben en una. */
.check-group { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); }

/* Grupo de radios en línea, como los estados del marcador. */
.radio-tiles { display: grid; gap: var(--sp-2); }

.radio-tile {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 48px;
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}

.radio-tile:hover { border-color: var(--border-strong); background: var(--surface-hover); }

.radio-tile:has(input:checked) {
  border-color: var(--primary);
  background: var(--primary-soft);
}

.radio-tile__key {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  color: var(--text-muted);
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  padding-top: var(--sp-2);
}

.form-actions--split { justify-content: space-between; }

/* Contador de caracteres/segmentos del SMS. */
.counter { font-size: var(--fs-sm); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.counter.is-warning { color: var(--warning); font-weight: var(--fw-semibold); }
.counter.is-danger { color: var(--danger); font-weight: var(--fw-semibold); }

/* ==========================================================================
   8. BOTONES
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 36px;
  padding: var(--sp-1) var(--sp-4);
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  font: inherit;
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold);
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--transition), border-color var(--transition),
              color var(--transition), box-shadow var(--transition), transform var(--transition);
}

.btn:hover { text-decoration: none; background: var(--surface-hover); border-color: var(--gray-400); }
.btn:active { transform: translateY(1px); }

.btn[disabled],
.btn.is-disabled,
.btn[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
  pointer-events: none;
}

.btn svg { width: 18px; height: 18px; stroke: currentColor; stroke-width: 1.8; fill: none; stroke-linecap: round; stroke-linejoin: round; }

.btn--primary {
  background: var(--brand-600);
  border-color: var(--brand-600);
  color: #fff;
  box-shadow: var(--shadow-xs);
}

.btn--primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); color: #fff; }

.btn--secondary {
  background: var(--surface);
  border-color: var(--border-strong);
  color: var(--text);
}

/* Cuando este botón es un <a>, el `a:hover` general le cambiaba el color y le
   añadía subrayado. Se fija aquí, como en el resto de variantes. */
.btn--secondary:hover,
.btn--secondary:focus-visible {
  color: var(--text);
  text-decoration: none;
}

.btn--danger {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
}

.btn--danger:hover {
  background: var(--danger-hover);
  border-color: var(--danger-hover);
  color: #fff;
}

.btn--success {
  background: var(--success);
  border-color: var(--success);
  color: #fff;
}

.btn--success:hover {
  background: var(--success-hover);
  border-color: var(--success-hover);
  color: #fff;
}

.btn--ghost { background: transparent; border-color: transparent; color: var(--link); }
.btn--ghost:hover { background: var(--primary-soft); border-color: transparent; }

.btn--link {
  min-height: 0;
  padding: 0;
  background: none;
  border: 0;
  color: var(--link);
  font-weight: var(--fw-medium);
}

.btn--link:hover { background: none; text-decoration: underline; }

/* Tamaños. En móvil ningún botón baja de 44px de alto (ver §15). */
.btn--sm { min-height: 30px; padding: var(--sp-1) var(--sp-3); font-size: var(--fs-sm); }
.btn--lg { min-height: 46px; padding: var(--sp-2) var(--sp-6); font-size: var(--fs-md); }

/* En táctil se recupera el objetivo de 44 px: el botón compacto es para
   ratón, y el marcador se usa de pie y con el pulgar. */
@media (pointer: coarse) {
  .btn { min-height: 44px; padding-block: var(--sp-2); }
  .btn--sm { min-height: 38px; }
  .btn--lg { min-height: 52px; }
}
.btn--block { width: 100%; }

.btn-group { display: inline-flex; flex-wrap: wrap; gap: var(--sp-2); }

/* Barra de acciones pegada al fondo en móvil: guardar siempre al alcance. */
.sticky-actions {
  position: sticky;
  bottom: 0;
  z-index: var(--z-header);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  padding: var(--sp-3);
  margin: var(--sp-4) calc(-1 * var(--sp-3)) 0;
  background: var(--surface);
  border-top: 1px solid var(--border);
  box-shadow: 0 -4px 12px rgba(13, 27, 34, 0.06);
}

.sticky-actions .btn { flex: 1 1 140px; }

/* ==========================================================================
   9. BADGES Y ETIQUETAS DE ESTADO
   --------------------------------------------------------------------------
   Los modificadores son exactamente los valores de LeadStatus::badge():
   info, warning, secondary, dark, primary, success (+ danger).
   ========================================================================== */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 0.2em 0.65em;
  border: 1px solid var(--secondary-line);
  border-radius: var(--radius-pill);
  background: var(--secondary-soft);
  color: var(--secondary);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  line-height: 1.5;
  white-space: nowrap;
  vertical-align: middle;
}

.badge--info      { background: var(--info-soft);      border-color: var(--info-line);      color: var(--info); }
.badge--warning   { background: var(--warning-soft);   border-color: var(--warning-line);   color: var(--warning); }
.badge--secondary { background: var(--secondary-soft);  border-color: var(--secondary-line); color: var(--secondary); }
.badge--primary   { background: var(--primary-soft);   border-color: var(--primary-line);   color: var(--primary); }
.badge--success   { background: var(--success-soft);   border-color: var(--success-line);   color: var(--success); }
.badge--danger    { background: var(--danger-soft);    border-color: var(--danger-line);    color: var(--danger); }

.badge--dot::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}

/* Aquí vivían `--solid` y `--dark`, pastillas de fondo macizo. Se fueron con
   lo que las usaba: en una tabla de estados pastel, la única sólida se lleva la
   mirada, y la que la tenía era «Cerrado» — el estado que menos importa. */

.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  padding: 0.15em 0.55em;
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
}

/* El total de tiempo de una ficha: la cifra es el dato, no un apunte. */
.timespent__total {
  margin: 0;
  font-size: var(--fs-2xl);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  line-height: var(--lh-tight);
}

/* La hora y el reloj que la cambia, juntos. El botón vive al lado del dato que
   modifica y no en la columna de acciones: allí quedaba a cuatro columnas de
   distancia de la hora que se iba a tocar. */
.agenda__hour {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
}

/* El reloj, ajustado a la hora que acompaña.

   Más pequeño, porque a 30px pesaba más que el propio dato y estiraba la fila.
   Y bajado un pelo: una hora son dígitos sin descendentes, así que su centro
   óptico cae por debajo del centro de su caja y un icono centrado a la
   perfección se ve alto. */
.agenda__hour .iconbtn {
  width: 1.5rem;
  height: 1.5rem;
  transform: translateY(1px);
}

.agenda__hour .iconbtn svg { width: 0.85rem; height: 0.85rem; }

/* --- Panel de leads: parrilla de días por fracciones de hora ----------- */


/* La cabecera y la columna de horas se quedan fijas: con treinta filas y diez
   columnas, al desplazarse se pierde de vista qué día y qué hora se está
   mirando, que es lo único que hace legible una rejilla. */
.board__wrap { max-height: 70vh; overflow: auto; }

.board {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--fs-xs);
}

.board th,
.board td {
  border-bottom: 1px solid var(--border-subtle, var(--border));
  border-right: 1px solid var(--border-subtle, var(--border));
}

.board thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: var(--sp-2);
  background: var(--surface);
  text-align: center;
  vertical-align: bottom;
}

.board__corner {
  position: sticky;
  left: 0;
  z-index: 3;
  width: 3.5rem;
  background: var(--surface);
}

.board__day-name { display: block; font-weight: var(--fw-semibold); }
.board__day-date { display: block; color: var(--text-subtle); font-size: 0.68rem; }

.board__day-count {
  display: inline-block;
  min-width: 1.4em;
  margin-top: 0.2rem;
  padding: 0 0.35em;
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.board__day-count.is-empty { opacity: 0.45; }

/* El día de hoy y los cerrados, marcados en la propia columna: es lo que evita
   contar cabeceras para saber en qué día se está. */
.board thead th.is-today { box-shadow: inset 0 -3px 0 var(--primary); }
.board thead th.is-closed .board__day-name { color: var(--text-subtle); }

.board__hour {
  position: sticky;
  left: 0;
  z-index: 1;
  padding: 0.2rem var(--sp-2);
  background: var(--surface);
  color: var(--text-subtle);
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-normal);
  text-align: right;
  white-space: nowrap;
  vertical-align: top;
}

/* La hora en punto se marca más: cuarenta filas de cuartos sin referencia se
   leen como una mancha y se pierde la cuenta. */
.board__row.is-hour > * { border-top: 1px solid var(--border); }

/* Salto de horas: la línea discontinua dice que entre esta fila y la de arriba
   falta tiempo. Sin ella, 13:45 y 16:00 pegadas se leen como seguidas. */
.board__row.is-gap > * { border-top: 2px dashed var(--border); }
.board__row.is-hour .board__hour { color: var(--text); font-weight: var(--fw-semibold); }

.board__cell {
  min-width: 8.5rem;
  padding: 0.15rem;
  vertical-align: top;
}

.board__cell.is-today { background: var(--surface-2); }

/* Cada ficha es un momento. El tiempo va delante y en ancho fijo para que la
   columna se lea en vertical aunque los nombres midan distinto. */
.board__chip {
  display: flex;
  align-items: baseline;
  gap: 0.3rem;
  padding: 0.1rem 0.35rem;
  margin-bottom: 0.1rem;
  border-radius: var(--radius-sm);
  border-left: 3px solid currentColor;
  text-decoration: none;
  line-height: 1.35;
}

.board__chip-time { font-variant-numeric: tabular-nums; opacity: 0.75; flex: 0 0 auto; }

.board__chip-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: var(--fw-medium);
}

.board__chip:hover { filter: brightness(0.96); }

.board__chip--info      { background: var(--info-soft);      color: var(--info); }
.board__chip--warning   { background: var(--warning-soft);   color: var(--warning); }
.board__chip--secondary { background: var(--secondary-soft); color: var(--secondary); }
.board__chip--primary   { background: var(--primary-soft);   color: var(--primary); }
.board__chip--success   { background: var(--success-soft);   color: var(--success); }
.board__chip--danger    { background: var(--danger-soft);    color: var(--danger); }

.board__more {
  display: block;
  padding: 0 0.35rem;
  color: var(--text-subtle);
  font-size: 0.68rem;
}

/* ==========================================================================
   EL MÓVIL COMO AURICULAR DEL MARCADOR
   ========================================================================== */

/* Pantalla de una sola cosa: a quién llamas y el botón. Sin menú y sin nada
   que competa, porque se usa con una mano mientras la otra está en el teclado
   del portátil. */
.handset {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  min-height: 100vh;
  min-height: 100dvh;
  padding: var(--sp-4);
  background: var(--surface-2);
}

.handset__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

.handset__who { font-weight: var(--fw-semibold); }

/* El estado de la conexión. Vacío no ocupa: solo se ve cuando hay algo que
   decir, y lo que dice es si el número de la pantalla puede estar viejo. */
.handset__status { text-align: right; }
.handset__status:empty { display: none; }
.handset__status.is-bad { color: var(--danger); font-weight: var(--fw-semibold); }

.handset__card,
.handset__empty {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.handset__empty { flex: 1 1 auto; justify-content: center; text-align: center; color: var(--text-muted); }
.handset__title { margin: 0; font-size: var(--fs-lg); color: var(--text); }

.handset__label {
  margin: 0;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-subtle);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* El nombre grande: es lo que se lee de un vistazo antes de descolgar, y lo
   que evita saludar a quien no es. */
.handset__name {
  margin: 0;
  font-size: var(--fs-2xl);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  overflow-wrap: anywhere;
}

.handset__meta { margin: 0; color: var(--text-muted); font-size: var(--fs-sm); }
.handset__meta:empty { display: none; }

/* El botón ocupa lo que hace falta para acertar con el pulgar sin mirar,
   porque se pulsa con la vista puesta en el portátil. */
.handset__call {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  min-height: 72px;
  border-radius: var(--radius-lg);
  background: var(--success);
  color: #fff;
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
}

.handset__call svg {
  width: 1.4rem;
  height: 1.4rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* El color se fija en TODOS los estados del enlace.

   La regla global `a:hover` lo pinta azul y lo subraya, y en un móvil el estado
   de hover se queda pegado después de tocar: el botón se quedaba con el número
   en azul hasta tocar en otro sitio. */
.handset__call,
.handset__call:link,
.handset__call:visited,
.handset__call:hover,
.handset__call:focus,
.handset__call:active {
  color: #fff;
  text-decoration: none;
}

/* Y sin el recuadro gris que pinta el navegador al tocar: aquí el aviso de que
   se ha pulsado lo da el propio botón, abajo. */
.handset__call { -webkit-tap-highlight-color: transparent; }

/* Al pulsar: se hunde. Es un gesto que se hace sin mirar la pantalla, así que
   la confirmación tiene que notarse de reojo; un cambio de color a secas no se
   ve con el teléfono en la mano y la vista puesta en el portátil.

   El tono oscuro se declara aquí, y no con `--success-line`, porque ése es un
   verde claro pensado para bordes de pastilla: como sombra bajo un botón verde
   oscuro se ve como un halo, no como relieve. */
.handset__call {
  --call-deep: #14603a;
  transition: transform 0.1s ease, background-color 0.1s ease, box-shadow 0.1s ease;
  box-shadow: 0 4px 0 var(--call-deep);
}

.handset__call:active {
  transform: translateY(4px);
  background: var(--call-deep);
  box-shadow: none;
}

/* En modo oscuro el verde de marca es más claro, así que el hundido también
   sube: con el tono de arriba, pulsar parecía apagar el botón. */
@media (prefers-color-scheme: dark) {
  .handset__call { --call-deep: #2f8a5c; }
}

@media (prefers-reduced-motion: reduce) {
  .handset__call { transition: none; }
  .handset__call:active { transform: none; }
}

.handset__call[aria-disabled="true"] {
  background: var(--secondary);
  opacity: 0.7;
  box-shadow: none;
}

.handset__call[aria-disabled="true"]:active { transform: none; }

.handset__since { margin: 0; color: var(--text-subtle); font-size: var(--fs-xs); }

/* Al cambiar de ficha, un destello: avisa de que el número de debajo del dedo
   ya no es el de hace un segundo. */
.handset__card.is-new { animation: handset-new 1s ease-out both; }

@keyframes handset-new {
  0% { border-color: var(--success); box-shadow: 0 0 0 3px var(--success-soft); }
  100% { border-color: var(--border); box-shadow: var(--shadow-sm); }
}

/* Recargar: redondo, grande y centrado.

   Es el único gesto de esta pantalla aparte de llamar y se hace con el pulgar
   mientras la vista está en el portátil, así que se busca por su forma. Una
   barra con la palabra «Actualizar» obliga a bajar la mirada para leerla. */
.handset__reload-zone {
  display: grid;
  justify-items: center;
  gap: var(--sp-2);
  margin-top: auto;
  padding: var(--sp-4) 0;
}

.handset__reload {
  display: grid;
  place-items: center;
  width: 84px;
  height: 84px;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--surface);
  color: var(--primary);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}

.handset__reload svg {
  width: 34px;
  height: 34px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Se hunde al pulsar: en un móvil no hay cursor que confirme el toque. */
.handset__reload:active { transform: scale(0.94); box-shadow: none; }

/* Mientras pide, gira. Es lo que distingue «no ha pasado nada porque va lento»
   de «no ha pasado nada porque no funciona». */
.handset__reload.is-loading svg { animation: handset-spin 0.8s linear infinite; }

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

.handset__reload-text {
  color: var(--text-subtle);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

@media (prefers-reduced-motion: reduce) {
  .handset__reload.is-loading svg { animation: none; }
  .handset__reload { transition: none; }
}

@media (prefers-reduced-motion: reduce) {
  .handset__card.is-new { animation: none; }
}

/* --- El panel en el móvil: una lista por día, no la rejilla ------------- */

/* Cada pantalla enseña lo suyo. Una matriz de siete columnas por cuarenta
   filas en 375 píxeles se arrastra en dos direcciones y las celdas vacías
   ocupan lo mismo que las llenas; una lista de lo que hay se lee de un
   pulgar. */
.board__mobile { display: none; }

/* Barra para saltar de día, con su contador. Se desplaza a lo ancho en vez de
   apilarse: ocupa una línea pase lo que pase y se recorre con el pulgar. */
.board__jump {
  display: flex;
  gap: var(--sp-2);
  overflow-x: auto;
  padding-bottom: var(--sp-2);
  margin-bottom: var(--sp-2);
  -webkit-overflow-scrolling: touch;
}

.board__jump-day {
  display: grid;
  justify-items: center;
  gap: 0.1rem;
  flex: 0 0 auto;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
}

.board__jump-day.is-today { border-color: var(--primary); color: var(--primary); }
.board__jump-date { color: var(--text-subtle); font-weight: var(--fw-normal); }

.board__jump-count {
  min-width: 1.5em;
  padding: 0 0.35em;
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.board__jump-count.is-empty { opacity: 0.45; }

.board__dayblock { margin-bottom: var(--sp-3); scroll-margin-top: var(--sp-4); }
.board__dayblock-date { margin-left: var(--sp-2); color: var(--text-subtle); font-weight: var(--fw-normal); }

.board__list { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--sp-2); }

/* Hora, quién y qué le pasa. La hora en ancho fijo para que la columna se lea
   en vertical aunque los nombres midan distinto. */
.board__item {
  display: grid;
  grid-template-columns: 3.2rem minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-2);
}

.board__item-time {
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-semibold);
  font-size: var(--fs-sm);
}

.board__item-type { color: var(--text-subtle); font-size: var(--fs-xs); white-space: nowrap; }

.board__item .board__chip { margin: 0; min-height: 32px; }

@media (max-width: 720px) {
  .board__mobile { display: block; }
  .board__grid-card { display: none; }
}

/* --- Estado de una cita, editable en la propia fila ------------------- */

/* Es un `<select>` con la pastilla puesta: se lee de un barrido como una
   etiqueta de color y se cambia sin abrir nada. El color lo pone el estado
   actual, así que la columna sigue diciendo lo mismo que antes. */
.statepick {
  appearance: none;
  -webkit-appearance: none;
  padding: 0.2em 1.6em 0.2em 0.65em;
  border: 1px solid var(--secondary-line);
  border-radius: var(--radius-pill);
  background-color: var(--secondary-soft);
  color: var(--secondary);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  font-family: inherit;
  line-height: 1.5;
  cursor: pointer;

  /* La flecha va pintada aquí porque `appearance: none` se lleva la nativa, y
     sin ella el desplegable se lee como una etiqueta que no se puede tocar. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.45em center;
  background-size: 0.7em;
}

.statepick:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }

.statepick--danger    { background-color: var(--danger-soft);    border-color: var(--danger-line);    color: var(--danger); }
.statepick--warning   { background-color: var(--warning-soft);   border-color: var(--warning-line);   color: var(--warning); }
.statepick--success   { background-color: var(--success-soft);   border-color: var(--success-line);   color: var(--success); }
.statepick--secondary { background-color: var(--secondary-soft); border-color: var(--secondary-line); color: var(--secondary); }

/* Las opciones del desplegable las pinta el sistema: sobre el fondo pastel de
   la pastilla, el texto del menú heredaría un color que no se lee. */
.statepick option { color: var(--text); background: var(--surface); }

/* La fecha del último aviso, debajo de la pastilla. Existe siempre —vacía no
   ocupa— porque al marcar sin recargar hay que tener dónde escribirla. */
.statepick__note { display: block; margin-top: 0.15rem; }
.statepick__note:empty { display: none; }

/* Guardando: el color ya ha cambiado, así que aquí solo se apaga un poco para
   decir «esto todavía está en el aire». Un spinner por fila sería más ruido
   que información en una agenda de veinte citas. */
.agenda__day tr.is-saving .statepick { opacity: 0.55; }
.agenda__day tr.is-saving { cursor: progress; }

/* Guardado: un destello y se va. Un aviso por cada marca serían veinte
   carteles seguidos repasando la agenda del día; el destello dice lo mismo y
   no mueve nada de sitio. */
.agenda__day tr.is-saved > * { animation: row-saved 1.2s ease-out both; }

@keyframes row-saved {
  0% { background-color: var(--success-soft); }
  100% { background-color: transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .agenda__day tr.is-saved > * { animation: none; }
}

/* --- Cabecera de la ficha del lead ------------------------------------ */

/* Lo primero que se ve al descolgar. El orden es deliberado: quién es, de
   quién es, qué se quedó pendiente y solo entonces el botón de llamar. */

.recordhead__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-3);
}

.recordhead__who { min-width: 0; }

.recordhead__name {
  margin: 0;
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  overflow-wrap: anywhere;
}

.recordhead__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* De quién es la ficha: una línea, no una tarjeta. Antes estaba enterrado seis
   filas más abajo y reasignar era otra tarjeta entera. */
.recordhead__owner {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin: 0;
  font-size: var(--fs-sm);
}

.recordhead__owner-label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-subtle);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.recordhead__owner-name { font-weight: var(--fw-semibold); }

/* Lo acordado y lo último anotado. Fondo propio porque es lo que hay que haber
   leído antes de marcar, no un dato más de la ficha. */
.recordhead__due {
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border-radius: var(--radius);
  border-left: 3px solid var(--primary);
  background: var(--surface-sunken);
}

.recordhead__due-when {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-2);
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.recordhead__due-label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-subtle);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.recordhead__note { margin: 0; font-size: var(--fs-sm); }
.recordhead__note p { margin: 0; }

.recordhead__note footer {
  margin-top: var(--sp-1);
  color: var(--text-subtle);
  font-size: var(--fs-xs);
}

.recordhead__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
}

/* El botón de llamar ocupaba el ancho entero y dos dedos de alto. Sigue siendo
   el más visible, pero del tamaño de la acción: en el escritorio es un clic. */
.recordhead__call {
  gap: var(--sp-2);
  font-size: var(--fs-md);
  font-variant-numeric: tabular-nums;
}

.recordhead__call svg {
  width: 1rem;
  height: 1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* En el móvil sí se llama de verdad desde aquí, y ahí el ancho completo es lo
   que hace que se acierte con el pulgar a la primera. */
@media (max-width: 640px) {
  .recordhead__actions { flex-direction: column; align-items: stretch; }
  .recordhead__actions form { display: contents; }
  .recordhead__actions .btn { width: 100%; }
  .recordhead__call { min-height: 48px; }
}

/* --- Elegir día y hora ------------------------------------------------ */

/* Dos campos en una línea, con el día ocupando lo que le sobre a la hora. En
   el móvil se apilan: en 360px, un date y un select en paralelo dejan los dos
   ilegibles. */
.datetime { display: grid; gap: var(--sp-2); }

.datetime__fields {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(7.5rem, auto);
  gap: var(--sp-2);
}

@media (max-width: 420px) {
  .datetime__fields { grid-template-columns: 1fr; }
}

.datetime__field { min-width: 0; }

/* El teclado del móvil encoge los controles nativos por debajo de lo que un
   pulgar acierta; 44px es el mínimo con el que se pulsa sin fallar. */
.datetime__fields .input,
.datetime__fields .select { min-height: 44px; }

.datetime__quick { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* Atajo de día: «Mañana» es la respuesta más repetida y con el calendario
   nativo son tres toques. Se lee como una pastilla pulsable, no como un botón
   de acción, porque no guarda nada: solo rellena la fecha. */
.chip {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 0 0.7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
}

.chip:hover,
.chip:focus-visible {
  border-color: var(--primary);
  color: var(--primary);
  background: var(--surface-hover);
}

/* Por qué no hay horas ese día. Vacío no ocupa sitio. */
.datetime__note {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

.datetime__note:empty { display: none; }

@media (prefers-reduced-motion: reduce) {
  .chip { transition: none; }
}

/* ==========================================================================
   10. ALERTAS FLASH
   ========================================================================== */

.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--secondary-line);
  border-left-width: 4px;
  border-radius: var(--radius);
  background: var(--secondary-soft);
  color: var(--text);
  font-size: var(--fs-base);
}

.alert__icon { flex: 0 0 auto; width: 20px; height: 20px; margin-top: 1px; stroke: currentColor; stroke-width: 1.8; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.alert__body { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.alert__title { margin: 0 0 var(--sp-1); font-size: var(--fs-base); font-weight: var(--fw-semibold); }
.alert__body p { margin: 0; }
.alert__body p + p { margin-top: var(--sp-1); }



.alert--success { background: var(--success-soft); border-color: var(--success-line); border-left-color: var(--success); color: var(--success); }
.alert--error,
.alert--danger  { background: var(--danger-soft);  border-color: var(--danger-line);  border-left-color: var(--danger);  color: var(--danger); }
.alert--warning { background: var(--warning-soft); border-color: var(--warning-line); border-left-color: var(--warning); color: var(--warning); }
.alert--info    { background: var(--info-soft);    border-color: var(--info-line);    border-left-color: var(--info);    color: var(--info); }

/* Aviso flotante breve (portapapeles, atajos). Lo crea app.js. */
/* Avisos apilados abajo a la derecha.

   Antes era una pastilla centrada que se sustituía a sí misma: dos avisos
   seguidos —«copiado» y luego «guardado»— se pisaban y el primero no llegaba a
   leerse. Apilados a un lado no tapan el contenido ni se estorban. */
.toasts {
  position: fixed;
  right: var(--sp-5);
  bottom: var(--sp-5);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  width: min(92vw, 380px);
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  pointer-events: auto;
  animation: toast-in 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes toast-in {
  from { opacity: 0; transform: translateX(28px); }
  to { opacity: 1; transform: none; }
}

.toast.is-leaving { animation: toast-out 0.24s ease both; }

@keyframes toast-out {
  to { opacity: 0; transform: translateX(28px); }
}

/* El icono lleva el color; el texto, el significado. Un color no es un mensaje
   para quien no lo distingue, así que el titular también lo dice. */
.toast__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 1.4rem;
  height: 1.4rem;
  margin-top: 0.1rem;
  border-radius: var(--radius-sm);
}

.toast__icon svg {
  width: 0.8rem;
  height: 0.8rem;
  fill: none;
  stroke: #fff;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.toast--ok .toast__icon { background: var(--success); }
.toast--error .toast__icon { background: var(--danger); }
.toast--info .toast__icon { background: var(--info, var(--primary)); }

.toast__body { flex: 1 1 auto; min-width: 0; }
.toast__body b { display: block; font-size: var(--fs-sm); font-weight: var(--fw-semibold); }

.toast__body p {
  margin: 0.1rem 0 0;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  overflow-wrap: anywhere;
}

.toast__close {
  flex: 0 0 auto;
  padding: 0 0.15rem;
  border: 0;
  background: transparent;
  color: var(--text-subtle);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}

.toast__close:hover { color: var(--text); }

/* En el móvil ocupan el ancho, que es donde se leen sin estorbar al pulgar. */
@media (max-width: 640px) {
  .toasts { left: var(--sp-3); right: var(--sp-3); bottom: var(--sp-3); width: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .toast, .toast.is-leaving { animation: none; }
}

/* ==========================================================================
   11. MODAL
   ========================================================================== */

.modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: none;
  align-items: flex-end;
  justify-content: center;
  padding: 0;
}

.modal.is-open { display: flex; }

.modal__overlay {
  position: absolute;
  inset: 0;
  background: rgba(8, 16, 20, 0.6);
}

.modal__dialog {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 560px;
  max-height: 92vh;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.modal__head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
}

.modal__title { margin: 0; flex: 1 1 auto; font-size: var(--fs-md); font-weight: var(--fw-semibold); }
.modal__body { flex: 1 1 auto; padding: var(--sp-5); overflow-y: auto; -webkit-overflow-scrolling: touch; }

.modal__foot {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  justify-content: flex-end;
  padding: var(--sp-3) var(--sp-5) var(--sp-5);
  border-top: 1px solid var(--border);
  background: var(--surface-2);
}

.modal__foot .btn { flex: 1 1 130px; }

/* El body no debe hacer scroll detrás del modal (clase que pone app.js). */
body.has-modal { overflow: hidden; }

/* ==========================================================================
   12. PAGINACIÓN, PESTAÑAS, TOOLTIP, PROGRESO
   ========================================================================== */

.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-4);
}

.pagination__summary { color: var(--text-muted); font-size: var(--fs-sm); }

.pagination__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  margin: 0 0 0 auto;
  padding: 0;
  list-style: none;
}

.pagination__link {
  display: grid;
  place-items: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 var(--sp-2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
}

.pagination__link:hover { background: var(--surface-hover); border-color: var(--border-strong); text-decoration: none; }

.pagination__link.is-active {
  background: var(--brand-600);
  border-color: var(--brand-600);
  color: #fff;
  font-weight: var(--fw-semibold);
}

.pagination__link.is-disabled,
.pagination__gap {
  display: grid;
  place-items: center;
  min-width: 44px;
  min-height: 44px;
  color: var(--text-subtle);
  pointer-events: none;
  border: 1px solid transparent;
}

/* --- Pestañas --------------------------------------------------------- */

.tabs {
  display: flex;
  gap: var(--sp-1);
  margin-bottom: var(--sp-4);
  padding-bottom: 1px;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}

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

.tabs__item {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 36px;
  padding: var(--sp-1) var(--sp-4);
  border: 1px solid transparent;
  border-bottom: 2px solid transparent;
  border-radius: var(--radius) var(--radius) 0 0;
  color: var(--text-muted);
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  white-space: nowrap;
}

.tabs__item:hover { background: var(--surface-hover); color: var(--text); text-decoration: none; }

.tabs__item.is-active,
.tabs__item[aria-current="page"] {
  color: var(--link);
  border-bottom-color: var(--brand-600);
  font-weight: var(--fw-semibold);
}

/* --- Tooltip: solo CSS, con `data-tip` como texto --------------------- */

.tip { position: relative; }

.tip::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-toast);
  max-width: 240px;
  width: max-content;
  padding: var(--sp-1) var(--sp-2);
  background: var(--gray-900);
  color: #fff;
  border-radius: var(--radius-sm);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  line-height: 1.4;
  white-space: normal;
  text-align: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--transition), visibility var(--transition);
  pointer-events: none;
}

.tip:hover::after,
.tip:focus-visible::after { opacity: 1; visibility: visible; }

/* En pantallas táctiles el hover no existe: el tooltip nunca es la única
   vía de acceso a la información, así que aquí simplemente se oculta. */
@media (hover: none) {
  .tip::after { display: none; }
}

/* --- Barra de progreso ------------------------------------------------ */

.progress {
  height: 8px;
  background: var(--surface-sunken);
  border-radius: var(--radius-pill);
  overflow: hidden;
}

.progress__bar {
  height: 100%;
  width: 0;
  background: var(--brand-500);
  border-radius: var(--radius-pill);
  transition: width 320ms ease;
}

.progress--lg { height: 14px; }
.progress__bar--success { background: var(--success); }
.progress__bar--warning { background: var(--warning); }
.progress__bar--danger { background: var(--danger); }

.progress-row { display: grid; gap: var(--sp-1); }
.progress-row__head { display: flex; justify-content: space-between; gap: var(--sp-2); font-size: var(--fs-sm); }
.progress-row__value { font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }

/* ==========================================================================
   13. KPI, TIMELINE, ESTADO VACÍO, TEMPORIZADOR
   ========================================================================== */

.kpis {
  display: grid;
  gap: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  margin-bottom: var(--sp-5);
}

.kpi {
  display: grid;
  gap: var(--sp-1);
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
}

.kpi__label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-subtle);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.kpi__value {
  font-size: var(--fs-2xl);
  font-weight: var(--fw-bold);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.kpi__unit { font-size: var(--fs-md); font-weight: var(--fw-medium); color: var(--text-muted); }
.kpi__foot { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--text-muted); }

.kpi__delta { font-weight: var(--fw-semibold); }
.kpi__delta--up { color: var(--success); }
.kpi__delta--down { color: var(--danger); }
.kpi__delta--flat { color: var(--text-muted); }

/* Un contador que se puede abrir. Se marca con la flecha y el subrayado del
   número al pasar por encima: sin eso, cinco cajas iguales y solo algunas
   pulsables no se distinguen hasta que se prueba. */
.kpi--link {
  position: relative;
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.kpi--link::after {
  content: "";
  position: absolute;
  top: var(--sp-4);
  right: var(--sp-4);
  width: 0.45rem;
  height: 0.45rem;
  border-top: 1.5px solid var(--text-subtle);
  border-right: 1.5px solid var(--text-subtle);
  transform: rotate(45deg);
  opacity: 0.5;
  transition: opacity 0.15s ease, border-color 0.15s ease;
}

.kpi--link:hover,
.kpi--link:focus-visible {
  border-color: var(--primary);
  box-shadow: var(--shadow-sm);
}

.kpi--link:hover::after,
.kpi--link:focus-visible::after {
  opacity: 1;
  border-color: var(--primary);
}

.kpi--link:hover .kpi__value { color: var(--primary); }

@media (prefers-reduced-motion: reduce) {
  .kpi--link { transition: none; }
}

.kpi--accent { border-left: 3px solid var(--brand-500); }
.kpi--success { border-left: 3px solid var(--success); }
.kpi--warning { border-left: 3px solid var(--warning); }
.kpi--danger { border-left: 3px solid var(--danger); }

/* --- Timeline de actividad ------------------------------------------- */

.timeline { margin: 0; padding: 0 0 0 var(--sp-5); list-style: none; position: relative; }

.timeline::before {
  content: "";
  position: absolute;
  top: 6px;
  bottom: 6px;
  left: 5px;
  width: 2px;
  background: var(--border);
}

.timeline__item { position: relative; padding: 0 0 var(--sp-5); }
.timeline__item:last-child { padding-bottom: 0; }

.timeline__item::before {
  content: "";
  position: absolute;
  top: 6px;
  left: calc(-1 * var(--sp-5) + 1px);
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--border-strong);
}

.timeline__item--primary::before { border-color: var(--brand-500); }
.timeline__item--success::before { border-color: var(--success); }
.timeline__item--danger::before { border-color: var(--danger); }
.timeline__item--warning::before { border-color: var(--warning); }

.timeline__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--text-subtle);
}

.timeline__title { margin: var(--sp-1) 0 0; font-size: var(--fs-base); font-weight: var(--fw-semibold); }
.timeline__text { margin: var(--sp-1) 0 0; font-size: var(--fs-sm); color: var(--text-muted); overflow-wrap: anywhere; }

/* --- Estado vacío ---------------------------------------------------- */

.empty {
  display: grid;
  justify-items: center;
  gap: var(--sp-3);
  padding: var(--sp-10) var(--sp-5);
  text-align: center;
  color: var(--text-muted);
}

.empty__icon {
  width: 48px;
  height: 48px;
  stroke: var(--border-strong);
  stroke-width: 1.5;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.empty__title { margin: 0; font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--text); }
.empty__text { margin: 0; max-width: 46ch; font-size: var(--fs-sm); }

/* --- Temporizador del marcador --------------------------------------- */

.timer {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.timer__label { font-family: var(--font); font-size: var(--fs-xs); font-weight: var(--fw-medium); color: var(--text-muted); letter-spacing: 0; }
.timer.is-long { background: var(--warning-soft); border-color: var(--warning-line); color: var(--warning); }

/* Panel de atajos de teclado del marcador. */
.shortcuts { display: grid; gap: var(--sp-2); font-size: var(--fs-sm); }
.shortcuts__row { display: flex; align-items: center; gap: var(--sp-3); }
.shortcuts__keys { flex: 0 0 auto; display: flex; gap: var(--sp-1); }
.shortcuts__desc { color: var(--text-muted); }

/* Los atajos solo tienen sentido con teclado físico. */
@media (hover: none) and (pointer: coarse) {
  .shortcuts-card { display: none; }
}

/* ==========================================================================
   14. SITIO PÚBLICO (landings, gracias, confirmación, legales)
   ========================================================================== */

.site { display: flex; flex-direction: column; min-height: 100vh; }

.site__header {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.site__brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  color: var(--text);
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
}

.site__brand:hover { text-decoration: none; color: var(--text); }

.site__phone {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;
  margin-left: auto;
  padding: var(--sp-2) var(--sp-4);
  border: 1px solid var(--brand-200);
  border-radius: var(--radius-pill);
  background: var(--primary-soft);
  color: var(--link);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
}

.site__phone:hover { text-decoration: none; background: var(--brand-100); }

.site__main { flex: 1 1 auto; }

.site__footer {
  padding: var(--sp-6) var(--sp-4) var(--sp-8);
  background: var(--gray-900);
  color: var(--gray-300);
  font-size: var(--fs-sm);
}

.site__footer a { color: var(--gray-100); text-decoration: underline; }
.site__footer a:hover { color: #fff; }

.site__footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3) var(--sp-5);
  max-width: 1080px;
  margin: 0 auto;
}

.site__legal-nav { display: flex; flex-wrap: wrap; gap: var(--sp-4); margin: 0; padding: 0; list-style: none; }
.site__legal-nav a { min-height: 44px; display: inline-flex; align-items: center; }
.site__copy { margin: 0; color: var(--gray-400); }

/* --- Hero de landing -------------------------------------------------- */

.hero {
  padding: var(--sp-8) var(--sp-4) var(--sp-10);
  background:
    radial-gradient(120% 80% at 15% 0%, var(--brand-50) 0%, transparent 60%),
    var(--bg);
}

.hero__inner {
  display: grid;
  gap: var(--sp-8);
  max-width: 1080px;
  margin: 0 auto;
  align-items: start;
}

.hero__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
  padding: 0.25em 0.8em;
  border-radius: var(--radius-pill);
  background: var(--primary-soft);
  border: 1px solid var(--primary-line);
  color: var(--primary);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.hero__title {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-2xl);
  font-weight: var(--fw-bold);
  letter-spacing: -0.02em;
  line-height: 1.15;
}

.hero__lead {
  margin: 0 0 var(--sp-5);
  max-width: 52ch;
  font-size: var(--fs-md);
  color: var(--text-muted);
}

.hero__points { display: grid; gap: var(--sp-3); margin: 0 0 var(--sp-5); padding: 0; list-style: none; }

.hero__point {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  font-size: var(--fs-base);
}

.hero__point::before {
  content: "";
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin-top: 2px;
  border-radius: 50%;
  background: var(--brand-500) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23fff' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m3.5 8.5 3 3 6-7'/%3E%3C/svg%3E") center / 13px 13px no-repeat;
}

.hero__media img { border-radius: var(--radius-lg); box-shadow: var(--shadow); }

.hero__note { font-size: var(--fs-xs); color: var(--text-subtle); }

/* Hero con imagen de fondo.
   La URL llega en la variable --hero-bg desde la plantilla (atributo style),
   porque la imagen la elige cada landing en el CRM y no puede estar en la
   hoja. El degradado va ENCIMA de la foto: sin él, un fondo claro deja el
   titular ilegible, y eso es justo donde está la propuesta de valor. Se ha
   bajado al mínimo que mantiene el contraste AA del titular: la foto tiene
   que verse. Los textos sobre la foto llevan además sombra, que da
   legibilidad sin oscurecer la imagen entera. */
.hero--image {
  position: relative;
  background-image:
    linear-gradient(180deg, rgba(10, 22, 26, 0.42) 0%, rgba(10, 22, 26, 0.24) 45%, rgba(10, 22, 26, 0.50) 100%),
    var(--hero-bg);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* Sobre la foto, el texto va en claro pase lo que pase con el tema. */
.hero--image .hero__title,
.hero--image .hero__lead,
.hero--image .hero__point,
.hero--image .hero__note { color: #fff; }

/* La sombra hace el trabajo que antes hacía el degradado oscuro. */
.hero--image .hero__title { text-shadow: 0 2px 12px rgba(0, 0, 0, 0.55); }

.hero--image .hero__lead,
.hero--image .hero__note,
.hero--image .hero__point { text-shadow: 0 1px 8px rgba(0, 0, 0, 0.6); }

.hero--image .hero__lead,
.hero--image .hero__note { opacity: 0.92; }

.hero--image .hero__eyebrow {
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
}

.hero--image .hero__point::before { color: #fff; }

/* En móvil la foto ocupa toda la altura visible y el texto queda encima;
   fijarla causaría saltos en iOS, así que se desplaza con la página. */
@media (max-width: 767px) {
  .hero--image { background-attachment: scroll; }
}

/* La tarjeta del formulario mantiene fondo sólido: es lo que tiene que
   destacar sobre la foto. */
.hero--image .capture { box-shadow: 0 18px 50px rgba(0, 0, 0, 0.35); }

/* --- Formulario de captación destacado -------------------------------- */

.capture {
  position: relative;
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 4px solid var(--brand-500);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.capture__title { margin: 0 0 var(--sp-1); font-size: var(--fs-lg); }
.capture__sub { margin: 0 0 var(--sp-5); font-size: var(--fs-sm); color: var(--text-muted); }
.capture__form { display: grid; gap: var(--sp-4); }

.capture .input,
.capture .select,
.capture .textarea { min-height: 48px; font-size: var(--fs-md); }

.capture .btn { min-height: 52px; font-size: var(--fs-md); }

.capture__consent { font-size: var(--fs-sm); }
.capture__consent a { text-decoration: underline; }

.capture__trust {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2) var(--sp-4);
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
  font-size: var(--fs-xs);
  color: var(--text-subtle);
  text-align: center;
}

/* --- Páginas de resultado: gracias, confirmación ---------------------- */

.result {
  display: grid;
  justify-items: center;
  gap: var(--sp-4);
  max-width: 620px;
  margin: 0 auto;
  padding: var(--sp-10) var(--sp-4) var(--sp-12);
  text-align: center;
}

.result__mark {
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: var(--success-soft);
  border: 2px solid var(--success-line);
  color: var(--success);
}

.result__mark svg { width: 34px; height: 34px; stroke: currentColor; stroke-width: 2.2; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.result__mark--warning { background: var(--warning-soft); border-color: var(--warning-line); color: var(--warning); }
.result__mark--danger { background: var(--danger-soft); border-color: var(--danger-line); color: var(--danger); }

.result__title { margin: 0; font-size: var(--fs-xl); }
.result__text { margin: 0; max-width: 48ch; color: var(--text-muted); }

.result__panel {
  width: 100%;
  margin-top: var(--sp-2);
  padding: var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  text-align: left;
}

.result__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-3); width: 100%; }
.result__actions .btn { flex: 1 1 180px; }

/* Resumen de la cita en la página de confirmación. */
.appointment-summary { display: grid; gap: var(--sp-3); margin: 0; }
.appointment-summary__row { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: baseline; }
.appointment-summary__key { flex: 0 0 110px; font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--text-subtle); text-transform: uppercase; letter-spacing: 0.05em; }
.appointment-summary__val { flex: 1 1 160px; margin: 0; font-size: var(--fs-md); font-weight: var(--fw-medium); }

/* --- Páginas legales -------------------------------------------------- */

.legal {
  max-width: var(--prose-max);
  margin: 0 auto;
  padding: var(--sp-8) var(--sp-4) var(--sp-12);
}

.legal h1 { margin-bottom: var(--sp-2); font-size: var(--fs-2xl); }
.legal__updated { margin-bottom: var(--sp-8); color: var(--text-subtle); font-size: var(--fs-sm); }
.legal h2 { margin-top: var(--sp-8); font-size: var(--fs-lg); }
.legal h3 { margin-top: var(--sp-6); font-size: var(--fs-md); }
.legal li + li { margin-top: var(--sp-2); }

.legal table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--sp-4) 0;
  font-size: var(--fs-sm);
}

.legal th,
.legal td { padding: var(--sp-2) var(--sp-3); border: 1px solid var(--border); text-align: left; }
.legal th { background: var(--surface-2); }

/* --- Acceso al CRM y página de error --------------------------------- */

.auth {
  display: grid;
  place-items: center;
  min-height: 100vh;
  padding: var(--sp-5) var(--sp-4);
}

.auth__card {
  width: 100%;
  max-width: 400px;
  padding: var(--sp-6) var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
}

.auth__brand { display: grid; justify-items: center; gap: var(--sp-2); margin-bottom: var(--sp-6); text-align: center; }
.auth__title { margin: 0; font-size: var(--fs-lg); }
.auth__sub { margin: 0; font-size: var(--fs-sm); color: var(--text-muted); }

.errorpage {
  display: grid;
  place-items: center;
  min-height: 100vh;
  padding: var(--sp-8) var(--sp-4);
}

.errorpage__inner { width: 100%; max-width: 720px; text-align: center; }

.errorpage__status {
  display: block;
  font-size: var(--fs-4xl);
  font-weight: var(--fw-bold);
  line-height: 1;
  color: var(--brand-500);
  font-variant-numeric: tabular-nums;
}

.errorpage__title { margin: var(--sp-4) 0 var(--sp-2); font-size: var(--fs-xl); }
.errorpage__text { margin: 0 auto var(--sp-6); max-width: 52ch; color: var(--text-muted); }
.errorpage__actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-3); }

/* Traza: solo se pinta en modo depuración, y solo si hay excepción. */
.trace {
  margin-top: var(--sp-8);
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.trace__head {
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
}

.trace__meta { display: grid; gap: var(--sp-1); padding: var(--sp-3) var(--sp-4); font-size: var(--fs-sm); border-bottom: 1px solid var(--border); }
.trace__meta code { overflow-wrap: anywhere; }

.trace__code {
  margin: 0;
  max-height: 55vh;
  padding: var(--sp-4);
  overflow: auto;
  background: var(--surface-sunken);
  color: var(--text);
  font-size: var(--fs-xs);
  line-height: 1.6;
  white-space: pre;
  tab-size: 4;
}

/* ==========================================================================
   15. RESPONSIVE Y ACCESIBILIDAD
   ========================================================================== */

/* En móvil, 16px en los controles evita que iOS haga zoom al enfocar, y
   todo lo pulsable llega a 44px. */
@media (max-width: 767px) {
  .input,
  .select,
  .textarea { font-size: 16px; }

  .btn,
  .btn--sm { min-height: 44px; }

  .table th,
  .table td { padding: var(--sp-3); }

  .modal__dialog { max-height: 88vh; }

  /* Listado en fichas: la vista añade `data-label` a cada celda. */
  .table--stacked { min-width: 0; }
  .table--stacked thead { display: none; }

  .table--stacked tbody tr {
    display: grid;
    gap: var(--sp-1);
    padding: var(--sp-3);
    margin-bottom: var(--sp-3);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
  }

  .table--stacked tbody td {
    display: grid;
    grid-template-columns: 40% 1fr;
    gap: var(--sp-3);
    padding: var(--sp-1) 0;
    border: 0;
    text-align: left;
  }

  .table--stacked tbody td::before {
    content: attr(data-label);
    font-size: var(--fs-xs);
    font-weight: var(--fw-semibold);
    color: var(--text-subtle);
    text-transform: uppercase;
    letter-spacing: 0.05em;
  }

  .table--stacked tbody td:not([data-label]) { grid-template-columns: 1fr; }
}

/* Tablet: la cabecera muestra ya el nombre del usuario. */
@media (min-width: 640px) {
  .main { padding: var(--sp-2) var(--sp-4) var(--sp-10); }
  .header { padding: var(--sp-2) var(--sp-5); }
  .header__user-meta { display: block; }
  .sticky-actions { margin-left: calc(-1 * var(--sp-5)); margin-right: calc(-1 * var(--sp-5)); }
  .sticky-actions .btn { flex: 0 1 auto; }
  .hero { padding: var(--sp-12) var(--sp-5); }
  .hero__title { font-size: var(--fs-3xl); }
  .modal { align-items: center; padding: var(--sp-5); }
  .modal__dialog { border-radius: var(--radius-xl); max-height: 86vh; }
  .modal__foot .btn { flex: 0 1 auto; }
  .site__header { padding: var(--sp-4) var(--sp-6); }
  .capture { padding: var(--sp-6); }
}

/* Escritorio: barra lateral fija, colapsable a iconos. */
@media (min-width: 1024px) {
  .app {
    display: grid;
    grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
    grid-template-areas: "sidebar body";
  }

  .app__body { grid-area: body; min-width: 0; display: flex; flex-direction: column; }

  .sidebar {
    grid-area: sidebar;
    position: sticky;
    top: 0;
    height: 100vh;
    width: auto;
    transform: none;
    transition: none;
  }

  .backdrop { display: none; }

  .app.is-collapsed { grid-template-columns: var(--sidebar-w-collapsed) minmax(0, 1fr); }

  /* Colapsada: solo iconos. Los rótulos siguen en el DOM para el lector de
     pantalla, pero fuera de la vista. */
  .app.is-collapsed .sidebar__label,
  .app.is-collapsed .sidebar__count,
  .app.is-collapsed .sidebar__group-title,
  .app.is-collapsed .sidebar__brand > span:not(.sidebar__mark) { display: none; }

  .app.is-collapsed .sidebar__brand { justify-content: center; padding-inline: 0; }
  .app.is-collapsed .sidebar__link { justify-content: center; padding-inline: 0; }
  .app.is-collapsed .sidebar__nav { padding-inline: var(--sp-2); }
  .app.is-collapsed .sidebar__group + .sidebar__group { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--sidebar-border); }

  .main { padding: var(--sp-2) var(--sp-5) var(--sp-12); }
  .header { padding: var(--sp-2) var(--sp-6); }
  .sticky-actions { position: static; margin: var(--sp-4) 0 0; padding: 0; background: none; border: 0; box-shadow: none; }

  .hero__inner { grid-template-columns: 1.05fr 0.95fr; gap: var(--sp-12); align-items: center; }
  .hero__title { font-size: var(--fs-3xl); }
  .form-grid--wide { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Sin animación para quien la ha desactivado en el sistema. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .btn:active { transform: none; }
}

/* Bordes visibles cuando el usuario pide más contraste. */
@media (prefers-contrast: more) {
  :root {
    --border: var(--gray-400);
    --border-strong: var(--gray-600);
    --text-muted: var(--gray-700);
  }

  .badge, .alert, .card, .btn { border-width: 2px; }
}

@media print {
  .sidebar,
  .header,
  .backdrop,
  .site__footer,
  .pagination,
  .form-actions,
  .sticky-actions,
  .modal { display: none !important; }

  body { background: #fff; color: #000; }
  .app { display: block; }
  .card { border-color: #999; box-shadow: none; break-inside: avoid; }
  .table-wrap { overflow: visible; }
  .table { min-width: 0; font-size: 10pt; }
  a { color: #000; text-decoration: underline; }
}

/* ==========================================================================
   AYUDA PLEGABLE
   --------------------------------------------------------------------------
   Explicaciones dentro de la propia pantalla, plegadas por defecto. Se usa
   <details> nativo: ni una línea de JavaScript, así que funciona con la CSP
   puesta y con el teclado sin que haya que programar nada.
   ========================================================================== */

.help { border: 0; }

.help__summary {
  cursor: pointer;
  padding: var(--sp-4);
  font-weight: var(--fw-semibold);
  color: var(--text);
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.help__summary::-webkit-details-marker { display: none; }

/* Triángulo propio: el nativo no se puede estilar de forma consistente. */
.help__summary::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-right: 2px solid var(--text-subtle);
  border-bottom: 2px solid var(--text-subtle);
  transform: rotate(-45deg);
  transition: transform 0.15s ease;
}

.help[open] .help__summary::before { transform: rotate(45deg); }

.help__summary:hover { color: var(--primary); }
.help__summary:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }

.help__body {
  padding: 0 var(--sp-4) var(--sp-4);
  border-top: 1px solid var(--border);
  padding-top: var(--sp-4);
  font-size: var(--fs-sm);
  line-height: 1.55;
  max-width: 68ch;
}

.help__title {
  margin: var(--sp-4) 0 var(--sp-2);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--text);
}

.help__body > .help__title:first-child { margin-top: 0; }

.help__list { margin: 0 0 var(--sp-2); padding-left: 1.25rem; }
.help__list li { margin-bottom: 0.25rem; }

.help__body p { margin: 0 0 var(--sp-2); }

kbd {
  display: inline-block;
  padding: 0.1em 0.4em;
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm, 0.25rem);
  background: var(--surface-2, var(--bg));
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.8em;
  line-height: 1.4;
}

/* ==========================================================================
   AGENDA
   --------------------------------------------------------------------------
   Las citas se agrupan por día, así que cada día es una tarjeta. Lo que se
   busca es poder barrer la columna de horas de un vistazo y que solo salten
   a la vista las filas que piden algo.
   ========================================================================== */

/* Una sola línea entre el buscador y las citas: a la izquierda el filtro
   rápido, a la derecha el envío masivo. Antes eran dos franjas apiladas. */
.agenda__toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
}

.agenda__day { margin-bottom: var(--sp-5); }

/* El día de hoy lleva un filo de color: es a lo que se entra a mirar. */
.agenda__day--today { border-left: 3px solid var(--primary); }

/* Contador de citas del día, junto al título. */
.agenda__count {
  display: inline-block;
  margin-left: var(--sp-2);
  padding: 0.05em 0.5em;
  border-radius: var(--radius-pill);
  background: var(--primary-soft);
  color: var(--primary);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  vertical-align: middle;
}

/* La hora en tabular para que las cifras queden en columna aunque cambie el
   ancho de los dígitos. */
.agenda__time {
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-semibold);
  font-size: var(--fs-base);
  white-space: nowrap;
}

.agenda__name { display: block; font-weight: var(--fw-semibold); }
.agenda__phone { display: block; font-size: var(--fs-sm); color: var(--text-muted); white-space: nowrap; }

.agenda__state { display: flex; flex-direction: column; gap: 0.15rem; align-items: flex-start; }

.agenda__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
}

/* Cita pasada sin marcar: lo único que en esta pantalla está "pendiente de
   ti", así que se señala en la fila entera y no solo en la etiqueta. */
.table tbody tr.is-pending > * { background: var(--warning-soft, transparent); }

/* Reprogramar, plegado. El summary se pinta como un botón, así que se le
   quita el triángulo nativo. */
.agenda__more > summary { list-style: none; cursor: pointer; }
.agenda__more > summary::-webkit-details-marker { display: none; }

.agenda__reschedule {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
}

.agenda__reschedule .input { width: auto; min-width: 12rem; }

/* Columnas que no deben estirarse. */
.table__tight { width: 1%; white-space: nowrap; }
.table__actions { width: 1%; }

.input--sm { padding: 0.35rem 0.55rem; font-size: var(--fs-sm); }

/* Un aviso más en la columna de KPIs. */
.kpi--warn .kpi__value { color: var(--warning); }

@media (max-width: 640px) {
  .agenda__toolbar { flex-direction: column; align-items: stretch; }
  .agenda__toolbar .btn { width: 100%; }
  .table__tight, .table__actions { width: auto; white-space: normal; }
}

/* El atributo `hidden` tiene que ganar a cualquier `display` de una clase.
   La hoja del navegador lo declara con especificidad mínima, así que una
   regla como `.field { display: grid }` lo anulaba y el elemento seguía
   viéndose aunque el JavaScript lo hubiera ocultado. */
[hidden] { display: none !important; }

/* ==========================================================================
   ACORDEÓN DE RESOLUCIÓN
   --------------------------------------------------------------------------
   Cada estado es una fila pulsable que despliega sus propios campos. La
   selección sigue siendo un radio nativo: el teclado, los atajos 1-6 y el
   envío funcionan sin que el CSS tenga nada que ver.
   ========================================================================== */

.accordion {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.accordion__item + .accordion__item { border-top: 1px solid var(--border); }

.accordion__head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  cursor: pointer;
  background: var(--surface);
  transition: background var(--transition);

  /* Objetivo táctil cómodo: esto se usa en el móvil, entre llamadas. */
  min-height: 3rem;
}

.accordion__head:hover { background: var(--surface-2, var(--bg)); }

.accordion__item.is-open .accordion__head {
  background: var(--primary-soft);
  color: var(--primary);
  font-weight: var(--fw-semibold);
}

/* El radio se oculta a la vista pero sigue existiendo para el teclado y los
   lectores de pantalla: la fila entera es su etiqueta. */
.accordion__radio {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.accordion__radio:focus-visible + .accordion__label { outline: 2px solid var(--focus-ring); outline-offset: 3px; }

/* Número del atajo de teclado. */
.accordion__key {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: var(--radius-sm, 0.25rem);
  background: var(--bg);
  border: 1px solid var(--border);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-subtle);
}

.accordion__item.is-open .accordion__key {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

.accordion__label { flex: 1 1 auto; }

.accordion__body {
  padding: var(--sp-4);
  border-top: 1px solid var(--border);
  background: var(--bg);
  display: grid;
  gap: var(--sp-3);
}

/* ==========================================================================
   AVISO DE GESTIÓN EN CURSO
   --------------------------------------------------------------------------
   Botón sólido en la cabecera, presente en todo el CRM. Tiene que verse desde
   el otro lado de la sala: un registro reservado y olvidado no lo trabaja
   nadie hasta que salta la liberación automática, así que aquí interesa que
   moleste un poco.
   ========================================================================== */

/* --- Tarjeta plegable ---------------------------------------------------- */

/* La cabecera de la tarjeta hace de interruptor. Mismo aspecto que un
   `card__head` normal: plegable no significa que tenga que verse distinto,
   solo que se pueda cerrar. */
.foldcard > summary { list-style: none; }

/* Safari pinta su propio triángulo con este pseudo-elemento. */
.foldcard > summary::-webkit-details-marker { display: none; }

.foldcard__head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  cursor: pointer;
  border-radius: var(--radius-lg);
  transition: background var(--transition);
}

.foldcard__head:hover { background: var(--surface-sunken); }

.foldcard__head:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

/* Abierta, la cabecera y el cuerpo son una sola pieza. */
.foldcard[open] > .foldcard__head {
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  border-bottom: 1px solid var(--border);
}

.foldcard__title {
  margin: 0;
  flex: 1 1 auto;
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
}

.foldcard__chevron {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  color: var(--text-subtle);
  transition: transform var(--transition);
}

.foldcard__chevron svg {
  width: 1.1rem;
  height: 1.1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* La flecha apunta a lo que va a pasar: cerrada mira abajo («se abre»), abierta
   mira arriba («se cierra»). */
.foldcard[open] > .foldcard__head .foldcard__chevron { transform: rotate(180deg); }

@media (prefers-reduced-motion: reduce) {
  .foldcard__chevron { transition: none; }
}

/* --- Interruptor del modo continuo ------------------------------------- */

/* Uno, no dos. Antes encendido eran una etiqueta verde y un botón «Pausar»
   sueltos, y apagado un botón distinto: el mismo concepto cambiando de forma
   según el estado, que es justo lo que impide leerlo como un interruptor.

   Misma pastilla y mismo tamaño en los dos estados; solo cambian el relleno y
   el icono. Comparte forma con el distintivo de «Gestión abierta», que está al
   lado y habla de lo mismo. */
.chainmode { display: inline-flex; }

.chainmode__switch {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 36px;
  padding: 0 0.85rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text-muted);
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--transition), border-color var(--transition), color var(--transition);
}

.chainmode__switch:hover { border-color: var(--primary); color: var(--primary); }

.chainmode__switch.is-on {
  background: var(--success);
  border-color: var(--success);
  color: #fff;
}

.chainmode__switch.is-on:hover { background: var(--success); color: #fff; filter: brightness(1.06); }

.chainmode__icon {
  width: 0.85rem;
  height: 0.85rem;
  flex: none;
  fill: currentColor;
  stroke: none;
}

/* La pausa se dibuja con dos trazos, no con relleno. */
.chainmode__icon--action {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
  opacity: 0.85;
  margin-left: 0.1rem;
}

/* Un punto que late: dice «esto está corriendo ahora mismo», que es distinto
   de «esto está configurado así». */
.chainmode__dot {
  width: 0.5rem;
  height: 0.5rem;
  flex: none;
  border-radius: 50%;
  background: currentColor;
  animation: chainmode-pulse 1.8s ease-in-out infinite;
}

@keyframes chainmode-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.45; transform: scale(0.8); }
}

/* El estado escrito: un color no es un mensaje para quien no lo distingue. */
.chainmode__state {
  font-weight: var(--fw-normal);
  font-size: var(--fs-xs);
  opacity: 0.85;
}

@media (prefers-reduced-motion: reduce) {
  .chainmode__dot { animation: none; }
}

/* En una pantalla estrecha se queda el estado, que es el dato, y se va la
   palabra larga: la pastilla y el icono ya dicen qué es. */
@media (max-width: 640px) {
  .chainmode__label { display: none; }
}

.held-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin-left: auto;
  padding: 0.4rem 0.9rem 0.4rem 0.45rem;
  border-radius: var(--radius-pill);

  /* Color de marca, no ámbar: en la cabecera el ámbar sólido chilla y compite
     con el aviso de modo pruebas. El verde petróleo destaca sobre la barra
     clara, se integra con el resto y deja el ámbar para lo que de verdad es
     una advertencia. */
  background: var(--primary);
  color: #fff;

  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  text-decoration: none;
  white-space: nowrap;
  box-shadow: 0 0 0 0 rgba(22, 104, 116, 0.5);
  animation: held-glow 2.4s ease-out infinite;
  transition: transform var(--transition), filter var(--transition);
}

/* Al pasar por encima se OSCURECE, no se aclara: con brightness(1.06) el
   fondo se iba hacia el claro y el texto blanco perdía contraste.
   Y sobre todo: el `a:hover` general de la hoja le ponía el color de enlace
   —verde oscuro— sobre fondo verde, que era lo que hacía ilegible el texto.
   Por eso el color y el subrayado se fijan aquí de forma explícita. */
.held-badge:hover,
.held-badge:focus-visible {
  background: var(--primary-hover);
  color: #fff;
  text-decoration: none;
  transform: translateY(-1px);
}
.held-badge:active { transform: translateY(0); }
.held-badge:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }

/* El halo late hacia fuera; no mueve nada de sitio, así que no descoloca la
   cabecera ni provoca reflow. */
@keyframes held-glow {
  0%   { box-shadow: 0 0 0 0 rgba(22, 104, 116, 0.5); }
  70%  { box-shadow: 0 0 0 0.55rem rgba(22, 104, 116, 0); }
  100% { box-shadow: 0 0 0 0 rgba(22, 104, 116, 0); }
}

.held-badge__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.18);
  flex: 0 0 auto;
}

.held-badge__icon svg {
  width: 1rem;
  height: 1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  animation: held-ring 2.4s ease-in-out infinite;
  transform-origin: center;
}

/* El teléfono tirita como si estuviera sonando. */
@keyframes held-ring {
  0%, 70%, 100% { transform: rotate(0deg); }
  75% { transform: rotate(-12deg); }
  80% { transform: rotate(10deg); }
  85% { transform: rotate(-8deg); }
  90% { transform: rotate(6deg); }
}

.held-badge__text { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }

.held-badge__label {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.8;
}

.held-badge__name {
  font-weight: var(--fw-bold);
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 16ch;
}

.held-badge__timer {
  padding-left: var(--sp-2);
  border-left: 1px solid rgba(255, 255, 255, 0.28);
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-bold);
}

/* Sin animaciones para quien las ha desactivado: el color sólido ya destaca
   lo suficiente. */
@media (prefers-reduced-motion: reduce) {
  .held-badge, .held-badge__icon svg { animation: none; }
}

/* En móvil se queda el icono y el cronómetro: el nombre no cabe junto al
   avatar y el aviso sigue siendo inconfundible. */
@media (max-width: 700px) {
  .held-badge { padding: 0.35rem 0.6rem 0.35rem 0.35rem; }
  .held-badge__text { display: none; }
}

/* ---------------------------------------------------------------------------
   Primeros pasos
   ---------------------------------------------------------------------------
   Dos listas con forma distinta a propósito: la del comercial es un recorrido
   (línea vertical, números, se lee de arriba abajo una vez) y la de
   configuración es una lista de tareas (marca de verificado, estado, se vuelve
   a ella hasta terminarla). Si las dos se pintaran igual, la segunda parecería
   otro texto explicativo más y nadie la usaría como lo que es. */

.onboarding__progress-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
}

.onboarding__progress-title { margin: 0; font-size: var(--fs-md); }

.onboarding__progress-count {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}

/* --- El recorrido del comercial ----------------------------------------- */

.steps {
  --steps-marker: 40px;

  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--sp-5);
}

.steps__item {
  position: relative;
  display: grid;
  grid-template-columns: var(--steps-marker) 1fr;
  gap: var(--sp-4);
  align-items: start;
}

/* La línea que une los pasos. Va en el ::before del propio elemento y no en un
   borde del marcador para poder cortarla en el último sin un modificador. */
.steps__item:not(:last-child)::before {
  content: "";
  position: absolute;
  left: calc(var(--steps-marker) / 2 - 1px);
  top: var(--steps-marker);
  bottom: calc(var(--sp-5) * -1);
  width: 2px;
  background: var(--border);
}

.steps__marker {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: var(--steps-marker);
  height: var(--steps-marker);
  border-radius: 50%;
  background: var(--primary-soft);
  color: var(--primary);
}

.steps__marker svg {
  width: 20px;
  height: 20px;
  stroke: currentColor;
  stroke-width: 1.8;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* El icono de «reproducir» es una silueta rellena, no un trazo. */
.steps__marker svg path[d^="M8 5.5"] { fill: currentColor; stroke: none; }

.steps__content { min-width: 0; padding-top: var(--sp-1); }

.steps__title {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-1);
  font-size: var(--fs-md);
}

.steps__number {
  flex: 0 0 auto;
  color: var(--primary);
  font-size: var(--fs-sm);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}

.steps__body { margin: 0 0 var(--sp-3); color: var(--text-muted); }
.steps__body:last-child { margin-bottom: 0; }

/* --- La lista de configuración ------------------------------------------ */

.checklist {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--sp-3);
}

.checklist__item {
  display: grid;
  grid-template-columns: 26px 1fr;
  gap: var(--sp-3);
  align-items: start;
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
}

/* Lo hecho se apaga: la vista tiene que dejar a la vista lo que falta. */
.checklist__item.is-done {
  background: var(--surface-sunken);
  border-color: transparent;
}

.checklist__mark {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
  background: var(--surface);
}

.checklist__item.is-done .checklist__mark {
  border-color: transparent;
  background: var(--success);
  color: #fff;
}

.checklist__mark svg {
  width: 15px;
  height: 15px;
  stroke: currentColor;
  stroke-width: 2.6;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.checklist__content { min-width: 0; }

.checklist__title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: 0 0 var(--sp-1);
  font-size: var(--fs-md);
}

.checklist__why { margin: 0 0 var(--sp-2); color: var(--text-muted); font-size: var(--fs-sm); }

.checklist__status {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--success);
}

.checklist__status.is-pending { color: var(--warning); }

.checklist__hint {
  margin: calc(var(--sp-2) * -1) 0 var(--sp-3);
  color: var(--text-muted);
  font-size: var(--fs-xs);
}

/* --- Notas sueltas ------------------------------------------------------- */

.notes-grid {
  display: grid;
  gap: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

.note {
  padding: var(--sp-4);
  border-radius: var(--radius-lg);
  background: var(--surface-sunken);
  border-left: 3px solid var(--primary);
}

.note__title { margin: 0 0 var(--sp-1); font-size: var(--fs-base); }
.note__body { margin: 0 0 var(--sp-2); color: var(--text-muted); font-size: var(--fs-sm); }
.note__body:last-child { margin-bottom: 0; }

@media (max-width: 640px) {
  .steps { --steps-marker: 32px; }
  .steps__item { gap: var(--sp-3); }
  .checklist__item { padding: var(--sp-3); }
}

/* ---------------------------------------------------------------------------
   Barra de filtros plegable
   ---------------------------------------------------------------------------
   Ocho campos encima de la tabla empujaban los resultados fuera de pantalla.
   Es un <details>, así que abre y cierra sin JavaScript. */

.filters-panel > summary {
  list-style: none;
}

/* Safari pinta su propio triángulo con este pseudo-elemento. */
.filters-panel > summary::-webkit-details-marker {
  display: none;
}

.filters-panel__toggle {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5);

  /* Altura fija pase lo que pase dentro.

     La cabecera lleva piezas que unos listados tienen y otros no: el contador,
     el aviso de filtros activos, «Quitar filtros» y el icono de descarga. Sin
     esto, la barra de contactos —que no exporta— salía más baja que la de
     leads y clientes, y al ir de un listado a otro la tabla daba un salto. */
  min-height: 3.5rem;
  box-sizing: border-box;

  cursor: pointer;
  color: var(--text);
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold);
  border-radius: var(--radius-lg);
  transition: background var(--transition);
}

.filters-panel__toggle:hover { background: var(--surface-sunken); }

.filters-panel__toggle:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

/* Abierta, el encabezado y el cuerpo son una sola pieza. */
.filters-panel[open] > .filters-panel__toggle {
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  border-bottom: 1px solid var(--border);
}

.filters-panel__icon {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  stroke: currentColor;
  stroke-width: 1.8;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--text-muted);
}

.filters-panel__label { flex: 0 0 auto; }

/* El recuento se lleva el espacio sobrante y empuja los distintivos a la
   derecha, para que la cabecera se lea de izquierda a derecha:
   qué es, cuánto hay, qué está filtrando. */
/* La leyenda del panel, dentro de la cabecera del filtro.

   `margin-left: auto` la empuja a la derecha: así queda pegada a «Quitar
   filtros» y no separa el texto del recuento, que se leen juntos. */
.filters-panel__extra {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
  margin-left: auto;
}

/* En el móvil se va: en 375 píxeles ocupaba cuatro líneas y empujaba el
   recuento fuera de la pantalla. Allí no hace falta, porque la lista lleva el
   nombre del estado escrito en cada línea.

   La regla va aquí y no con el resto del panel a propósito: una media query no
   añade especificidad, así que puesta antes de esta definición perdía. */
@media (max-width: 720px) {
  .filters-panel__extra { display: none; }
}

.filters-panel__count {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-normal);
  font-variant-numeric: tabular-nums;
}

.filters-panel__chevron {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  color: var(--text-muted);
  transition: transform var(--transition);
}

.filters-panel__chevron svg {
  width: 16px;
  height: 16px;
  stroke: currentColor;
  stroke-width: 2;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.filters-panel[open] .filters-panel__chevron { transform: rotate(180deg); }

@media (prefers-reduced-motion: reduce) {
  .filters-panel__chevron { transition: none; }
}

/* Apunte gris de la cabecera plegada: el periodo de un informe tiene que
   leerse sin desplegar nada. */
.filters-panel__note {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-normal);
}

/* Con algo debajo (el pie de descarga de los informes), la cabecera cerrada no
   puede redondear su borde inferior. */
.filters-panel:has(+ .card__foot) > .filters-panel__toggle {
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  border-bottom: 1px solid var(--border);
}

/* ---------------------------------------------------------------------------
   Marca de agua
   ---------------------------------------------------------------------------
   Firma las pantallas con datos de paciente. No impide la captura —en web eso
   no se puede detectar— pero hace que cualquier captura filtrada señale a
   quien la tenía delante.

   Por debajo del panel lateral y de los diálogos, para no escribir encima de
   la navegación; por encima de todo lo demás, que es lo que sale en la foto. */

.watermark {
  position: fixed;
  inset: 0;
  z-index: 20;
  overflow: hidden;
  pointer-events: none;
  user-select: none;
}

.watermark__grid {
  /* Rejilla de tamaño fijo, no flex centrado ni `auto-fill`.
     Con flex la última fila quedaba a medias y centrada, y con `auto-fill` el
     número de columnas dependía del ancho, así que en una pantalla grande las
     filas se acababan antes de llegar abajo: la esquina inferior derecha se
     quedaba sin firmar. Con un número fijo de columnas y las filas repartidas
     con `space-between`, la cuadrícula cubre el alto completo sea cual sea la
     pantalla. */
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  align-content: space-between;
  justify-items: center;
  column-gap: 1.5rem;

  /* Más grande que la pantalla: al girar, las esquinas quedarían vacías. */
  width: 170%;
  height: 170%;
  margin: -35% 0 0 -35%;
  transform: rotate(-24deg);
}

.watermark__text {
  color: var(--text);
  font-size: 0.8125rem;
  font-weight: var(--fw-semibold);
  letter-spacing: 0.04em;
  white-space: nowrap;

  /* Legible en una captura, ignorable mientras se trabaja. */
  opacity: 0.07;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .watermark__text { opacity: 0.1; }
}

:root[data-theme="dark"] .watermark__text { opacity: 0.1; }

/* En papel y en PDF se sube el contraste: son los formatos que se reenvían. */
@media print {
  .watermark { position: absolute; }
  .watermark__text { opacity: 0.16; color: #000; }
}

/* Un campo que ocupa la fila entera dentro de .form-grid. Los grupos de
   casillas se vuelven ilegibles en media columna. */
.field--wide { grid-column: 1 / -1; }

/* Formulario de una sola línea: etiqueta, campo y botón alineados abajo, para
   las pruebas de envío de la pantalla de ajustes. */
.form-inline {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-3);
}

.form-inline .field { flex: 1 1 220px; min-width: 0; }

/* ---------------------------------------------------------------------------
   Ayuda de pantalla: la «i» y su bocadillo
   ---------------------------------------------------------------------------
   Antes era un tooltip que se salía por arriba —la cabecera está pegada al
   borde de la ventana— y un modal que tapaba toda la pantalla para leer dos
   frases. Ahora la explicación sale de la propia «i», anclada a ella. */

.infotip { position: relative; flex: 0 0 auto; display: inline-flex; }

/* Mismo lenguaje que el avatar del usuario: círculo, relleno suave de marca y
   un aro fino. Es la forma que esta interfaz ya usa para «esto identifica algo
   y se puede pulsar», así que la «i» no tiene que inventarse otra. */
.infotip__btn {
  flex: 0 0 auto;
  display: inline-grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--primary-line);
  border-radius: 50%;
  background: var(--primary-soft);
  color: var(--primary);
  cursor: pointer;

  transition:
    color var(--transition),
    border-color var(--transition),
    background var(--transition),
    box-shadow var(--transition);
}

.infotip__btn svg { width: 16px; height: 16px; fill: currentColor; }

/* Sin aro en el glifo: el botón ya es el círculo, y dos círculos
   concéntricos a 30 px se emborronan. */
.infotip__ring { display: none; }

.infotip__btn:hover {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

/* Abierto: el botón se comporta como un control activo, no como un adorno. */
/* Abierto: se invierte. El relleno pasa a ser el color y el glifo el hueco,
   igual que un avatar seleccionado. */
.infotip__btn[aria-expanded="true"] {
  color: #fff;
  border-color: var(--brand-600);
  background: var(--brand-600);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

/* --- El bocadillo -------------------------------------------------------- */

.infotip__bubble {
  position: absolute;
  top: calc(100% + 0.7rem);
  left: -0.75rem;
  z-index: var(--z-toast);
  width: max-content;
  max-width: min(24rem, calc(100vw - 2rem));
  padding: var(--sp-4) var(--sp-4) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.85rem;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.5) inset,
    0 18px 40px -12px rgba(13, 27, 34, 0.28),
    0 4px 10px -4px rgba(13, 27, 34, 0.14);
}

/* El pico: un cuadrado girado, centrado justo sobre el borde. Su mitad de
   abajo tapa por sí sola la línea del borde del bocadillo, así que no hace
   falta una segunda pieza — que era justo lo que antes lo escondía. */
.infotip__bubble::before {
  content: "";
  position: absolute;
  top: -0.375rem;
  left: 1.05rem;
  width: 0.7rem;
  height: 0.7rem;
  transform: rotate(45deg);
  background: var(--surface);
  border-top: 1px solid var(--border);
  border-left: 1px solid var(--border);
  border-radius: 0.14rem 0 0 0;
}

.infotip__eyebrow {
  margin: 0 0 var(--sp-3);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--border);
  color: var(--text-subtle);
  font-size: 0.6875rem;
  font-weight: var(--fw-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Entrada corta y con origen en la «i»: parece que sale de ella, no que
   aparece encima. Solo a la entrada; al cerrar desaparece sin ceremonia. */
@keyframes infotip-in {
  from { opacity: 0; transform: translateY(-0.35rem) scale(0.975); }
  to { opacity: 1; transform: none; }
}

.infotip__bubble:not([hidden]) {
  transform-origin: 1.4rem top;
  animation: infotip-in 170ms cubic-bezier(0.2, 0.9, 0.3, 1);
}

@media (prefers-reduced-motion: reduce) {
  .infotip__bubble:not([hidden]) { animation: none; }
}

/* En pantalla estrecha se ancla al borde de la ventana en vez de salirse. */
@media (max-width: 30rem) {
  .infotip__bubble { position: fixed; left: 1rem; right: 1rem; width: auto; max-width: none; }
  .infotip__bubble::before { display: none; }
}

/* Cuerpo de la ayuda: texto corrido legible, no una ficha de datos. */
.prose-help { max-width: 60ch; display: grid; gap: var(--sp-3); }
.prose-help p { margin: 0; color: var(--text-muted); }
.prose-help strong { color: var(--text); font-weight: var(--fw-semibold); }
.prose-help ul { margin: 0; padding-left: 1.15rem; display: grid; gap: var(--sp-2); color: var(--text-muted); }

/* Los recuadros de la cabecera dejan de necesitar el margen superior que
   compensaba el bloque de título desaparecido, y el contenido arranca antes. */
.main > .card:first-child,
.main > .stack > .card:first-child { margin-top: 0; }

/* «Quitar filtros», en la cabecera del panel: visible sin desplegarlo, que es
   justo cuando hace falta. */
.filters-panel__clear {
  flex: 0 0 auto;
  padding: 0.15rem 0.5rem;
  border-radius: var(--radius);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  text-decoration: none;
}

.filters-panel__clear:hover { color: var(--danger); background: var(--danger-soft); }

/* Descargar lo filtrado, en la misma cabecera. Es un icono y no un botón con
   texto porque comparte la línea con el recuento, los filtros activos y
   «Quitar filtros»: una palabra más y la cabecera deja de leerse de un golpe. */
.filters-panel__export {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  width: 1.85rem;
  height: 1.85rem;
  border-radius: var(--radius);
  color: var(--text-muted);
  text-decoration: none;
  transition: color 0.15s ease, background-color 0.15s ease;
}

.filters-panel__export svg {
  width: 1.05rem;
  height: 1.05rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.filters-panel__export:hover,
.filters-panel__export:focus-visible {
  color: var(--primary);
  background: var(--surface-hover);
}

/* La fecha abre la fila. Se probó en gris y más pequeña, y quedaba peor que
   la de la cita: es un dato de trabajo, no un apunte. Mismo color y tamaño que
   el resto de la fila; solo las cifras van de ancho fijo, para que las columnas
   de fecha y hora cuadren unas debajo de otras. */
.table__when { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------------
   Llamada entrante
   ------------------------------------------------------------------
   El buscador por teléfono de la cabecera. Es lo único del CRM que se usa con
   una urgencia de segundos —el teléfono está sonando—, así que está siempre en
   el mismo punto, anclado a la derecha, y se abre encima de lo que haya sin
   taparlo del todo. */

.incoming { position: relative; flex: 0 0 auto; }
.incoming > summary { list-style: none; cursor: pointer; }
.incoming > summary::-webkit-details-marker { display: none; }

/* Mismo tamaño y comportamiento que los demás iconos de la barra, pero con el
   color de acento: es un botón de acción, no una opción más. */
.incoming__btn {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius);
  color: var(--primary);
  background: var(--primary-soft);
  border: 1px solid var(--primary-line);
  transition: background var(--transition), color var(--transition);
}

.incoming__btn svg {
  width: 22px;
  height: 22px;
  stroke: currentColor;
  stroke-width: 1.8;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.incoming__btn:hover { background: var(--primary); color: #fff; }
.incoming[open] .incoming__btn { background: var(--primary); color: #fff; }
.incoming__btn:focus-visible { outline: 3px solid var(--focus-ring); outline-offset: 2px; }

.incoming__panel {
  position: absolute;
  right: 0;
  top: calc(100% + var(--sp-2));
  z-index: var(--z-header);
  width: min(24rem, calc(100vw - var(--sp-4) * 2));
  padding: var(--sp-3);
  display: grid;
  gap: var(--sp-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

.incoming__form { display: flex; gap: var(--sp-2); }

/* Cifras de ancho fijo y algo más grandes: se teclea un número de nueve
   dígitos mirando la pantalla del móvil, no el teclado. */
.incoming__input {
  flex: 1 1 auto;
  min-width: 0;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

/* Mientras llega la respuesta la lista se atenúa en vez de vaciarse: parpadear
   entre dos listas con el dedo yendo hacia una fila es cómo se abre la ficha
   equivocada. */
.incoming.is-loading { opacity: 0.55; transition: opacity var(--transition); }

.incoming__hint { margin: 0; font-size: var(--fs-sm); color: var(--text-muted); }

.incoming__empty { display: grid; gap: var(--sp-2); justify-items: start; }

.incoming__count {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

.incoming__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--sp-1);

  /* Con quince leads de la misma persona el panel no puede llegar al suelo de
     la pantalla: se desplaza dentro. */
  max-height: min(24rem, 60vh);
  overflow-y: auto;
}

.incoming__link {
  display: grid;
  gap: 2px;
  padding: var(--sp-2);
  border-radius: var(--radius);
  color: var(--text);
  text-decoration: none;
}

.incoming__link:hover,
.incoming__link:focus-visible { background: var(--surface-hover); text-decoration: none; }
.incoming__link:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }

.incoming__head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.incoming__name { font-weight: var(--fw-semibold); }

/* Marca del primero de la lista. Quien llama lo hace casi siempre por lo
   último que pidió, y esto ahorra leer cuatro fechas. */
.incoming__last {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--primary);
}

.incoming__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

.incoming__meta > span + span::before {
  content: '·';
  margin-right: var(--sp-2);
}

/* La cita, destacada: es lo que cambia la primera frase de la conversación. */
.incoming__when {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.incoming__new {
  display: block;
  padding-top: var(--sp-2);
  border-top: 1px solid var(--border);
  font-size: var(--fs-sm);
}

/* En un móvil el panel ocupa el ancho de la pantalla menos un margen a cada
   lado: anclado al botón se saldría por la izquierda, porque el botón está
   pegado al borde derecho y el panel mide más que lo que queda hasta él.

   Se fija a la ventana, y por eso lleva un `top` propio: con `position: fixed`
   el `top: 100%` de la regla de arriba deja de medirse desde el botón y pasa a
   medirse desde la ventana —el alto entero de la pantalla— y el panel acaba
   debajo del pliegue, invisible. La cabecera es `sticky` en el borde superior,
   así que esta distancia siempre cae justo debajo del botón. */
@media (max-width: 40rem) {
  .incoming__panel {
    position: fixed;
    top: calc(var(--header-h) + 4px);
    right: var(--sp-3);
    left: var(--sp-3);
    width: auto;
  }
}

/* La pantalla completa: el mismo buscador cuando no hay JavaScript. */
.incoming-page__form {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

.incoming-page__field { flex: 1 1 16rem; min-width: 0; }

/* ------------------------------------------------------------------
   Simulador
   ------------------------------------------------------------------
   Parámetros a un lado y resultado al otro, los dos a la vista: mover un
   número y tener que bajar para ver el efecto rompe justo lo que hace útil una
   pantalla así. En móvil se apilan, con los parámetros primero. */

.simulator {
  display: grid;
  gap: var(--sp-4);
  align-items: start;
}

/* Los escenarios y los parámetros, en una columna. Son dos tarjetas y no una
   porque la de arriba lleva formularios POST —guardar y borrar— y la de abajo
   es un GET: un formulario dentro de otro no es HTML válido. */
.simulator__side { display: grid; gap: var(--sp-3); align-content: start; min-width: 0; }

@media (min-width: 64rem) {
  .simulator { grid-template-columns: 22rem 1fr; }

  /* La columna se queda fija mientras se recorre el resultado, que es largo:
     si no, cambiar un parámetro obliga a subir del todo. */
  .simulator__side {
    position: sticky;
    top: calc(var(--header-h) + var(--sp-3));
    max-height: calc(100vh - var(--header-h) - var(--sp-5));
    overflow-y: auto;
  }
}

/* Lista de escenarios guardados. */
.simscen {
  margin: 0 0 var(--sp-3);
  padding: 0;
  list-style: none;
  display: grid;
  gap: 2px;
}

.simscen__item {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  border-radius: var(--radius);
}

.simscen__item:hover { background: var(--surface-hover); }

/* El activo se marca: al volver a la pantalla, lo primero es saber cuál de los
   guardados se está mirando. */
.simscen__item.is-active { background: var(--primary-soft); }
.simscen__item.is-active .simscen__load { color: var(--primary); font-weight: var(--fw-semibold); }

.simscen__load {
  flex: 1 1 auto;
  min-width: 0;
  padding: var(--sp-2);
  color: var(--text);
  font-size: var(--fs-sm);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.simscen__load:hover { text-decoration: none; }

/* La × solo aparece al pasar por encima o con el foco: borrar no es algo que
   deba estar pidiendo el dedo en una lista que se usa para abrir. */
.simscen__del {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  margin-right: var(--sp-1);
  padding: 0;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--transition), color var(--transition);
}

.simscen__item:hover .simscen__del,
.simscen__del:focus-visible { opacity: 1; }
.simscen__del:hover { color: var(--danger); }

.simscen__del svg {
  width: 15px;
  height: 15px;
  stroke: currentColor;
  stroke-width: 2;
  fill: none;
  stroke-linecap: round;
}

/* En una pantalla táctil no hay «pasar por encima»: ahí se ve siempre. */
@media (hover: none) {
  .simscen__del { opacity: 1; }
}

.simsave { display: flex; gap: var(--sp-2); }
.simsave__name { flex: 1 1 auto; min-width: 0; }

.simgroup__title {
  margin: var(--sp-4) 0 var(--sp-1);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

.simgroup__title:first-child { margin-top: 0; }

/* De dónde viene el valor de partida. Sin esto, alguien cambia el horario en
   Ajustes, vuelve aquí y no entiende por qué se han movido las cifras. */
.simgroup__origin {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

.simgroup {
  display: grid;
  gap: var(--sp-3);
  padding-bottom: var(--sp-2);
}

.simfield__control { display: flex; align-items: center; gap: var(--sp-2); }
.simfield__control .input { flex: 1 1 auto; min-width: 0; font-variant-numeric: tabular-nums; }

.simfield__unit {
  flex: 0 0 auto;
  font-size: var(--fs-xs);
  color: var(--text-muted);
  white-space: nowrap;
}

.simulator__actions {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
  padding-top: var(--sp-3);
  border-top: 1px solid var(--border);
}

.simulator__result { display: grid; gap: var(--sp-4); min-width: 0; }
.simresult { display: grid; gap: var(--sp-4); }

/* Atenuar mientras recalcula, no vaciar: parpadear entre dos cifras es lo que
   impide comparar con la de hace un segundo, que es para lo que se usa esto. */
.simulator__result.is-loading { opacity: 0.55; transition: opacity var(--transition); }

/* Las tres cifras por las que se abre la pantalla. */
.simhead {
  display: grid;
  gap: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
}

.simhead__item {
  padding: var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}

.simhead__label {
  margin: 0;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

.simhead__value {
  margin: var(--sp-1) 0 0;
  font-size: 2rem;
  font-weight: var(--fw-bold);
  line-height: 1.1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* Un margen negativo no puede leerse igual que uno bueno. */
.simhead__value.is-bad { color: var(--danger); }

.simhead__note {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

/* Avisos del modelo: van pegados a las cifras porque corrigen su lectura. */
.simnote {
  margin: 0;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius);
  border: 1px solid transparent;
  font-size: var(--fs-sm);
}

.simnote--danger { background: var(--danger-soft); border-color: var(--danger-line, var(--border)); color: var(--text); }
.simnote--warning { background: var(--warning-soft); border-color: var(--warning-line, var(--border)); color: var(--text); }
.simnote--info { background: var(--surface-hover); color: var(--text-muted); }

/* Pista bajo el valor de un KPI, para la banda de referencia. */
.kpi__hint {
  margin: var(--sp-1) 0 0;
  font-size: var(--fs-xs);
  color: var(--text-muted);
}

/* La fila del total de una tabla del simulador. */
.table tr.is-total th,
.table tr.is-total td {
  font-weight: var(--fw-semibold);
  border-top: 2px solid var(--border);
}
