:root{
  /* Alias de compatibilidad → cada uno apunta a tokens.css (el estilo vive allí) */
  --teal:var(--color-accion);--teal-dark:var(--color-accion-hover);--teal-soft:var(--color-accion-suave);
  --ink:var(--texto-principal);--muted:var(--texto-secundario);--line:var(--color-borde);
  --surface:var(--color-superficie);--canvas:var(--color-fondo);--success:var(--ok-texto);
  --warning:var(--aviso-texto);--danger:var(--error-texto);--blue:var(--info-texto);
  --shadow:var(--sombra-flotante-suave);--radius:var(--radio-l)
}
*{box-sizing:border-box}html{font-family:var(--fuente);color:var(--ink);background:var(--canvas)}body{margin:0}button,input,select,textarea{font:inherit}.hidden{display:none!important}
/* svh, no vh: en móvil la barra del navegador hacía saltar la pantalla al aparecer/ocultarse. */
.login-view{min-height:100svh;display:grid;grid-template-columns:1.08fr .92fr;background:var(--blanco)}.login-brand{position:relative;overflow:hidden;background:linear-gradient(140deg,var(--verde-700) 0%,var(--verde-600) 56%,var(--verde-400) 100%);display:flex;align-items:flex-end;padding:9vh 8vw;color:var(--blanco)}
/* La escena 3D se pinta debajo del texto; si no hay WebGL, queda el degradado de .login-brand. */
.login-scene{position:absolute;inset:0;width:100%;height:100%;display:block;z-index:1}
/* Velo entre la escena y el texto: sin él, el titular blanco cae encima de torres claras y
   pierde contraste. Es un degradado, no un tinte plano: la escena se sigue viendo arriba. */
.login-brand::after{content:'';position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(to top,rgba(4,38,32,.90) 0%,rgba(4,38,32,.62) 28%,rgba(4,38,32,.10) 62%,rgba(4,38,32,0) 84%)}
.login-copy{position:relative;z-index:2;max-width:620px}.eyebrow{font-size:var(--texto-12);letter-spacing:.17em;font-weight:700;color:var(--teal)}.eyebrow.light{color:var(--texto-marca-claro)}.login-title{font-size:clamp(2.6rem,4.4vw,5.2rem);line-height:.98;letter-spacing:-.055em;margin:18px 0 26px;font-weight:700}.login-copy .login-sub{font-size:var(--texto-20);line-height:1.65;max-width:520px;color:var(--texto-marca-claro);margin:0}.login-features{display:flex;gap:10px;flex-wrap:wrap;margin-top:38px}.login-features span{border:1px solid rgba(255,255,255,.32);border-radius:var(--radio-pill);padding:9px 13px;font-size:var(--texto-12);white-space:nowrap}.login-panel{display:grid;place-items:center;padding:7vw}.login-card{width:min(430px,100%);display:grid;gap:19px}.login-logo{width:280px;max-width:85%;margin-bottom:24px}.login-card h1{font-size:var(--texto-26);margin:0 0 7px;letter-spacing:-.03em}.login-card p{margin:0;color:var(--muted)}
/* El error del acceso: junto a los campos, persistente y enfocable (antes solo salía como
   toast en la esquina contraria de la pantalla). */
.login-error{margin:0;padding:11px 13px;border-radius:var(--radio-m);background:var(--error-fondo);color:var(--error-texto);font-size:var(--texto-13);font-weight:600;outline:none}
.login-error:focus-visible{box-shadow:var(--anillo-foco)}
.campo-clave{position:relative;display:block}
.campo-clave input{width:100%;padding-right:46px}
.ver-clave{position:absolute;right:6px;top:50%;transform:translateY(-50%);display:grid;place-items:center;width:34px;height:34px;border:0;border-radius:var(--radio-m);background:none;color:var(--muted);cursor:pointer}
.ver-clave:hover,.ver-clave.activo{color:var(--teal-dark);background:var(--teal-soft)}
.mayus-aviso{margin:-8px 0 0;font-size:var(--texto-12);font-weight:600;color:var(--warning)}
/* --- Variante «vidrio» (?escena=vidrio): la escena ocupa toda la pantalla y la tarjeta
   flota encima como panel de vidrio. La variante por defecto («ciudad») no toca nada. --- */
.escena-vidrio{grid-template-columns:1fr!important}
.escena-vidrio .login-brand,.escena-vidrio .login-panel{grid-area:1/1}
.escena-vidrio .login-panel{z-index:3;place-items:center end;padding:6vw 7vw;width:100%}
.escena-vidrio .login-card{background:rgba(255,255,255,.13);backdrop-filter:blur(26px) saturate(1.5);-webkit-backdrop-filter:blur(26px) saturate(1.5);border:1px solid rgba(255,255,255,.26);border-radius:var(--radio-xl,24px);padding:34px 32px 30px;box-shadow:0 24px 60px rgba(3,32,27,.28);color:var(--blanco)}
.escena-vidrio .login-card h1,.escena-vidrio .login-card p,.escena-vidrio label{color:var(--blanco)}
.escena-vidrio .login-card small{color:rgba(255,255,255,.72)}
/* El PNG del logo es OPACO (no lleva transparencia): invertirlo lo convertía en un rectángulo
   blanco. Sobre el vidrio va en su placa blanca, con sus colores de marca intactos. */
.escena-vidrio .login-logo{width:196px;background:var(--blanco);border-radius:14px;padding:12px 16px;margin-bottom:20px}
.escena-vidrio .login-card input{background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.3);color:var(--blanco)}
.escena-vidrio .login-card input::placeholder{color:rgba(255,255,255,.55)}
.escena-vidrio .login-card input:focus{border-color:rgba(255,255,255,.8);box-shadow:0 0 0 3px rgba(255,255,255,.18)}
.escena-vidrio .ver-clave{color:rgba(255,255,255,.7)}
.escena-vidrio .ver-clave:hover,.escena-vidrio .ver-clave.activo{color:var(--blanco);background:rgba(255,255,255,.16)}
.escena-vidrio .button.primary{background:var(--blanco);color:var(--verde-700)}
.escena-vidrio .button.primary:hover{background:var(--texto-marca-claro)}
.escena-vidrio .login-error{background:rgba(255,255,255,.92);color:var(--error-texto)}
/* En móvil la tarjeta de vidrio ocupa el centro: el texto de marca se quitaría de debajo, así
   que se oculta y la identidad la lleva el logo de la tarjeta. */
@media(max-width:760px){.escena-vidrio .login-panel{place-items:center;padding:28px 22px 44px}.escena-vidrio .login-brand{min-height:100svh}.escena-vidrio .login-copy{display:none}}label{display:grid;gap:8px;font-size:var(--texto-13);font-weight:700;align-content:start}
/* `display:grid` de arriba gana al [hidden]{display:none} del navegador, así que ocultar un campo
   con el atributo hidden no surtía efecto. Se restituye explícitamente. */
label[hidden]{display:none}input,select,textarea{border:1px solid var(--input-borde);border-radius:var(--radio-m);padding:13px 14px;background:var(--blanco);color:var(--ink);outline:none;transition:border-color var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out)}input:focus,select:focus,textarea:focus{border-color:var(--teal);box-shadow:var(--anillo-foco)}.button{border:0;border-radius:var(--radio-m);padding:12px 17px;font-weight:700;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:9px}.button:disabled{opacity:.45;cursor:not-allowed}.button.primary{background:var(--teal);color:var(--blanco)}.button.primary:hover{background:var(--teal-dark)}.button.secondary{background:var(--teal-soft);color:var(--teal-dark)}.button.ghost{background:var(--blanco);border:1px solid var(--line);color:var(--ink)}.button.danger{background:var(--error-fondo);color:var(--error-texto)}.button.small{padding:7px 10px;border-radius:var(--radio-m);font-size:var(--texto-12)}.wide{width:100%;justify-content:space-between;padding:15px 17px}.login-card small{text-align:center;color:var(--texto-tenue)}.login-card label small{text-align:left;font-weight:600}
.app-view{min-height:100vh;display:grid;grid-template-columns:240px 1fr}.sidebar{position:fixed;z-index:20;inset:0 auto 0 0;width:240px;background:var(--blanco);border-right:1px solid var(--line);padding:27px 17px 18px;display:flex;flex-direction:column;overflow:hidden}.sidebar-logo{display:block;padding:0 10px 32px;flex:0 0 auto}.sidebar-logo img{width:184px}.logo-mark{display:none}.sidebar nav{display:grid;gap:4px;flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain}.nav-section{font-size:var(--texto-11);color:var(--texto-tenue);font-weight:700;letter-spacing:.16em;padding:18px 12px 7px}.nav-link{display:flex;gap:12px;align-items:center;padding:11px 12px;text-decoration:none;color:var(--texto-secundario);border-radius:var(--radio-m);font-size:var(--texto-14);font-weight:600}.nav-link:hover{background:var(--gris-fondo);color:var(--ink)}.nav-link.active{background:var(--teal-soft);color:var(--teal-dark);font-weight:700}.nav-icon{font-size:var(--texto-16);width:20px;text-align:center}.sidebar-foot{flex:0 0 auto;margin-top:auto;border-top:1px solid var(--line);padding:16px 10px 0}.environment{display:flex;align-items:center;gap:8px;color:var(--muted);font-size:var(--texto-11)}.environment i{width:7px;height:7px;border-radius:50%;background:var(--ok-texto);box-shadow:0 0 0 4px var(--ok-fondo)}.logout{border:0;background:none;padding:13px 0 0;color:var(--texto-secundario);font-size:var(--texto-12);cursor:pointer}.main-shell{grid-column:2;min-width:0}.topbar{height:78px;background:rgba(255,255,255,.94);backdrop-filter:blur(10px);border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;padding:0 32px;position:sticky;top:0;z-index:10}.top-search{display:flex;align-items:center;gap:8px;background:var(--canvas);border-radius:var(--radio-m);padding:8px 12px;width:min(410px,45vw)}.top-search input{border:0;background:transparent;padding:3px;width:100%;box-shadow:none}.top-actions,.user-menu{display:flex;align-items:center;gap:15px}.icon-button{position:relative;border:0;background:var(--gris-fondo);border-radius:var(--radio-m);width:40px;height:40px;cursor:pointer}.notification-dot{position:absolute;right:8px;top:8px;width:6px;height:6px;background:var(--error-texto);border-radius:50%}.avatar{width:38px;height:38px;border-radius:var(--radio-m);background:linear-gradient(145deg,var(--teal),var(--verde-400));color:var(--blanco);display:grid;place-items:center;font-weight:700}.user-menu strong,.user-menu span{display:block}.user-menu strong{font-size:var(--texto-13)}.user-menu span{font-size:var(--texto-11);color:var(--muted);margin-top:2px}.menu-toggle{display:none}.content{padding:32px clamp(22px,3.2vw,54px) 70px;max-width:1680px;margin:auto}.page-bar{display:flex;justify-content:space-between;align-items:center;gap:16px;margin:0 0 18px;padding:0 0 14px;border-bottom:1px solid var(--line);min-height:44px}.page-bar h1{font-size:var(--texto-22);letter-spacing:-.035em;margin:0}.page-bar{flex-wrap:wrap}.page-bar>h1{flex:1 1 auto}.page-bar .head-actions{margin-left:auto;justify-content:flex-end;align-items:center}.page-bar .filter-input{max-width:260px}.bar-count{color:var(--muted);font-size:var(--texto-12);white-space:nowrap;align-self:center}.filter-row{display:flex;gap:8px;flex-wrap:wrap;margin:-6px 0 16px}
/* EMBUDO (primitiva D): la POSICIÓN codifica el estado, que es el canal más preciso que existe
   (Cleveland & McGill 1984). Por eso las tarjetas no llevan chip de estado: sería decir dos veces
   lo mismo, y era justo lo que llenaba de rojo la pantalla anterior. */
.kb-explica{color:var(--muted);font-size:var(--texto-12);margin:0 0 14px;max-width:76ch}.bloque-titulo{font-size:var(--texto-16);margin:26px 0 6px;letter-spacing:-.02em}
/* Selección múltiple en Cobros: la barra solo aparece cuando hay algo seleccionado (no ocupa
   sitio en el caso normal) y va pegada abajo, donde está la mano. */
.sel-cell{display:flex;align-items:center;gap:9px;font-weight:700;cursor:pointer}
.sel-cell input{width:17px;height:17px;flex-shrink:0;accent-color:var(--teal,#0a6b5f);cursor:pointer}
.sel-bar{position:sticky;bottom:14px;z-index:6;display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  margin:0 0 12px;padding:12px 16px;border-radius:var(--radio-l);background:var(--verde-900,#0d2421);
  color:var(--blanco);box-shadow:var(--sombra-2)}
.sel-bar b{font-weight:800}
/* Entrada que solo existe cuando hay trabajo: el número es el motivo de estar ahí. */
tr.grupo-aviso td{background:var(--gris-fondo);padding:12px 17px;border-top:2px solid var(--line)}tr.grupo-aviso strong{font-size:var(--texto-13)}tr.grupo-aviso small{display:block;color:var(--muted);font-weight:400;margin-top:2px}.nav-pendiente .nav-badge{margin-left:auto;background:var(--teal,#0a6b5f);color:#fff;border-radius:var(--radio-pill);padding:1px 8px;font-size:var(--texto-11);font-weight:800}
.sel-bar .button.ghost{color:var(--blanco);border-color:rgba(255,255,255,.35);background:transparent}

/* auto-fit y NO grid-auto-flow:column: las columnas que no caben bajan a una segunda fila en vez
   de obligar a desplazar en horizontal. Se pierde la lectura en una sola línea en pantallas
   estrechas, pero el orden sigue siendo izquierda→derecha, arriba→abajo, y el scroll lateral en
   escritorio es de las cosas que peor se toleran (NN/g: además esconde lo que queda a la derecha). */
.kanban{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px;
  align-items:start;padding-bottom:8px}
.kb-col{background:var(--gris-fondo);border-radius:var(--radio-l);padding:12px;min-height:90px;display:grid;gap:9px;align-content:start}
.kb-col header h2{font-size:var(--texto-13);margin:0;display:flex;justify-content:space-between;align-items:baseline;gap:8px}
.kb-col header h2 b{font-size:var(--texto-12);color:var(--muted)}
.kb-col header p{margin:3px 0 0;font-size:var(--texto-11);color:var(--muted);line-height:1.35}
.kb-card{background:var(--blanco);border:1px solid var(--line);border-radius:var(--radio-m);padding:11px;display:grid;gap:3px}
.kb-card strong{font-size:var(--texto-12)}
.kb-card small{font-size:var(--texto-11);color:var(--muted)}
.kb-card .button{margin-top:7px;justify-self:start}
.kb-vacio{margin:0;font-size:var(--texto-11);color:var(--muted);font-style:italic}
.kb-cerradas{margin-top:18px}
.kb-cerradas summary{cursor:pointer;font-size:var(--texto-12);font-weight:600;color:var(--muted);padding:6px 0}
@media(max-width:760px){.kanban{grid-template-columns:1fr}}
.chip-filter{border:1px solid var(--line);background:var(--blanco);border-radius:var(--radio-pill);padding:6px 12px;font-size:var(--texto-12);font-weight:600;cursor:pointer;color:var(--texto-secundario)}.chip-filter b{font-weight:800;margin-left:2px}.chip-filter:hover{border-color:var(--teal,#0a6b5f)}.chip-filter.is-on{background:var(--verde-100,#e6f2ef);border-color:var(--teal,#0a6b5f);color:var(--teal-dark,#0a6b5f)}small.urgente{color:var(--error-texto,#b3261e);font-weight:600}.table-wrap.bleed{background:var(--blanco);border:1px solid var(--line);border-radius:var(--radio-l)}.table-wrap.bleed table{min-width:0}.head-actions{display:flex;gap:9px}.metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:15px;margin:20px 0}.metric{background:var(--blanco);border:1px solid var(--line);border-radius:var(--radius);padding:21px;min-height:120px;display:flex;flex-direction:column;justify-content:space-between;gap:16px;box-shadow:0 3px 15px rgba(28,67,61,.025)}.metric-icon{width:35px;height:35px;border-radius:var(--radio-m);background:var(--teal-soft);display:grid;place-items:center;color:var(--teal);font-weight:700}.metric.warning .metric-icon{background:var(--aviso-fondo);color:var(--aviso-texto)}.metric.danger .metric-icon{background:var(--error-fondo);color:var(--danger)}.metric.blue .metric-icon{background:var(--info-fondo);color:var(--blue)}.metric.success .metric-icon{background:var(--ok-fondo);color:var(--success)}.metric-value{font-size:var(--texto-26);font-weight:700;letter-spacing:-.04em}.metric-label{font-size:var(--texto-13);color:var(--muted)}.metric-detail{font-size:var(--texto-11);color:var(--texto-tenue);margin-top:3px}.grid-2{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr);gap:15px}.card{background:var(--blanco);border:1px solid var(--line);border-radius:var(--radius);padding:23px;box-shadow:0 3px 15px rgba(28,67,61,.025)}.card-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:17px}.card h2{font-size:var(--texto-16);margin:0}.card-kicker{font-size:var(--texto-11);color:var(--muted)}.occupancy{display:grid;grid-template-columns:180px minmax(0,1fr);align-items:center;gap:25px}.donut{--percent:70;position:relative;width:164px;height:164px;border-radius:50%;background:conic-gradient(var(--teal) calc(var(--percent)*1%),var(--gris-linea) 0);display:grid;place-items:center}.donut:before{content:"";width:116px;height:116px;background:var(--blanco);border-radius:50%}.donut-label{position:absolute;text-align:center}.donut-label strong{display:block;font-size:var(--texto-26)}.donut-label span{font-size:var(--texto-11);color:var(--muted)}.inventory-summary{display:grid;gap:17px}.summary-line{display:flex;justify-content:space-between;border-bottom:1px solid var(--line);padding-bottom:13px}.summary-line span{color:var(--muted);font-size:var(--texto-12)}.summary-line strong{font-size:var(--texto-16)}.timeline{display:grid}.timeline-item{display:grid;grid-template-columns:12px minmax(0,1fr) auto;gap:10px;padding:12px 0;border-bottom:1px solid var(--line);align-items:center}.timeline-item:last-child{border:0}.timeline-dot{width:8px;height:8px;background:var(--teal);border-radius:50%;box-shadow:0 0 0 4px var(--teal-soft)}.timeline-item strong{font-size:var(--texto-12)}.timeline-item span{display:block;font-size:var(--texto-11);color:var(--muted)}.status{display:inline-flex;align-items:center;border-radius:var(--radio-pill);padding:5px 9px;background:var(--gris-fondo);color:var(--texto-secundario);font-size:var(--texto-11);font-weight:700}.status.disponible,.status.confirmada,.status.completada,.status.aprobada,.status.activo{background:var(--ok-fondo);color:var(--ok-texto)}.status.bloqueada,.status.pendiente,.status.nueva,.status.en_revision{background:var(--aviso-fondo);color:var(--aviso-texto)}.status.rechazada,.status.urgente,.status.cancelada,.status.caducada{background:var(--error-fondo);color:var(--error-texto)}.status.convertida,.status.asignada{background:var(--info-fondo);color:var(--info-texto)}
.table-card{padding:0;overflow:hidden}.table-toolbar{display:flex;justify-content:space-between;gap:15px;padding:18px 20px;border-bottom:1px solid var(--line)}.filter-input{max-width:330px;width:100%}.table-wrap{overflow:auto}table{width:100%;border-collapse:collapse;min-width:760px}th{text-align:left;padding:13px 17px;background:var(--gris-fondo);color:var(--texto-secundario);font-size:var(--texto-11);text-transform:uppercase;letter-spacing:.08em}td{padding:15px 17px;border-top:1px solid var(--gris-linea);font-size:var(--texto-12);vertical-align:middle}td strong{display:block;font-size:var(--texto-12)}td small{display:block;color:var(--muted)}tr:hover td{background:var(--gris-050)}.empty{padding:45px;text-align:center;color:var(--muted)}.agent-card{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:16px;align-items:start;padding:18px;border:1px solid var(--line);border-radius:var(--radio-l);margin-bottom:10px}.agent-symbol{width:42px;height:42px;border-radius:var(--radio-m);background:var(--teal-soft);color:var(--teal-dark);display:grid;place-items:center;font-weight:700}.agent-card h3{font-size:var(--texto-14);margin:2px 0 5px}.agent-card p{font-size:var(--texto-12);color:var(--muted);margin:3px 0}.confidence{font-size:var(--texto-11);font-weight:700;color:var(--teal-dark)}.agent-actions{display:flex;gap:7px}.workflow{display:grid;grid-template-columns:repeat(9,minmax(0,1fr));gap:8px;align-items:stretch}.workflow-step{position:relative;border:1px solid var(--line);background:var(--blanco);border-radius:var(--radio-l);padding:16px 11px;min-height:110px;text-align:center}.workflow-step b{display:grid;place-items:center;width:28px;height:28px;border-radius:50%;background:var(--teal-soft);color:var(--teal);margin:0 auto 9px;font-size:var(--texto-11)}.workflow-step span{font-size:var(--texto-11);font-weight:700}.workflow-step:not(:last-child):after{content:"›";position:absolute;right:-8px;top:44%;z-index:2;color:var(--tinta-300);font-size:var(--texto-20)}.department-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}.department{border-top:4px solid var(--teal)}.department ul{margin:13px 0 0;padding-left:18px;color:var(--muted);font-size:var(--texto-12);line-height:1.8}.availability-box{background:linear-gradient(135deg,var(--verde-700),var(--verde-400));color:var(--blanco);border-radius:var(--radio-xl);padding:28px;margin-bottom:18px}.availability-box h2{font-size:var(--texto-26);margin:0 0 8px}.availability-box p{color:var(--texto-marca-claro);margin:0 0 21px}.availability-form{display:grid;grid-template-columns:repeat(4,minmax(0,1fr)) auto;gap:9px}.availability-form input,.availability-form select{border:0}.room-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:15px}.room-card{background:var(--blanco);border:1px solid var(--line);border-radius:var(--radio-l);overflow:hidden}.room-image{height:145px;background:linear-gradient(145deg,var(--verde-100),var(--gris-050));display:grid;place-items:center;color:var(--texto-secundario);font-weight:700}.room-body{padding:17px}.room-body h3{margin:0 0 5px;font-size:var(--texto-16)}.room-meta{color:var(--muted);font-size:var(--texto-11)}.room-price{font-weight:700;font-size:var(--texto-20);margin:14px 0}.room-price small{font-size:var(--texto-11);color:var(--muted);font-weight:600}.dialog{width:min(540px,calc(100% - 30px));border:0;border-radius:var(--radio-l);padding:0;box-shadow:0 30px 100px rgba(14,46,40,.25)}.dialog::backdrop{background:rgba(13,36,33,.46);backdrop-filter:blur(3px)}.dialog form{padding:27px;position:relative}.dialog-close{position:absolute;right:17px;top:14px;border:0;background:var(--gris-fondo);border-radius:50%;width:32px;height:32px;cursor:pointer}.dialog h2{margin:0 0 7px}.dialog p{color:var(--muted);font-size:var(--texto-13)}.dialog-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:13px;align-items:start}.dialog-actions{display:flex;justify-content:flex-end;gap:9px;margin-top:22px}.toast{position:fixed;z-index:100;right:22px;bottom:22px;background:var(--verde-900);color:var(--blanco);border-radius:var(--radio-m);padding:13px 17px;box-shadow:var(--shadow);font-size:var(--texto-12);transform:translateY(120px);opacity:0;transition:.25s}.toast.show{transform:translateY(0);opacity:1}.toast.error{background:var(--error-texto)}.progress-row{display:grid;gap:7px;margin:15px 0}.progress-meta{display:flex;justify-content:space-between;font-size:var(--texto-12)}.progress{height:8px;background:var(--gris-linea);border-radius:var(--radio-pill);overflow:hidden}.progress i{display:block;height:100%;background:var(--teal);border-radius:var(--radio-pill)}.marketing-roadmap{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}.roadmap-item{padding:16px;background:var(--gris-050);border-radius:var(--radio-m)}.roadmap-item b{display:block;font-size:var(--texto-12);color:var(--teal);margin-bottom:8px}.roadmap-item strong{font-size:var(--texto-12)}.roadmap-item p{font-size:var(--texto-11);color:var(--muted);line-height:1.55}
@media(max-width:1100px){.metrics{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-2{grid-template-columns:minmax(0,1fr)}.room-grid,.department-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.workflow{grid-template-columns:repeat(3,minmax(0,1fr))}.workflow-step:after{display:none}.availability-form{grid-template-columns:repeat(2,minmax(0,1fr))}.marketing-roadmap{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* Entre 760 y 1100 px el titular y los chips se estrangulaban (4 líneas + 3 filas de chips). */
@media(max-width:1100px) and (min-width:761px){.login-brand{padding:7vh 5vw}.login-title{font-size:clamp(2.2rem,4vw,3.4rem)}.login-copy .login-sub{font-size:var(--texto-16)}.login-features{gap:8px;margin-top:26px}.login-features span{padding:7px 11px}.login-panel{padding:5vw}}
/* Móvil: la marca NO desaparece (antes quedaba una página en blanco). Se convierte en una
   banda superior con la escena y el titular; el formulario va debajo. */
@media(max-width:760px){.login-view{grid-template-columns:1fr;grid-template-rows:auto 1fr}.login-brand{min-height:34svh;padding:26px 24px;align-items:flex-end}.login-title{font-size:clamp(1.9rem,8vw,2.6rem);margin:10px 0 0}.login-copy .login-sub,.login-features{display:none}.login-panel{padding:32px 24px 44px}.login-logo{width:210px;margin-bottom:14px}.app-view{display:block}.sidebar{transform:translateX(-100%);transition:transform .25s var(--ease-out);width:260px;box-shadow:var(--shadow)}.sidebar.open{transform:translateX(0)}.main-shell{margin:0}.menu-toggle{display:block}.topbar{padding:0 16px}.top-search{display:none}.content{padding:24px 16px 60px}.page-bar{align-items:flex-start;flex-direction:column;row-gap:10px}.page-bar .filter-input{max-width:none}.page-bar .head-actions{width:100%}.head-actions{flex-wrap:wrap}.page-head h1{font-size:var(--texto-26)}.metrics{grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}.metric{min-height:108px;padding:16px;gap:12px}.grid-2,.occupancy{grid-template-columns:minmax(0,1fr)}.donut{margin:auto}.room-grid,.department-grid{grid-template-columns:minmax(0,1fr)}.workflow{grid-template-columns:repeat(2,minmax(0,1fr))}.availability-form{grid-template-columns:minmax(0,1fr)}.user-menu div:not(.avatar){display:none}.head-actions .button span{display:none}.agent-card{grid-template-columns:auto 1fr}.agent-actions{grid-column:2}.dialog-grid{grid-template-columns:minmax(0,1fr)}}


/* --- Rotación, cobros y admisión (Fase 1 · H4-H7) --- */
.status.sem-ok{background:var(--ok-fondo);color:var(--ok-texto)}
.status.sem-media{background:var(--aviso-fondo);color:var(--aviso-texto)}
.status.sem-no{background:var(--error-fondo);color:var(--error-texto)}
/* Neutro: ni bien ni mal, «no hay nada que hacer aquí». En la conciliación lo lleva el movimiento
   ya registrado; darle un color del semáforo lo haría competir por una atención que no merece. */
.status.sem-neutro{background:var(--gris-fondo);color:var(--muted)}
/* Subir un fichero como acción principal: el «Choose File» del navegador no se puede estilar, así
   que el botón es la etiqueta y el input se esconde DENTRO de ella (sigue siendo accesible por
   teclado y por lector de pantalla; `display:none` lo sacaría del orden de tabulación). */
.button.file-cta{cursor:pointer;position:relative;overflow:hidden}
.button.file-cta input[type=file]{position:absolute;inset:0;opacity:0;cursor:pointer;font-size:0}
/* Fila de conciliación: «este movimiento del banco» → «este recibo». Dos columnas de igual peso
   porque la comparación ES la tarea. Por debajo de 900 px se parte en dos líneas: en una sola,
   cada texto se quedaba en 67 px (medido a 375) y no se podía leer ninguno de los dos. */
.concilia-row{align-items:flex-start;gap:12px}
.concilia-mov{display:flex;gap:9px;align-items:flex-start;flex:1;min-width:0}
.concilia-dest{flex:1;min-width:0}
.concilia-row>.status{flex-shrink:0}
@media(max-width:900px){
  .concilia-row{flex-wrap:wrap}
  .concilia-mov{flex:1 1 100%}
  /* La flecha convierte dos bloques apilados en una frase: esto se va a aplicar a aquello. */
  .concilia-dest{flex:1 1 auto;padding-left:25px;position:relative}
  .concilia-dest:before{content:"↳";position:absolute;left:6px;top:0;color:var(--muted)}
}
/* Vistas mensuales del calendario: quién · el dato de esta vista · el estado · la acción. Anchos
   fijos en las dos columnas de la derecha para que los chips y los botones caigan EN LA MISMA
   VERTICAL en todas las filas; con anchos automáticos cada fila los ponía en un sitio distinto. */
.sub-tabs{margin:-4px 0 10px}
.mes-row{align-items:center;gap:12px}
.mes-quien{flex:1 1 240px;min-width:0}
.mes-dato{flex:1 1 200px;min-width:0;font-size:var(--texto-12)}
.mes-row>.status{flex:0 0 118px;text-align:center}
.mes-accion{flex:0 0 232px;display:flex;justify-content:flex-end;gap:6px;align-items:center}
.mes-accion .inline-select{margin:0}
@media(max-width:1000px){
  .mes-row{flex-wrap:wrap}
  .mes-quien{flex:1 1 100%}
  .mes-dato{flex:1 1 auto}
  .mes-accion{flex:1 1 100%;justify-content:flex-start}
}
.status.estado-chip{font-weight:700;letter-spacing:.02em}
.status.estado-chip.todo-hecho{background:var(--ok-fondo);color:var(--ok-texto)}
.status.estado-chip.renovada{background:var(--verde-100);color:var(--verde-700)}
.status.estado-chip.libre{background:var(--info-fondo);color:var(--info-texto)}
.status.estado-chip.renovacion{background:var(--aviso-fondo);color:var(--aviso-texto)}
.status.estado-chip.falta{background:var(--error-fondo);color:var(--error-texto)}
.renewal-select{padding:6px 8px;border-radius:var(--radio-m);border:1px solid var(--line);font-size:var(--texto-12);max-width:112px}
.row-actions{display:flex;gap:6px;flex-wrap:wrap}
.doc-checklist{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.upload-row{display:flex;gap:8px;align-items:center;margin-top:10px;flex-wrap:wrap}
.upload-row select,.upload-row input[type=file]{padding:7px 9px;border:1px solid var(--line);border-radius:var(--radio-m);font-size:var(--texto-12)}

/* --- Altas y edición desde la interfaz (formularios en diálogo) --- */
.field-hint{font-weight:400;font-size:var(--texto-11);color:var(--muted);line-height:1.35}
.check-field{display:grid;gap:4px;font-size:var(--texto-13);font-weight:600;align-content:start}
.check-field span{display:flex;gap:8px;align-items:center}
.check-field input[type=checkbox]{width:16px;height:16px;accent-color:var(--teal,var(--verde-600))}
.dialog-grid .span-2{grid-column:1/-1}
.form-advanced{margin-top:14px;border:1px solid var(--line);border-radius:var(--radio-m);padding:10px 14px;background:rgba(0,0,0,.015)}
.form-advanced summary{cursor:pointer;font-size:var(--texto-12);font-weight:700;color:var(--muted);padding:4px 0}
.form-advanced[open] summary{margin-bottom:10px}
.form-advanced .dialog-grid{margin-top:4px}
.form-error{margin:14px 0 0;padding:11px 14px;border-radius:var(--radio-m);background:var(--error-fondo);border:1px solid var(--error-borde);color:var(--error-texto);font-size:var(--texto-12);font-weight:600;line-height:1.45}
.field-hint.hint-warning{color:var(--aviso-texto);font-weight:700}

/* --- Elegir la unidad del piso (alta de inquilino) ---
   Con 85 pisos y ~295 habitaciones, un desplegable con todas es inservible: primero el piso y
   luego sus habitaciones como fichas que se leen de un vistazo. El color es el MISMO que el del
   calendario (verde libre / rojo ocupada) para no aprender dos lenguajes distintos. */
.unit-legend{display:block;font-size:var(--texto-12);font-weight:700;color:var(--muted);margin:2px 0 8px}
.unit-picker{display:flex;flex-wrap:wrap;gap:8px}
.unit-chip{display:grid;gap:1px;min-width:104px;padding:9px 12px;text-align:left;cursor:pointer;
  border:1.5px solid var(--line);border-radius:var(--radio-m);background:var(--blanco);
  font-family:inherit;transition:transform var(--dur-1,.12s) ease,border-color var(--dur-1,.12s) ease,box-shadow var(--dur-1,.12s) ease}
.unit-chip strong{font-size:var(--texto-14);color:var(--tinta-900)}
.unit-chip span{font-size:var(--texto-12);color:var(--tinta-600);font-weight:600}
.unit-chip small{font-size:var(--texto-11);color:var(--tinta-500)}
.unit-chip.is-free{border-color:#bfe3c9;background:var(--excel-disponible)}
.unit-chip.is-busy{border-color:var(--excel-sinpagar-borde);background:var(--excel-sinpagar)}
.unit-chip:hover{transform:translateY(-1px);box-shadow:var(--sombra-1)}
/* La elegida se marca con el verde de marca y un tick: es la única decisión de esta cuadrícula. */
.unit-chip.is-selected{border-color:var(--verde-600);box-shadow:0 0 0 3px var(--verde-100);background:var(--blanco)}
.unit-chip.is-selected strong::after{content:' ✓';color:var(--verde-600)}
.unit-chip:focus-visible{outline:2px solid var(--verde-600);outline-offset:2px}
.unit-empty{border:1px dashed var(--line);border-radius:var(--radio-m);padding:12px 14px;background:var(--gris-050)}
.unit-empty p{margin:0 0 10px;font-size:var(--texto-13);color:var(--tinta-600)}
@media (prefers-reduced-motion:reduce){.unit-chip{transition:none}.unit-chip:hover{transform:none}}
/* Las opciones largas (p. ej. «— 510 €/mes · OCUPADA en esas fechas») no deben ensanchar el diálogo:
   la celda puede encoger y el select se recorta cerrado; desplegado se lee entero. */
.dialog-grid label{min-width:0}
.dialog-grid select,.dialog-grid input,.dialog-grid textarea{width:100%;max-width:100%}

/* --- Ficha del piso: estado de ocupación por habitación --- */
.status.libre{background:var(--ok-fondo);color:var(--ok-texto)}
.status.sin_pagar{background:var(--aviso-fondo);color:var(--aviso-texto)}

/* --- Auditoría UX 2026-07-04: buscador global, atajo de avisos, enlaces de ficha y toast accionable --- */
.top-search{position:relative}
.global-results{position:absolute;top:calc(100% + 6px);left:0;right:0;background:var(--blanco);border:1px solid var(--line);border-radius:var(--radio-m);box-shadow:var(--shadow);max-height:min(420px,60vh);overflow:auto;z-index:30;padding:6px}
.global-group{font-size:var(--texto-11);color:var(--texto-tenue);font-weight:700;letter-spacing:.14em;text-transform:uppercase;padding:9px 10px 4px}
.global-hit{display:block;width:100%;text-align:left;border:0;background:none;border-radius:var(--radio-m);padding:8px 10px;cursor:pointer}
.global-hit:hover,.global-hit:focus-visible{background:var(--teal-soft)}
.global-hit strong{display:block;font-size:var(--texto-12)}.global-hit small{color:var(--muted);font-size:var(--texto-11)}
.notif-count[hidden]{display:none}
.notif-count{position:absolute;right:-5px;top:-5px;min-width:17px;height:17px;border-radius:var(--radio-pill);background:var(--error-texto);color:var(--blanco);font-size:var(--texto-11);font-weight:700;display:grid;place-items:center;padding:0 4px}
.inline-link{color:var(--teal-dark);text-decoration:underline;cursor:pointer;font-weight:inherit}
button.inline-link{background:none;border:0;padding:0;font:inherit}
.inline-link:hover{color:var(--teal)}
.toast-action{border:0;background:rgba(255,255,255,.16);color:var(--blanco);border-radius:var(--radio-m);padding:6px 10px;margin-left:11px;font-size:var(--texto-12);font-weight:700;cursor:pointer}
.toast-action:hover{background:rgba(255,255,255,.28)}
.field-error-input{border-color:var(--danger)!important;box-shadow:var(--anillo-error)!important}


/* ==========================================================================
   REDISEÑO VISUAL 2026-07 · Notion (limpio) + Apple (pulido) + Liquid Glass
   Acabado: tipografía nítida, esquinas coherentes, scroll fino, vidrio en las
   capas flotantes y micro-movimiento con intención. Todo el color desde tokens.
   Respeta prefers-reduced-motion.
   ========================================================================== */

/* — Render de tipografía nítido (Apple) — */
html{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility;scroll-behavior:smooth}

/* — Scrollbars finas y discretas (Notion/Apple) — */
*{scrollbar-width:thin;scrollbar-color:var(--scroll-thumb) transparent}
::-webkit-scrollbar{width:11px;height:11px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--scroll-thumb);border-radius:var(--radio-pill);border:3px solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background:var(--scroll-thumb-hover);background-clip:content-box}

/* — TOPBAR de vidrio esmerilado (se ve el contenido pasar por debajo) — */
.topbar{background:var(--glass-fondo);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border-bottom:1px solid var(--glass-borde);box-shadow:0 1px 1px rgba(23,35,34,.03)}
.top-search{transition:box-shadow var(--dur-2) var(--ease-out),background var(--dur-2) var(--ease-out)}
.top-search:focus-within{background:var(--blanco);box-shadow:var(--anillo-foco)}
.icon-button{transition:background var(--dur-2) var(--ease-out),transform var(--dur-1) var(--ease-out)}
.icon-button:hover{background:var(--color-borde)}
.icon-button:active{transform:scale(.94)}

/* — SIDEBAR: limpio (Notion), estados cuidados — */
.nav-link{transition:background var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out)}
/* B4 (auditoría 06): el menú se recorre decenas de veces al día; el desplazamiento y el rebote del icono eran ruido. Solo cambia el fondo. */
.nav-link.active{box-shadow:0 1px 2px rgba(10,107,95,.12)}


/* — BOTONES: elevación de acento + press físico — */
.button{transition:background var(--dur-2) var(--ease-out),transform var(--dur-1) var(--ease-out),box-shadow var(--dur-2) var(--ease-out)}
.button.primary{box-shadow:var(--sombra-accion-reposo)}
.button.primary:hover{box-shadow:var(--sombra-accion);transform:translateY(-1px)}
.button:active{transform:translateY(0) scale(.97)}

/* — CARDS / MÉTRICAS: radios coherentes + hover lift — */
.card,.table-card{border-radius:var(--radio-l)}
.metric,.room-card,.agent-card{border-radius:var(--radio-l);transition:transform var(--dur-3) var(--ease-out),box-shadow var(--dur-3) var(--ease-out),border-color var(--dur-3) var(--ease-out)}
.metric:hover,.room-card:hover{transform:translateY(-3px);box-shadow:var(--sombra-2)}


/* — CHIPS / STATUS: transición suave — */
.status{transition:background var(--dur-1) var(--ease-out),color var(--dur-1) var(--ease-out)}

/* — TABLAS: filas reactivas, contenedor redondeado abajo — */
.table-wrap{border-radius:0 0 var(--radio-l) var(--radio-l)}
tbody tr{transition:background var(--dur-1) var(--ease-out)}

/* — INPUTS: radio coherente (el foco ya va por --anillo-foco) — */
input,select,textarea{border-radius:var(--radio-m)}

/* — DIÁLOGO: vidrio esmerilado + entrada con escala/fade — */
.dialog{border-radius:var(--radio-xl);background:var(--glass-fondo-alto);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border:1px solid var(--glass-borde);box-shadow:var(--sombra-3);animation:dlg-in var(--dur-4) var(--ease-out)}
.dialog::backdrop{background:rgba(13,36,33,.4);-webkit-backdrop-filter:blur(6px) saturate(115%);backdrop-filter:blur(6px) saturate(115%);animation:fade-in var(--dur-4) var(--ease-out)}
.dialog-close{transition:background var(--dur-2) var(--ease-out),transform var(--dur-2) var(--ease-spring)}
.dialog-close:hover{background:var(--color-borde)}
@keyframes dlg-in{from{opacity:0;transform:translateY(10px) scale(.975)}to{opacity:1;transform:none}}
@keyframes fade-in{from{opacity:0}to{opacity:1}}

/* — POPOVER del buscador global: vidrio — */
.global-results{background:var(--glass-fondo-alto);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border-color:var(--glass-borde);box-shadow:var(--glass-sombra)}
.global-hit{transition:background var(--dur-1) var(--ease-out)}

/* — TOAST: radio coherente — */
.toast{border-radius:var(--radio-l)}

/* — ENTRADA DE PÁGINA (auditoría skills · P2-2): fundido corto y solo-opacidad. Antes había un stagger con
   desplazamiento que se RE-EJECUTABA en cada navegación (0.34s + retardos hasta .12s), lo que añadía latencia
   percibida en una herramienta que se navega decenas de veces al día (Emil: no ralentizar lo de alta frecuencia).
   Un fundido de ~0.2s suaviza el cambio sin frenar. — */
.content>*{animation:page-in var(--dur-2) var(--ease-out) both}
@keyframes page-in{from{opacity:0}to{opacity:1}}

/* — Menú móvil sobre vidrio — */
@media(max-width:760px){
  .sidebar{background:var(--glass-fondo-alto);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur)}
}

/* — Respeta a quien prefiere menos movimiento — */
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms!important;animation-delay:0s!important}
}


/* ==========================================================================
   REFINAMIENTO v2 · según la guía de dirección (Notion + Apple + Liquid Glass)
   Corrige el primer pase (D3) y añade los detalles "que gritan Apple".
   ========================================================================== */
@property --percent{syntax:"<number>";inherits:false;initial-value:0}

/* — D3: sombra de card/métrica a la familia ÚNICA (adiós a la sombra verde casi invisible) + padding coherente — */
.card,.metric{box-shadow:var(--sombra-1);padding:var(--esp-5)}
.metric:hover,.room-card:hover{transform:translateY(-2px)}   /* eleva un solo nivel, sutil */

/* — Cristal con labio de luz interior (parece cristal, no plástico) — */
.topbar{box-shadow:var(--glass-realce),0 1px 1px rgba(23,35,34,.03)}
.global-results{box-shadow:var(--glass-realce),var(--glass-sombra)}
.dialog{box-shadow:var(--glass-realce),var(--sombra-3)}

/* — Foco de teclado accesible (el ratón no lo dispara) — */
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,summary:focus-visible,[tabindex]:focus-visible{outline:none;box-shadow:var(--anillo-foco)}

/* — Marcador de barra que CRECE en el enlace de nav activo — */
.nav-link{position:relative}
.nav-link::before{content:"";position:absolute;left:2px;top:50%;width:3px;height:0;border-radius:var(--radio-pill);background:var(--color-accion);transform:translateY(-50%);transition:height var(--dur-2) var(--ease-spring)}
.nav-link.active::before{height:18px}

/* — Guía de ojo en la fila al hover (acento izquierdo, sin reflow) — */
tbody tr:hover td:first-child{box-shadow:inset 3px 0 0 var(--color-accion-suave)}

/* — Cifras tabulares: importes y fechas no bailan al filtrar — */
td,th,.metric-value{font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
td{font-size:var(--texto-13)}

/* — Cabeceras de tabla fijas al hacer scroll (vidrio ligero + despegue) — */
.table-wrap{max-height:calc(100vh - 234px);overflow:auto;overscroll-behavior:contain}
/* Cabecera de tabla fija SÓLIDA (auditoría skills · P1-2): el vidrio se reserva para el chrome flotante de
   marca (topbar, diálogo, popover). Sobre datos que hacen scroll por debajo, un fondo translúcido resta
   legibilidad y suma coste GPU en una herramienta de uso intensivo → cabecera opaca y nítida. */
.table-wrap th{position:sticky;top:0;z-index:3;background:var(--gris-fondo);box-shadow:var(--sombra-sticky)}
.content{scroll-padding-top:90px}

/* — Donut que se dibuja al aparecer — */
.donut{transition:--percent var(--dur-4) var(--ease-out)}

/* — LOGIN: la flecha que promete avance —
   (las dos órbitas CSS las sustituyó la escena 3D de #login-scene: dos capas de composición
   permanentes por una rotación de 70 s que no se veía. Auditoría 2026-07-31.) */
.button.wide span{display:inline-block;transition:transform var(--dur-2) var(--ease-out)}
.button.wide:hover span{transform:translateX(3px)}

/* — Fallback si el navegador no soporta vidrio (opaco, sin cristal) — */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .topbar,.global-results,.toast{background:var(--blanco)}
  .table-wrap th{background:var(--gris-fondo)}
  @media(max-width:760px){.sidebar{background:var(--blanco)}}
}

/* ==================== UPGRADE v3 · Iconos semánticos + dashboard que responde + equilibrio ==================== */
/* Iconos SVG (Lucide, trazo 1.75): un solo estilo en todo el CRM. */
.nav-icon{display:inline-grid;place-items:center;width:20px;height:20px;color:currentColor;flex:none;font-size:0}
.nav-icon svg,.metric-icon svg,.agent-symbol svg{display:block}
.top-search-icon{display:inline-grid;place-items:center;color:var(--texto-secundario)}
.icon-button{color:var(--texto-secundario)}
.icon-button svg{display:block;margin:auto}
/* Métricas que navegan: lo clicable debe parecer clicable (affordance + chevron). */
a.metric{text-decoration:none;color:inherit}
.metric-link{position:relative;cursor:pointer}
.metric-link .metric-go{position:absolute;right:16px;top:13px;font-size:var(--texto-20);line-height:1;color:var(--tinta-300);transition:transform var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out)}
.metric-link:hover .metric-go{color:var(--color-accion);transform:translateX(3px)}
.metric-link:focus-visible{box-shadow:var(--anillo-foco)}
/* Dashboard: donut compacto (parte-todo única) + inventario que navega — sin vacíos muertos. */
@media(min-width:761px){.occupancy{grid-template-columns:132px minmax(0,1fr);gap:24px}}
.donut{width:128px;height:128px;text-decoration:none;color:inherit}
.donut:before{width:88px;height:88px}
.donut-label strong{font-size:var(--texto-20)}
a.donut{cursor:pointer;transition:transform var(--dur-2) var(--ease-out)}
a.donut:hover{transform:scale(1.04)}
.inventory-summary{gap:0}
.summary-line{padding:12px 8px;margin:0 -8px;border-bottom:1px solid var(--line);align-items:center}
.inventory-summary .summary-line:last-child{border-bottom:0}
a.summary-line{text-decoration:none;color:inherit;cursor:pointer;border-radius:var(--radio-s);transition:background var(--dur-1) var(--ease-out)}
a.summary-line:hover{background:var(--gris-050)}
.summary-line .go{font-style:normal;color:var(--tinta-300);display:inline-block;transition:transform var(--dur-2) var(--ease-out),color var(--dur-2) var(--ease-out)}
a.summary-line:hover .go{color:var(--color-accion);transform:translateX(2px)}
/* La columna de movimientos pesa más que la de ocupación (D4: 1fr / 1.2fr). */
@media(min-width:1101px){.grid-2{grid-template-columns:minmax(0,1fr) minmax(0,1.2fr)}}
/* Movimientos agrupados por día: una fila serena por grupo, expandible. */
.move-group{border-bottom:1px solid var(--line)}
.move-group:last-child{border-bottom:0}
.move-group summary{display:flex;align-items:center;gap:12px;padding:13px 8px;margin:0 -8px;cursor:pointer;list-style:none;border-radius:var(--radio-s);transition:background var(--dur-1) var(--ease-out)}
.move-group summary::-webkit-details-marker{display:none}
.move-group summary:hover{background:var(--gris-050)}
.move-title{flex:1;display:grid;gap:2px;min-width:0}
.move-title strong{font-size:var(--texto-13)}
.move-title span{font-size:var(--texto-11);color:var(--muted)}
.move-status{display:inline-flex;align-items:center;gap:5px;font-size:var(--texto-11);font-weight:600;color:var(--texto-secundario)}
.move-status svg{color:var(--ok-texto)}
.move-chev{color:var(--tinta-300);font-size:var(--texto-16);line-height:1;transition:transform var(--dur-2) var(--ease-out)}
.move-group[open] .move-chev{transform:rotate(90deg)}
.move-items{display:grid;gap:2px;padding:2px 0 12px 28px}
.move-items a{font-size:var(--texto-12);color:var(--texto-secundario);text-decoration:none;padding:5px 8px;border-radius:var(--radio-s);transition:background var(--dur-1) var(--ease-out)}
.move-items a:hover{background:var(--gris-050);color:var(--ink)}
.move-group.salida .timeline-dot{background:var(--aviso-600);box-shadow:0 0 0 4px var(--aviso-100)}
.move-group.entrada .timeline-dot{background:var(--verde-600);box-shadow:0 0 0 4px var(--verde-100)}
/* Tarjeta-enlace al calendario: el calendario entero vive en su pantalla, aquí solo el pulso. */
.calendar-link-card{display:flex;align-items:center;justify-content:space-between;gap:18px;margin-top:15px;flex-wrap:wrap}
.calendar-link-info{display:flex;align-items:center;gap:14px;min-width:0}
.calendar-link-icon{width:46px;height:46px;border-radius:var(--radio-m);background:var(--verde-100);color:var(--verde-700);display:grid;place-items:center;flex:none}
.calendar-link-info h2{margin:0 0 3px;font-size:var(--texto-16)}
.calendar-link-info p{margin:0;font-size:var(--texto-12);color:var(--muted)}
.calendar-link-actions{display:flex;gap:9px;flex-wrap:wrap}
.calendar-link-actions .button{text-decoration:none}
/* Sin scroll horizontal también en portátiles pequeños: la tabla se densifica antes que desbordar. */
@media(max-width:1320px){
  th{padding:11px 8px}
  td{padding:12px 8px;font-size:var(--texto-12)}
  td strong{font-size:var(--texto-12)}
  .button.small{padding:7px 10px}
  .status{padding:4px 5px;font-size:var(--texto-11)}
  /* El select de renovación no dicta el ancho de la tabla: se recorta cerrado (abierto enseña el texto completo). */
  .renewal-select{max-width:104px}
}
/* Portátil estrecho: el sidebar cede espacio antes de que nada desborde. */
@media(max-width:1160px){
  .app-view{grid-template-columns:204px 1fr}
  .sidebar{width:204px;padding:22px 12px 16px}
  .sidebar-logo img{width:148px}
  .content{padding:24px 18px 60px}
  th{padding:10px 6px}
  td{padding:11px 6px}
  .button.small{padding:6px 8px;font-size:var(--texto-11)}
}

/* ==================== Seguimiento P1 · selector de mes en español + vacío-guía (D5.03) ==================== */
/* Selector de mes con «cara propia en español»: el <input type=month> nativo va transparente
   encima (abre su calendario con showPicker en el clic); el usuario ve «julio 2026», no «July 2026». */
.month-field{position:relative;display:inline-flex;vertical-align:middle}
.month-field .month-face{display:inline-flex;align-items:center;gap:8px;height:var(--boton-alto);padding:0 12px;border:1px solid var(--input-borde);border-radius:var(--radio-m);background:var(--color-superficie);color:var(--texto-principal);font-weight:600;font-size:var(--texto-13);white-space:nowrap;pointer-events:none;transition:border-color var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out)}
.month-field .month-face svg{color:var(--texto-secundario);flex:none}
.month-field input{position:absolute;inset:0;width:100%;height:100%;margin:0;padding:0;border:0;opacity:0;cursor:pointer}
.month-field:hover .month-face{border-color:var(--color-accion)}
.month-field:focus-within .month-face{border-color:var(--color-accion);box-shadow:var(--anillo-foco)}

/* Vacío-guía: en vez de una tabla esqueleto de «SIN GENERAR», una frase de qué habrá aquí + el botón que lo crea. */
.empty-guide{display:flex;flex-direction:column;align-items:center;text-align:center;gap:12px;padding:52px 32px}
.empty-guide .empty-guide-icon{width:52px;height:52px;border-radius:var(--radio-l);background:var(--color-accion-suave);color:var(--color-accion-texto);display:grid;place-items:center}
.empty-guide h2{font-size:var(--texto-16);margin:0}
.empty-guide p{margin:0;color:var(--muted);font-size:var(--texto-14);max-width:52ch;line-height:1.55}
.empty-guide .button{margin-top:6px;text-decoration:none}
.empty-guide-note{font-weight:600}

/* ==================== Seguimiento P2 · pie de acciones fijo + facts + acentos Fase 2 (D4/D5) ==================== */
/* Pie de acciones FIJO en diálogos (D4·05): el cuerpo hace scroll si crece, las acciones no se van con él.
   El primario (= acción de la tarea) queda al final; «Cerrar»/«Cancelar» (ghost) se separa a la izquierda. */
.dialog form{padding:0;display:flex;flex-direction:column;max-height:min(90vh,880px)}
#dialog-content{padding:26px 27px 0;overflow:hidden auto;overscroll-behavior:contain;min-height:0}
/* El pie comparte el MISMO material vidrio que el cuerpo del diálogo (antes era blanco sólido opaco →
   se leía como un recuadro blanco ajeno sobre el glass). Redondea sus esquinas inferiores para seguir la
   silueta del modal en vez de cortar en recto. */
.dialog-actions{position:sticky;bottom:0;margin:22px -27px 0;padding:14px 27px 24px;background:var(--glass-fondo-alto);-webkit-backdrop-filter:var(--glass-blur);backdrop-filter:var(--glass-blur);border-top:1px solid var(--color-borde);border-radius:0 0 var(--radio-xl) var(--radio-xl)}
.dialog-actions>.button.ghost:first-child:not(:only-child),
.dialog-actions>.button.danger:first-child:not(:only-child){margin-right:auto}
/* Móvil: cuatro acciones no caben en una fila a 375px → reparten ancho y saltan de línea (2×2),
   en vez de que «Cerrar» se salga por la izquierda. Objetivos táctiles anchos (D5.05e). */
@media(max-width:760px){
  .dialog-actions{flex-wrap:wrap}
  .dialog-actions>.button{flex:1 1 42%}
  .dialog-actions>.button.ghost:first-child:not(:only-child),
  .dialog-actions>.button.danger:first-child:not(:only-child){margin-right:0}
}

/* Acento Fase 2 · chips de rotación/semáforo como pastillas físicas (labio de luz interior + sombra corta) */
.status.sem-ok,.status.sem-media,.status.sem-no,.status.estado-chip{box-shadow:inset 0 1px 0 rgba(255,255,255,.55),0 1px 1.5px rgba(23,35,34,.09)}

/* Acento Fase 2 · el donut de ocupación se dibuja al entrar (0 → % real; `from` sin `to` = el valor inline del elemento) */
@keyframes donut-draw{from{--percent:0}}
.donut{animation:donut-draw var(--dur-4) var(--ease-out)}

/* Acento Fase 2 · la barra de progreso crece al aparecer (escala en X desde la izquierda; no toca el ancho real) */
@keyframes progress-grow{from{transform:scaleX(0)}}
.progress i{transform-origin:left;animation:progress-grow var(--dur-4) var(--ease-out)}

/* Acento Fase 2 · apertura suave de las secciones plegables del formulario. Mejora progresiva:
   solo donde el navegador sabe animar a altura auto; si no, se pliega al instante como hasta ahora. */
@supports (interpolate-size:allow-keywords){
  :root{interpolate-size:allow-keywords}
  .form-advanced::details-content{block-size:0;overflow:hidden;transition:block-size var(--dur-3) var(--ease-out),content-visibility var(--dur-3) var(--ease-out);transition-behavior:allow-discrete}
  .form-advanced[open]::details-content{block-size:auto}
}

/* ==================== Tablas → cards (D5.05c) + táctil ≥44 px (D5.05e) ====================
   Las clases m-* las anota mobileCards() en app.js al pintar cada tabla; fuera de este media query son inertes.
   BREAKPOINT 1080px (auditoría skills · P1-1): las cards entran ANTES que el shell móvil (≤760px, sidebar
   drawer). Entre 761 y 1080px el sidebar de escritorio sigue presente pero la tabla ya no cabría en horizontal
   (con el sidebar, el ancho útil baja de los 760px de min-width) → se muestra como cards en vez de desbordar.
   Así el scroll horizontal desaparece en TODA la franja tablet/portátil; solo queda en el calendario (que en
   móvil pasa a vista por mes). Por encima de 1080px la tabla cabe holgada y se muestra normal. */
@media(max-width:1080px){
  .table-wrap{max-height:none;overflow:visible}
  .m-cards{display:block;min-width:0}
  .m-cards thead{display:none}
  .m-cards tbody{display:grid;gap:10px}
  .m-cards tr{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;padding:14px;border:1px solid var(--line);border-radius:var(--radio-m);background:var(--blanco)}
  .m-cards tr:hover td:first-child{box-shadow:none}
  .m-cards td{display:block;border:0;padding:0;font-size:var(--texto-13)}
  .m-cards td.m-hide{display:none}
  .m-cards td.m-title{flex:1 1 100%}
  /* La cabecera de un grupo (Cobros: «Vencidas · 24 · 13.600 €») ocupa la fila, no una cajita. */
  .m-cards tr.grupo-aviso{padding:0;overflow:hidden}
  .m-cards tr.grupo-aviso td{flex:1 1 100%;padding:10px 14px}
  .m-cards td.m-title strong{font-size:var(--texto-14)}
  .m-cards td[data-th]::before{content:attr(data-th);display:block;margin-bottom:2px;font-size:var(--texto-11);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--texto-tenue)}
  .m-cards td.m-actions{flex:1 1 100%;display:flex;flex-wrap:wrap;gap:9px;margin-top:2px}
  .m-cards td.m-actions .button{flex:1 1 auto;min-height:44px;font-size:var(--texto-12)}
  .m-cards td.m-actions select{width:100%;max-width:none;min-height:44px}
  /* Objetivos táctiles ≥44 px también fuera de las cards (D5.05e). */
  .filter-input{min-height:44px}
  .table-toolbar{flex-wrap:wrap}
  .head-actions .button,.page-bar>.button{min-height:44px}
  .add-menu>.button{min-height:44px}
}

/* ==================== Auditoría skills · P2 · menú "+ Añadir" + notas de vocabulario ====================
   P2-3 · Un solo primario "+ Añadir" con menú, en vez de 4 botones de alta compitiendo en la cabecera.
   El popover escala desde su esquina superior derecha (origen = el botón que lo abre, criterio Emil para
   popovers), no desde el centro. */
/* La cabecera se eleva sobre las secciones siguientes (métricas, grid) para que el popover que desborda por
   debajo del botón no quede tapado. z-index:1 la mantiene por DEBAJO de la topbar sticky (z-index:10). */
.page-bar{position:relative;z-index:1}
.add-menu{position:relative;display:inline-flex}
.add-menu>.button{gap:6px}
.add-menu-list{position:absolute;top:calc(100% + 6px);right:0;min-width:196px;background:var(--color-superficie);border:1px solid var(--color-borde);border-radius:var(--radio-m);box-shadow:var(--sombra-2);padding:6px;z-index:40;display:grid;gap:2px;transform-origin:top right;animation:add-menu-in var(--dur-2) var(--ease-out)}
.add-menu-list[hidden]{display:none}
.add-menu-list button{display:flex;align-items:center;gap:10px;width:100%;text-align:left;border:0;background:none;border-radius:var(--radio-s);padding:10px;font:inherit;font-size:var(--texto-13);font-weight:600;color:var(--texto-principal);cursor:pointer;transition:background var(--dur-1) var(--ease-out),color var(--dur-1) var(--ease-out)}
.add-menu-list button:hover,.add-menu-list button:focus-visible{background:var(--color-accion-suave);color:var(--color-accion-texto);outline:none}
.add-menu-list button svg{color:var(--texto-secundario);flex:none}
.add-menu-list button:hover svg,.add-menu-list button:focus-visible svg{color:var(--color-accion-texto)}
@keyframes add-menu-in{from{opacity:0;transform:scale(.96) translateY(-4px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.add-menu-list{animation:none}}

/* P2-6 · La capa de alias del inicio de este fichero (--teal, --ink, --muted, --line, --surface, --canvas,
   --success, --warning, --danger, --blue, --shadow, --radius) es un SHIM DE COMPATIBILIDAD heredado: cada
   alias apunta 1:1 a un token semántico de tokens.css. Se conserva para no reescribir el CSS histórico, pero
   está DEPRECADO: el código nuevo debe consumir directamente los semánticos (--color-accion, --texto-principal,
   --color-borde, --color-superficie, --color-fondo, --ok-texto…). No añadir nuevos alias. */

/* ==================== Auditoría skills · P3 · pulido y delight ==================== */
/* P3-3 · Barra de carga superior indeterminada: el sistema "dice" que está trabajando (Nielsen #1). */
.load-bar{position:fixed;top:0;left:0;right:0;height:2px;z-index:200;pointer-events:none;opacity:0;transition:opacity var(--dur-2) var(--ease-out)}
.load-bar.on{opacity:1}
.load-bar::before{content:"";position:absolute;top:0;left:-40%;height:100%;width:40%;background:var(--color-accion);border-radius:var(--radio-pill)}
.load-bar.on::before{animation:load-slide 1.1s var(--ease-in-out) infinite}
@keyframes load-slide{0%{left:-40%}100%{left:100%}}

/* P3-2 · El popover del buscador global escala desde la barra (origen arriba, criterio Emil para popovers). */
.global-results{transform-origin:top center;animation:search-pop var(--dur-2) var(--ease-out)}
@keyframes search-pop{from{opacity:0;transform:scale(.98) translateY(-4px)}to{opacity:1;transform:none}}

/* P3-4 · Feedback táctil al pulsar filas y elementos de menú clicables (los .button ya lo tenían). */
a.metric:active,a.summary-line:active,.move-group summary:active,.global-hit:active,.add-menu-list button:active{transform:scale(.99)}

/* Bajo prefers-reduced-motion: la barra de carga queda estática y visible; el popover no escala. */
@media(prefers-reduced-motion:reduce){
  .load-bar.on::before{animation:none;left:0;width:100%;opacity:.55}
  .global-results{animation:none}
}


/* ==================== El contrato como plantilla editable (motor C3) ====================
   El contrato de Word, dentro del CRM: se ve el documento tal cual y los datos que se rellenan
   solos son piezas verdes dentro del texto. Objetivo: que Evelyn edite un contrato sin saber que
   por debajo hay HTML ni llaves dobles. */
/* Estos dos diálogos son de trabajo (un documento y una lista de decisiones): necesitan sitio.
   Se ensanchan solos según lo que contienen, sin clases extra desde el JS. */
.dialog:has(.tpl-editor){width:min(1080px,calc(100% - 30px))}
.dialog:has(.gap-list){width:min(880px,calc(100% - 30px))}
.template-card{margin-top:18px}
.template-head{display:flex;gap:20px;justify-content:space-between;align-items:flex-start;flex-wrap:wrap}
.template-head h2{margin:6px 0 6px;font-size:var(--texto-20)}
.template-head p{margin:0;max-width:62ch;color:var(--muted);font-size:var(--texto-13);line-height:1.55}
.template-actions{display:flex;gap:9px;flex-wrap:wrap}

/* Huecos detectados en el Word: qué dice el hueco (con su frase alrededor) y qué dato se le asigna. */
.gap-list{display:grid;gap:8px;margin:14px 0 4px;max-height:46vh;overflow:auto;padding-right:4px}
.gap-row{display:grid;grid-template-columns:minmax(0,1fr) minmax(190px,240px);gap:12px;align-items:center;
  padding:10px 12px;border:1px solid var(--gris-linea);border-radius:var(--radio-m);background:var(--blanco)}
.gap-what strong{display:block;font-size:var(--texto-13);color:var(--tinta-900)}
.gap-what small{display:block;color:var(--tinta-500);font-size:var(--texto-11);line-height:1.45;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gap-pick select{width:100%}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* Editor: el documento a la izquierda, los datos disponibles a la derecha. */
.tpl-editor{display:grid;grid-template-columns:minmax(0,1fr) 240px;gap:14px;margin:14px 0 10px;align-items:start}
.tpl-doc{max-height:52vh;overflow:auto;padding:20px 22px;background:var(--blanco);border:1px solid var(--gris-linea);
  border-radius:var(--radio-m);font-family:Georgia,"Times New Roman",serif;font-size:13px;line-height:1.6;color:var(--tinta-900)}
.tpl-doc:focus{outline:none;border-color:var(--verde-600);box-shadow:var(--anillo-foco,0 0 0 3px var(--verde-100))}
.tpl-doc h1{font-size:16px;text-align:center;margin:0 0 6px}
.tpl-doc h2{font-size:14px;margin:18px 0 6px;border-bottom:1px solid var(--gris-linea);padding-bottom:3px}
.tpl-doc p{margin:0 0 8px;text-align:justify}
.tpl-doc ul{margin:0 0 8px 18px;padding:0}
.tpl-doc li{margin:0 0 4px}
.tpl-doc .rellenar{border-bottom:1px solid var(--tinta-500);min-width:80px;display:inline-block}
/* La pieza de dato: se lee como una etiqueta, no como código. Atómica: Retroceso la borra entera. */
.campo{display:inline-block;padding:1px 7px;margin:0 1px;border-radius:var(--radio-pill);
  background:var(--verde-100);color:var(--verde-900);border:1px solid #bcdcd5;
  font-family:var(--fuente);font-size:11px;font-weight:600;white-space:nowrap;cursor:pointer;user-select:all}
.campo::before{content:"›";margin-right:4px;color:var(--verde-600);font-weight:700}
.campo:hover{background:#cfe7e2}
/* Bloque condicional: no es un dato, es una regla («esto solo sale si hay pareja»). Distinto color
   para que no se confunda con un campo que se rellena. */
.condicion{display:inline-block;padding:1px 8px;margin:0 2px;border-radius:var(--radio-s);
  background:var(--aviso-100);color:var(--aviso-600);border:1px dashed #d9c07a;
  font-family:var(--fuente);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;
  white-space:nowrap;cursor:pointer;user-select:all}
.tpl-palette{display:grid;gap:10px;position:sticky;top:0;max-height:52vh;overflow:auto;padding-right:2px}
.tpl-palette .filter-input{max-width:none}
.tpl-group h4{margin:8px 0 6px;font-size:var(--texto-11);text-transform:uppercase;letter-spacing:.07em;color:var(--tinta-500)}
.tpl-field{display:block;width:100%;text-align:left;margin-bottom:5px;padding:7px 10px;cursor:pointer;
  border:1px solid var(--gris-linea);border-radius:var(--radio-s);background:var(--blanco);
  font-family:inherit;font-size:var(--texto-12);color:var(--tinta-900)}
.tpl-field:hover{border-color:var(--verde-600);background:var(--verde-100)}
.tpl-name{display:grid;gap:4px;font-size:var(--texto-13);font-weight:600;max-width:340px}

/* Editar un contrato en el móvil no tiene sentido: la paleta pasa debajo y se avisa. */
@media(max-width:860px){
  .tpl-editor{grid-template-columns:minmax(0,1fr)}
  .tpl-palette{position:static;max-height:200px}
  .gap-row{grid-template-columns:minmax(0,1fr)}
}

/* ==========================================================================
   AUDITORÍA DE DESBORDES 2026-07-27 · nada debe generar scroll horizontal
   --------------------------------------------------------------------------
   Medido en el navegador (1440 / 1200 / 1101 / 900 / 375 px) sobre las 23
   pantallas. Las pistas `1fr` de las cuadrículas ya pasaron a `minmax(0,1fr)`
   arriba, en su sitio; aquí van las reglas ADITIVAS que faltaban.
   Regla de oro de esta sección: ningún cambio estético, solo contención.
   ========================================================================== */

/* — 1. El menú lateral ya no hace scroll horizontal al pasar el ratón —
   `.sidebar nav` declara solo `overflow-y:auto`; por la regla de CSS Overflow
   («si un eje no es visible, el otro visible pasa a auto») su `overflow-x`
   COMPUTA a `auto`. Como `.nav-link:hover` desplaza el enlace 2px a la derecha
   (translateX), el área desplazable crecía a 196px sobre 194px de ancho y
   aparecía una barra horizontal / rebote en el menú.
   Se arregla en dos capas: el `padding-right` deja sitio real a esos 2px (el
   enlace ya no sobresale, así que no se recorta el fondo al desplazarse) y
   `overflow-x:hidden` blinda el eje ante cualquier contenido futuro. */
.sidebar nav{overflow-x:hidden;padding-right:3px}
/* …y ese `hidden` escondía en silencio 1,4 px del enlace más largo («Propuestas del CRM» con su
   contador, y las cabeceras en mayúsculas espaciadas): la rejilla del menú tomaba el ancho mínimo
   del contenido más largo. Lo encontró el detector de desborde (web/desborde.html). Con la
   columna a `minmax(0,1fr)` el texto que no quepa salta de línea en vez de quedar recortado. */
.sidebar nav{grid-template-columns:minmax(0,1fr)}
.sidebar nav>*{min-width:0}

/* — 2. Las KPI no se comen unas a otras —
   Los importes de `Intl.NumberFormat('es-ES',{currency})` llevan un espacio
   DURO (U+00A0) antes del €: «128.450,75 €» es UNA palabra que no parte. Con
   `repeat(4,1fr)` el mínimo automático de la pista crecía hasta ese ancho y las
   4 columnas dejaban de ser iguales (210/198/198/198 px a 1101px); con importes
   de 7 cifras la fila se salía 125px y la página ganaba 107px de scroll.
   `minmax(0,1fr)` (ya aplicado) fija las pistas y esto deja que el número parta. */
.metric,.metric>div{min-width:0}
.metric-value{overflow-wrap:break-word}
.metric-label,.metric-detail{overflow-wrap:break-word}

/* — 3. Las celdas de cuadrícula pueden encoger —
   Un hijo de grid/flex tiene `min-width:auto` = no baja de su min-content, que
   es lo que empuja la cuadrícula fuera de su caja. Se libera en las que
   contienen texto largo (direcciones, correos, importes). */
.grid-2>*,.occupancy>*,.timeline-item>*,.agent-card>*,
.room-grid>*,.department-grid>*,.marketing-roadmap>*,
.summary-line>*,.relation-row>*,.document-row>*,.profile-facts>*{min-width:0}
.relation-row strong,.relation-row small,.document-row strong,.document-row small,
.profile-facts strong,.summary-line strong{overflow-wrap:break-word}

/* — 4. El buscador de disponibilidad cabe en su caja —
   `<input>`/`<select>` traen un ancho intrínseco propio (~177px un texto) que
   `min-width:auto` respeta: las 5 columnas del formulario se salían 13px a
   1200px y 35px a 1101px. Con `min-width:0` los campos ceden y reparten. */
.availability-form>*{min-width:0}
.availability-form input,.availability-form select{width:100%}

/* — 5. Un desplegable largo se corta con puntos suspensivos, no a hachazos —
   En «Gastos por inquilino» el selector de piso («PIS-003 · Alameda …») medía
   23px más que su caja de 330px y el texto quedaba cortado a media letra. */
select.filter-input{text-overflow:ellipsis}

/* — 6. Una tabla que NO se convierte en cards sigue pudiendo desplazarse —
   Por debajo de 1080px `.table-wrap` pasaba a `overflow:visible`, algo que solo
   es correcto cuando `mobileCards()` ha convertido la tabla en fichas. Si una
   tabla se queda sin la clase `.m-cards` (config `mobile` ausente o vacía), sus
   760px de `min-width` quedaban RECORTADOS por el `overflow:hidden` de
   `.table-card`, sin barra con la que llegar a las columnas de la derecha.
   Ahora el valor por defecto vuelve a ser `auto` y solo las tablas realmente
   convertidas en cards liberan el desbordamiento. */
@media(max-width:1080px){
  .table-wrap{overflow:auto}
  .table-wrap:has(.m-cards){overflow:visible}
}

/* — 7. Ninguna imagen desborda su contenedor —
   El logotipo del menú son 184px fijos dentro de una caja de 185px: 1px de
   holgura. Cualquier cambio de ancho del panel lo sacaba fuera. */
img{max-width:100%;height:auto}

/* — 8. Las cabeceras reparten en varias líneas antes que apretar el texto —
   `.page-head`/`.head-actions` eran flex sin `wrap`: con 4 acciones (Cobros:
   mes + Descargar + Conceptos + Generar) los botones se estrujaban y partían
   sus etiquetas por dentro en portátiles. */
.page-bar,.head-actions,.table-toolbar,.calendar-link-actions{flex-wrap:wrap}
.page-bar>h1{min-width:0;overflow-wrap:break-word}

/* — 9. Red de seguridad: el documento nunca hace scroll lateral —
   `clip` (y no `hidden`) no crea contenedor de desplazamiento, así que no rompe
   `position:sticky` de la topbar ni de las cabeceras de tabla. Es el último
   cinturón: los desbordes reales se corrigen arriba, en su origen.
   DECISIÓN (estudio de Homming, HANDOFF §0.2, 2026-09-24): se QUEDA, pero ya no puede esconder nada
   sin que se sepa. Es el `overflow-x:hidden` con el que Homming tapaba desbordes que nadie medía; aquí
   el detector (web/desborde.html) la quita en cada medición y mira por debajo, página y cajas. Para
   quien trabaja, un desborde nuevo se ve recortado un momento en vez de mover toda la pantalla; para
   quien revisa, el detector lo canta. Si algún día el detector deja de pasarse, quitar esta línea. */
@supports (overflow:clip){html{overflow-x:clip}}

/* ══════════════════════════════════════════════════════════════════════════
   AUDITORÍA DEL MENÚ LATERAL (2026-07-31) · de 23 entradas a 11
   Piezas nuevas de navegación. El razonamiento y las fuentes están en
   estudio-intuitividad/2026-07-auditoria-menu-lateral.md; aquí solo el CSS.
   ══════════════════════════════════════════════════════════════════════════ */

/* — 1. La barra cabe entera sin scroll —
   El menú vive dentro de `.sidebar nav`, que es un contenedor con scroll propio:
   lo que no entra desaparece SIN avisar (ni barra visible ni sombra). Con 11
   entradas + 4 separadores hay que apurar unos pocos píxeles para que a 1440×900
   —el portátil del equipo— no quede nada por debajo del pliegue. El objetivo táctil
   se queda en 40px de alto (WCAG 2.5.8 pide ≥24px; en móvil se devuelve a 44px).
   (2026-09-24: con esto solo cabía a ≥893 px de alto. Las pantallas más bajas
   compactan el menú por ALTURA: bloque «El menú cabe por altura», al final.) */
.nav-link{padding:10px 12px}
.nav-section{padding:15px 12px 6px}
.sidebar-logo{padding-bottom:24px}
@media(max-width:760px){.nav-link{padding:13px 12px}}

/* — 2. Pestañas de sección —
   Rutas hermanas de la misma tarea (Pisos · Habitaciones · Como lo ve el cliente).
   Visibles al llegar: no hay que recordar que existen, que es justo lo que falla
   con un acordeón. Se desplazan en horizontal solo ellas si no caben. */
/* Las pestañas SALTAN DE LÍNEA, nunca se desplazan (estudio de Homming, HANDOFF §0.3). Antes llevaban
   overflow-x:auto con la barra oculta: el mismo mecanismo que escondía la pestaña «Incidencias» de la
   ficha de un piso en Homming por debajo de 1280 px. Aquí ya pasaba a 390 px (4-5 px escondidos en
   Pisos, 45 px en «El mes») y, con 6 pestañas, a 1024 px. Además, tests/test_pestanas.py falla si un
   grupo pasa de 5. */
.page-tabs{display:flex;flex-wrap:wrap;width:max-content;max-width:100%;gap:4px;margin:-8px 0 20px;padding:4px;background:var(--gris-fondo);border-radius:var(--radio-m)}
.page-tabs a{flex:none;display:inline-flex;align-items:center;padding:8px 14px;border-radius:var(--radio-s);text-decoration:none;color:var(--texto-secundario);font-size:var(--texto-13);font-weight:600;white-space:nowrap;transition:background var(--dur-1) var(--ease-out),color var(--dur-1) var(--ease-out)}
.page-tabs a:hover{color:var(--ink)}
.page-tabs a.on{background:var(--blanco);color:var(--teal-dark);font-weight:700;box-shadow:0 1px 3px rgba(28,67,61,.10)}

/* — 3. Conmutador Mapa | Panel dentro de la cabecera —
   Mismo gesto que el conmutador flotante del mapa, para que las dos caras del
   inicio se sientan una sola pantalla y el viaje deje de ser de ida. */
.view-switch{display:inline-flex;gap:2px;padding:3px;background:var(--gris-fondo);border-radius:var(--radio-m)}
.view-switch>*{display:inline-flex;align-items:center;gap:6px;padding:7px 12px;border-radius:var(--radio-s);font-size:var(--texto-13);font-weight:600;color:var(--texto-secundario);text-decoration:none}
.view-switch>.on{background:var(--blanco);color:var(--teal-dark);font-weight:700;box-shadow:0 1px 3px rgba(28,67,61,.10)}
.view-switch a:hover{color:var(--ink)}

/* — 4. Menú del avatar —
   Casa de lo técnico e informativo (registros, colas internas, ayuda) y de «Salir».
   Reutiliza el desplegable de «+ Añadir» del panel: mismo componente, misma física. */
.user-box{position:relative}
.user-menu{border:0;background:none;padding:6px 8px;border-radius:var(--radio-m);cursor:pointer;font:inherit;text-align:left;transition:background var(--dur-1) var(--ease-out)}
.user-menu:hover{background:var(--gris-fondo)}
.user-chev{color:var(--muted);flex:none}
.user-menu-list{position:absolute;top:calc(100% + 8px);right:0;min-width:224px;background:var(--color-superficie);border:1px solid var(--color-borde);border-radius:var(--radio-m);box-shadow:var(--sombra-2);padding:6px;z-index:40;display:grid;gap:2px;transform-origin:top right;animation:add-menu-in var(--dur-2) var(--ease-out)}
.user-menu-list[hidden]{display:none}
.user-menu-list a,.user-menu-list button{display:flex;align-items:center;gap:10px;width:100%;text-align:left;border:0;background:none;border-radius:var(--radio-s);padding:10px;font:inherit;font-size:var(--texto-13);font-weight:600;color:var(--texto-principal);text-decoration:none;cursor:pointer;transition:background var(--dur-1) var(--ease-out),color var(--dur-1) var(--ease-out)}
.user-menu-list a:hover,.user-menu-list a:focus-visible,.user-menu-list button:hover,.user-menu-list button:focus-visible{background:var(--color-accion-suave);color:var(--color-accion-texto);outline:none}
.user-menu-list svg{color:var(--texto-secundario);flex:none}
.user-menu-list a:hover svg,.user-menu-list button:hover svg{color:var(--color-accion-texto)}
.user-menu-list #logout{border-top:1px solid var(--line);border-radius:0 0 var(--radio-s) var(--radio-s);margin-top:4px;padding-top:12px;color:var(--texto-secundario)}

/* ══════════════════════════════════════════════════════════════════════════
   AUDITORÍA VISUAL EN NAVEGADOR (2026-08-03) · el acabado
   Todo lo de aquí sale de medir el DOM, no de mirarlo. El razonamiento está en
   estudio-intuitividad/2026-08-auditoria-visual-navegador.md.
   ══════════════════════════════════════════════════════════════════════════ */

/* A1 · EL SALTO DE 11 PX. Las pantallas largas tienen barra de scroll y las cortas no, así que
   al ir de Pisos (borde derecho 1383) a Propietarios (1394) saltaba TODA la interfaz: titular,
   tarjetas y botones. Reservar el hueco siempre lo deja quieto. Va también en los diálogos, que
   scrollean por dentro y tenían el mismo baile entre una ficha larga y una corta. */
html{scrollbar-gutter:stable}
dialog{scrollbar-gutter:stable}

/* A2 · DOS PÍXELES. Los controles nativos (select, date, time) tienen una caja intrínseca distinta
   a la de un input de texto: con el mismo padding salían 46 px contra 44. En una rejilla de dos
   columnas sus bordes inferiores no coincidían. Se fija la altura, que es lo único que iguala
   cajas de naturaleza distinta; el padding vertical pasa a 0 para que el texto siga centrado. */
input:not([type=checkbox]):not([type=radio]):not([type=file]),select,
.dialog-grid input,.filter-input{height:44px;padding-top:0;padding-bottom:0}
textarea{padding-top:11px;padding-bottom:11px}

/* A3 · EL HUECO DE LA REJILLA IMPAR. .profile-facts es de dos columnas: con cinco datos, el quinto
   se quedaba solo y dejaba un agujero a su derecha. Si es el último y hace número impar, ocupa la
   fila entera — un dato ancho se lee bien, un agujero no se lee de ninguna manera. */
.profile-facts>div:last-child:nth-child(odd){grid-column:1/-1}

/* A4 · LA VERTICAL DE LAS FILAS. En la ficha del piso, la habitación libre lleva un botón más y,
   como la fila empuja desde la derecha, ese botón movía 87 px el chip y el botón de SU fila
   respecto a las otras tres. Con la acción a ancho fijo, la columna es una columna de verdad.
   Mismo criterio que .mes-row en las vistas mensuales, donde los 26 chips caen en la misma x. */
.dialog-content .relation-row,#dialog-content .relation-row{gap:12px}
#dialog-content .relation-row>:first-child{flex:1 1 auto;min-width:0}
#dialog-content .relation-row>.status{flex:0 0 auto;margin-left:auto}
#dialog-content .relation-row>div:last-child:not(:first-child){flex:0 0 210px;display:flex;
  justify-content:flex-end;align-items:center;gap:6px}
/* Y dentro de esa columna, el chip anclado a la IZQUIERDA y los botones a la derecha. Con solo el
   ancho fijo, la fila de cuatro seguía empujando el chip 79 px porque `flex-end` reparte desde la
   derecha: el botón de más movía al chip. Con dos anclas opuestas, el chip cae siempre en la misma
   x tenga la fila un botón o tres. */
#dialog-content .relation-row>div:last-child:not(:first-child)>.status{margin-right:auto}

/* A5 · EL PIE QUE SE COME EL CONTENIDO. La barra de acciones es sticky con fondo al 86 %: el
   contenido seguía pasando por debajo y se veía a través, medio borroso — parecía que allí había
   algo pulsable y no lo había. Fondo opaco, y hueco al final del cuerpo para que el último bloque
   tenga sitio propio en vez de esconderse. */
#dialog-content{padding-bottom:0}
#dialog-content .dialog-actions{background:var(--blanco)}
#dialog-content>*:nth-last-child(2){margin-bottom:8px}

/* A6 · DOS EJES EN LA MISMA IDEA. El mensaje de vacío estaba centrado y el botón que va justo
   debajo, a la izquierda. Son la misma frase: «no hay nada / créalo». Un solo eje. */
.empty.compact+.button{display:flex;margin-left:auto;margin-right:auto}

/* A7 · RETIRADO: NO ERA UN DEFECTO. Mi sonda marcó 8 px de desborde en .inventory-summary y en los
   .move-group del panel. Medido de cerca: sus filas llevan `margin:0 -8px` a propósito —un sangrado
   para que el fondo del hover cubra algo más que el texto— y caben de sobra dentro de los 24 px de
   relleno de la tarjeta (fila 303→761, tarjeta 286→778). No se corta nada.
   Es el MISMO error que cometí con el pie de las fichas: medir una caja deliberadamente más ancha
   que su carril de contenido y llamarlo descuadre. Regla aprendida: `scrollWidth > clientWidth`
   señala margen negativo tan a menudo como desborde real; hay que ir a mirar antes de arreglar. */

/* ===============================================================================================
   D1 · LA FICHA ES UNA PANTALLA (auditoría visual 2026-08 · bloque DESPUÉS)
   Las cuatro fichas 360º dejan de ser <dialog>. Un diálogo sirve para una TAREA que empieza y
   acaba; un objeto que se consulta necesita sitio propio, ancho y URL. Lo que aquí se define es el
   marco compartido por las cuatro: si comparten esqueleto, están alineadas entre sí y no solo cada
   una consigo misma — que es el descuadre que de verdad se nota al pasar de una a otra.
   =============================================================================================== */

/* Vuelta atrás: encima del título, no dentro del contenido. Es navegación, no contenido. */
a.card-back{display:inline-flex;align-items:center;gap:6px;text-decoration:none;color:var(--muted);
  font-size:var(--texto-12);font-weight:600;margin:0 0 12px;padding:6px 10px 6px 6px;
  border-radius:var(--radio-pill);min-height:32px}
a.card-back:hover{background:var(--gris-fondo);color:var(--ink);text-decoration:none}

/* La cabecera de una ficha lleva antetítulo + nombre + una línea de identidad. Sigue siendo una
   .page-bar (mismo borde inferior, mismo carril que las listas: cambiar de lista a ficha no mueve
   nada de sitio), solo que su lado izquierdo es un bloque de tres líneas en vez de un <h1> suelto. */
.page-bar.ficha-bar{align-items:flex-end}
.ficha-title{min-width:0;flex:1 1 auto;display:grid;gap:2px}
.ficha-title .eyebrow{font-size:var(--texto-11);letter-spacing:.15em}
.ficha-title h1{overflow-wrap:break-word}
.ficha-sub{margin:2px 0 0;color:var(--muted);font-size:var(--texto-13);overflow-wrap:break-word}

/* Dos columnas: lo que cambia (quién vive, qué se debe, qué se rompió) y lo que identifica (datos,
   documentos, historial). La proporción 1.62 es la que deja la columna estrecha justo por encima
   del ancho de una .profile-facts de dos celdas sin que se estrechen. */
.ficha{display:grid;grid-template-columns:minmax(0,1.62fr) minmax(0,1fr);gap:16px;align-items:start}
.ficha-col{display:grid;gap:16px;min-width:0}
.ficha-card{padding:20px 23px}
.ficha-card .card-head{margin-bottom:6px}
.ficha-card .profile-facts{margin:12px 0 0}
.ficha-card .relation-row:first-of-type{border-top:0}
.ficha-econ{margin:12px 0 0}
/* La respuesta a «¿está libre?» va antes que cualquier tarjeta y se lee de un vistazo. */
.ficha-ahora{margin:0;padding:13px 16px;background:var(--blanco);border:1px solid var(--line);
  border-left:3px solid var(--teal);border-radius:var(--radius);font-size:var(--texto-13)}
.ficha-veredicto{margin:12px 0 0}
.ficha-card .doc-checklist{margin-top:10px}
.ficha-card .upload-row{margin-top:14px}
.ficha-card .entity-history{margin-top:0;border-top:0;padding-top:0}

/* Las mismas dos anclas opuestas que arreglaron A4, ahora también fuera del diálogo: la columna de
   acción a ancho fijo y el chip pegado a su izquierda. Sin esto, una fila con «+ Inquilino» dejaría
   su chip 80 px a la izquierda del de la fila de al lado. */
.ficha .relation-row{gap:12px}
.ficha .relation-row>:first-child{flex:1 1 auto;min-width:0}
.ficha .relation-row>.status{flex:0 0 auto;margin-left:auto}
.ficha .relation-row>div:last-child:not(:first-child){flex:0 0 190px;display:flex;
  justify-content:flex-end;align-items:center;gap:6px}
.ficha .relation-row>div:last-child:not(:first-child)>.status{margin-right:auto}

/* D4 · El botón «···». Cuadrado, del tamaño de los demás de la barra, sin texto que compita. */
.more-button{padding-left:10px;padding-right:10px}
.more-button svg{display:block}

@media(max-width:1080px){
  .ficha{grid-template-columns:minmax(0,1fr)}
  /* En una sola columna el lateral va DESPUÉS: primero lo que se hace, luego lo que se consulta. */
  .ficha-side{order:2}
}
@media(max-width:760px){
  .page-bar.ficha-bar{align-items:flex-start}
  /* En móvil los botones caben en dos filas. Repartidos desde la derecha dejaban tres bordes
     izquierdos distintos —el título en 18, la primera fila en 60, la segunda en 90—; alineados
     desde la izquierda, las dos filas y el título comparten el mismo eje. */
  .page-bar.ficha-bar .head-actions{justify-content:flex-start;margin-left:0}
  .ficha .relation-row{flex-wrap:wrap}
  .ficha .relation-row>div:last-child:not(:first-child){flex:1 1 100%;justify-content:flex-start}
  .ficha .relation-row>div:last-child:not(:first-child)>.status{margin-right:0}
}

/* El vacío de una sección se lee en el MISMO carril que su contenido. Un texto centrado dentro de
   una tarjeta alineada a la izquierda mete dos ejes en la misma caja — el mismo defecto que A6, en
   otro sitio. Aquí además el vacío es una frase, no una pantalla: no necesita 45 px de aire. */
.ficha-card .empty,.ficha-card .empty.compact{padding:14px 0 4px;text-align:left}
.ficha-card .empty.compact+.button{margin-left:0}
.file-name{font-size:var(--texto-12);color:var(--muted);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto}

/* El historial y el buzón se inyectan después de pintar (fillHistory/fillInbox). Cuando traen algo,
   son una tarjeta más de la columna; cuando no, su hueco vacío no debe abrir un espacio fantasma
   en la rejilla. */
.ficha-side .entity-history{margin-top:0;border-top:0;padding:16px 23px;background:var(--blanco);
  border:1px solid var(--line);border-radius:var(--radius);box-shadow:0 3px 15px rgba(28,67,61,.025)}
.ficha-col>div:empty{display:none}
/* La subida de documentos, en dos filas con sentido: primero QUÉ es, luego CUÁL y el envío. */
.ficha-card .upload-row>select{flex:1 1 100%}
.ficha-card .upload-row>.file-cta,.ficha-card .upload-row>.button:last-child{flex:0 0 auto}
.ficha-card .upload-row>.button:last-child{margin-left:auto}

/* D2 · LA HISTORIA DE LA FICHA. Un punto por hito, con su icono dentro. Un solo eje de color: lo
   que pide atención (avería abierta) y el dinero. Con un color por tipo la línea se convierte en un
   semáforo roto y deja de leerse de un vistazo — Healey (1996): dos atributos preatentivos a la vez
   como mucho, aquí el color y la forma del icono ya son dos. */
.ficha-card .timeline-item{grid-template-columns:26px minmax(0,1fr) auto;padding:10px 0}
.ficha-card .timeline-dot{width:26px;height:26px;border-radius:50%;box-shadow:none;
  background:var(--gris-fondo);color:var(--texto-secundario);display:grid;place-items:center}
.ficha-card .timeline-dot.tl-alerta{background:var(--aviso-fondo);color:var(--aviso-texto)}
.ficha-card .timeline-dot.tl-dinero{background:var(--ok-fondo);color:var(--ok-texto)}
.ficha-card .timeline-item small{color:var(--muted);font-size:var(--texto-11)}
a.timeline-link{display:block;text-decoration:none;color:inherit;border-radius:var(--radio-m);
  margin:0 -8px;padding:0 8px}
a.timeline-link:hover{background:var(--gris-fondo);text-decoration:none}
a.timeline-link .timeline-item{border-bottom-color:transparent}
.econ-line{display:flex;align-items:flex-start;gap:6px;color:var(--muted)}
.econ-line svg{flex:none;margin-top:1px}

/* ===============================================================================================
   D3 · UN SOLO CÓDIGO DE COLOR (auditoría visual 2026-08 · bloque DESPUÉS)

   La auditoría había escrito «Ocupada = ingreso = verde; Libre = coste = ámbar». Al ir a aplicarlo
   y MEDIR los dos lenguajes en la misma página, el diagnóstico resultó ser otro — y la propuesta,
   equivocada. Lo medido:

     Disponible / Libre   chip rgb(230,244,235)   calendario rgb(225,244,229)   ✔ el mismo verde
     Reservada (pagada)   chip rgb(251,241,215)   calendario rgb(236,168,168)   ✘ ámbar vs rosa
     Ocupada              chip rgb(234,240,251)   —                             ✘ ese azul, en el
                                                                                  calendario, es
                                                                                  «Plataforma»

   Dos conclusiones. La primera: **el verde no hay que tocarlo**, ya coincide en las dos pantallas.
   La segunda, la de fondo: el calendario viene del Excel del equipo y su color no responde a «¿esto
   da dinero?» sino a **«¿puedo vender esto?»** — verde sí, rosa no, ámbar aún no se sabe. Es la
   pregunta correcta para un calendario y la tienen interiorizada desde antes del CRM. Cambiarla por
   la mía habría sido imponerle al negocio una lógica peor y además nueva.

   Así que la unificación va al revés de lo que yo había propuesto: **mandan los chips a hablar el
   idioma del calendario**, no el calendario a hablar el mío.

     · «Ocupada» sale del azul. Ese azul ya significaba «reserva de plataforma»: quien aprendió el
       calendario leía un chip azul como «vino de HousingAnywhere».
     · «Reservada» sale del ámbar. El ámbar es la familia de «pendiente / bloqueada» —una
       advertencia— y «reservada (pagada) y verificada en banco» es justo el estado BUENO. El chip
       decía lo contrario de la verdad.

   Las dos pasan a la familia de «ocupado» del calendario: la habitación está tomada, no se vende.
   El azul queda libre para lo que el calendario dice que es: el canal.
   =============================================================================================== */
.status.ocupada,.status.reservada{background:var(--cal-ocupada-fondo);color:var(--cal-ocupada-texto)}
/* La fila de filtros bajada desde la tabla: mismo carril que el título, no un escalón más adentro. */
.filter-row.hoisted{margin:0 0 16px}
.filter-row.hoisted .filter-input{max-width:340px;flex:1 1 260px}

/* El selector de mes medía 40 px (`--boton-alto`, un token que miente: el .button real sale a 44 por
   su padding) y quedaba 2 px más bajo y 2 más alto que los botones de su misma fila, flotando en el
   centro. Es el mismo defecto que A2 arregló en los inputs, en el único control que se quedó fuera. */
.month-field .month-face{height:auto;min-height:44px}

/* §10.2 · EL CAMINO DE LA FIANZA. Cinco pasos en una línea, con el actual encendido y los pasados
   apagados. No es una barra de progreso decorativa: contesta «¿y esta en qué punto está?», que era
   justo lo que la pantalla obligaba a deducir de tres chips sueltos. */
.pasos{display:flex;flex-wrap:wrap;gap:4px;margin-top:7px}
.paso{font-size:var(--texto-11);font-weight:600;color:var(--texto-tenue);background:var(--gris-fondo);
  border-radius:var(--radio-pill);padding:3px 9px;white-space:nowrap}
.paso.hecho{color:var(--ok-texto);background:var(--ok-fondo)}
.paso.ahora{color:var(--blanco);background:var(--teal)}
small.listo{color:var(--ok-texto);font-weight:600}

/* ===============================================================================================
   §9 · EL PANEL DE CAMPO. Rosa abre esto en el móvil, de pie en un portal, con una mano. Todo lo de
   aquí está dimensionado para el pulgar y ordenado por la pregunta que trae: dónde primero (hay que
   llegar), qué después, y un solo botón. En escritorio se convierte en rejilla porque la oficina
   también entra a mirarlo, pero el orden de lectura no cambia.
   =============================================================================================== */
.campo-bloque{margin:0 0 26px}
.campo-bloque h2{font-size:var(--texto-16);margin:0 0 12px;display:flex;align-items:center;gap:9px}
.campo-num{font-size:var(--texto-11);font-weight:700;background:var(--gris-fondo);color:var(--texto-secundario);
  border-radius:var(--radio-pill);padding:2px 9px}
.campo-bloque.campo-alerta h2{color:var(--error-texto)}
.campo-bloque.campo-alerta .campo-num{background:var(--error-fondo);color:var(--error-texto)}
.campo-card{background:var(--blanco);border:1px solid var(--line);border-radius:var(--radius);
  padding:16px 18px;margin-bottom:10px;box-shadow:0 3px 15px rgba(28,67,61,.025)}
.campo-donde{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:var(--texto-12);
  font-weight:600;color:var(--texto-secundario)}
.campo-donde svg{flex:none;color:var(--teal)}
.campo-donde small{width:100%;color:var(--muted);font-weight:400;margin-top:2px}
.campo-card h3{font-size:var(--texto-16);margin:8px 0 0;letter-spacing:-.01em}
.campo-nota{margin:6px 0 0;color:var(--muted);font-size:var(--texto-13)}
.campo-pie{display:flex;align-items:center;gap:12px;margin-top:14px}
.campo-cuando{font-size:var(--texto-12);color:var(--muted);white-space:nowrap}
/* El botón ocupa lo que sobra: en el móvil es la única diana y tiene que ser grande de verdad. */
.campo-pie .button{flex:1 1 auto;min-height:48px;justify-content:center}
@media(min-width:900px){
  .campo-bloque>.campo-card{display:inline-block;vertical-align:top}
  .campo-bloque{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:10px}
  .campo-bloque h2{grid-column:1/-1;margin-bottom:0}
  .campo-bloque .empty{grid-column:1/-1}
  .campo-card{margin-bottom:0}
}
/* En el móvil, los dos botones del panel de campo son la pantalla: uno debajo de otro y a todo lo
   ancho. Repartidos desde la derecha dejaban tres bordes izquierdos distintos, y además una diana
   más pequeña justo donde solo hay un pulgar. */
@media(max-width:760px){
  .page-bar-campo .head-actions{width:100%;flex-direction:column;align-items:stretch;margin-left:0}
  .page-bar-campo .head-actions .button{width:100%;min-height:48px;justify-content:center}
}
/* Y el vacío se lee en el mismo eje que su título, como en las fichas. */
.campo-bloque .empty,.campo-bloque .empty.compact{text-align:left;padding:6px 0 2px}

/* §2.2 · Con la acción nueva («Dice que pagó») la celda de acciones pasa a tener tres botones y
   `flex-wrap` los repartía dejando DOS bordes izquierdos distintos —1166 y 1240— según cuántos
   cupieran en cada fila. Una columna de acciones tiene que ser una columna: todos los botones
   arrancan en la misma x y el principal manda arriba. Mismo criterio que A4 en las fichas. */
td.row-actions{align-items:flex-start;align-content:flex-start;row-gap:5px}
td.row-actions>*{margin-right:auto}
/* En una fila ya cobrada, el sitio del botón principal lo ocupa la fecha del cobro. Compartiendo
   línea con «Desglose» lo empujaba a 1246 mientras en el resto de filas caía en 1166: una sola fila
   distinta de las 26. La fecha ocupa su línea, como el botón al que sustituye. */
td.row-actions>small{flex:0 0 100%;padding-top:6px}
/* El importe del mes es lo que se busca en esta lista: cifra tabular y a la derecha del chip. */
.liq-total{font-variant-numeric:tabular-nums;white-space:nowrap}

/* ===============================================================================================
   AUDITORÍA VISUAL DEL BLOQUE DESPUÉS (2026-08-04) · lo que solo se ve a 375 px
   =============================================================================================== */

@media(max-width:760px){
  /* Los botones de cabecera se repartían desde la derecha y dejaban tres bordes izquierdos
     distintos —en Cobros: 317, 58 y 206— mientras el título estaba en 18. Alineados desde la
     izquierda, todas las filas comparten el eje del título. Las fichas y el panel de campo ya lo
     hacían por su cuenta; esto lo extiende a las 23 pantallas. */
  .page-bar .head-actions{justify-content:flex-start;margin-left:0}

  /* Una fila de dos columnas no cabe en 375 px. En Fianzas el botón se salía 43 px de su fila, y
     en los documentos del propietario el chip «Verificado» se comprimía de 61 a 52 px y se cortaba
     la palabra. La regla existía dentro de `.ficha`; el defecto vive en todas las filas iguales. */
  .relation-row,.document-row{flex-wrap:wrap;row-gap:8px}
  .relation-row>:first-child{flex:1 1 100%;min-width:0}
  .relation-row>:last-child:not(:first-child){flex:1 1 100%;justify-content:flex-start;margin-left:0}
  .document-row>.status,.document-row>.doc-actions{margin-left:0}
  /* Un chip nunca se encoge: es una palabra, y media palabra no dice nada. */
  .status{flex:none;max-width:100%}
}
@media(max-width:760px){
  /* En 165 px de tarjeta, un importe de cinco cifras no cabe a 26 px. Antes se partía; ahora entra. */
  .metric-value{font-size:var(--texto-20)}
}

/* ===============================================================================================
   AUDITORÍA 06 (2026-09-23, skills de Emil Kowalski) · rediseno-visual/06-auditoria-emil-2026-09.md
   =============================================================================================== */

/* — F1 · A2 · Un solo tamaño de botón. `.button` no fijaba letra y heredaba 16 px del documento:
   en la misma barra convivían botones de 29 px y de 46 px («Añadir» junto a «Actualizar»). Ahora
   todo botón mide lo mismo que un campo, y el borde transparente iguala a los que no tienen borde
   con el `ghost` (antes «Editar» medía 31 px y «Ver ficha» 29 px en la misma fila). — */
.button{font-size:var(--texto-13);line-height:1.2;min-height:var(--boton-alto);padding:0 16px;border:1px solid transparent}
.button.ghost{border-color:var(--line)}
.button.small{font-size:var(--texto-12);min-height:var(--boton-alto-sm);padding:0 11px}
.button.wide{font-size:var(--texto-14);min-height:48px;padding:0 17px}

/* — F1 · A1 · Fecha con cara española (ver enhanceDateInput en app.js). El campo nativo sigue en su
   sitio —con su borde, su foco y su estado de error—; solo se vuelve invisible SU texto, y encima se
   pinta «1 oct 2026». Nada de posicionar a mano la altura: la da el propio input. — */
.date-field{position:relative;display:block;min-width:0}
.date-field>input{width:100%;color:transparent}
.date-field>input::-webkit-datetime-edit{opacity:0}
.date-field>input::-webkit-calendar-picker-indicator{opacity:0;cursor:pointer}
.date-face{position:absolute;inset:0;display:flex;align-items:center;gap:8px;padding:0 14px;pointer-events:none;color:var(--texto-principal);font-size:var(--texto-13);font-weight:500;white-space:nowrap;overflow:hidden}
.date-face svg{color:var(--texto-secundario);flex:none}
.date-face.is-empty{color:var(--texto-tenue)}
.date-field>input:disabled+.date-face,.date-field:has(input:disabled) .date-face{opacity:.55}

/* — F2 · B1 · Toast. `transition:.25s` animaba TODAS las propiedades; y el desplazamiento de 120 px
   iba a mano. Ahora solo transform y opacidad, sale por donde entró (su propia altura + el margen)
   y se va más rápido de lo que llega: la respuesta del sistema no se hace esperar. — */
.toast{transform:translateY(calc(100% + 22px));transition:transform 160ms var(--ease-out),opacity 160ms var(--ease-out)}
.toast.show{transition-duration:220ms}
.toast:not(.show){pointer-events:none}

/* — F2 · B2 · Diálogo. Se abre decenas de veces al día (cada «Editar»): 0,46 s era el doble del
   presupuesto de interfaz (<300 ms) y al cerrar desaparecía de golpe. Con transiciones (no keyframes)
   la entrada y la salida se pueden interrumpir, y @starting-style da la entrada sin JS. Donde el
   navegador no lo soporta, el diálogo simplemente aparece: nunca se queda a medias. — */
.dialog,.dialog::backdrop{animation:none}
.dialog{opacity:0;transform:translateY(8px) scale(.98);transition:opacity 150ms var(--ease-out),transform 150ms var(--ease-out),overlay 150ms allow-discrete,display 150ms allow-discrete}
.dialog[open]{opacity:1;transform:none;transition-duration:220ms}
.dialog::backdrop{opacity:0;transition:opacity 150ms var(--ease-out),overlay 150ms allow-discrete,display 150ms allow-discrete}
.dialog[open]::backdrop{opacity:1;transition-duration:220ms}
@starting-style{
  .dialog[open]{opacity:0;transform:translateY(8px) scale(.98)}
  .dialog[open]::backdrop{opacity:0}
}

/* — F2 · B3 · En pantallas táctiles no hay «pasar por encima»: un toque dejaba la tarjeta levantada,
   el donut agrandado o la flecha desplazada hasta tocar otra cosa. Los cambios de COLOR se quedan
   (confirman el toque); los de POSICIÓN y ESCALA solo existen con ratón. — */
@media (hover:none){
  .metric:hover,.room-card:hover,.button.primary:hover,a.donut:hover,.unit-chip:hover,.booking-bar:hover,
  .pin-wrap:hover .pin,.button.wide:hover span,.metric-link:hover .metric-go,a.summary-line:hover .go{transform:none}
  .metric:hover,.room-card:hover{box-shadow:var(--sombra-1)}
}

/* — F2 · B5 · Menú lateral del móvil con curva de cajón (arranca decidido, frena suave). — */
@media(max-width:760px){
  .sidebar{transition:transform var(--dur-3) var(--ease-drawer)}
}

/* — F2 · B6 · «Menos movimiento» no es «cero movimiento». La regla general dejaba todo en 0,001 ms,
   también los fundidos que explican qué ha cambiado. Ahora se anulan las animaciones (keyframes) y
   cualquier transición de posición o escala; los fundidos de opacidad y color se conservan. — */
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-property:opacity,color,background-color,border-color,box-shadow!important}
  .dialog,.dialog[open]{transform:none}
  @starting-style{.dialog[open]{transform:none}}
  .toast{transform:none}
}

/* — F3 · A3 · Métricas sin huérfanas. La rejilla era de 4 columnas fijas: Inicio tiene 5 tarjetas
   (la 5.ª quedaba sola en otra fila) y Cobros 3 (dejaba un hueco a la derecha). Ahora las columnas
   salen del número de tarjetas y del ancho: 5 en una fila a partir de ~1250 px; debajo, se reparten.
   En móvil (2 columnas) la última impar ocupa la fila entera en vez de quedarse media. — */
@media(min-width:761px){
  .metrics{grid-template-columns:repeat(auto-fit,minmax(170px,1fr))}
}
@media(max-width:760px){
  .metrics>:last-child:nth-child(odd){grid-column:1/-1}
}

/* — F3 · A4 · Cabecera de lista en UNA fila (título · buscador · recuento · botón). El buscador
   tenía `width:100%` y empujaba el botón principal a una segunda fila, aislado a la derecha. Ahora
   tiene un ancho de base que cede antes de que nada salte de línea. — */
@media(min-width:761px){
  .page-bar .head-actions>.filter-input{flex:0 1 240px;width:240px;min-width:150px}
}

/* — F3 · A6 · Formulario de alta. — */
/* (a) El aviso «ya conocemos a esta persona» se monta tras el email como un hueco vacío: ocupaba la
   celda de la derecha y dejaba «Email» solo en su fila. Ocupa la fila entera y, vacío, no existe. */
.dialog-grid>#tenant-known{grid-column:1/-1}
.dialog-grid>#tenant-known:empty{display:none}
/* (b) Las secciones plegables parecían barras desactivadas (gris sobre gris, triángulo de texto).
   Ahora se leen como lo que son, algo que se abre: texto en color de acción y un chevron de trazo
   —el mismo idioma que los iconos Lucide— que gira al abrir. */
.form-advanced{background:var(--color-superficie)}
.form-advanced summary{display:flex;align-items:center;gap:10px;list-style:none;color:var(--color-accion-texto);font-size:var(--texto-13)}
.form-advanced summary::-webkit-details-marker{display:none}
.form-advanced summary::before{content:"";flex:none;width:6px;height:6px;margin:0 2px 0 1px;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(-45deg);transition:transform var(--dur-2) var(--ease-out)}
.form-advanced[open] summary::before{transform:rotate(45deg)}
.form-advanced summary:hover{color:var(--color-accion)}
/* (c) La × iba en posición absoluta sobre un cuerpo que hace scroll: al bajar, los campos pasaban
   por debajo de ella. Ahora ocupa su propia franja arriba y el cuerpo empieza debajo. */
.dialog-close{position:relative;z-index:2;flex:none;align-self:flex-end;right:auto;top:auto;margin:14px 16px -14px auto;display:grid;place-items:center}
#dialog-content{padding-top:0}
/* (d) Los importes llevan teclado numérico (inputmode) y no necesitan las flechitas de subir/bajar
   de 1 en 1 euro, que además se comían el final de la cifra. */
input[inputmode=decimal]{-moz-appearance:textfield;appearance:textfield}
input[inputmode=decimal]::-webkit-inner-spin-button,input[inputmode=decimal]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}

/* — F4 · A7 · Los chevrons y flechas son ahora iconos Lucide (antes glifos › ‹ ← → de la fuente, con
   otro grosor y otra altura). Se alinean como bloque para no heredar la línea de texto. — */
.summary-line .go,.metric-link .metric-go,.move-chev{display:inline-flex;align-items:center;vertical-align:middle}
.cal-month-switch .button svg,.calendar-year-switcher .button svg{flex:none}

/* — F4 · A5 · La fila entera abre la ficha: cursor de enlace y el nombre con aspecto de título (se
   subraya al pasar por la fila, que es lo que se va a abrir). Sin movimiento: es una lista que se
   recorre decenas de veces al día. — */
tr.row-link{cursor:pointer}
.row-title{color:inherit;text-decoration:none}
tr.row-link:hover .row-title,.row-title:focus-visible{color:var(--color-accion-texto);text-decoration:underline;text-underline-offset:3px}
/* A 375 px, con «Añadir» ya a tamaño normal, la barra de Inicio (Mapa|Panel · Añadir · Actualizar)
   se pasaba 11 px y «Actualizar» caía sola a otra fila. Un poco menos de relleno lateral y cabe. */
@media(max-width:760px){
  .head-actions .add-menu>.button{padding:0 12px}
  .view-switch>*{padding-left:10px;padding-right:10px}
}

/* ══════════════════════════════════════════════════════════════════════════
   AUDITORÍA 07 · al píxel, en producción (2026-09-23)
   Medido con el DOM en crm.habitaccion.com, pantalla a pantalla. El porqué de
   cada regla está en rediseno-visual/07-auditoria-pixel-2026-09.md.
   ══════════════════════════════════════════════════════════════════════════ */

/* P1 · EL TITULAR. `.page-bar h1` pedía var(--texto-22), un token que no existe: la declaración se
   descartaba y todos los titulares (y el nombre de cada ficha) heredaban 16 px, lo mismo que el título
   de una tarjeta. Sin jerarquía entre la pantalla y sus bloques. */
.page-bar h1{font-size:var(--texto-20)}

/* P2 · EL TITULAR Y LAS PESTAÑAS SALTABAN. La barra medía lo que su control más alto (nada, un botón de
   40, un buscador de 44, el año de 49) y al cambiar de pestaña el titular se movía entre y=114,8 y 135 y
   las pestañas 15 px. Todo control de la barra mide lo que un botón y la barra guarda ese alto vacía. */
.page-bar{min-height:calc(var(--boton-alto) + 15px)}
.page-bar .head-actions>input.filter-input:not([type=checkbox]):not([type=radio]),
.page-bar .head-actions>select{height:var(--boton-alto);font-size:var(--texto-13)}
.page-bar .head-actions>select.filter-input{width:auto;flex:0 1 auto;max-width:280px}
.page-bar .month-field .month-face{min-height:var(--boton-alto);height:var(--boton-alto)}
.page-bar .head-actions>.button.small{min-height:var(--boton-alto);font-size:var(--texto-13);padding:0 16px}
.page-bar .view-switch{height:var(--boton-alto);align-items:stretch}
.page-bar .view-switch>*{display:inline-flex;align-items:center}
.calendar-year-box{height:var(--boton-alto);padding:0 16px;display:flex;flex-direction:column;align-items:center;justify-content:center;font-size:var(--texto-16)}
.calendar-year-box span{font-size:var(--texto-11);margin-bottom:2px;letter-spacing:.12em}
/* En iPhone un campo por debajo de 16 px hace zoom al enfocarlo: en móvil el buscador conserva 16. */
@media(max-width:760px){.page-bar .head-actions>input.filter-input:not([type=checkbox]):not([type=radio]){font-size:16px}}

/* P3 · CARRILES INVISIBLES. El carril de las pestañas (Año/El mes, Pisos/Habitaciones…), el de Mapa/Panel
   y las columnas de Solicitudes eran --gris-fondo… el mismo gris que el fondo de la app: la pestaña activa
   flotaba sola y las columnas eran texto suelto con 12 px de sangría inexplicable. Un tono por debajo. */
.page-tabs,.page-bar .view-switch{background:color-mix(in srgb,var(--color-borde) 70%,var(--color-fondo))}
.kb-col{background:color-mix(in srgb,var(--color-borde) 45%,var(--color-fondo))}
/* Las descripciones de columna ocupan una o dos líneas: «Nada aquí» caía a dos alturas (y=341 y 356). */
.kb-col header p{min-height:calc(2 * 1.35em)}

/* P4 · MÉTRICAS. Con `space-between` la cifra se pegaba abajo, así que su altura dependía de cuántas líneas
   tuviera la etiqueta: 261, 277 y 293 en la misma fila. La cifra es lo que se compara: arranca a la misma y. */
.metric{justify-content:flex-start}
/* El chevron iba 19 px por encima del centro del icono (208 frente a 227): centrado con él (icono 35, chevron 18). */
.metric-link .metric-go{top:calc(var(--esp-5) + 8.5px)}
@media(max-width:760px){.metric-link .metric-go{top:24.5px}}
/* Una métrica que no es enlace no se levanta al pasar el ratón: prometía un clic que no existe (Fianzas, Cobros…). */
.metric:not(.metric-link):hover{transform:none;box-shadow:var(--sombra-1)}

/* P5 · TABLAS. td.row-actions era `display:flex`: una celda flex deja de ser celda, así que medía 63 px en una
   fila de 79,5 («Editar» 8 px por encima del centro) y su borde no casaba con el de la fila (escalón de 1 px
   en la última columna). Vuelve a ser celda; los botones fluyen en línea y centrados. En móvil manda .m-cards. */
td.row-actions{display:table-cell;vertical-align:middle}
td.row-actions>*{vertical-align:middle;margin:2px 6px 2px 0}
td.row-actions>small{display:block;padding-top:6px}
/* La celda-título de la tarjeta móvil sube con `order`, sin mover el DOM (ver mobileCards). */
.m-cards td.m-title{order:-1}
/* El nombre (strong, 12 px) salía más pequeño que el dato de al lado (13 px) y el detalle (small) a 10,83 px,
   bajo el suelo de 11 de la escala. */
td strong{font-size:var(--texto-13)}
td small{font-size:var(--texto-11)}
/* Un chip es una sola pieza: «Por habitaciones» se partía en dos líneas dentro de la píldora. */
.status{white-space:nowrap}

/* P6 · DIÁLOGOS. `dialog{scrollbar-gutter:stable}` reservaba 13 px aunque el diálogo nunca hace scroll (lo hace
   #dialog-content, que ponía OTROS 11): márgenes 28 / 50 px, el pie blanco sin llegar al borde y su esquina
   redonda dejando ver el contenido; y al abrir una sección los campos encogían 11 px de golpe. El cuerpo
   sigue desplazándose con rueda, trackpad y teclado; la barra, que se come el ancho, no se pinta. */
dialog{scrollbar-gutter:auto}
.dialog{overflow:hidden}
#dialog-content{scrollbar-width:none}
#dialog-content::-webkit-scrollbar{display:none}
/* Las casillas traían el margen del navegador (3 px 3 px 3 px 4 px): 4 px fuera de la columna de los campos. */
#dialog-content input[type=checkbox]{margin:0}
/* El texto de un <select> nativo va 4 px más adentro que el de un input con el mismo relleno. */
#dialog-content select,.availability-form select{padding-left:10px}
/* Un marcador con el mismo peso que un valor escrito se confunde con él («LEZ-1», «Lezama 1»). */
input::placeholder,textarea::placeholder{font-weight:400}

/* P7 · EL AVISO TAPABA EL BOTÓN. Con un diálogo abierto el toast se muda dentro (top layer), y el backdrop-filter
   del diálogo lo convierte en su marco de `position:fixed`: su «abajo a la derecha» era… el pie del diálogo,
   encima de «Añadir unidad». Dentro del diálogo aparece arriba, centrado y sin tocar la ×. */
.dialog>.toast{top:14px;bottom:auto;left:50%;right:auto;max-width:calc(100% - 120px);transform:translate(-50%,calc(-100% - 22px))}
.dialog>.toast.show{transform:translate(-50%,0)}
@media(prefers-reduced-motion:reduce){.dialog>.toast,.dialog>.toast.show{transform:translate(-50%,0)}}

/* P8 · DESPLEGABLES CON EL TRIÁNGULO DEL NAVEGADOR. «Últimos cambios» y «Rechazadas y caducadas» usaban el
   marcador nativo (▸) mientras el resto de secciones llevan el chevron de .form-advanced. */
.entity-history>summary,.kb-cerradas>summary{display:flex;align-items:center;gap:10px;list-style:none;cursor:pointer}
.entity-history>summary::-webkit-details-marker,.kb-cerradas>summary::-webkit-details-marker{display:none}
.entity-history>summary::before,.kb-cerradas>summary::before{content:"";flex:none;width:6px;height:6px;margin:0 2px 0 1px;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(-45deg);transition:transform var(--dur-2) var(--ease-out)}
.entity-history[open]>summary::before,.kb-cerradas[open]>summary::before{transform:rotate(45deg)}
.summary-icon{display:inline-flex;color:var(--texto-secundario)}

/* P9 · «QUÉ HA PASADO». Los hitos-enlace tenían el separador transparente y los de dinero no: una sola línea
   entre el 3.º y el 4.º. Todos separados menos el último. */
.ficha-card a.timeline-link .timeline-item,.ficha-card .timeline-item{border-bottom:1px solid var(--line)}
.ficha-card .timeline>:last-child .timeline-item,.ficha-card .timeline>.timeline-item:last-child{border-bottom-color:transparent}

/* P10 · SUELTOS. */
/* Dos tarjetas seguidas se tocaban (0 px) en Liquidaciones, Fianzas y Limpiezas. */
.content>.card+.card{margin-top:16px}
/* Los vacíos y el veredicto de admisión heredaban los 16 px del body. */
.empty{font-size:var(--texto-13)}
.ficha-veredicto{font-size:var(--texto-13)}
/* El menú «…» medía lo que su botón (196 px) y partía «Registrar incidencia aquí» en dos líneas. */
.add-menu-list button{white-space:nowrap}
/* «Ver el / reparto»: un enlace de dos palabras no se parte. */
a.inline-link[href^="#utilities"]{white-space:nowrap}
/* La píldora activa del último enlace del menú tocaba la raya de «Entorno seguro» (0,3 px). */
.sidebar nav{padding-bottom:8px}
/* Filtros del calendario: 44 / 41 / 41 px alineados por abajo (centros a 1,5 px) y letra de 13,44, 11,52 y
   10,56 px, fuera de la escala. Todos a la altura de un botón y en tokens. */
/* (Prefijo .content: property-calendar.css se carga DESPUÉS y con la misma especificidad ganaba.) */
.content .calendar-filters input:not([type=checkbox]):not([type=radio]):not([type=file]),.content .calendar-filters select,.content .calendar-result-count{height:var(--boton-alto);font-size:var(--texto-13)}
.content .calendar-filters label{font-size:var(--texto-11)}
.content .calendar-result-count{font-size:var(--texto-12)}
/* El <input type=month> transparente del selector de mes medía 44 (la regla A2 de alturas le gana a su
   height:100%) y su zona de clic asomaba 4 px por debajo de la cara de 40. */
.month-field input:not([type=checkbox]):not([type=radio]):not([type=file]){height:100%}

/* Eliminar una ficha (2026-09-23): lo que bloquea o lo que se va con ella, como lista legible. */
.delete-list{margin:12px 0 0;padding-left:20px;font-size:var(--texto-13);line-height:1.55;color:var(--ink)}
.delete-list li+li{margin-top:4px}

/* ==========================================================================
   CONTRASTE (2026-09-23, petición de Juan: «todo toma un mismo color»)
   Antes el fondo (#f5f8f7) y las cards blancas se separaban 1,07:1, las líneas 1,2:1 y el borde
   de los campos 1,4:1: todo parecía una sola superficie. La regla que sigue es la de la
   biblioteca UX (región común de Palmer 1992; WCAG 1.4.11): cada zona es una caja que se ve, y
   cada control tiene un límite visible. El grueso va en tokens.css (fondo, líneas, campos);
   aquí queda lo que no cuelga de un token.
   ========================================================================== */
/* Cabecera y menú: paneles blancos con su borde, separados del fondo gris del contenido. */
.topbar{background:var(--glass-fondo-alto);border-bottom:1px solid var(--color-borde)}
.sidebar{border-right:1px solid var(--color-borde)}
/* Menú: cada sección es un bloque con su separador, y el texto se lee sin pasar el ratón. */
.nav-section{border-top:1px solid var(--color-borde);margin-top:8px;padding-top:14px}
.sidebar nav>.nav-section:first-child{border-top:0;margin-top:0;padding-top:4px}
.nav-link{color:var(--texto-principal)}
.nav-link .nav-icon{color:var(--texto-secundario)}
.nav-link:hover{background:var(--gris-fondo)}
.nav-link.active,.nav-link.active .nav-icon{color:var(--color-accion-texto)}
.nav-link.active{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--color-accion) 22%,transparent)}
/* Botones: todos tienen caja. El secundario (verde suave) lleva un borde de su color. */
.button.ghost{border-color:var(--gris-control)}
.button.ghost:hover{background:var(--gris-050);border-color:var(--texto-secundario)}
.button.secondary{border-color:color-mix(in srgb,var(--color-accion) 30%,transparent)}
.button.secondary:hover{border-color:color-mix(in srgb,var(--color-accion) 55%,transparent)}
/* Tablas: la cabecera es una franja propia y las filas se separan con una línea que se ve. */
th{border-bottom:1px solid var(--color-borde)}
/* Diálogos opacos: el cristal al 86% sobre la pantalla oscurecida los dejaba grises y con la tabla
   de detrás asomando entre los campos. Un formulario es dato: superficie blanca y sólida. */
.dialog{background:var(--blanco);-webkit-backdrop-filter:none;backdrop-filter:none}
.dialog::backdrop{background:rgba(13,36,33,.5)}
/* Tablero de solicitudes: cada columna es una caja con su borde, no una mancha gris sobre gris. */
.kb-col{background:color-mix(in srgb,var(--color-borde) 55%,var(--color-fondo));border:1px solid var(--color-borde)}

/* — Cifra = destino (estudio de Homming, HANDOFF §0.7): la lista filtrada desde el Inicio lo dice —
   Caja con borde, no un texto gris: si el filtro pasa desapercibido, la lista parece entera y miente. */
.filtro-activo{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;margin:0 0 14px;padding:8px 10px;border:1px solid var(--color-borde);border-radius:var(--radio-m);background:var(--color-superficie)}
.filtro-chip{display:inline-flex;align-items:center;gap:6px;min-width:0;padding:4px 10px;border:1px solid var(--color-accion);border-radius:var(--radio-pill);background:var(--color-accion-suave);color:var(--color-accion-texto);font-size:var(--texto-13);font-weight:700;overflow-wrap:anywhere}
.filtro-n{color:var(--texto-secundario);font-size:var(--texto-13)}
.filtro-activo .button{margin-left:auto}

/* — Ocupación con fecha (estudio de Homming, HANDOFF §1.1): «hasta el 30 jun · libre desde el 1 jul» — */
.orden-lista{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}
.orden-lista>span{font-size:var(--texto-12);font-weight:600;color:var(--texto-secundario)}
a.chip-filter{display:inline-flex;align-items:center;text-decoration:none}
.ocup-linea{color:var(--texto-secundario)}
.ocup-linea b{color:var(--texto-principal);font-weight:700}
/* «Libres y por liberar» en Rotación: filas en rejilla (sin scroll interno); en móvil, dos columnas. */
/* Ejemplo en euros de la gestión del propietario (HANDOFF §3.4): caja con borde, no un párrafo suelto. */
.gestion-ejemplo{display:grid;gap:4px;margin:4px 0 8px;padding:10px 12px;border:1px solid var(--color-borde);border-radius:var(--radio-m);background:var(--color-fondo);font-size:var(--texto-13);color:var(--texto-secundario)}
.gestion-ejemplo[hidden]{display:none}
.gestion-ejemplo strong,.gestion-ejemplo b{color:var(--texto-principal)}
.timeline-leyenda{margin:12px 0 0;padding-top:10px;border-top:1px solid var(--color-borde);font-size:var(--texto-13);color:var(--texto-secundario)}
.libres-card{margin-bottom:20px}
.libres{display:grid}
.libre-fila{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1.3fr) minmax(0,2fr) minmax(0,.8fr);gap:6px 14px;align-items:start;padding:10px 2px;border-top:1px solid var(--color-borde)}
.libre-fila>div{min-width:0;overflow-wrap:anywhere}
.libre-fila small{display:block;color:var(--texto-secundario)}
.libre-cab{border-top:0;padding-top:0;font-size:var(--texto-12);font-weight:700;color:var(--texto-secundario)}
.libre-precio{text-align:right}
.libres-nota{margin:12px 0 0;padding-top:10px;border-top:1px solid var(--color-borde);font-size:var(--texto-13);color:var(--texto-secundario)}
/* Temporadas con nombre (HANDOFF §1.6): una caja con borde propia, los botones y los meses saltan de
   línea (nunca desplazan). En la caja, el mismo fondo que el lienzo para despegarla de la card. */
.temporadas{display:flex;flex-wrap:wrap;align-items:center;gap:8px 16px;margin:0 0 12px;padding:10px 12px;border:1px solid var(--color-borde);border-radius:var(--radio-m);background:var(--color-fondo)}
.libres-card .card-head .button{white-space:nowrap}
.temporadas-titulo{font-size:var(--texto-13);font-weight:700;color:var(--texto-principal)}
.temporadas-botones{display:flex;flex-wrap:wrap;gap:6px}
.temporadas-botones .button small{font-weight:500;opacity:.85}
.temporadas-fechas{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;margin-left:auto}
.temporadas-fechas label{display:flex;align-items:center;gap:6px;font-size:var(--texto-13);color:var(--texto-secundario)}
.temporadas-fechas input{width:9.5em;min-width:0}
.libre-fila small.libre-aviso{color:var(--aviso-texto);font-weight:600}
@media(max-width:760px){
  .libre-cab{display:none}
  .libre-fila{grid-template-columns:minmax(0,1fr) auto}
  .libre-fila>div:nth-child(2),.libre-fila>div:nth-child(3){grid-column:1/-1}
  .libre-precio{grid-column:2;grid-row:1}
  .temporadas-fechas{margin-left:0}
}
/* La fecha en la fila de la habitación del calendario: escrita, no dibujada. «Sin datos», en gris. */
.cal-unit .cal-unit-libre,.cal-m-label .cal-unit-libre{display:block;font-weight:700;color:var(--color-accion-texto)}
.cal-unit .cal-unit-libre.ocupada,.cal-unit .cal-unit-libre.bloqueada,.cal-m-label .cal-unit-libre.ocupada,.cal-m-label .cal-unit-libre.bloqueada{color:var(--texto-principal)}
.cal-unit .cal-unit-libre.sin_datos,.cal-m-label .cal-unit-libre.sin_datos{color:var(--texto-secundario);font-weight:600}
/* ¿Quién me debe? (HANDOFF §1.2): lo vencido se distingue sin leer — importe en rojo de texto
   (--error-texto, 5,1:1) y una franja a la izquierda de su grupo. */
.debe.vencida{color:var(--error-texto)}
tr.grupo-aviso.grupo-vencida td{border-left:4px solid var(--error-texto)}
tr.grupo-aviso.grupo-dice_pagado td{border-left:4px solid var(--aviso-texto)}
/* La fianza como dato en la ficha del inquilino (HANDOFF §1.3): importe + estado; debajo, el paso. */
.profile-facts .dato-fianza strong{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.profile-facts .dato-fianza small{display:block;margin-top:4px;color:var(--texto-secundario);font-weight:400;font-size:var(--texto-12)}
.relation-row .fianza-linea{color:var(--texto-secundario)}
.profile-facts .dato-fianza .status{text-transform:none;letter-spacing:0;margin:0;font-weight:700}
/* La barra de «Marcar como pagados» solo existe con algo seleccionado: su display:flex ganaba al
   atributo [hidden] y se veía siempre, con los botones apuntando a nada. */
.sel-bar[hidden]{display:none}
/* Contacto a un clic (HANDOFF §2.1): el teléfono y el email son enlaces con borde (se ven pulsables
   sin pasar el ratón); lo que no se puede hacer se dice en gris, no se esconde. */
.contacto{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;margin-top:6px}
.contacto-link{display:inline-flex;align-items:center;gap:6px;min-height:32px;max-width:100%;padding:4px 12px;border:1px solid var(--color-borde);border-radius:var(--radio-pill);background:var(--color-superficie);color:var(--color-accion-texto);font-size:var(--texto-13);font-weight:600;text-decoration:none;overflow-wrap:anywhere}
.contacto-link:hover{border-color:var(--color-accion)}
.contacto-link svg{flex:none}
.contacto-no{font-size:var(--texto-12);color:var(--texto-secundario)}
.relation-row .contacto{margin:4px 0}
/* «Avisar al piso» (HANDOFF §2.2): qué avisar como opciones grandes con borde; debajo, a quién le
   llega y a quién no (y por qué), y el texto tal cual saldrá. */
.seccion-acciones{display:inline-flex;flex-wrap:wrap;align-items:center;gap:8px 14px}
.aviso-plantillas{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0;padding:0;border:0;min-width:0}
.aviso-plantillas legend{width:100%;margin-bottom:8px;font-weight:700;font-size:var(--texto-13)}
.aviso-opcion{display:inline-flex;align-items:center;gap:8px;min-height:40px;padding:6px 14px;border:1px solid var(--input-borde);border-radius:var(--radio-m);background:var(--color-superficie);cursor:pointer;font-weight:600;font-size:var(--texto-13)}
.aviso-opcion:has(input:checked){border-color:var(--color-accion);background:var(--color-accion-suave);color:var(--color-accion-texto)}
.dialog-grid label[hidden]{display:none}
.aviso-preview{margin-top:14px;padding:12px 14px;border:1px solid var(--color-borde);border-radius:var(--radio-m);background:var(--color-superficie)}
.aviso-preview:empty{display:none}
.aviso-recuento{margin:0 0 6px}
.aviso-lista{margin:0 0 8px;padding-left:18px}
.aviso-lista small{color:var(--texto-secundario)}
.aviso-no li{color:var(--texto-secundario)}
.aviso-texto{margin-top:8px;padding:10px 12px;border-left:3px solid var(--color-accion);background:var(--color-fondo);border-radius:var(--radio-s);overflow-wrap:anywhere}
.aviso-texto span{display:block;font-size:var(--texto-12);color:var(--texto-secundario)}
.aviso-texto p{margin:4px 0 0}
/* Una sección de ficha con acciones en la cabecera: si no caben junto al título, bajan de línea
   (antes el título «Habitaciones (4)» se partía en dos para dejarles sitio). */
.ficha-card .card-head:has(.seccion-acciones){flex-wrap:wrap;gap:8px 14px}
.ficha-card .card-head:has(.seccion-acciones) h2{flex:1 0 auto}
.aviso-lista{font-size:var(--texto-13)}

/* ==========================================================================
   EL MENÚ CABE POR ALTURA (2026-09-24 · checklist anti-Homming n.º 4: «≤16 entradas sin scroll»)
   Medido con `nav.scrollHeight > nav.clientHeight` y los 5 roles: el menú de administración
   (12 entradas + «Propuestas» cuando hay algo que aprobar + 4 secciones) necesitaba 745 px y solo
   cabía a partir de 893 px de alto. A 1219×778 dejaba fuera «Cobros del mes», «Liquidaciones» y
   «Fianzas»; a 1280×720, 173 px escondidos. Sin barra visible: lo de abajo no se descubre.
   No se quita ni se esconde nada: en las pantallas bajas se aprietan los márgenes, en dos
   escalones. El enlace baja de 40 a 34 px y, en las muy bajas, a 30 (WCAG 2.5.8 pide ≥24 px con
   ratón). En móvil (≤760 px, cajón) no cambia: 44 px.
   Resultado: cabe entero hasta 630 px de alto. Va al final del fichero porque el bloque de
   CONTRASTE de arriba vuelve a fijar los márgenes de `.nav-section` y ganaría por orden.
   ========================================================================== */
/* La rejilla del menú estiraba las filas hasta llenar la columna: con 3 entradas (incidencias,
   limpieza) cada enlace medía 204-245 px y la píldora activa era un bloque de un cuarto de pantalla. */
.sidebar nav{align-content:start}
/* La imagen en línea dejaba 4 px de hueco de descendente bajo el logo. */
.sidebar-logo img{display:block}
/* Escalón 1 · portátiles (≤900 px de alto): el menú necesita 609 px; cabe hasta 741 px de alto. */
@media(min-width:761px) and (max-height:900px){
  .sidebar{padding-top:20px;padding-bottom:14px}
  .sidebar-logo{padding-bottom:16px}
  .sidebar nav{gap:2px}
  .nav-link{padding-top:7px;padding-bottom:7px}
  .nav-section{margin-top:6px;padding-top:10px;padding-bottom:4px}
  .sidebar-foot{padding-top:10px}
}
/* Escalón 2 · pantallas bajas (≤740 px: 1280×720, 1366×768 con la barra del navegador): 538 px,
   cabe hasta 630. El logo baja a la misma medida que ya tiene en el menú estrecho (≤1160 px). */
@media(min-width:761px) and (max-height:740px){
  .sidebar{padding-top:14px;padding-bottom:10px}
  .sidebar-logo{padding-bottom:10px}
  .sidebar-logo img{width:auto;height:34px}
  .nav-link{padding-top:5px;padding-bottom:5px}
  .nav-section{margin-top:4px;padding-top:7px;padding-bottom:3px}
  .sidebar-foot{padding-top:8px}
}
