/* ============================================================
   FoodOps Pro — Design System (rediseño 2026)
   Tokens (oscuro/claro) · shell sidebar+topbar · componentes
   Las clases conservan sus nombres para no romper las pantallas.
   ============================================================ */
:root,[data-theme="dark"]{
  --bg:#0d0d0f; --bg-card:#141417; --bg-input:#1a1a1e; --bg-hover:#1a1a1e;
  --surface-2:#1a1a1e; --surface-hi:#202026;
  --border:#26262b; --border-md:#33333b;
  --text:#f4f4f6; --text-sub:#9a9aa3; --text-muted:#5e5e67;
  --accent:#e5321a; --accent-hi:#ff4a30; --accent-dim:rgba(229,50,26,.14);
  --accent-b:#5b8dff; --accent-g:#36b37e; --accent-a:#e0a83a; --accent-o:#f97316; --accent-r:#ef4444; --accent-p:#a78bfa;
  --accent-c:#38bdf8; --accent-pk:#f472b6;
  --shadow:0 18px 50px rgba(0,0,0,.40);
  --topbar-h:60px; --sidebar-w:248px; --radius:9px; --radius-lg:11px;
  --trans:.15s ease; --ease:cubic-bezier(.23,1,.32,1);
  --mono:'JetBrains Mono',ui-monospace,'SF Mono',Menlo,monospace;
}
[data-theme="light"]{
  --bg:#f4f4f6; --bg-card:#ffffff; --bg-input:#f1f1f4; --bg-hover:#f0f0f3;
  --surface-2:#f0f0f3; --surface-hi:#e9e9ee;
  --border:#e6e6ea; --border-md:#d6d6de;
  --text:#19191f; --text-sub:#5a5a64; --text-muted:#9a9aa4;
  --accent:#dc2d15; --accent-hi:#bf280f; --accent-dim:rgba(220,45,21,.10);
  --accent-b:#2f6df0; --accent-g:#1f9d63; --accent-a:#b9831f; --accent-o:#d9620f; --accent-r:#d62a2f; --accent-p:#7c54d6;
  --accent-c:#0284c7; --accent-pk:#db2777;
  --shadow:0 18px 50px rgba(20,20,30,.10);
}
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{font-size:14px;-webkit-font-smoothing:antialiased}
body{font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:var(--bg);color:var(--text);line-height:1.6;min-height:100vh;
  transition:background .3s var(--ease),color .3s var(--ease)}
a{color:var(--accent-b);text-decoration:none}
a:hover{color:var(--accent)}
.num,.data-table td.num,.kpi-value .num{font-family:var(--mono);font-feature-settings:"tnum";letter-spacing:-.01em}
::-webkit-scrollbar{width:7px;height:7px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--border-md);border-radius:3px}
@media(prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ── APP SHELL ───────────────────────────────────────────── */
.app{display:grid;grid-template-columns:var(--sidebar-w) 1fr;min-height:100vh}
.main-content{display:flex;flex-direction:column;min-width:0}
.page-content{padding:26px 28px 40px;max-width:1320px;width:100%;animation:fadein .35s var(--ease)}
@keyframes fadein{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* ── SIDEBAR ─────────────────────────────────────────────── */
.scrim{display:none;position:fixed;inset:0;background:rgba(0,0,0,.55);z-index:150;opacity:0;transition:opacity .25s var(--ease)}
.scrim.show{display:block;opacity:1}
.sidebar{background:var(--bg-card);border-right:1px solid var(--border);display:flex;flex-direction:column;position:sticky;top:0;height:100vh;z-index:200}
.brand{display:flex;align-items:center;justify-content:center;gap:11px;padding:18px;border-bottom:1px solid var(--border);min-height:72px;flex-shrink:0}
.brand .logo-h{max-height:50px;max-width:200px;width:auto;object-fit:contain}
.brand-fallback{display:flex;align-items:center;gap:10px}
.brand-mark{width:32px;height:32px;border-radius:9px;background:var(--accent);display:grid;place-items:center;font-weight:800;color:#fff;font-size:15px;box-shadow:0 2px 10px rgba(229,50,26,.35)}
.brand-name{font-weight:700;letter-spacing:-.02em;font-size:15px;color:var(--text)}.brand-name span{color:var(--accent)}
.brand-sub{font-size:10px;color:var(--text-muted);letter-spacing:.14em;text-transform:uppercase;margin-top:1px}
/* SIN padding arriba: ese padding forma parte del área que hace scroll, así que los ítems
   pasaban por esa franja POR ENCIMA de donde se pega el buscador. Lo aporta ahora .sidebar-search,
   que es quien tiene que tapar esa zona. */
.nav{flex:1;overflow-y:auto;padding:0 12px 8px;display:flex;flex-direction:column;gap:1px}
/* El buscador del sidebar, pegado arriba. Los márgenes negativos + el padding equivalente hacen
   que su fondo llegue a los bordes del sidebar: dentro del padding lateral de .nav, los ítems se
   veían pasar también por los lados. El borde inferior marca dónde acaba lo fijo y empieza lo que
   se desplaza — sin él, el corte parece un fallo de pintado. */
.sidebar-search{position:sticky;top:0;z-index:5;background:var(--bg-card);
  margin:0 -12px 4px;padding:10px 12px;border-bottom:1px solid var(--border)}
.navgroup-head{display:flex;align-items:center;gap:6px;width:100%;background:none;border:none;cursor:pointer;font-family:inherit;
  font-size:10px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--text-muted);padding:15px 12px 6px}
.navgroup-head:hover{color:var(--text-sub)}
.navgroup-head .chev{margin-left:auto;width:13px;height:13px;stroke-width:2.2;transition:transform .25s var(--ease)}
.navgroup.collapsed .navgroup-head .chev{transform:rotate(-90deg)}
.navgroup-body{display:grid;grid-template-rows:1fr;transition:grid-template-rows .26s var(--ease)}
.navgroup.collapsed .navgroup-body{grid-template-rows:0fr}
.navgroup-body>.inner{overflow:hidden;min-height:0;display:flex;flex-direction:column;gap:1px}
.nav-item{display:flex;align-items:center;gap:11px;padding:9px 12px;border-radius:var(--radius);color:var(--text-sub);font-weight:500;font-size:13.5px;position:relative;
  transition:background var(--trans),color var(--trans);text-decoration:none}
.nav-item svg{width:18px;height:18px;flex-shrink:0;stroke-width:1.7}
.nav-item:hover{background:var(--surface-2);color:var(--text)}
.nav-item.active{background:var(--accent-dim);color:var(--text);font-weight:600}
.nav-item.active::before{content:"";position:absolute;left:-12px;top:50%;transform:translateY(-50%);width:3px;height:20px;border-radius:0 3px 3px 0;background:var(--accent)}
.nav-item.active svg{color:var(--accent)}
.nav-badge{margin-left:auto;font-family:var(--mono);font-size:11px;background:var(--accent);color:#fff;border-radius:20px;padding:1px 7px;font-weight:600}
.sidebar-foot{border-top:1px solid var(--border);padding:12px;display:flex;align-items:center;gap:10px;flex-shrink:0}
.user-avatar{width:34px;height:34px;border-radius:9px;background:var(--surface-hi);border:1px solid var(--border-md);display:grid;place-items:center;font-weight:700;font-size:13px;color:var(--text);flex-shrink:0}
.user-name{font-size:13px;font-weight:600;color:var(--text);line-height:1.2}
.user-role{font-size:11px;color:var(--text-muted);text-transform:capitalize}
.logout{margin-left:auto;color:var(--text-muted);display:grid;place-items:center;width:32px;height:32px;border-radius:8px;transition:var(--trans)}
.logout:hover{color:var(--accent);background:var(--surface-2)}

/* ── TOPBAR ──────────────────────────────────────────────── */
.topbar{height:var(--topbar-h);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:14px;padding:0 28px;position:sticky;top:0;
  background:color-mix(in srgb,var(--bg) 82%,transparent);backdrop-filter:blur(10px);z-index:100;flex-shrink:0}
.crumb{font-size:16px;font-weight:700;letter-spacing:-.02em;color:var(--text)}
.crumb small{color:var(--text-muted);font-weight:500}
.topbar-spacer{margin-left:auto}
/* Hora de una marca de asistencia: se lee como texto, pero es editable (admin) */
.hour-edit{font:inherit;color:inherit;background:none;border:0;padding:2px 4px;margin:-2px -4px;
  border-radius:6px;cursor:pointer;border-bottom:1px dashed var(--border-md);transition:var(--trans)}
.hour-edit:hover{background:var(--surface-2);color:var(--accent);border-bottom-color:transparent}
.hour-edit:focus-visible{outline:2px solid var(--accent);outline-offset:1px}

.topbar-clock{display:flex;align-items:baseline;gap:8px;user-select:none;white-space:nowrap}
.topbar-clock .tc-date{font-size:12.5px;color:var(--text-sub);text-transform:capitalize}
.topbar-clock .tc-time{font-family:var(--mono);font-size:14px;font-weight:600;color:var(--text);
  font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.icon-btn{width:38px;height:38px;border-radius:9px;border:1px solid var(--border);background:var(--bg-card);display:grid;place-items:center;color:var(--text-sub);cursor:pointer;transition:var(--trans)}
.icon-btn:hover{background:var(--surface-2);color:var(--text)}
.icon-btn:active{transform:scale(.95)}
.icon-btn svg{width:18px;height:18px;stroke-width:1.8}
.hamburger{display:none}
.btn-salir{font-size:12.5px;color:var(--text-sub);background:var(--bg-card);border:1px solid var(--border);padding:8px 14px;border-radius:9px;cursor:pointer;transition:var(--trans);text-decoration:none}
.btn-salir:hover{color:var(--accent);border-color:var(--border-md)}

/* ── SECTION HEADER ──────────────────────────────────────── */
.section-header{display:flex;justify-content:space-between;align-items:flex-end;margin-bottom:22px;gap:14px;flex-wrap:wrap}
.section-header-left h2{font-size:23px;font-weight:800;color:var(--text);margin-bottom:3px;letter-spacing:-.03em}
.section-header-left p{font-size:13.5px;color:var(--text-sub)}
/* Selector de bloque (segmented) */
.seg{display:inline-flex;background:var(--surface-2);border:1px solid var(--border);border-radius:11px;padding:4px;gap:4px}
.seg-btn{border:none;background:none;font-family:inherit;font-size:13.5px;font-weight:600;color:var(--text-sub);padding:8px 18px;border-radius:8px;cursor:pointer;display:flex;align-items:center;gap:8px;transition:transform .12s var(--ease),background var(--trans),color var(--trans)}
.seg-btn svg{width:16px;height:16px;stroke-width:1.9;fill:none;stroke:currentColor}
.seg-btn:active{transform:scale(.97)}
.seg-btn.on{background:var(--bg-card);color:var(--text);box-shadow:0 1px 4px rgba(0,0,0,.18)}
.seg-btn.on svg{color:var(--accent)}
@media(max-width:520px){.seg{width:100%}.seg-btn{flex:1;justify-content:center;padding:11px 8px}}
@media(max-width:860px){.dash-cols{grid-template-columns:1fr!important}}

/* ── IMPRESIÓN (PDF vía navegador) ── */
.print-only{display:none}
@media print{
  :root{--bg:#fff;--bg-card:#fff;--surface-2:#fff;--surface-hi:#eee;--border:#cfcfcf;--border-md:#bdbdbd;--text:#000;--text-sub:#333;--text-mut:#666;--accent:#c92a14}
  .sidebar,.topbar,.scrim,.seg,.filter-bar,.icon-btn,.btn,.no-print{display:none!important}
  .app{display:block}
  .main-content{display:block}
  .page-content{padding:0!important;max-width:100%!important;animation:none!important}
  body{background:#fff!important;color:#000!important}
  .print-only{display:block;margin-bottom:16px}
  .card,.kpi-card{break-inside:avoid;box-shadow:none!important}
  .section-header{margin-bottom:10px}
}

/* ── KPI CARDS ───────────────────────────────────────────── */
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px;margin-bottom:22px}
.kpi-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:17px 18px;transition:border-color .2s var(--ease)}
.kpi-card:hover{border-color:var(--border-md)}
.kpi-label{font-size:12px;font-weight:500;color:var(--text-sub);margin-bottom:11px}
.kpi-value{font-size:26px;font-weight:700;letter-spacing:-.01em;line-height:1.1;font-family:var(--mono);font-variant-numeric:tabular-nums}
.kpi-card .kpi-value{color:var(--text)}   /* número neutro y mono: anula los c-* decorativos */
.kpi-sub{font-size:12px;color:var(--text-muted);margin-top:6px}
/* Tarjetas KPI uniformes y limpias (sin borde superior de color, estilo del mockup). */

/* ── CARD ────────────────────────────────────────────────── */
.card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);margin-bottom:16px;overflow:hidden}
.card-header{padding:14px 18px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:8px}
.card-title{font-size:13px;font-weight:700;color:var(--text);letter-spacing:-.01em;display:flex;align-items:center;gap:6px}
.card-body{padding:18px}

/* ── TABLAS ──────────────────────────────────────────────── */
.table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table.data-table{width:100%;border-collapse:collapse;font-size:13.5px}
.data-table th{padding:11px 18px;text-align:left;font-size:10.5px;font-weight:600;text-transform:uppercase;letter-spacing:.07em;color:var(--text-muted);border-bottom:1px solid var(--border);white-space:nowrap}
.data-table td{padding:13px 18px;border-bottom:1px solid var(--border);color:var(--text-sub);vertical-align:middle}
.data-table tbody tr{transition:background .12s var(--ease)}
.data-table tbody tr:last-child td{border-bottom:none}
.data-table tbody tr:hover td{background:var(--surface-2)}
.data-table td.strong{font-weight:600;color:var(--text)}

/* ── BADGES ──────────────────────────────────────────────── */
.badge{display:inline-flex;align-items:center;gap:5px;padding:3px 10px;border-radius:20px;font-size:11.5px;font-weight:600;letter-spacing:.01em}
.badge-green{background:rgba(54,179,126,.13);color:var(--accent-g)}
.badge-blue{background:rgba(91,141,255,.14);color:var(--accent-b)}
.badge-red{background:var(--accent-dim);color:var(--accent)}
.badge-amber{background:rgba(224,168,58,.14);color:var(--accent-a)}
.badge-gray{background:var(--surface-hi);color:var(--text-muted)}
.badge-orange{background:rgba(249,115,22,.13);color:var(--accent-o)}
.badge-purple{background:rgba(167,139,250,.14);color:var(--accent-p)}
.badge-cyan{background:rgba(56,189,248,.14);color:var(--accent-c)}
.badge-pink{background:rgba(244,114,182,.14);color:var(--accent-pk)}

/* ── BOTONES ─────────────────────────────────────────────── */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:7px;padding:9px 16px;border-radius:var(--radius);border:1px solid transparent;font-family:inherit;font-size:13.5px;font-weight:600;cursor:pointer;
  transition:transform .12s var(--ease),background var(--trans),border-color var(--trans),color var(--trans);white-space:nowrap;text-decoration:none;min-height:38px}
.btn:active{transform:scale(.97)}
.btn-primary{background:var(--accent);color:#fff}
.btn-primary:hover{background:var(--accent-hi);color:#fff}
.btn-blue{background:var(--accent-b);color:#fff}
.btn-blue:hover{filter:brightness(1.08)}
.btn-ghost{background:var(--bg-card);color:var(--text-sub);border-color:var(--border)}
.btn-ghost:hover{background:var(--surface-2);color:var(--text)}
.btn-danger{background:var(--accent-dim);color:var(--accent)}
.btn-danger:hover{background:var(--accent);color:#fff}
.btn-sm{padding:6px 12px;font-size:12.5px;min-height:32px}
.btn-xs{padding:4px 9px;font-size:11.5px;min-height:27px;border-radius:7px}
.btn:disabled{opacity:.45;cursor:not-allowed}
.btn-full{width:100%}

/* ── FORMS ───────────────────────────────────────────────── */
.form-group{display:flex;flex-direction:column;gap:6px;margin-bottom:15px}
.form-label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-sub)}
.form-control{background:var(--bg-input);border:1px solid var(--border);color:var(--text);border-radius:var(--radius);padding:10px 13px;font-size:13.5px;font-family:inherit;outline:none;width:100%;transition:border-color var(--trans);min-height:40px}
.form-control:focus{border-color:var(--accent)}
.form-control::placeholder{color:var(--text-muted)}
input[type=checkbox],input[type=radio]{accent-color:var(--accent);width:16px;height:16px;cursor:pointer;flex:none}
textarea.form-control{min-height:80px;line-height:1.5}
select.form-control{cursor:pointer}
.form-row{display:grid;gap:13px}
.form-row-2{grid-template-columns:1fr 1fr}
.form-row-3{grid-template-columns:1fr 1fr 1fr}
.form-row-4{grid-template-columns:1fr 1fr 1fr 1fr}

/* ── ALERTS ──────────────────────────────────────────────── */
.alert{padding:12px 16px;border-radius:var(--radius);font-size:13px;margin-bottom:16px;display:flex;align-items:center;gap:8px;border:1px solid transparent}
.alert-danger{background:rgba(239,68,68,.08);border-color:rgba(239,68,68,.25);color:var(--accent-r)}
.alert-success{background:rgba(54,179,126,.09);border-color:rgba(54,179,126,.25);color:var(--accent-g)}
.alert-info{background:rgba(91,141,255,.09);border-color:rgba(91,141,255,.25);color:var(--accent-b)}
.alert-warn{background:rgba(224,168,58,.09);border-color:rgba(224,168,58,.25);color:var(--accent-a)}

/* ── MODAL ───────────────────────────────────────────────── */
.modal-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.6);backdrop-filter:blur(3px);z-index:500;align-items:center;justify-content:center;padding:20px}
.modal-overlay.show{display:flex;animation:fadein .2s var(--ease)}
.modal{background:var(--bg-card);border:1px solid var(--border-md);border-radius:14px;width:100%;max-width:680px;max-height:88vh;overflow-y:auto;box-shadow:var(--shadow);animation:modalrise .26s var(--ease)}
@keyframes modalrise{from{opacity:0;transform:translateY(12px) scale(.98)}to{opacity:1;transform:none}}
.modal-header{padding:17px 20px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}
.modal-title{font-size:15px;font-weight:700;color:var(--text);letter-spacing:-.01em}
.modal-close{background:none;border:none;color:var(--text-muted);font-size:20px;cursor:pointer;padding:4px;min-width:40px;min-height:40px;display:flex;align-items:center;justify-content:center;border-radius:8px;transition:var(--trans)}
.modal-close:hover{color:var(--text);background:var(--surface-2)}
.modal-body{padding:20px}
.modal-footer{padding:15px 20px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:8px;flex-wrap:wrap}

/* ── LOGIN ───────────────────────────────────────────────── */
.login-page{min-height:100vh;display:grid;place-items:center;background:var(--bg);padding:24px;position:relative}
.login-page::before{content:"";position:fixed;inset:0;pointer-events:none;background:radial-gradient(620px 420px at 50% -8%,var(--accent-dim),transparent 70%)}
.login-box{position:relative;width:100%;max-width:400px;background:var(--bg-card);border:1px solid var(--border);border-radius:18px;padding:40px 34px;box-shadow:var(--shadow);animation:modalrise .5s var(--ease)}
.login-logo{text-align:center;margin-bottom:30px;display:flex;flex-direction:column;align-items:center}
.login-logo .logo-c{width:138px;height:auto;object-fit:contain;margin-bottom:14px}
.login-logo .icon{width:84px;height:84px;background:var(--accent);border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:38px;color:#fff;font-weight:900;margin-bottom:14px;box-shadow:0 8px 26px rgba(229,50,26,.4)}
.login-logo h1{font-size:21px;font-weight:800;color:var(--text);letter-spacing:-.02em}
.login-logo h1 span{color:var(--accent)}
.login-logo p{color:var(--text-muted);font-size:12.5px;margin-top:5px}
.theme-fab{position:fixed;top:20px;right:20px;z-index:5}

/* ── TOAST ───────────────────────────────────────────────── */
#toast-container{position:fixed;bottom:20px;right:18px;z-index:9999;display:flex;flex-direction:column;gap:9px}
.toast{padding:12px 17px;border-radius:var(--radius);font-size:13px;font-weight:600;color:#fff;box-shadow:var(--shadow);animation:toastIn .24s var(--ease) forwards;max-width:320px}
.toast-success{background:var(--accent-g)}
.toast-error{background:var(--accent-r)}
.toast-info{background:var(--accent-b)}
@keyframes toastIn{from{transform:translateX(110px);opacity:0}to{transform:none;opacity:1}}

/* ── PRODUCCION ──────────────────────────────────────────── */
.prod-table{width:100%;border-collapse:collapse}
.prod-table th{padding:11px 12px;border-bottom:1px solid var(--border);font-size:10.5px;font-weight:600;text-transform:uppercase;letter-spacing:.07em;color:var(--text-muted);text-align:center}
.prod-table th:first-child{text-align:left}
.prod-table td{padding:9px 10px;border-bottom:1px solid var(--border);vertical-align:middle}
.prod-table td:first-child{font-weight:600;color:var(--text);padding-left:14px}
.prod-table tbody tr:last-child td{border-bottom:none}
.prod-input{width:74px;background:var(--bg-input);border:1px solid var(--border);color:var(--text);border-radius:7px;padding:7px 6px;font-size:14px;font-weight:700;text-align:center;outline:none;display:block;margin:0 auto;min-height:40px;transition:border-color var(--trans);font-family:var(--mono)}
.prod-input:focus{border-color:var(--accent)}

/* ── MENU CICLICO ────────────────────────────────────────── */
.menu-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:7px}
.menu-day{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden}
.menu-day-header{background:var(--surface-2);padding:6px;font-size:10px;font-weight:700;text-align:center;color:var(--accent);border-bottom:1px solid var(--border)}
.menu-comida{padding:6px;border-bottom:1px solid var(--border);min-height:46px}
.menu-comida:last-child{border-bottom:none}
.menu-comida-label{font-size:8px;font-weight:700;text-transform:uppercase;margin-bottom:3px}
.menu-receta-tag{font-size:8.5px;background:var(--accent-dim);color:var(--accent);border-radius:4px;padding:2px 6px;margin-bottom:2px;display:flex;align-items:center;gap:2px;cursor:pointer}
.menu-receta-tag:hover{background:var(--accent);color:#fff}
.menu-add-btn{font-size:8.5px;color:var(--text-muted);cursor:pointer;padding:2px 0}
.menu-add-btn:hover{color:var(--accent)}

/* ── STOCK ───────────────────────────────────────────────── */
.stock-bar-wrap{display:flex;align-items:center;gap:8px}
.stock-bar{width:48px;height:4px;background:var(--surface-hi);border-radius:2px;overflow:hidden}
.stock-bar-fill{height:100%;border-radius:2px}

/* ── FILTER BAR ──────────────────────────────────────────── */
.filter-bar{display:flex;gap:8px;align-items:center;margin-bottom:16px;flex-wrap:wrap}
.filter-bar .form-control{width:auto}

/* ── COMIDA TABS ─────────────────────────────────────────── */
.comida-tabs{display:flex;gap:5px;margin-bottom:16px;flex-wrap:wrap}
.comida-tab{padding:8px 16px;border-radius:8px;border:1px solid var(--border);background:var(--bg-card);color:var(--text-sub);font-size:13px;font-weight:600;cursor:pointer;min-height:38px;transition:var(--trans)}
.comida-tab.active-des{border-color:rgba(245,158,11,.4);background:rgba(245,158,11,.1);color:var(--accent-a)}
.comida-tab.active-alm{border-color:rgba(34,197,94,.4);background:rgba(34,197,94,.1);color:var(--accent-g)}
.comida-tab.active-cen{border-color:rgba(167,139,250,.4);background:rgba(167,139,250,.1);color:var(--accent-p)}

/* ── INSUMO ROW ──────────────────────────────────────────── */
.insumo-row{display:grid;grid-template-columns:1fr 110px 80px 80px auto;gap:8px;align-items:center;padding:6px 0;border-bottom:1px solid var(--border)}
.insumo-row:last-child{border-bottom:none}

/* ── COLORS ──────────────────────────────────────────────── */
.c-green{color:var(--accent-g)}.c-blue{color:var(--accent-b)}.c-red{color:var(--accent-r)}
.c-amber{color:var(--accent-a)}.c-orange{color:var(--accent-o)}.c-purple{color:var(--accent-p)}
.c-muted{color:var(--text-muted)}.c-white{color:var(--text)}
/* Las mismas clases, con la especificidad suficiente para ganarle a `.data-table td`.
   Sin esto no pintaban DENTRO de una tabla: `.data-table td` es (0,1,1) y declara
   color:var(--text-sub), mientras que `.c-red` es (0,1,0) — gana el td y el color se pierde en
   silencio. Llevaba así desde siempre, y se comía avisos que sí importan: las facturas vencidas de
   cuentas_pagar.php:140, el stock insuficiente de produccion.php y los montos de consolidado.php.
   Es el mismo tratamiento que `.num` ya tenía escrito como `.data-table td.num` (línea 35). */
.data-table td.c-green{color:var(--accent-g)}.data-table td.c-blue{color:var(--accent-b)}
.data-table td.c-red{color:var(--accent-r)}.data-table td.c-amber{color:var(--accent-a)}
.data-table td.c-orange{color:var(--accent-o)}.data-table td.c-purple{color:var(--accent-p)}
.data-table td.c-muted{color:var(--text-muted)}.data-table td.c-white{color:var(--text)}

/* ════════════ RESPONSIVE ════════════ */
@media(max-width:1100px){.kpi-grid{grid-template-columns:repeat(2,1fr)}}
@media(max-width:860px){
  .app{grid-template-columns:1fr}
  .sidebar{position:fixed;left:0;top:0;width:272px;transform:translateX(-100%);transition:transform .26s var(--ease)}
  .sidebar.open{transform:none;box-shadow:0 0 50px rgba(0,0,0,.5)}
  .hamburger{display:grid}
  .page-content{padding:18px 16px 36px}
  .section-header-left h2{font-size:20px}
  .topbar{padding:0 16px}
  .menu-grid{grid-template-columns:repeat(3,1fr);gap:5px}
  .form-row-2,.form-row-3,.form-row-4{grid-template-columns:1fr}
  .section-header{align-items:stretch}
  .section-header .btn{width:100%}
  .hide-mobile{display:none!important}
}
@media(max-width:520px){
  .kpi-grid{grid-template-columns:1fr}
  .crumb{font-size:15px}
  .topbar-clock .tc-date{display:none}   /* en móvil queda solo la hora */
  .menu-grid{grid-template-columns:repeat(2,1fr)}
  .data-table th,.data-table td{padding:10px 12px;font-size:12.5px}
}
@media(max-width:768px){
  .modal-overlay{align-items:flex-end;padding:0}
  .modal{border-radius:16px 16px 0 0;max-width:100%;max-height:92vh}
  .modal-footer{flex-direction:column}
  .modal-footer .btn{width:100%}
}

/* Rol de programación */
.rol-scroll{overflow-x:auto;overflow-y:visible;max-width:100%}
.rol-grid{border-collapse:separate;border-spacing:0;font-size:12px}
.rol-grid th,.rol-grid td{border-bottom:1px solid var(--border);padding:0}
.rol-sticky{position:sticky;left:0;z-index:2;background:var(--bg-card);text-align:left;
  min-width:230px;max-width:230px;padding:6px 10px;border-right:1px solid var(--border-md)}
.rol-head{z-index:3}
.rol-grid thead th{position:sticky;top:0;z-index:1;background:var(--bg-card)}
.rol-grid thead th.rol-sticky{z-index:3}
.rol-nombre{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rol-meta{display:flex;gap:6px;align-items:center;margin-top:2px;font-size:11px}
.rol-dia{width:30px;min-width:30px;text-align:center;padding:4px 0;font-family:var(--mono);font-size:10px}
.rol-dow{display:block;color:var(--text-muted)}
.rol-num{display:block;font-weight:600}
.rol-finde .rol-dow,.rol-finde .rol-num{color:var(--accent-a)}
.rol-feriado{background:var(--accent-dim)}
.rol-feriado .rol-dow,.rol-feriado .rol-num{color:var(--accent)}
.rol-celda.rol-feriado:hover{background:var(--accent-dim)}
.rol-celda{width:30px;min-width:30px;height:30px;text-align:center;cursor:pointer;
  user-select:none;transition:background .08s}
.rol-celda:hover{background:var(--surface-2)}
.rol-celda .badge{padding:1px 3px;font-size:9px;width:100%;display:block}
.rol-semana{border-left:2px solid var(--border-md)}
.rol-celda.rol-guardando{opacity:.45}
.rol-celda.rol-error{background:var(--accent-dim);outline:1px solid var(--accent)}
.rol-celda.rol-activa{outline:2px solid var(--accent);outline-offset:-2px;position:relative;z-index:1}

/* Inventario: pills de resumen (filtran por estado) + cards coloreadas por estado */
.inv-pills{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:18px}
.inv-pill{display:flex;align-items:center;gap:9px;padding:10px 16px;border-radius:var(--radius-lg);
  border:1px solid var(--border);background:var(--bg-card);cursor:pointer;font-size:12.5px;font-weight:600;
  color:var(--text-sub);transition:border-color var(--trans),background var(--trans);font-family:inherit}
.inv-pill:hover{border-color:var(--border-md)}
.inv-pill-count{font-family:var(--mono);font-feature-settings:"tnum";font-size:17px;font-weight:700;color:var(--text)}
.inv-pill--ok{border-color:color-mix(in srgb,var(--accent-g) 32%,var(--border))}
.inv-pill--ok .inv-pill-count{color:var(--accent-g)}
.inv-pill--ok.active{background:color-mix(in srgb,var(--accent-g) 15%,var(--bg-card));border-color:var(--accent-g)}
.inv-pill--low{border-color:color-mix(in srgb,var(--accent-a) 32%,var(--border))}
.inv-pill--low .inv-pill-count{color:var(--accent-a)}
.inv-pill--low.active{background:color-mix(in srgb,var(--accent-a) 15%,var(--bg-card));border-color:var(--accent-a)}
.inv-pill--zero{border-color:color-mix(in srgb,var(--accent) 32%,var(--border))}
.inv-pill--zero .inv-pill-count{color:var(--accent)}
.inv-pill--zero.active{background:color-mix(in srgb,var(--accent) 15%,var(--bg-card));border-color:var(--accent)}

/* Card de inventario: angosto, pintado por completo con el color del estado,
   línea medidora con marca del mínimo (tick), stock a la derecha y último movimiento. */
.inv-card{position:relative;display:flex;flex-direction:column;gap:8px;text-decoration:none;color:inherit;
  padding:11px 12px 10px;border-radius:var(--radius-lg);border:1px solid var(--border);background:var(--bg-card);
  transition:border-color var(--trans),transform var(--trans)}
.inv-card:hover{transform:translateY(-2px)}
.inv-card--ok{background:color-mix(in srgb,var(--accent-g) 14%,var(--bg-card));
  border-color:color-mix(in srgb,var(--accent-g) 30%,var(--border))}
.inv-card--low{background:color-mix(in srgb,var(--accent-a) 14%,var(--bg-card));
  border-color:color-mix(in srgb,var(--accent-a) 32%,var(--border))}
.inv-card--zero{background:color-mix(in srgb,var(--accent) 14%,var(--bg-card));
  border-color:color-mix(in srgb,var(--accent) 32%,var(--border))}
.inv-card--ok:hover{border-color:var(--accent-g)}
.inv-card--low:hover{border-color:var(--accent-a)}
.inv-card--zero:hover{border-color:var(--accent)}

.inv-card-top{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
.inv-card-name{font-size:12.5px;line-height:1.22;font-weight:700;color:var(--text);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.inv-card-stock{flex-shrink:0;text-align:right;line-height:1}
.inv-card-stock-n{font-family:var(--mono);font-feature-settings:"tnum";letter-spacing:-.02em;
  font-size:17.5px;font-weight:700;color:var(--text)}
.inv-card--zero .inv-card-stock-n{color:var(--accent)}
.inv-card-unidad{display:block;font-size:10px;font-weight:500;color:var(--text-sub);margin-top:3px}

.inv-gauge{position:relative;height:6px;border-radius:4px;background:var(--border-md)}
.inv-gauge-fill{position:absolute;left:0;top:0;bottom:0;border-radius:4px}
.inv-gauge-fill--ok{background:var(--accent-g)}
.inv-gauge-fill--low{background:var(--accent-a)}
.inv-gauge-fill--zero{background:var(--accent)}
.inv-gauge-fill--red{background:var(--accent-r)}
.inv-gauge-tick{position:absolute;top:-3px;bottom:-3px;left:50%;width:2px;border-radius:2px;
  background:var(--text-muted);transform:translateX(-1px)}

.inv-card-mov{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--text-sub);min-width:0}
.inv-card-mov svg{width:13px;height:13px;flex-shrink:0}
.inv-card-mov .mv-in{color:var(--accent-g)}
.inv-card-mov .mv-out{color:var(--accent)}
.inv-card-mov .mv-lbl{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.inv-card-mov .mv-when{color:var(--text-muted);flex-shrink:0;margin-left:auto;padding-left:8px}
.inv-card-mov .mv-none{color:var(--text-muted)}
@media(prefers-reduced-motion:reduce){.inv-card{transition:none}.inv-card:hover{transform:none}}

/* ── Tipo de movimiento como botones (form de movimiento + modal) ── */
.mov-types{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.mov-type{display:flex;flex-direction:column;align-items:center;gap:5px;padding:10px 6px;border-radius:10px;
  border:1px solid var(--border);background:var(--bg-input);color:var(--text-sub);cursor:pointer;
  font-size:12px;font-weight:600;font-family:inherit;transition:border-color var(--trans),color var(--trans),background var(--trans)}
.mov-type svg{width:17px;height:17px}
.mov-type:hover{color:var(--text);border-color:var(--border-md)}
.mov-type.on{border-width:1.5px}
.mov-type.on.g{color:var(--accent-g);border-color:var(--accent-g);background:color-mix(in srgb,var(--accent-g) 13%,var(--bg-card))}
.mov-type.on.r{color:var(--accent);border-color:var(--accent);background:color-mix(in srgb,var(--accent) 13%,var(--bg-card))}
.mov-type.on.o{color:var(--accent-o);border-color:var(--accent-o);background:color-mix(in srgb,var(--accent-o) 13%,var(--bg-card))}
.mov-type.on.b{color:var(--accent-b);border-color:var(--accent-b);background:color-mix(in srgb,var(--accent-b) 13%,var(--bg-card))}

/* ── Combobox con búsqueda en vivo (destino de salida) ── */
.combo{position:relative}
.combo-caret{position:absolute;right:12px;top:12px;width:16px;height:16px;color:var(--text-muted);pointer-events:none}
.combo-list{position:absolute;left:0;right:0;top:calc(100% + 4px);background:var(--bg-card);border:1px solid var(--border-md);
  border-radius:9px;box-shadow:var(--shadow);max-height:190px;overflow-y:auto;z-index:30;display:none;padding:4px}
.combo-list.open{display:block}
.combo-opt{padding:8px 11px;border-radius:7px;font-size:13px;cursor:pointer;color:var(--text)}
.combo-opt:hover{background:var(--surface-2)}
.combo-empty{padding:8px 11px;font-size:12px;color:var(--text-muted)}

/* Modal "Reemplazar en recetas": el combo-list es el último elemento del modal-body y .modal
   trae overflow-y:auto, así que la lista quedaba recortada contra el borde del modal (mismo
   problema que .card--oc-lineas resolvió con overflow:visible). Acotado a este modal por id
   para no cambiar el scroll de los demás modales del sistema.
   Pero quitarle el overflow al modal también le quita su scroll, y el cuerpo lista TODAS las
   recetas que usan el producto: con muchas, el pie ("Reemplazar y eliminar") quedaba fuera de
   pantalla y era inalcanzable. Se resuelve por los dos lados: (1) la lista de recetas tiene su
   propio tope con scroll, que es lo único que crece sin límite; (2) el overlay desplaza, con el
   modal centrado por márgenes automáticos — que se resuelven a 0 cuando no hay espacio libre,
   así el modal se pega arriba en vez de salirse por el borde. */
#modalReemplazo{overflow-y:auto}
#modalReemplazo.show{align-items:flex-start}
#modalReemplazo .modal{overflow:visible;max-height:none;margin:auto 0;flex-shrink:0}
#repRecetas{max-height:min(34vh,220px);overflow-y:auto}
/* En móvil los modales son hoja inferior (@media 768px, más abajo). Como estas reglas van por id
   le ganan a las de la media query, así que hay que devolver el pegado abajo acá: con
   margin-top:auto, no con align-items:flex-end — el margen automático se resuelve a 0 cuando no
   hay espacio libre, así que si la hoja no cabe se pega arriba y sigue alcanzable entera, en vez
   de dejar su borde superior fuera de la pantalla. */
@media(max-width:768px){
  #modalReemplazo .modal{margin:auto 0 0}
  #repRecetas{max-height:min(28vh,180px)}
}

/* ── Caja de contexto del modal: teñida por estado + franja de último movimiento ── */
.mov-ctx{border-radius:10px;overflow:hidden;border:1px solid var(--border);background:var(--surface-2);font-size:13px;color:var(--text)}
.mov-ctx--ok{background:color-mix(in srgb,var(--accent-g) 12%,var(--bg-card));border-color:color-mix(in srgb,var(--accent-g) 28%,var(--border))}
.mov-ctx--low{background:color-mix(in srgb,var(--accent-a) 12%,var(--bg-card));border-color:color-mix(in srgb,var(--accent-a) 28%,var(--border))}
.mov-ctx--zero{background:color-mix(in srgb,var(--accent) 12%,var(--bg-card));border-color:color-mix(in srgb,var(--accent) 28%,var(--border))}
.mov-ctx-body{padding:12px 14px}
.mov-ctx-strip{display:flex;align-items:center;gap:7px;padding:9px 14px;font-size:12px;font-weight:500}
.mov-ctx-strip svg{width:14px;height:14px;flex-shrink:0}
.mov-ctx-strip .when{margin-left:auto;opacity:.85;font-weight:400}
.mov-ctx-strip b{color:inherit;font-weight:700}
.mov-ctx-strip--in{background:color-mix(in srgb,var(--accent-g) 20%,transparent);color:var(--accent-g)}
.mov-ctx-strip--out{background:color-mix(in srgb,var(--accent) 20%,transparent);color:var(--accent)}
.mov-ctx-strip--none{background:var(--surface-2);color:var(--text-muted)}

/* ── Modos masivos de la vista de tabla (conteo/salidas/ingresos) ── */
.modebar{display:flex;gap:6px;flex-wrap:wrap}
.mode-btn{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:600;padding:6px 12px;min-height:32px;
  border-radius:9px;border:1px solid var(--border);background:var(--bg-card);color:var(--text-sub);cursor:pointer;font-family:inherit;transition:var(--trans)}
.mode-btn svg{width:15px;height:15px}
.mode-btn:hover{color:var(--text);border-color:var(--border-md)}
.mode-btn.c{border-color:color-mix(in srgb,var(--accent-a) 40%,var(--border));color:var(--accent-a)}
.mode-btn.s{border-color:color-mix(in srgb,var(--accent) 40%,var(--border));color:var(--accent)}
.mode-btn.i{border-color:color-mix(in srgb,var(--accent-g) 40%,var(--border));color:var(--accent-g)}
.mode-btn.active{color:#fff}
.mode-btn.active.c{background:var(--accent-a);border-color:var(--accent-a)}
.mode-btn.active.s{background:var(--accent);border-color:var(--accent)}
.mode-btn.active.i{background:var(--accent-g);border-color:var(--accent-g)}

.modealert{display:none;align-items:center;gap:14px;flex-wrap:wrap;padding:11px 15px;border-radius:11px;
  border:1px solid var(--border-md);background:var(--bg-card);margin-bottom:16px;font-size:13px}
.modealert.on{display:flex}
.modealert.mode-c{border-color:color-mix(in srgb,var(--accent-a) 35%,var(--border));background:color-mix(in srgb,var(--accent-a) 7%,var(--bg-card))}
.modealert.mode-s{border-color:color-mix(in srgb,var(--accent) 35%,var(--border));background:color-mix(in srgb,var(--accent) 7%,var(--bg-card))}
.modealert.mode-i{border-color:color-mix(in srgb,var(--accent-g) 35%,var(--border));background:color-mix(in srgb,var(--accent-g) 7%,var(--bg-card))}
.modealert .desc b{font-weight:700}
.modealert .ma-spacer{margin-left:auto}
.modealert .ma-field{display:flex;align-items:center;gap:7px}
.modealert .ma-field label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--text-sub);white-space:nowrap}
.modealert .form-control{min-height:34px;padding:6px 10px;font-size:13px;width:auto}

/* columnas que aparecen/ocultan según el modo */
.inv-tabla .col-input,.inv-tabla .col-diff{display:none}
.inv-tabla.mode-on .col-input,.inv-tabla.mode-on .col-diff{display:table-cell}
.inv-tabla.mode-on .col-valor{display:none}
/* El costo es por FILA y SOLO del modo «Ingresos»: un conteo no es una compra y una salida
   consume lotes que ya traen su costo. Por eso no cuelga de .mode-on como las de arriba. */
.inv-tabla .col-costo{display:none}
.inv-tabla.mode-i .col-costo{display:table-cell}
/* Borrar recarga la página y se llevaría por delante las cantidades tecleadas del modo masivo:
   la ✕ y las casillas se esconden mientras haya un modo activo, igual que las columnas de
   arriba (la barra "Eliminar seleccionados" la limpia setMode(), vive fuera de la tabla). */
.inv-tabla.mode-on .inv-col-del,.inv-tabla.mode-on .inv-col-sel{display:none}
.inv-tabla.mode-c .col-input.mode-th,.inv-tabla.mode-c .col-diff.mode-th{color:var(--accent-a)}
.inv-tabla.mode-s .col-input.mode-th,.inv-tabla.mode-s .col-diff.mode-th{color:var(--accent)}
.inv-tabla.mode-i .col-input.mode-th,.inv-tabla.mode-i .col-diff.mode-th,
.inv-tabla.mode-i .col-costo.mode-th{color:var(--accent-g)}
.cinp,.kinp{width:104px;background:var(--bg-input);border:1px solid var(--border-md);color:var(--text);border-radius:7px;
  padding:6px 9px;font-size:13px;font-family:var(--mono);font-feature-settings:"tnum";text-align:right;outline:none}
.cinp:focus,.kinp:focus{border-color:var(--accent)}
.cinp.changed{border-color:currentColor}
/* El costo es opcional y secundario frente a la cantidad: más angosto y sin el resalte de
   .changed —no es un cambio de stock, es el precio del que sí lo es—. */
.kinp{width:92px}
.kinp::placeholder{font-family:'Inter',sans-serif;font-size:11.5px;color:var(--text-muted)}
.diff{font-family:var(--mono);font-feature-settings:"tnum";font-weight:700;font-size:12.5px}
.diff-plus{color:var(--accent-g)}.diff-minus{color:var(--accent)}.diff-zero{color:var(--text-muted)}
.neg-hint{font-size:10.5px;color:var(--accent);font-weight:600}

.savebar{position:fixed;left:var(--sidebar-w);right:0;bottom:0;display:none;align-items:center;justify-content:space-between;gap:14px;
  padding:12px 28px;background:color-mix(in srgb,var(--bg-card) 92%,transparent);backdrop-filter:blur(10px);
  border-top:1px solid var(--border-md);z-index:120}
.savebar.on{display:flex}
.savebar .cnt{font-size:13px;color:var(--text-sub)}
.savebar .cnt b{color:var(--text);font-weight:700;font-family:var(--mono)}
.savebar #saveBtn{color:#fff}
.savebar.mode-c #saveBtn{background:var(--accent-a)}
.savebar.mode-s #saveBtn{background:var(--accent)}
.savebar.mode-i #saveBtn{background:var(--accent-g)}
.savebar #saveBtn:disabled{opacity:.45;cursor:not-allowed}
@media(max-width:820px){.savebar{left:0}}
.rol-celda.rol-error.rol-activa{background:var(--accent-dim)}

/* ── Interacciones tipo Excel del rol ── */
.rol-fill-handle{position:absolute;right:-2px;bottom:-2px;width:8px;height:8px;background:var(--accent);
  border:1px solid var(--bg-card);cursor:crosshair;z-index:5}
.rol-celda.rol-sel{background:color-mix(in srgb,var(--accent) 16%,transparent);
  outline:1px solid color-mix(in srgb,var(--accent) 45%,transparent);outline-offset:-1px;position:relative}
.rol-tip{position:fixed;z-index:600;pointer-events:none;background:var(--text);color:var(--bg);
  font-size:11px;font-weight:600;padding:3px 8px;border-radius:6px;font-family:var(--mono);
  white-space:nowrap;box-shadow:0 4px 14px rgba(0,0,0,.35)}
.rol-menu{position:fixed;z-index:650;background:var(--bg-card);border:1px solid var(--border-md);
  border-radius:10px;box-shadow:var(--shadow);padding:4px;max-height:64vh;overflow:auto;min-width:160px}
.rol-menu button{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:none;border:none;
  color:var(--text);font-family:inherit;font-size:12.5px;padding:6px 9px;border-radius:6px;cursor:pointer}
.rol-menu button:hover{background:var(--surface-2)}
.rol-menu .badge{flex-shrink:0}

/* ── CAPTURA DE LÍNEAS (includes/lineas_captura.php) ────────────────── */
/* Nació con la orden de compra —de ahí el prefijo oc- de las clases— y hoy la comparte
   cualquier documento que capture líneas de productos (la guía de remisión, sin costo). */
/* Card propia (no .card general): necesita overflow visible para que el combo-list
   de búsqueda no se recorte contra el borde de la card ni del table-wrap (overflow-x:auto
   computa overflow-y:auto por la regla del spec CSS de "un solo eje visible = auto"). */
.card--oc-lineas{overflow:visible}
.card--oc-lineas .table-wrap{overflow:visible}
.oc-lineas td{vertical-align:top}
.oc-lineas .combo-list{max-height:260px;overflow-y:auto;z-index:60}
.oc-lineas .combo-opt{display:flex;justify-content:space-between;gap:10px;align-items:baseline}
.oc-opt-precio{font-family:var(--mono);font-size:12px;color:var(--text-muted);white-space:nowrap}
/* La opción de la captura de líneas puede llevar tres piezas —nombre, código y precio— y
   .combo-opt reparte con space-between: sin esto el código quedaría flotando en mitad de la
   fila. El nombre se lleva el espacio sobrante y los dos datos en mono quedan juntos a la
   derecha, como en el combobox compartido. min-width:0 deja que el nombre largo se ajuste
   (sigue partiendo en varias líneas, que en una columna estrecha es mejor que recortarlo). */
.lc-opt>span:first-child{flex:1 1 auto;min-width:0}
.combo-more{padding:8px 11px;font-size:11.5px;color:var(--text-muted)}
.combo-opt.activo{background:color-mix(in srgb,var(--accent) 16%,var(--surface-2));
  outline:1.5px solid var(--accent);outline-offset:-1.5px}
.oc-ayuda{padding:10px 16px;font-size:12px;border-top:1px solid var(--border)}
/* Recepción por entregas: la línea que ya llegó completa en una entrega anterior. Sin color
   semántico a propósito —lo recibido no es "bueno" ni "malo", es pasado—: el verde y el rojo
   de la casa significan otra cosa y reutilizarlos aquí los desafilaría. La opacidad y el
   tachado ya lo dicen todo. */
.oc-linea-lista{opacity:.62}
.oc-linea-lista s{text-decoration-thickness:1px}
.oc-linea-falta{color:var(--text-muted);font-size:11.5px;margin-top:4px}
/* «Llegó todo» / «Llegó por partes». La columna de casillas y el campo de cantidad son del
   segundo modo. Se emiten las dos cosas y manda el CSS: alternar por JS el `name` o el
   `disabled` de un input es justo como se cuela un campo que viaja cuando no debía. */
.oc-lineas.modo-todo .col-chk{display:none}
/* La columna «Recibido» se queda EN LOS DOS MODOS desde el 2026-08-03. «Llegó todo» era un botón
   ciego —entraba lo pendiente y no había nada que teclear— y no dejaba corregir una línea que
   llegó de más o de menos. Ahora los dos modos dejan escribir cantidades; lo que los distingue es
   si falta otra entrega, no si se pueden tocar los números. */
/* La columna «Falta» es la guía de lectura mientras se teclea al lado: mono para que los
   dígitos se alineen, y la unidad en tenue para que no compita con la cifra. */
.oc-c-falta{white-space:nowrap}
.oc-falta-num{font-family:var(--mono);color:var(--text-sub)}
.oc-falta-ud{color:var(--text-muted);font-size:11.5px}
.oc-footbar{display:flex;align-items:center;justify-content:flex-end;gap:16px;flex-wrap:wrap}
.oc-footbar-total{font-weight:700;color:var(--text)}
.oc-footbar-espacio{display:none}

@media(max-width:768px){
  /* Cada línea deja de ser fila y pasa a ser un bloque apilado: sin scroll horizontal. */
  .oc-lineas thead{display:none}
  .oc-lineas,.oc-lineas tbody,.oc-lineas tr,.oc-lineas td{display:block;width:100%}
  .oc-lineas tr{position:relative;padding:12px 14px 14px;border-bottom:1px solid var(--border)}
  .oc-lineas td{padding:0;border:none}
  .oc-lineas td.oc-c-prod{margin-bottom:8px;padding-right:76px}
  .oc-lineas .oc-c-cant,.oc-lineas .oc-c-costo{display:inline-block;width:calc(50% - 5px);vertical-align:top}
  .oc-c-cant{margin-right:8px}
  /* Sin columna de costo, la cantidad no comparte la línea con nadie. */
  .oc-lineas--sin-costo .oc-c-cant{width:100%;margin-right:0}
  .oc-c-cant::before{content:"Cantidad";display:block;font-size:11px;text-transform:uppercase;
    letter-spacing:.4px;color:var(--text-muted);margin-bottom:3px}
  .oc-c-costo::before{content:"Costo c/IGV";display:block;font-size:11px;text-transform:uppercase;
    letter-spacing:.4px;color:var(--text-muted);margin-bottom:3px}
  .oc-c-imp{margin-top:8px;text-align:right;font-family:var(--mono);font-weight:600}
  /* La casilla va anclada arriba a la izquierda, como el botón de quitar lo está a la derecha:
     de bloque propio se comería una línea entera por producto. El hueco solo se reserva en
     «por partes», que es cuando la casilla existe. */
  .oc-lineas .col-chk{position:absolute;top:12px;left:12px;width:auto;padding:2px}
  .oc-lineas.modo-partes td.oc-c-prod{padding-left:28px}
  .oc-lineas .col-chk input{width:20px;height:20px}
  /* «Falta» no compite por la fila con cantidad y costo —tres controles en 375px no caben—:
     va como línea propia encima, en pequeño, que es justo el papel de guía que tiene. */
  .oc-lineas .oc-c-falta{text-align:left;margin-bottom:6px}
  .oc-lineas .oc-c-falta::before{content:"Falta ";font-size:11px;text-transform:uppercase;
    letter-spacing:.4px;color:var(--text-muted)}
  .oc-lineas .oc-c-del{position:absolute;top:10px;right:12px;width:auto}
  .oc-c-del .btn{min-height:40px}
  .oc-lineas .combo-list{max-height:50vh}

  /* Total y acciones fijos al pie, siempre visibles mientras se teclea. */
  .oc-footbar{position:fixed;left:0;right:0;bottom:0;z-index:40;margin:0;padding:10px 14px;
    background:var(--bg-card);border-top:1px solid var(--border-md);
    box-shadow:0 -2px 12px rgba(0,0,0,.10);justify-content:space-between}
  /* Alto real fijado por JS (ver ajustarEspacioFootbar en includes/lineas_captura.php): la barra puede
     envolver a dos líneas en pantallas angostas y un número fijo la subestimaría. */
  .oc-footbar-espacio{display:block}
}

/* ── INVENTARIO: código de producto y buscador sobre la lista ─────────── */
.inv-cod{font-family:var(--mono);font-size:11px;color:var(--text-muted);margin-right:7px;letter-spacing:-.02em}
.inv-card-cod{display:block;font-family:var(--mono);font-size:10.5px;color:var(--text-muted);letter-spacing:-.02em;margin-bottom:2px}
.inv-cod-gen{font:inherit;font-size:10.5px;color:var(--accent);background:none;border:1px dashed var(--border-md);
  border-radius:6px;padding:1px 6px;margin-right:7px;cursor:pointer}
.inv-cod-gen:hover{background:var(--surface-2)}
/* max-width en el contenedor y no en el input: el botón de escanear se posiciona contra
   el contenedor, y si este midiera toda la fila el botón quedaría lejísimos del campo. */
.inv-buscador{margin:0 0 12px;position:relative;max-width:420px}
.inv-buscador .form-control{width:100%}

/* ── INVENTARIO: selección y borrado de productos ──────────────────────── */
.inv-col-sel{width:34px}
.inv-col-del{width:44px;text-align:right}
.inv-del-btn{font:inherit;font-size:13px;line-height:1;color:var(--text-muted);background:none;border:none;
  border-radius:6px;padding:4px 7px;cursor:pointer}
.inv-del-btn:hover{background:rgba(239,68,68,.12);color:var(--accent-r)}
.inv-selbar{display:flex;align-items:center;gap:10px;margin:0 0 12px;padding:8px 12px;
  background:var(--surface-2);border:1px solid var(--border-md);border-radius:10px;font-size:13px}

/* ── Utilidad genérica: ocultar un elemento (filtros JS que ocultan grupos completos) ── */
.ls-hide{display:none!important}

/* ── PROVEEDORES: lista agrupada por estado de deuda ────────────────────── */
.prov-group-header{display:flex;justify-content:space-between;align-items:baseline;gap:12px;
  padding:14px 18px;border-bottom:1px solid var(--border)}
.prov-group-title{font-size:13px;font-weight:700;color:var(--text)}
.prov-group-title b{font-family:var(--mono);font-feature-settings:"tnum";font-weight:700}
.prov-group-total{font-family:var(--mono);font-feature-settings:"tnum";font-variant-numeric:tabular-nums;
  font-weight:700;font-size:14px;color:var(--text);flex-shrink:0;white-space:nowrap}
.prov-group-total--deuda{color:var(--accent-r)}
/* Etiqueta que dice QUÉ suma la cabecera: en la misma ranura visual un grupo muestra
   deuda y el otro total comprado, y sin esto no hay forma de saber cuál es cuál. */
.prov-group-total-label{font-family:'Inter',sans-serif;font-weight:600;font-size:10px;
  text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin-right:6px}

.prov-row{display:flex;align-items:center;gap:16px;padding:14px 18px;border-bottom:1px solid var(--border)}
.prov-row:last-child{border-bottom:none}
.prov-row-main{flex:1;min-width:0}
.prov-row-top{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.prov-name{font-weight:700;font-size:14px;color:var(--text)}
.prov-row-sub{font-size:12px;color:var(--text-muted);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.prov-row-gauge{margin-top:9px;max-width:360px}
.prov-row-amounts{flex-shrink:0;text-align:right;min-width:130px}
.prov-deuda-value{font-family:var(--mono);font-feature-settings:"tnum";font-variant-numeric:tabular-nums;
  font-size:17px;font-weight:700;color:var(--accent-r)}
.prov-comprado-value{font-size:11.5px;color:var(--text-muted);margin-top:2px}
.prov-row-actions{display:flex;gap:4px;flex-shrink:0}

.prov-row--slim{padding:9px 18px}
.prov-row--slim .prov-row-main{display:flex;align-items:baseline;gap:8px;min-width:0}
.prov-row--slim .prov-name{font-size:13px}
.prov-row--slim .prov-row-ruc{font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.prov-row--slim .prov-row-amounts{font-family:var(--mono);font-feature-settings:"tnum";font-variant-numeric:tabular-nums;
  font-size:12.5px;min-width:auto}

@media(max-width:768px){
  .prov-row{flex-wrap:wrap;row-gap:8px}
  .prov-row-main{flex-basis:100%}
  .prov-row-actions{order:2}
  .prov-row-amounts{order:3;margin-left:auto;text-align:right}
  .prov-row--slim .prov-row-main{display:block}
  .prov-row--slim .prov-row-ruc{display:block;margin-top:1px}
}

/* ── Combobox reutilizable (includes/combobox.php + assets/js/combobox.js) ──
   Solo lo que le falta al bloque base de arriba: el hueco para el caret, el dato
   secundario de la opción, la marca de obligatorio sin llenar y el toque en móvil. */
.combo-input{padding-right:34px}
.combo-opt{display:flex;justify-content:space-between;align-items:center;gap:10px}
.combo-opt-extra{font-family:var(--mono);font-size:11.5px;color:var(--text-muted);white-space:nowrap}
.combo-invalido .combo-input{border-color:var(--accent-r)}
@media(max-width:768px){.combo-opt{padding:12px 11px;min-height:44px}}
.combo-opt--inactiva span:first-child{opacity:.75}
.combo-opt-tag{font-family:var(--mono);font-size:10px;letter-spacing:.4px;text-transform:uppercase;
  color:var(--accent-a);border:1px solid var(--accent-a);border-radius:999px;padding:1px 6px;white-space:nowrap}
.combo-deshabilitado .combo-caret{opacity:.4}
.form-label-nota{font-weight:400;text-transform:none;letter-spacing:0;color:var(--text-muted)}

/* ── ESCÁNER DE CÓDIGOS POR CÁMARA (assets/js/escaner.js) ─────────────────────
   Capa a pantalla completa: el vídeo ocupa todo y el marco de guía marca lo que
   de verdad se decodifica (escaner.js recorta justo ese trozo del cuadro).
   Va por encima de los modales (z-index 500) porque se abre desde uno de ellos. */
.escaner-capa{position:fixed;inset:0;z-index:900;background:#000;overflow:hidden;
  display:flex;align-items:center;justify-content:center;animation:fadein .18s var(--ease)}
.escaner-video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;background:#000}

/* Marco de guía: apaisado, como el código de un empaque. */
.escaner-marco{position:relative;width:min(86vw,460px);height:min(34vh,190px);
  border:2px solid rgba(255,255,255,.9);border-radius:12px;
  box-shadow:0 0 0 100vmax rgba(0,0,0,.45);pointer-events:none}
.escaner-linea{position:absolute;left:8px;right:8px;top:50%;height:2px;border-radius:2px;
  background:var(--accent-hi);box-shadow:0 0 10px var(--accent-hi);
  animation:escanerBarrido 2s var(--ease) infinite alternate}
@keyframes escanerBarrido{from{transform:translateY(-70px)}to{transform:translateY(70px)}}
@media(prefers-reduced-motion:reduce){.escaner-linea{animation:none}}

.escaner-top{position:absolute;top:0;left:0;right:0;display:flex;align-items:center;
  justify-content:space-between;gap:12px;
  padding:max(12px,env(safe-area-inset-top)) max(14px,env(safe-area-inset-right)) 12px max(14px,env(safe-area-inset-left));
  background:linear-gradient(to bottom,rgba(0,0,0,.7),transparent)}
.escaner-titulo{color:#fff;font-size:14.5px;font-weight:700;letter-spacing:-.01em}
.escaner-cerrar{background:rgba(0,0,0,.45);border:1px solid rgba(255,255,255,.28);color:#fff;
  font-size:19px;line-height:1;cursor:pointer;border-radius:10px;
  min-width:46px;min-height:46px;display:grid;place-items:center;transition:var(--trans)}
.escaner-cerrar:hover{background:rgba(255,255,255,.16)}
.escaner-cerrar:focus-visible{outline:2px solid #fff;outline-offset:2px}

.escaner-pie{position:absolute;left:0;right:0;bottom:0;text-align:center;
  padding:16px max(14px,env(safe-area-inset-left)) max(18px,env(safe-area-inset-bottom));
  background:linear-gradient(to top,rgba(0,0,0,.72),transparent)}
.escaner-ayuda{color:#fff;font-size:13.5px;margin:0;text-shadow:0 1px 3px rgba(0,0,0,.6)}

/* Aviso (permiso denegado, sin cámara, la librería no cargó). Tapa el visor: si no se
   puede leer, el vídeo no pinta nada. */
.escaner-aviso{display:none}
.escaner-capa--aviso .escaner-aviso{display:block;position:relative;z-index:2;
  max-width:min(92vw,420px);background:var(--bg-card);border:1px solid var(--border-md);
  border-radius:14px;padding:22px 20px;box-shadow:var(--shadow);text-align:center}
.escaner-capa--aviso .escaner-marco,
.escaner-capa--aviso .escaner-pie{display:none}
.escaner-capa--aviso .escaner-video{opacity:.15}
.escaner-aviso-txt{color:var(--text);font-size:13.5px;margin:0 0 16px;line-height:1.55}
.escaner-aviso-btns{display:flex;gap:8px;justify-content:center;flex-wrap:wrap}
.escaner-btn{font-family:inherit;font-size:13px;font-weight:600;padding:10px 16px;min-height:44px;
  border-radius:9px;border:1px solid transparent;background:var(--accent);color:#fff;cursor:pointer;
  transition:var(--trans)}
.escaner-btn:hover{background:var(--accent-hi)}
.escaner-btn--ghost{background:var(--surface-2);color:var(--text);border-color:var(--border-md)}
.escaner-btn--ghost:hover{background:var(--surface-hi)}
.escaner-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* Pantallas bajitas en horizontal: el marco no puede comerse la capa entera. */
@media(max-height:420px){
  .escaner-marco{height:min(46vh,130px)}
  @keyframes escanerBarrido{from{transform:translateY(-45px)}to{transform:translateY(45px)}}
}

/* Botón de cámara dentro de un campo. La clase `escan-on` la pone escanerBoton() al
   dibujarlo: el hueco a la derecha solo existe si el botón existe, así un navegador
   que no puede escanear no se queda con un campo cojo y sin explicación. */
.escan-on{position:relative}
.escan-btn{position:absolute;right:5px;top:50%;transform:translateY(-50%);
  width:34px;height:34px;padding:0;display:grid;place-items:center;cursor:pointer;
  background:var(--surface-2);border:1px solid var(--border-md);border-radius:8px;
  color:var(--text-sub);transition:var(--trans)}
.escan-btn:hover{background:var(--surface-hi);color:var(--text)}
.escan-btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.escan-btn[disabled]{opacity:.55;cursor:default}
.escan-btn svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round}
.escan-on > .form-control{padding-right:46px}
/* Cuando el campo ya trae la flecha del desplegable, el botón la empuja (la clase la pone
   escanerBoton() al ver la flecha: no todos los buscadores usan las mismas clases). */
.escan-on--caret > .form-control{padding-right:78px}
.escan-on--caret > .combo-caret{right:48px}

/* Aviso de "ese código no está en el catálogo" (escanerNoEncontrado). */
.escan-dlg-caja{max-width:440px}
.escan-dlg-txt{margin:0 0 12px;font-size:13.5px;color:var(--text-sub);line-height:1.55}
.escan-dlg-codigo{font-family:var(--mono);font-size:19px;font-weight:700;color:var(--text);
  letter-spacing:.06em;word-break:break-all;background:var(--surface-2);
  border:1px solid var(--border);border-radius:10px;padding:12px 14px;text-align:center}

/* ── PARETO DE ANALÍTICA (modules/inv_analitica.php) ──────────────────────────
   Una sola serie = un solo color: esto mide magnitud, no identidad, así que
   todas las barras van en var(--accent) y no hay leyenda que poner (el título
   dice qué se mide). El acumulado va como número por fila, NO como una curva
   contra un segundo eje: un Pareto de libro es el ejemplo clásico de gráfico de
   doble eje, que es justo lo que no hay que dibujar.
   El texto lleva tokens de texto, nunca el color de la barra. */
/* La 4ª columna (%) es 52px y no 44px porque el porcentaje individual pasó a un decimal:
   «100.0%» son 6 glifos y JetBrains Mono avanza 0.6em, que a 12px da 43.2px — cabía en 44px por
   0.8px, y solo si la fuente es la buena. En el fallback genérico `monospace` (cualquier avance
   entre 0.6 y 0.65em) se salía. El 100.0% no es hipotético: agrupando por categoría o proveedor
   una sola fila puede ser todo. Los 8px salen de la columna del nombre, que ya recorta con elipsis.
   La 5ª (acumulado) sigue en 48px: se quedó en enteros. */
.pareto-fila{display:grid;grid-template-columns:1fr 110px minmax(80px,2fr) 52px 48px;
  gap:12px;align-items:center;padding:5px 0}
.pareto-nombre{color:var(--text);font-size:13px;font-weight:600;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pareto-valor{font-family:var(--mono);font-size:12.5px;color:var(--text-sub);text-align:right}
.pareto-barra{background:var(--surface-2);border-radius:5px;height:10px;overflow:hidden}
/* Punta redondeada solo del lado del dato, anclada a la línea de base. */
.pareto-barra>span{display:block;height:100%;background:var(--accent);
  border-radius:0 4px 4px 0;min-width:2px}
.pareto-pct{font-family:var(--mono);font-size:12px;color:var(--text-muted);text-align:right}
.pareto-acum{font-family:var(--mono);font-size:12px;color:var(--text-sub);text-align:right;font-weight:600}
/* La fila donde el acumulado cruza el 80%: el corte que da sentido al gráfico.
   Se marca con una línea y con la etiqueta, no con otro color de barra — cambiar
   el color de una barra por su posición haría que el color significara rango. */
.pareto-fila--corte{border-bottom:1.5px solid var(--border);padding-bottom:9px;margin-bottom:4px;position:relative}
.pareto-fila--corte::after{content:'80%';position:absolute;right:0;bottom:-9px;
  font-family:var(--mono);font-size:10px;color:var(--text-muted);background:var(--bg-card);padding:0 4px}
.pareto-resto{display:flex;justify-content:space-between;margin-top:14px;padding-top:10px;
  border-top:1px solid var(--border);font-size:12.5px;color:var(--text-muted)}
.pareto-resto span{font-family:var(--mono)}
@media(max-width:768px){
  /* Bajo 768px se caen el porcentaje individual y el nombre a una línea propia:
     cinco columnas no caben, y lo que no puede faltar es nombre, valor y acumulado. */
  .pareto-fila{grid-template-columns:1fr 44px;grid-template-areas:'nom nom' 'val acum' 'bar bar';gap:4px 8px;padding:8px 0}
  /* El `padding:8px 0` de la línea de arriba pisa el `padding-bottom:9px` de la fila del corte
     (misma especificidad, regla posterior) y con él se movía la línea contra la que se apoya la
     etiqueta «80%», que va anclada a -9px. Se repite acá para que el corte conserve su hueco. */
  .pareto-fila--corte{padding-bottom:9px}
  .pareto-nombre{grid-area:nom;white-space:normal}
  .pareto-valor{grid-area:val;text-align:left}
  .pareto-acum{grid-area:acum}
  .pareto-barra{grid-area:bar}
  .pareto-pct{display:none}
}

/* ── Analítica · vista Precios ────────────────────────────────────────────────
   El «recorrido» es la pieza que hace la vista: una barra de mín a máx con un punto en el último
   precio. Pegado a la izquierda = compraste en tu mejor precio del período; pegado a la derecha =
   en el peor. Se lee sin hacer ninguna cuenta, que es exactamente lo que un número solo no consigue.
   Los colores son SEMÁNTICOS —verde/ámbar/rojo significan estado— y NO el acento de marca, que es
   identidad: mezclarlos haría que el rojo dejara de significar una sola cosa en la pantalla.
   Los tokens usados (--accent-g/-a/-r, --bg-card, --border-md, --mono) están definidos tanto en
   :root como en el bloque claro; una var() inexistente no falla en CSS, hereda en silencio. */
/* Los números de estado usan clases PROPIAS y no los ayudantes globales .c-red/.c-amber/
   .c-green — pero YA NO es porque el ayudante pierda dentro de una tabla: esa trampa de
   especificidad (`.data-table td` a (0,1,1) contra el (0,1,0) del ayudante) se cerró en `2943bdc`
   («Los colores de estado vuelven a verse dentro de las tablas», 2026-07-31), que reescribió los
   ayudantes a esta misma (0,2,1) y **nombra explícitamente** `cuentas_pagar.php:140` y
   `produccion.php` —que este comentario daba por rotos— entre lo que vino a arreglar: los dos SÍ
   pintan hoy. Estas se quedan propias por su cuenta: el NOMBRE dice qué SIGNIFICA el color
   (`--grave`/`--alerta`/`--bien`), no de qué color es, y siguen escritas contra `.data-table td`
   (0,2,1), como el ayudante ya reparado. */
.data-table th.precio-r,.data-table td.precio-r{text-align:right}
.data-table td.precio-ultimo{color:var(--text);font-weight:600}
.data-table td.precio-num--grave{color:var(--accent-r)}
.data-table td.precio-num--alerta{color:var(--accent-a)}
.data-table td.precio-num--bien{color:var(--accent-g)}
.data-table td.precio-num--neutro{color:var(--text-muted)}
.precio-nombre{color:var(--text);font-size:13px;font-weight:600;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:280px}
.precio-meta{font-size:11.5px;color:var(--text-muted);margin-top:2px}
.precio-rango{display:flex;align-items:center;gap:8px}
.precio-rango-lim{font-family:var(--mono);font-size:10.5px;color:var(--text-muted);
  font-variant-numeric:tabular-nums;white-space:nowrap}
/* El riel es el recorrido entero (de mín a máx), no una barra de progreso: no se rellena.
   Rellenarlo se leería como «cuánto llevas», que acá no significa nada. */
.precio-riel{position:relative;flex:1;min-width:60px;height:5px;border-radius:3px;
  background:var(--border-md)}
/* El punto puede quedar en 0% o en 100%; el translate lo deja medio fuera del riel a propósito,
   que es justo la lectura de «pegado al extremo». El anillo del color de la card lo separa del
   riel para que no se confunda con él cuando cae al medio. */
.precio-punto{position:absolute;top:50%;width:11px;height:11px;border-radius:50%;
  transform:translate(-50%,-50%);border:2px solid var(--bg-card);box-shadow:0 0 0 1px var(--border)}
.precio-punto--bajo{background:var(--accent-g)}
.precio-punto--medio{background:var(--accent-a)}
.precio-punto--alto{background:var(--accent-r)}
/* Mín y máx coinciden: el recorrido es un punto, no hay «mejor» ni «peor» y el color no debe
   fingir que los hay. Gris y al centro. */
.precio-punto--plano{background:var(--text-muted)}
@media(max-width:768px){
  /* Los límites NO se ocultan. Antes sí, con el argumento de que el riel ya dice dónde caíste y
     las cifras son el detalle — pero sin ellas el riel no tiene escala: un punto a media altura
     de un recorrido de 0,10 y uno de 40,00 se ven idénticos, y el único otro portador de la cifra
     es el `title` del punto, que en táctil NO EXISTE. En el almacén se usa el móvil, así que la
     columna que hace la vista quedaba ahí como un riel con un punto y ni una referencia numérica.
     Se encogen en vez de esconderse (y no se pasan a la línea secundaria del producto, que habría
     obligado a pintar el mismo número dos veces en el DOM y a que un lector de pantalla leyera
     los dos). La tabla vive en un `.table-wrap` con overflow-x, así que el ancho que piden no
     rompe la página. */
  .precio-rango-lim{font-size:9.5px}
  .precio-rango{gap:5px}
  .precio-riel{min-width:44px}
  .precio-nombre{white-space:normal;max-width:none}
}

/* ============================================================================
   COTIZADOR — la estructura del cotizador de EATS, portada.
   Acordeón por categoría con píldoras de producto, ítem personalizado y la
   columna de Resumen fija a la derecha. Se conservan las medidas y el orden
   del original; lo que cambia son los colores, que salen de los tokens del
   proyecto para que funcione en tema claro y oscuro (el original era claro).
   ========================================================================== */
.cot-grid{display:grid;grid-template-columns:1fr 300px;gap:16px;align-items:start}
.cot-izq{display:flex;flex-direction:column;gap:16px;min-width:0}
.cot-der{position:sticky;top:calc(var(--topbar-h) + 12px)}
@media(max-width:1100px){.cot-grid{grid-template-columns:1fr 260px}}
@media(max-width:900px){.cot-grid{grid-template-columns:1fr}.cot-der{position:static}}

.cot-cab{display:flex;align-items:center;gap:8px;padding:13px 16px;border-bottom:1px solid var(--border)}
.cot-cab-t{flex:1;font-size:13.5px;font-weight:700;color:var(--text)}
.cot-cab-n{font-size:12.5px;color:var(--text-muted)}

/* Acordeón por categoría */
.cat-block{border:1.5px solid var(--border);border-radius:var(--radius);overflow:hidden;margin-bottom:10px;background:var(--bg-card)}
.cat-block:last-child{margin-bottom:0}
.cat-hdr{display:flex;align-items:center;gap:8px;padding:11px 14px;background:var(--bg-input);cursor:pointer;user-select:none;transition:background .15s}
.cat-hdr:hover{background:var(--bg-hover)}
.cat-name{flex:1;font-size:13px;font-weight:700;color:var(--text)}
.cat-count{font-size:12px;color:var(--text-muted);background:var(--bg-hover);border:1px solid var(--border);border-radius:20px;padding:2px 8px;white-space:nowrap;transition:background .15s,color .15s}
.cat-block.has-items .cat-count{background:var(--accent-dim);border-color:transparent;color:var(--accent);font-weight:700}
.cat-chev{display:inline-block;font-size:12px;color:var(--text-muted);transition:transform .2s;flex-shrink:0;line-height:1}
.cat-block.open .cat-chev{transform:rotate(180deg)}
.cat-body{display:none;border-top:1.5px solid var(--border)}
.cat-body.open{display:block}
.cat-sep{height:1px;background:var(--border);margin:0 14px}
.cat-pills{display:flex;flex-wrap:wrap;gap:6px;padding:12px 14px}
.cat-search{flex:0 0 100%;padding:7px 10px;margin-bottom:4px;border:1.5px solid var(--border);border-radius:7px;font-size:13px;background:var(--bg-input);color:var(--text);outline:none;transition:border-color .15s}
.cat-search:focus{border-color:var(--accent)}
.cat-pill{display:inline-flex;align-items:center;gap:4px;padding:5px 12px;background:var(--accent-dim);border:1.5px solid var(--accent-dim);border-radius:20px;font-size:12px;font-weight:600;color:var(--accent);cursor:pointer;transition:background .15s,border-color .15s;-webkit-tap-highlight-color:transparent}
.cat-pill:hover{border-color:var(--accent)}
.cat-vacio{font-size:12px;color:var(--text-muted)}
.cat-free{padding:0 14px 12px;margin-top:10px}
.cat-free-lbl{font-size:11px;text-transform:uppercase;letter-spacing:.4px;color:var(--text-muted);margin-bottom:6px}
.cat-free-fields{display:flex;gap:8px;align-items:center;width:100%}
.cat-free-name{flex:1 1 auto;min-width:0;padding:7px 10px;border:1.5px solid var(--border);border-radius:7px;font-size:13px;background:var(--bg-input);color:var(--text);outline:none;transition:border-color .15s}
.cat-free-price{flex:0 0 110px;width:110px;padding:7px 10px;border:1.5px solid var(--border);border-radius:7px;font-size:13px;background:var(--bg-input);color:var(--text);outline:none;transition:border-color .15s}
.cat-free-name:focus,.cat-free-price:focus{border-color:var(--accent)}
.cat-free-btn{flex:0 0 auto;white-space:nowrap;padding:7px 14px;background:var(--accent);color:#fff;border:none;border-radius:7px;font-size:13px;font-weight:600;cursor:pointer;transition:background .15s}
.cat-free-btn:hover{background:var(--accent-hi)}

/* Ítem ya agregado. El precio es editable —el original lo dejaba fijo—, que es
   la única diferencia con aquella pantalla: cambiar un precio sin borrar la
   línea es justo lo que se hace al negociar. */
.item-row{display:grid;grid-template-columns:1fr 96px 70px 100px 32px;align-items:center;gap:6px;padding:8px 14px;border-bottom:1px solid var(--border);transition:background .1s}
.item-row:hover{background:var(--bg-hover)}
.item-row:last-child{border-bottom:none}
.item-name{font-size:13px;font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.item-price,.item-qty{width:100%;padding:5px 8px;border:1.5px solid var(--border);border-radius:6px;font-size:13px;text-align:center;background:var(--bg-input);color:var(--text);outline:none;transition:border-color .15s;-moz-appearance:textfield}
.item-price::-webkit-inner-spin-button,.item-price::-webkit-outer-spin-button,
.item-qty::-webkit-inner-spin-button,.item-qty::-webkit-outer-spin-button{display:none}
.item-price:focus,.item-qty:focus{border-color:var(--accent)}
.item-total{font-size:13px;font-weight:700;color:var(--text);text-align:right;white-space:nowrap;font-family:var(--mono)}
.item-del{width:26px;height:26px;display:flex;align-items:center;justify-content:center;background:none;border:1.5px solid var(--border);border-radius:6px;color:var(--text-muted);cursor:pointer;font-size:11px;transition:all .15s;justify-self:center}
.item-del:hover{background:var(--accent-dim);border-color:var(--accent-r);color:var(--accent-r)}
@media(max-width:640px){
  .item-row{grid-template-columns:1fr 70px 32px;grid-template-areas:"n n n" "p q d" "t t t";gap:6px 8px;padding:10px 14px}
  .item-name{grid-area:n}.item-price{grid-area:p}.item-qty{grid-area:q}
  .item-del{grid-area:d}.item-total{grid-area:t;text-align:right}
  .cat-free-fields{flex-wrap:wrap}.cat-free-price{flex:1 1 100px;width:auto}
}

/* Resumen */
.cot-tot{display:flex;flex-direction:column;gap:6px}
.tot-row{display:flex;justify-content:space-between;font-size:13px;color:var(--text-sub);padding:3px 0}
.tot-row span:last-child{font-family:var(--mono)}
.tot-fin{display:flex;justify-content:space-between;align-items:baseline;font-size:20px;font-weight:800;color:var(--text);padding:10px 0 0;margin-top:8px;border-top:2px solid var(--border)}
.tot-fin span:last-child{font-family:var(--mono)}
.tot-pp{text-align:right;font-size:12px;color:var(--text-muted);margin-top:4px;font-family:var(--mono)}

/* Línea de una orden de compra dada por cerrada sin haber llegado nada: se tacha porque no se
   cobró y ya no se va a cobrar, pero NO se esconde — la orden tiene que seguir diciendo qué se
   pidió. La que llegó corta no se tacha: sí trajo algo, y tacharla diría que no. */
.oc-linea-cerrada td{opacity:.55;text-decoration:line-through}
.oc-linea-cerrada td .badge{text-decoration:none;opacity:1}

/* Captura de líneas: un producto que ya está en otra fila. No se impide —dos líneas del mismo
   producto son dos LOTES, con su vencimiento y su precio— pero se marca un instante, porque
   repetirlo por descuido sigue siendo lo más frecuente. */
.l-repetido{animation:l-rep 1.6s ease-out}
@keyframes l-rep{0%,60%{background:var(--accent-dim)}100%{background:transparent}}

/* Gráficos del reporte de órdenes: barras en HTML con los tokens del proyecto, sin librería. Una
   sola serie y un solo color, salvo en cumplimiento, donde el color SÍ significa un estado. */
.ocg-nota{font-size:12px;color:var(--text-muted);margin-bottom:12px;max-width:70ch}
.ocg-fila{display:flex;align-items:center;gap:10px;padding:3.5px 0;font-size:13px}
.ocg-et{flex:0 0 30%;max-width:30%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ocg-riel{flex:1;height:9px;background:var(--bg-input);border-radius:5px;overflow:hidden;min-width:40px}
.ocg-riel--dos{display:flex}
.ocg-barra{display:block;height:100%;background:var(--accent)}
/* Resaltado: la barra clara es el TOTAL y la fuerte, anidada dentro, la parte que corresponde al
   filtro puesto. La escala no se mueve —eso es lo que lo hace útil frente a filtrar de verdad—, así
   que un proveedor con S/ 344 de un producto no parece enorme si su total son S/ 20 000. */
.ocg-barra.ocg-barra--total{background:color-mix(in srgb,var(--accent) 26%,transparent)}
.ocg-barra.ocg-barra--parte{background:var(--accent);border-radius:5px}
.ocg-de{display:block;font-size:11px;color:var(--text-muted)}
.ocg-ok{background:var(--accent-g)}
.ocg-corta{background:var(--accent-a)}
.ocg-val{flex:0 0 auto;font-family:var(--mono);text-align:right;min-width:92px}
.ocg-ac{flex:0 0 auto;font-family:var(--mono);color:var(--text-muted);min-width:56px;text-align:right;font-size:12px}
/* La fila donde el acumulado cruza el 80%: la línea que separa los pocos que importan del resto. */
.ocg-80{border-bottom:2px solid var(--accent);padding-bottom:6px;margin-bottom:2px}
.ocg-resto .ocg-et{color:var(--text-muted);font-style:italic}
@media(max-width:640px){.ocg-et{flex-basis:42%;max-width:42%}.ocg-ac{display:none}}

/* Explorador del reporte de órdenes: los tres controles en una línea, y la matriz con la primera
   columna fija para que al desplazarse a la derecha no se pierda de vista qué fila se está leyendo. */
.ocx-ctrl{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.ocx-ctrl .form-label{margin:0;white-space:nowrap}
.ocx-ctrl .form-control{width:auto;min-width:150px}
.ocx-matriz th:first-child,.ocx-matriz td:first-child{position:sticky;left:0;background:var(--bg-card);z-index:1}
.ocx-matriz tfoot th{background:var(--bg-input);font-weight:700}

/* El lienzo del explorador: alto fijo porque Chart.js con maintainAspectRatio:false necesita que
   el contenedor lo tenga — sin él el canvas crece en cada redibujado. */
.ocx-lienzo{position:relative;height:380px;width:100%}
@media(max-width:640px){.ocx-lienzo{height:300px}}

/* Brecha de precio sospechosa en el sobrecosto. Va escrita como `.data-table td.x` —(0,2,1)— y no
   con los ayudantes globales `.c-amber`: `.data-table td` fija `color` con (0,1,1) y le ganaría,
   perdiendo el color en silencio. Es la misma trampa ya anotada para la vista Precios. */
.data-table td.oc-brecha-ojo{color:var(--accent-a);font-weight:700}

/* Detalle de una fila de sobrecosto: etiqueta a la izquierda y cifra a la derecha, en mono para
   que los números se alineen entre sí — que es lo que se compara al leerlos. */
.ocs-fila:hover td{background:var(--bg-hover)}
.sb-fila{display:flex;justify-content:space-between;align-items:baseline;gap:16px;padding:7px 0;border-bottom:1px solid var(--border)}
.sb-fila:last-child{border-bottom:none}
.sb-et{color:var(--text-sub);font-size:13px}
.sb-val{font-family:var(--mono);font-weight:600;text-align:right;white-space:nowrap}

/* Aviso de sobrecosto bajo el campo de costo, al recibir. Ámbar y no rojo a propósito: pagar más
   no es un error —a veces hay urgencia, o el barato no tenía— y un rojo empujaría a corregir un
   precio que puede ser correcto. Es un dato puesto donde se decide, no una alarma. */
.r-aviso{font-size:11px;line-height:1.3;color:var(--accent-a);margin-top:3px;white-space:normal}

/* Calendario del tablero de Comedores: una celda por día. Vacío y cero se distinguen a la vista. */
.vtb-cal{display:flex;flex-wrap:wrap;gap:3px;max-width:100%}
.vtb-cal-d{width:14px;height:14px;border-radius:3px;background:var(--bg-input);display:block}
.vtb-cal-d.vtb-cal-vacio{background:transparent;border:1px dashed var(--border)}
.vtb-cal-d.vtb-cal-cero{background:var(--bg-input);border:1px solid var(--accent-a)}

/* Umbral de color en la tasa de corrección del tablero de Comedores. Clase PROPIA
   (`.data-table td.x`, (0,2,1)) y no el ayudante global `.c-amber`/`.c-red` — pero no porque el
   ayudante pierda dentro de una tabla: esa trampa de especificidad se cerró en `2943bdc` («Los
   colores de estado vuelven a verse dentro de las tablas», 2026-07-31), que reescribió también
   los ayudantes globales a esta misma (0,2,1). Se queda propia por su cuenta: lleva el PESO
   (`font-weight:700`) sin añadirlo aparte, y el NOMBRE dice qué significa el color, no de qué
   color es. */
.data-table td.vtb-tasa--media{color:var(--accent-a);font-weight:700}
.data-table td.vtb-tasa--alta{color:var(--accent-r);font-weight:700}
