:root {
  --bg: #f4f3ef;
  --panel: #ffffff;
  --soft: #eeeae1;
  --ink: #1c2023;
  --muted: #6b7278;
  --line: #e2ddd1;
  --brand: #315f5b;
  --brand-dark: #1f3634;
  --accent: #9a703d;
  --danger: #b3413f;
  --ok: #2f7655;
  --warn: #94621f;
  --radius: 12px;
  --radius-sm: 9px;
  --shadow-sm: 0 1px 2px rgba(20,24,28,.05), 0 1px 1px rgba(20,24,28,.03);
  --shadow-md: 0 10px 24px rgba(20,24,28,.08), 0 2px 6px rgba(20,24,28,.04);
  --shadow-lg: 0 22px 48px rgba(20,24,28,.16);
  --ease: cubic-bezier(.2,.7,.2,1);
}

/* Tarea #91 (Tony 2026-08-28): "lo veo el programa muy año 2000" -- refresco
   visual ligero. Alcance a proposito acotado: colores/tipografia/sombras/
   radios/iconos/transiciones. NO se toca ni una clase, ni un selector, ni
   la estructura de ningun modulo -- cero riesgo sobre la logica de la app.
   La causa mas gorda del aspecto "antiguo": este fichero ya pedia la fuente
   Inter pero nunca se cargaba en ningun sitio (index.html no tenia el
   <link>), asi que todo el texto caia siempre al fallback del sistema
   (Segoe UI / Arial). Con Inter cargada de verdad cambia mucho de un
   plumazo. El resto es sombra/profundidad/radios mas generosos y
   transiciones suaves en botones, pills y tarjetas -- la paleta de marca
   (verde --brand / --brand-dark / dorado --accent) se mantiene intacta a
   proposito porque tambien la usa el documento impreso (identidad visual
   de cara al cliente), no se toca el color, solo el "cuerpo" del interfaz. */

* { box-sizing: border-box; }
html { scrollbar-color: var(--line) transparent; }
body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--ink);
  font-family: "Inter", "Segoe UI", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--line); border-radius: 999px; }
::-webkit-scrollbar-thumb:hover { background: var(--muted); }

button, input, select, textarea { font: inherit; }
button {
  cursor: pointer;
  transition: background-color .15s var(--ease), border-color .15s var(--ease),
    box-shadow .15s var(--ease), transform .1s var(--ease), color .15s var(--ease);
}
button:disabled { cursor: not-allowed; opacity: .55; transform: none !important; box-shadow: none !important; }
h1, h2, h3, p { margin: 0; }
h1 { font-size: 28px; line-height: 1.15; font-weight: 800; letter-spacing: -.01em; }
h2 { font-size: 18px; font-weight: 800; letter-spacing: -.005em; }
h3 { font-size: 14px; font-weight: 800; }

/* Tony 2026-09-11: "no cambiaste nada bonito" -- tenia razon, la direccion
   visual (fotografia real de producto, no generica) se habia quedado en
   mockups/conversacion, nunca llego al codigo real. Primer cambio real y
   visible: el fondo de login pasa de gradientes abstractos a una foto real
   (recortada de la tarifa 2026 de Ikaya que Tony subio a
   catalogos_diseño/) -- mismo criterio que ya usan sus propios catalogos
   reales: fotografia de interior + velo oscuro de marca encima, no
   ilustracion generica de IA. AVISO para Tony: esta foto concreta es
   material de marketing de un proveedor (Ikaya), no propiedad de
   Catalogoventa -- razonable para uso interno/B2B como distribuidor
   autorizado, pero si algun dia se hace publica la pagina de login sin
   login previo, conviene confirmar con Ikaya que no hay problema en
   reutilizarla asi de forma permanente. */
.login {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 22px;
  background:
    radial-gradient(1100px 480px at 15% -10%, rgba(49,95,91,.22), transparent 60%),
    radial-gradient(900px 420px at 110% 10%, rgba(154,112,61,.16), transparent 60%),
    linear-gradient(180deg, rgba(23,42,40,.6), rgba(23,42,40,.78)),
    url("./assets/login-bg.jpg") center / cover no-repeat;
}
.login-card, .panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}
.login-card {
  width: min(460px, 100%);
  display: grid;
  gap: 18px;
  padding: 26px;
  border-top: 3px solid var(--accent);
  box-shadow: var(--shadow-lg);
}
.app-shell {
  min-height: 100vh;
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr);
}
.client-shell { grid-template-columns: 1fr; }
.sidebar {
  background: linear-gradient(175deg, var(--brand-dark) 0%, #172a28 100%);
  color: #fff;
  padding: 18px;
  box-shadow: var(--shadow-lg);
  position: relative;
  z-index: 4;
}
.brand {
  padding-bottom: 18px;
  border-bottom: 1px solid rgba(255,255,255,.14);
}
.brand span {
  display: block;
  color: #a9c4bf;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .03em;
  text-transform: uppercase;
}
.brand strong {
  display: block;
  margin-top: 3px;
  padding-bottom: 9px;
  font-size: 21px;
  letter-spacing: -.01em;
  position: relative;
}
/* Tony 2026-09-11 ("no cambiaste nada bonito"): la linea fina como firma
   grafica recurrente es el hilo comun en los 3 catalogos reales que subio
   (Enrollatech, Ikaya, Ikaya Topping) -- se repite aqui, bajo el nombre de
   la app en la barra lateral, como primer eco visible de esa direccion. */
.brand strong::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 28px;
  height: 2px;
  background: var(--accent);
}
.brand-logo {
  display: block;
  width: 44px;
  height: 44px;
  object-fit: contain;
  border-radius: var(--radius-sm);
  margin-bottom: 10px;
  background: #fff;
  padding: 4px;
  box-shadow: var(--shadow-sm);
}
.login-logo {
  display: flex;
  justify-content: center;
}
.login-logo img {
  width: 110px;
  height: 110px;
  object-fit: contain;
  border-radius: 16px;
}
@media (min-width: 600px) {
  .login-card { width: min(560px, 100%); }
  .login-logo img {
    width: 220px;
    height: 220px;
    border-radius: 24px;
  }
}
.client-brand {
  align-items: center;
  gap: 12px;
}
.client-logo {
  width: 64px;
  height: 64px;
  object-fit: contain;
  border-radius: var(--radius-sm);
  background: #fff;
  border: 1px solid var(--line);
  padding: 3px;
}
.client-logo-preview {
  display: block;
  width: 72px;
  height: 72px;
  object-fit: contain;
  border-radius: var(--radius-sm);
  background: #fff;
  border: 1px solid var(--line);
  padding: 4px;
  margin-bottom: 6px;
}
.nav {
  display: grid;
  gap: 4px;
  margin-top: 18px;
}
.nav button {
  position: relative;
  width: 100%;
  min-height: 42px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: #cfe0dc;
  font-weight: 700;
  text-align: left;
  padding: 9px 11px 9px 16px;
}
.nav button::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 50%;
  transform: translateY(-50%) scaleY(0);
  width: 3px;
  height: 60%;
  border-radius: 999px;
  background: #6fe3c4;
  transition: transform .15s var(--ease);
}
.nav button:hover { background: rgba(255,255,255,.08); color: #fff; }
.nav button.active {
  background: rgba(255,255,255,.12);
  border-color: rgba(255,255,255,.14);
  color: #fff;
  font-weight: 800;
}
.nav button.active::before { transform: translateY(-50%) scaleY(1); }
.workspace { min-width: 0; }
.topbar {
  min-height: 68px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px 22px;
  border-bottom: 1px solid var(--line);
  background: rgba(244,243,239,.85);
  backdrop-filter: saturate(160%) blur(8px);
  -webkit-backdrop-filter: saturate(160%) blur(8px);
  position: sticky;
  top: 0;
  z-index: 3;
}
.page {
  width: min(1500px, 100%);
  margin: 0 auto;
  padding: 22px;
}
.page-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 14px;
  margin-bottom: 16px;
}
.grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 420px;
  gap: 16px;
  align-items: start;
}
.panel { overflow: hidden; }
.panel-pad { padding: 15px; }
.panel-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  padding: 14px 15px;
  border-bottom: 1px solid var(--line);
  background: #faf9f6;
}
.collapsible-section {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition: box-shadow .15s var(--ease);
}
.collapsible-section:hover { box-shadow: var(--shadow-md); }
.collapsible-section > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 14px 15px;
  background: #faf9f6;
  font-weight: 900;
  font-size: 16px;
  user-select: none;
}
.collapsible-section > summary::-webkit-details-marker { display: none; }
.collapsible-section > summary::before {
  content: "▸";
  display: inline-block;
  margin-right: 8px;
  color: var(--brand);
  transition: transform .15s var(--ease);
}
.collapsible-section[open] > summary::before { transform: rotate(90deg); }
.collapsible-section > summary:hover { background: #f1efe9; }
.collapsible-section-body {
  display: grid;
  gap: 12px;
  padding: 12px;
  border-top: 1px solid var(--line);
}
.stack { display: grid; gap: 12px; }
.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.opening-cpq-select-label { min-width: 180px; }
.opening-cpq-select-label select { min-width: 180px; }
.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.full { grid-column: 1 / -1; }
label {
  display: grid;
  gap: 6px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .01em;
}
input, select, textarea {
  min-height: 40px;
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--ink);
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}
textarea {
  min-height: 88px;
  resize: vertical;
}
input:focus, select:focus, textarea:focus {
  outline: 3px solid rgba(49,95,91,.16);
  border-color: var(--brand);
}
input[type="checkbox"], input[type="radio"] {
  width: 18px;
  min-height: 18px;
  height: 18px;
  flex: none;
}
.progress-track {
  width: 100%;
  height: 10px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
}
.progress-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--brand), #4a8b85);
  border-radius: 999px;
  transition: width .2s var(--ease);
}
.checkbox-inline {
  display: flex !important;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  cursor: pointer;
}
.button {
  min-height: 40px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  font-weight: 800;
  white-space: nowrap;
  box-shadow: var(--shadow-sm);
}
.button:hover:not(:disabled) { transform: translateY(-1px); box-shadow: var(--shadow-md); }
.button:active:not(:disabled) { transform: translateY(0); box-shadow: var(--shadow-sm); }
.button.primary { background: var(--brand); color: #fff; }
.button.primary:hover:not(:disabled) { background: #386b66; }
.button.dark { background: var(--brand-dark); color: #fff; }
.button.dark:hover:not(:disabled) { background: #244440; }
.button.subtle { background: var(--soft); color: var(--ink); border-color: var(--line); }
.button.subtle:hover:not(:disabled) { background: #e4dfd2; }
.button.danger { background: var(--danger); color: #fff; }
.button.danger:hover:not(:disabled) { background: #9c332f; }
.btn-inline {
  justify-self: start;
  align-self: end;
  width: auto;
  min-width: 0;
}
/* Tony 2026-09-15: "la gente no sabe meter una linea manual... hoy me
   llamaron por telefono para ver como podian meterlo". La linea manual
   (marca+descripcion+precio libre, tareas #81/#82) YA estaba disponible en
   TODOS los huecos, independiente del CPQ elegido -- el problema no era de
   alcance, era que el punto de entrada era un <details><summary
   class="muted"> -- texto gris pequeno sin pinta de boton, facil de pasar
   por alto. Se cambia solo el estilo del disparador para que parezca un
   boton real (como "+ Anadir otro producto" justo encima), sin tocar la
   logica del formulario ni el resto del flujo. */
.manual-line-details { margin-top: 10px; }
.manual-line-trigger {
  display: inline-block;
  cursor: pointer;
  background: var(--soft);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  font-weight: 800;
  box-shadow: var(--shadow-sm);
}
.manual-line-trigger:hover { background: #e4dfd2; }
.muted, .eyebrow { color: var(--muted); }
.eyebrow {
  margin-bottom: 5px;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.error {
  color: var(--danger);
  font-size: 13px;
  font-weight: 800;
  min-height: 18px;
}
.warning {
  color: #a15c00;
  font-size: 13px;
  font-weight: 800;
}
/* Tony 2026-09-07 ("no me ha sido sencillo avanzar... por los colores"):
   .error (rojo) se estaba usando a la vez para fallos reales (validacion de
   formulario) y para avisos de negocio sin urgencia de sistema (cliente sin
   visitar hace tiempo, usuario interno inactivo) -- mismo rojo para cosas
   de gravedad muy distinta. .attention usa el dorado de marca (--accent,
   la paleta ya existente, no un color nuevo inventado) para "esto merece tu
   atencion" sin decir "algo esta roto". Reservar .error de verdad para
   fallos/perdidas confirmadas.
   2026-09-07 (v126, "los colores son un semaforo, a partir de ahi tu
   decides"): cerrados los 3 usos que quedaban pendientes. Caducidad de
   descuento y recordatorio de visita vencido pasan a .attention (mismo
   patron: accion de negocio pendiente, no fallo ni perdida). Margen de
   visita negativo SE QUEDA en .error -- es dinero ya perdido en una visita
   concreta, no un plazo por vencer, encaja en "fallo/perdida confirmada". */
.attention {
  color: var(--accent);
  font-size: 13px;
  font-weight: 800;
}
/* Tony 2026-09-07 (auditoria UX, "tablas densas sin ningun punto de
   referencia visual para escanear rapido"): franja de color a la izquierda
   de la fila segun estado/alerta. Se aplica al primer <td>, no al <tr> --
   las tablas usan border-collapse:collapse, un border-left en el <tr> no
   se pinta de forma fiable en todos los navegadores con esa propiedad.
   Clase en el <table> (.table-flagged) para no afectar sin querer a otras
   tablas de la app (CPQ, lineas de presupuesto, etc.) que no tienen este
   concepto de alerta por fila. */
.table-flagged tr > td:first-child { border-left: 4px solid transparent; }
.table-flagged tr.flag-attention > td:first-child { border-left-color: var(--accent); }
.table-flagged tr.flag-warning > td:first-child { border-left-color: var(--warn); }
.table-flagged tr.flag-muted > td:first-child { border-left-color: var(--line); }

/* Tony 2026-09-07 (auditoria UX, "demasiados plegables apilados" al editar
   un cliente): pestañas simples para alternar entre "Datos" y "Visitas y
   contactos" sin tenerlos los dos desplegados a la vez. */
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--line); margin-bottom: 4px; }
.tab {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 10px 14px;
  font-size: 14px;
  font-weight: 700;
  color: var(--muted);
}
.tab:hover { color: var(--ink); }
.tab.active { color: var(--brand-dark); border-bottom-color: var(--brand); }
.notice {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 10px;
  background: #fff8ec;
  color: #644516;
  font-size: 13px;
}
.status, .pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 27px;
  border-radius: 999px;
  padding: 5px 11px 5px 9px;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: .01em;
}
.status::before {
  content: "";
  width: 6px;
  height: 6px;
  flex: none;
  border-radius: 999px;
  background: currentColor;
  opacity: .8;
}
.status { background: #e9eef4; color: #315f8a; }
.status.active { background: #e8f4ee; color: var(--ok); }
.status.draft { background: #fde3c8; color: #9a4b06; }
.status.order { background: #dcf5e3; color: #1d6d4a; }
.status.manufacturing { background: #8fd6ae; color: #0b3d24; }
.status.shipped { background: #cfe3fb; color: #1450a3; }
.status.pending, .status.sent { background: #f7efe3; color: var(--warn); }
.status.blocked, .status.rejected { background: #f4e6e6; color: var(--danger); }
.pill { background: var(--soft); color: var(--brand-dark); }
table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
th, td {
  padding: 11px 12px;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}
th {
  color: var(--muted);
  background: var(--soft);
  font-size: 11px;
  font-weight: 900;
  letter-spacing: .04em;
  text-transform: uppercase;
}
td small { display: block; margin-top: 4px; color: var(--muted); }
.clickable { cursor: pointer; transition: background-color .12s var(--ease); }
.clickable:hover, .selected { background: #f5f7f7; }
.total {
  display: grid;
  gap: 4px;
  padding: 16px;
  background: linear-gradient(160deg, var(--brand-dark), #16302d);
  color: #fff;
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}
.total span { color: #cbd7d3; font-size: 12px; font-weight: 800; letter-spacing: .01em; }
.total strong { font-size: 26px; letter-spacing: -.01em; }
.brand-breakdown {
  display: grid;
  gap: 8px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: #faf9f6;
}
.brand-total {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  align-items: center;
  padding: 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: #fff;
}
.room {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.room-title {
  padding: 10px 12px;
  background: #faf9f6;
  border-bottom: 1px solid var(--line);
  font-weight: 900;
}
/* Tony 2026-09-16: "fichas de presupuesto" -- la pantalla donde de verdad
   pasa el tiempo, a diferencia del login (que casi no pisa). El acento
   dorado del refresco visual (v136) solo llegaba al login y al sidebar; se
   extiende aqui, en la misma linea visual (mismo --accent, mismo grosor de
   3px que .login-card), sin tocar --brand/--accent en si (siguen
   congelados por el documento impreso, tarea #91). .quote-workspace es una
   clase nueva SOLO en la ficha de presupuesto activa (ver renderQuoteWorkspace
   en 05-quote-workspace-and-print.js) -- no toca el resto de paneles
   (dashboard, clientes, tarifas...) que siguen igual. */
.quote-workspace { border-top: 3px solid var(--accent); }
.quote-workspace .room-title { border-left: 3px solid var(--accent); padding-left: 9px; }
.opening {
  display: grid;
  gap: 8px;
  padding: 10px;
  border-bottom: 1px solid var(--line);
}
.opening:last-child { border-bottom: 0; }
.line {
  display: grid;
  gap: 8px;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: #fff;
  transition: box-shadow .15s var(--ease), border-color .15s var(--ease);
}
.line:hover { box-shadow: var(--shadow-sm); border-color: #d5cfc0; }
.line-main, .line-edit {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  align-items: center;
}
.line-detail { color: var(--brand-dark); }
.line-note { display: block; color: #7a5b00; }
.line-edit {
  justify-content: flex-start;
  flex-wrap: wrap;
}
.line-edit label {
  width: 130px;
}
/* Tarea #143: la nota de linea es texto libre, no cabe en el ancho fijo de
   130px que usan los demas campos de .line-edit (cantidad, dto., etc). */
.line-edit label.line-notes-field {
  width: 100%;
}
.modal {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  grid-template-rows: auto 1fr;
  background: rgba(20,24,28,.72);
  backdrop-filter: blur(2px);
}
.modal[hidden] { display: none; }
.modal-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  padding: 12px 16px;
  background: var(--brand-dark);
  color: #fff;
}
.modal-frame {
  width: calc(100vw - 32px);
  height: calc(100vh - 88px);
  margin: 16px;
  border: 0;
  border-radius: var(--radius);
  background: #fff;
  box-shadow: var(--shadow-lg);
}
#toastContainer {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 60;
  display: grid;
  gap: 8px;
  pointer-events: none;
}
.toast {
  min-width: 190px;
  max-width: min(360px, calc(100vw - 36px));
  border-radius: var(--radius-sm);
  padding: 11px 13px;
  box-shadow: var(--shadow-lg);
  font-size: 13px;
  font-weight: 900;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .2s ease, transform .2s ease;
}
.toast.visible {
  opacity: 1;
  transform: translateY(0);
}
.toast.ok {
  background: var(--ok);
  color: #fff;
}
.toast.error {
  background: var(--danger);
  color: #fff;
}
.alarm-modal {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: grid;
  place-items: center;
  padding: 18px;
  background: rgba(20,24,28,.76);
  backdrop-filter: blur(2px);
}
.alarm-card {
  width: min(520px, 100%);
  display: grid;
  gap: 14px;
  border: 1px solid #efc2c2;
  border-radius: var(--radius);
  padding: 18px;
  background: #fff7f5;
  box-shadow: var(--shadow-lg);
}
.alarm-card p {
  white-space: pre-wrap;
  line-height: 1.45;
}
.client-quote-view {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  box-shadow: var(--shadow-md);
}
.client-quote-view .print-quote,
.print-quote {
  color: #111;
  font-size: 12px;
  padding: 18px;
  -webkit-print-color-adjust: exact;
  print-color-adjust: exact;
}
.client-quote-view .print-doc-header,
.print-doc-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 16px;
  border-bottom: 2px solid var(--brand);
  padding-bottom: 10px;
  margin-bottom: 10px;
}
.print-doc-brand strong { font-size: 16px; display: block; color: var(--brand-dark); }
.print-doc-brand span { display: block; }
.print-doc-brand small { color: #555; }
.print-doc-brand-client { display: flex; align-items: center; gap: 10px; }
.print-doc-logo { max-height: 42px; max-width: 140px; object-fit: contain; }
.print-doc-type { text-align: right; }
.print-doc-type strong { display: block; font-size: 14px; color: var(--accent); }
.client-quote-view .print-meta-row,
.client-quote-view .print-client-row,
.print-meta-row,
.print-client-row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  border-bottom: 1px solid #ddd;
  padding: 6px 0;
}
.print-meta-row > div,
.print-client-row > div {
  flex: 1;
  min-width: 140px;
}
.print-meta-row span,
.print-client-row span {
  display: block;
  color: #555;
  font-size: 10px;
  text-transform: uppercase;
}
.print-section-title {
  margin-top: 16px;
  font-size: 13px;
  text-transform: uppercase;
  color: var(--brand-dark);
  border-bottom: 1px solid var(--accent);
  padding-bottom: 4px;
}
.client-quote-view .print-brand-row,
.print-brand-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
}
.print-brand-row strong { color: var(--brand-dark); }
.print-end-customer-row strong { color: var(--brand-dark); }
.client-quote-view .print-room,
.client-quote-view .print-opening,
.client-quote-view .print-breakdown,
.print-room,
.print-opening,
.print-breakdown {
  margin-top: 18px;
}
/* Tony 2026-09-16: "no hace bien lo de descargar presupuesto" -- sale
   cortado / mal maquetado. Causa real: el boton "Descargar PDF" NO usa la
   impresion nativa del navegador (esa si respeta @media print de arriba),
   usa html2canvas+html2pdf para clonar el documento y trocearlo en paginas
   por PIXELES. Su modo "css" de corte de pagina busca en el DOM elementos
   con page-break-inside/break-inside:avoid para no serrarlos por la mitad
   -- pero styles.css no definia esa propiedad en ningun sitio fuera de
   @media print (que el clon nunca usa), asi que cualquier tabla de linea,
   hueco o bloque de totales que cayera justo en el limite de una pagina se
   cortaba a la mitad. Cuanto mas larga la descripcion de linea (mas
   complementos, badges de precio manual...) mas paginas, mas probabilidad
   de que algo caiga justo en el corte -- coincide con que el sintoma se ve
   mas ahora que antes. Fix: marcar los bloques que NO se deben serrar. */
.print-quote tr,
.print-opening,
.print-totals,
.print-signoff,
.print-payment,
.print-doc-header,
.print-meta-row,
.print-client-row {
  page-break-inside: avoid;
  break-inside: avoid;
}
.client-quote-view .print-quote table,
.print-quote table {
  width: 100%;
  border-collapse: collapse;
}
.client-quote-view .print-quote th,
.client-quote-view .print-quote td,
.print-quote th,
.print-quote td {
  border-bottom: 1px solid #ddd;
  padding: 7px 5px;
  text-align: left;
  vertical-align: top;
}
.client-quote-view .print-quote th,
.print-quote th {
  color: var(--brand-dark);
  border-bottom: 2px solid var(--brand);
  text-transform: uppercase;
  font-size: 10px;
}
.client-quote-view .print-quote small,
.print-quote small {
  display: block;
  color: #555;
  margin-top: 3px;
}
.print-totals {
  margin-top: 16px;
  margin-left: auto;
  max-width: 320px;
}
.print-totals-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 4px 0;
  border-bottom: 1px solid #ddd;
}
.print-totals-grand {
  border-bottom: none;
  border-top: 2px solid var(--brand);
  font-size: 14px;
  margin-top: 4px;
  padding-top: 8px;
  color: var(--brand-dark);
}
.print-totals-grand strong { color: var(--accent); }
.print-payment {
  margin-top: 16px;
  border-top: 1px solid #ddd;
  padding-top: 10px;
}
.print-signoff {
  display: flex;
  justify-content: space-between;
  gap: 24px;
  margin-top: 16px;
}
.print-signoff > div { flex: 1; }
.print-signoff span {
  display: block;
  color: #555;
  font-size: 10px;
  text-transform: uppercase;
  margin-bottom: 4px;
}
.print-signature-line { margin-top: 24px; }
.print-legal {
  margin-top: 16px;
  color: #555;
  font-size: 10px;
  font-style: italic;
}
/* Tarea #143 (Tony 2026-09-18): notas de texto libre a nivel de estancia,
   hueco y linea -- mismo estilo (fondo suave, borde izquierdo) en los 3
   niveles del documento impreso/PDF para que se distingan del resto del
   contenido a simple vista. */
.print-note {
  margin: 6px 0 0;
  padding: 6px 8px;
  background: #fdf6e8;
  border-left: 3px solid var(--accent, #c2570a);
  font-size: 11px;
  color: #444;
  white-space: pre-wrap;
}
.print-only { display: none; }

/* Tarea #85 (Tony 2026-08-28): "casi siempre me saca paginas en blanco" al
   imprimir/guardar como PDF. Causa real: `visibility: hidden` NO retira a
   los elementos del flujo del documento -- todo el resto de la app (menus,
   listados, formularios ocultos) seguia ocupando su altura real aunque no
   se viera, asi que el motor de impresion paginaba segun esa altura total
   (a menudo mucho mayor que el documento visible), generando paginas en
   blanco de sobra al final. Fix: forzar altura 0 y overflow oculto en TODO
   excepto en el contenido imprimible, que recupera su altura real. */
@media print {
  body * {
    visibility: hidden;
    height: 0 !important;
    overflow: hidden !important;
  }
  .print-only, .print-only * {
    visibility: visible;
    height: auto !important;
    overflow: visible !important;
  }
  .print-only {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
  }
}

@media (min-width: 1101px) {
  .grid > aside.stack {
    position: sticky;
    top: 16px;
    max-height: calc(100vh - 32px);
    overflow-y: auto;
  }
}

@media (max-width: 1100px) {
  .app-shell, .grid { grid-template-columns: 1fr; }
  .sidebar { position: static; }
  .nav { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
  .page, .login { padding: 12px; }
  .page-head, .topbar, .form-grid { display: grid; grid-template-columns: 1fr; }
  /* Tony 2026-09-11: "muchagente y yo el primero, lo haremos desde un
     movil... y los botones son muy grandes... muy dificil navegar".
     Causa real, confirmada en el CSS (no interpretacion): en movil el
     sidebar entero (logo + nav de 8 paginas) se apila ENCIMA del
     contenido (app-shell pasa a 1 columna a <=1100px), y el nav ademas
     se convertia en una lista vertical de 8 botones de 42px+ cada uno --
     es decir, antes de ver "Clientes" o cualquier pagina, habia que
     scrollear ~380px de menu. Se convierte el nav en una tira horizontal
     con scroll (patron "tab bar" movil) para que el menu ocupe una sola
     fila corta y el contenido quede a la vista enseguida. */
  .nav {
    display: flex;
    grid-template-columns: none;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    gap: 6px;
    padding-bottom: 6px;
    margin-top: 12px;
  }
  .nav button {
    width: auto;
    flex: 0 0 auto;
    white-space: nowrap;
    text-align: center;
    padding: 9px 14px;
  }
  .nav button::before {
    left: 50%;
    top: auto;
    bottom: 2px;
    transform: translateX(-50%) scaleX(0);
    width: 60%;
    height: 3px;
  }
  .nav button.active::before { transform: translateX(-50%) scaleX(1); }
  /* Segunda causa confirmada: .button lleva white-space:nowrap y texto
     largo en español ("Descargar CSV de producción", "Confirmar y
     lanzar pedido") -- en una pantalla de 375-428px cada boton ocupa el
     ancho completo el solo (aunque .row ya tiene flex-wrap, no cabe un
     segundo boton al lado), asi que una barra de 6-8 acciones se
     convertia en 6-8 filas de botones enormes antes de llegar al
     presupuesto en si. Se permite que el texto envuelva a 2 lineas
     dentro de un boton mas estrecho, para que quepan 2 (a veces 3) por
     fila en vez de 1. */
  .row .button {
    flex: 1 1 auto;
    min-width: 0;
    white-space: normal;
    font-size: 13px;
    line-height: 1.2;
    padding: 7px 10px;
    min-height: 36px;
  }
}
