/* LAYAW Project Manager — application styles.
   One stylesheet, no framework, no CDN, no web fonts. (BUILD-PLAN.md §4 rule 1) */

:root{
  --navy:#0d2137; --navy-2:#12314f; --navy-3:#1c4570;
  --teal:#14b8a6; --teal-d:#0d9488; --teal-l:#f0fdfa;
  --ink:#0f172a; --muted:#64748b; --faint:#94a3b8;
  --line:#e2e8f0; --line-2:#f1f5f9; --bg:#f8fafc; --card:#fff;
  --amber:#f59e0b; --amber-l:#fef3c7; --amber-d:#92400e;
  --red:#dc2626; --green:#16a34a;
  --p1:#3b82f6; --p2:#06b6d4; --p3:#f97316; --p4:#22c55e; --p5:#8b5cf6;
  --row-h:34px; --left-w:540px;
  --font:"Segoe UI",system-ui,-apple-system,sans-serif;
  /* Derived from the company's chosen colours at runtime — see lib/theme.js.
     Declared here so the app still renders correctly before any company is loaded. */
  --on-accent:#fff; --on-sidebar:#fff;
  /* V1 — every colour a screen paints is a token, so the dark theme is one block that
     redefines them (at the end of this file). Tinted pairs: -l is the wash behind,
     -m the border, -d the text on it. */
  --ink-2:#334155; --line-3:#cbd5e1; --row-sub:#fafcfe; --row-act:#fdfbf5;
  --navy-ink:#12314f;
  --red-l:#fee2e2; --red-m:#fecaca; --red-d:#991b1b;
  --green-l:#dcfce7; --green-m:#bbf7d0; --green-d:#166534;
  --amber-m:#fcd34d;
  --blue-l:#dbeafe; --blue-m:#bfdbfe; --blue-d:#1e40af;
  --glass-hi:rgba(255,255,255,.88); --modal-bg:rgba(255,255,255,.97);
  color-scheme:light;
}
*{box-sizing:border-box}
html,body{height:100%;margin:0}
body{font:13px/1.45 var(--font);color:var(--ink);background:var(--bg);overflow:hidden}
button,input,select{font:inherit}

/* ---------- layout ---------- */
.app{display:flex;height:100vh}
.sidebar{
  width:210px;flex:none;background:var(--navy);color:#fff;
  display:flex;flex-direction:column;
}
.brand{display:flex;gap:10px;align-items:center;padding:16px 14px;border-bottom:1px solid rgba(255,255,255,.08);min-height:71px}
.brand-text{min-width:0}
.brand-initials{
  background:var(--teal);color:var(--on-accent);display:grid;place-items:center;
  font-weight:800;font-size:15px;letter-spacing:.5px;
}
/* The brand book's three accepted styles are all drawn on white and there is no
   sanctioned reverse version — on the navy, the logo's dark "S" vanishes into the
   background. So the asset carries its own white field, already centred on the
   artwork's real bounds by tools/make-icons.ps1. Nothing to align in CSS. */
.brand-mark{
  /* Same reasoning as the printed logo: a fixed height, free width, and `contain` so a
     wordmark is not squeezed into a square. The initials fallback is square by nature. */
  height:38px;width:auto;max-width:118px;flex:none;border-radius:9px;display:block;
  object-fit:contain;object-position:left center;
  box-shadow:0 1px 3px rgba(0,0,0,.25);
}
.brand-initials{width:38px}
.brand-text b{display:block;font-size:12.5px;letter-spacing:.3px;color:var(--on-sidebar);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.brand-text span{display:block;font-size:10.5px;opacity:.62;color:var(--on-sidebar)}

/**
 * ⚠️ V1: the sidebar scrolls, because six groups do not fit on a laptop.
 *
 * `scrollbar-gutter: stable` reserves the track whether or not a bar is showing, so the
 * items do not shift sideways by a few pixels the moment the list gets long enough to
 * scroll. `overscroll-behavior: contain` stops a flick at the bottom of the nav from
 * scrolling the page behind it.
 */
.nav{
  flex:1;padding:6px 8px 14px;overflow-y:auto;overflow-x:hidden;
  scrollbar-gutter:stable;overscroll-behavior:contain;
}
/* A thin bar that is part of the sidebar rather than a grey Windows slab on top of it. */
.nav::-webkit-scrollbar{width:8px}
.nav::-webkit-scrollbar-track{background:transparent}
.nav::-webkit-scrollbar-thumb{background:rgba(255,255,255,.14);border-radius:99px}
.nav::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.26)}

.navgroup{margin-bottom:4px}
.nav a{
  display:flex;align-items:center;gap:9px;padding:8px 11px;margin-bottom:2px;
  color:var(--on-sidebar);opacity:.72;text-decoration:none;border-radius:8px;font-size:12.5px;
  position:relative;
}
.nav a .lbl-text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nav a:hover{background:rgba(127,127,127,.16);opacity:1}
.nav a.on{background:var(--teal);color:var(--on-accent);opacity:1;font-weight:600}
.nav a.disabled{opacity:.3;pointer-events:none}
.nav .ico{width:15px;text-align:center;flex:none;font-size:13px}
.nav .sect{
  font-size:9.5px;letter-spacing:1px;text-transform:uppercase;color:var(--muted);
  padding:14px 11px 5px;font-weight:700;
}

/**
 * The bubble Genard asked for: the tab you clicked swells for a moment.
 *
 * ⚠️ Deliberately one short pulse, not a bounce or a slide. This fires on EVERY
 * navigation — a dozen times an hour — and an animation you notice the twelfth time is
 * an animation you come to resent. It is a confirmation, not a performance.
 */
@keyframes nav-bubble{
  0%{transform:scale(1)}
  45%{transform:scale(1.045)}
  100%{transform:scale(1)}
}
.nav a.bubble{animation:nav-bubble .26s cubic-bezier(.34,1.56,.64,1)}
@media (prefers-reduced-motion:reduce){
  /* Somebody who has asked their machine to stop moving things has asked us too. */
  .nav a.bubble{animation:none}
}

/* A screen the plan calls for that is not written yet — see ui/screens/soon.js. */
.nav .soon-dot{flex:none;font-size:15px;line-height:1;opacity:.5}
.nav a.on .soon-dot{opacity:.75}

/* The CURRENT PROJECT dropdown. */
.projpick{padding:2px 11px 8px}
.projpick select{
  width:100%;background:rgba(127,127,127,.18);color:var(--on-sidebar);
  border:1px solid rgba(255,255,255,.14);border-radius:8px;
  padding:7px 9px;font-size:12.5px;cursor:pointer;
}
.projpick select:hover{background:rgba(127,127,127,.3)}
.projpick select:focus{outline:2px solid var(--teal);outline-offset:1px}
/* The native menu is drawn by the OS in its own colours, so the options need a
   readable pair of their own — white-on-white otherwise. */
.projpick select option{background:var(--card);color:var(--ink)}
.projpick.empty{font-size:11.5px;color:var(--on-sidebar);opacity:.6;line-height:1.4}
.projpick.empty a{color:var(--teal)}

.sidebar-foot{padding:10px;border-top:1px solid rgba(255,255,255,.08)}
.active-project{
  background:rgba(127,127,127,.16);border-radius:9px;padding:9px 11px;margin-bottom:8px;
  font-size:12px;line-height:1.35;color:var(--on-sidebar);
}
.active-project .lbl{font-size:9px;letter-spacing:.8px;text-transform:uppercase;opacity:.6;font-weight:700}
.active-project b{display:block;margin-top:2px}
.active-project .meta{opacity:.62;font-size:11px;margin-top:2px}
/* Who is signed in. Lives inside the active-project block so the sidebar foot stays
   one object rather than a stack of unrelated boxes. */
.whoami{
  display:flex;align-items:center;gap:8px;margin-top:9px;padding-top:8px;
  border-top:1px solid rgba(255,255,255,.13);
}
.whoami>div{min-width:0;flex:1}
.whoami b{display:block;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.whoami span{display:block;opacity:.6;font-size:10.5px;margin-top:1px}
.whoami .btn{padding:3px 9px;font-size:10.5px;background:rgba(255,255,255,.11);
  border-color:rgba(255,255,255,.16);color:var(--on-sidebar)}
.whoami .btn:hover{background:rgba(255,255,255,.2)}

/* Sync line. A coloured dot and a sentence — never a spinner, because a spinner
   makes someone wait for an answer instead of giving them one. */
.sync-status{margin-bottom:8px}
.sync-status a{
  display:flex;align-items:center;gap:7px;padding:6px 10px;border-radius:8px;
  background:rgba(127,127,127,.16);color:var(--on-sidebar);text-decoration:none;
  font-size:11px;line-height:1.35;
}
.sync-status a:hover{background:rgba(127,127,127,.26)}
.sync-status .dot{width:7px;height:7px;border-radius:99px;flex:none;background:var(--faint)}
.sync-status.good .dot{background:#22c55e}
.sync-status.warn .dot{background:#f59e0b}
.sync-status.bad .dot{background:#ef4444}
.sync-status.busy .dot{background:#38bdf8;animation:sync-pulse 1s infinite}
@keyframes sync-pulse{0%,100%{opacity:1}50%{opacity:.3}}

/* Undo. Loud on purpose and only present when there is something to undo — this is
   the one control somebody hunts for in a hurry, with their stomach dropping. */
.undo-bar{margin-bottom:8px}
.undo-bar button{
  width:100%;display:flex;align-items:center;gap:7px;padding:7px 10px;border-radius:8px;
  background:rgba(245,158,11,.22);border:1px solid rgba(245,158,11,.5);
  color:var(--on-sidebar);font:inherit;font-size:11px;line-height:1.35;
  text-align:left;cursor:pointer;
}
.undo-bar button:hover{background:rgba(245,158,11,.36)}
.undo-bar .key{margin-left:auto;opacity:.6;font-size:9.5px;letter-spacing:.3px;flex:none}

/* Edition line. Deliberately quieter than the sync line: this is a label, not a
   status, and it should read as part of the furniture until the trial is short. */
.edition{margin-bottom:8px}
.edition a{
  display:flex;align-items:baseline;justify-content:space-between;gap:8px;
  padding:6px 10px;border-radius:8px;background:rgba(127,127,127,.12);
  color:var(--on-sidebar);text-decoration:none;font-size:11px;opacity:.8;
}
.edition a:hover{background:rgba(127,127,127,.24);opacity:1}
.edition span{font-size:10px;opacity:.7}
.edition.warn a{background:rgba(245,158,11,.22);opacity:1}
.edition.bad a{background:rgba(239,68,68,.24);opacity:1}

/* The licence banner sits above the topbar, across the content column. A strip, not
   a dialog — it never covers what somebody is in the middle of doing. */
.licence-banner{
  display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  padding:9px 18px;font-size:12.5px;line-height:1.45;flex:none;
  background:var(--amber-l);color:var(--amber-d);border-bottom:1px solid var(--amber-m);
}
.licence-banner.bad{background:var(--red-l);color:var(--red-d);border-bottom-color:var(--red-m)}
.licence-banner span{flex:1;min-width:220px}
.licence-banner .btn{flex:none}
@media print{ .licence-banner{display:none} }
/* ⚠️ `hidden` must win over any `display` set above. It did not here: the empty banner
   kept its padding and amber fill, a thin yellow strip across the top of every screen
   (Genard, 30 Sep: "unsa na ang yellow nga bar babaw?"). */
[hidden]{display:none !important}

/* The device code. Big, spaced and selectable: it gets read aloud down a phone. */
.device-code{
  font-family:ui-monospace,"Cascadia Mono",Consolas,monospace;
  font-size:26px;font-weight:700;letter-spacing:2.5px;user-select:all;
  padding:12px 14px;margin:0 0 12px;border-radius:10px;
  background:var(--bg);border:1px dashed var(--line);display:inline-block;
}
ul.plain{margin:0 0 12px;padding-left:18px;color:var(--muted);font-size:12.5px;line-height:1.7}
.btn.link{background:none;border:none;padding:0 2px;color:var(--accent);text-decoration:underline}

.madeby{font-size:10.5px;color:var(--on-sidebar);opacity:.45;text-align:center;letter-spacing:.2px}
.madeby b{font-weight:700;letter-spacing:.5px;opacity:.85}
.version{font-size:9.5px;color:var(--on-sidebar);opacity:.28;text-align:center;margin-top:2px}

.content{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0}
.topbar{
  background:var(--card);border-bottom:1px solid var(--line);flex:none;
  padding:11px 18px;display:flex;align-items:center;gap:14px;flex-wrap:wrap;
}
.topbar h1{font-size:17px;margin:0;font-weight:700}
.topbar .sub{font-size:12px;color:var(--muted);margin-top:1px}
.screen{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}
.spacer{flex:1}

/* ---------- controls ---------- */
.btn{
  border:1px solid var(--line);background:var(--card);padding:6px 12px;border-radius:7px;
  cursor:pointer;color:var(--ink);font-size:12.5px;
}
.btn:hover{background:var(--line-2)}
.btn.primary{background:var(--teal);border-color:var(--teal);color:var(--on-accent);font-weight:600}
.btn.primary:hover{background:var(--teal-d)}
.btn.danger{color:var(--red);border-color:var(--red-m)}
.btn:disabled{opacity:.5;cursor:not-allowed}
.seg{display:flex;border:1px solid var(--line);border-radius:7px;overflow:hidden}
.seg button{border:0;background:var(--card);padding:6px 14px;cursor:pointer;color:var(--muted);border-right:1px solid var(--line);font-size:12.5px}
.seg button:last-child{border-right:0}
.seg button.on{background:var(--teal);color:var(--on-accent);font-weight:600}
.field{display:flex;flex-direction:column;gap:4px;margin-bottom:12px}
.field label{font-size:11px;font-weight:700;color:var(--muted);letter-spacing:.3px}
.field input,.field select,.field textarea{
  border:1px solid var(--line);border-radius:7px;padding:7px 9px;background:var(--card);
}
.field input:focus,.field select:focus,.field textarea:focus{outline:0;border-color:var(--teal)}
/* Notes grow with what is typed (dom.js autoGrow) and can still be dragged taller —
   a note cut off at the edge of a one-line box is a note nobody finishes reading. */
.field textarea{font:inherit;line-height:1.45;min-height:64px;resize:vertical;width:100%;
  box-sizing:border-box}
.hint{font-size:11.5px;color:var(--muted)}
.hint b{color:var(--ink)}

/* ---------- toolbar ---------- */
.toolbar{
  display:flex;align-items:center;gap:9px;padding:8px 18px;background:var(--card);
  border-bottom:1px solid var(--line);flex:none;flex-wrap:wrap;
}

/* ---------- KPI strip ---------- */
.kpis{display:flex;background:var(--card);border-bottom:1px solid var(--line);flex:none;overflow-x:auto}
.kpi{padding:9px 18px;border-right:1px solid var(--line);min-width:140px;flex:none}
.kpi .lbl{font-size:9.5px;letter-spacing:.7px;color:var(--muted);text-transform:uppercase;font-weight:700}
.kpi .val{font-size:16px;font-weight:700;margin-top:2px;font-variant-numeric:tabular-nums}
.kpi .sub{font-size:10.5px;color:var(--muted);margin-top:1px}
.kpi.good .val{color:var(--teal-d)}
.kpi.bad .val{color:var(--red)}
.bar-outer{height:5px;background:var(--line);border-radius:99px;margin-top:6px;width:110px}
.bar-inner{height:100%;background:var(--teal);border-radius:99px}

/* ---------- cards / empty ---------- */
.pad{padding:18px;overflow:auto;flex:1}
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:13px}
.card{
  background:var(--card);border:1px solid var(--line);border-radius:11px;padding:15px;
  transition:border-color .12s,box-shadow .12s;
}
/* ⚠️ Only a card that DOES something on click lights up and shows a hand (Genard,
   25 Sep: the whole Billings table lit up on hover). Most cards are plain containers —
   Activate, BOQ import, Cloud, the billing register — and a container that reacts like
   a button tells people to click it, and then nothing happens. */
.card:is([data-open], a, button, [role="button"]){cursor:pointer}
.card:is([data-open], a, button, [role="button"]):hover{border-color:var(--teal);box-shadow:0 3px 12px rgba(15,23,42,.07)}
.card h3{margin:0 0 3px;font-size:14.5px}
.card .meta{color:var(--muted);font-size:12px}
.card .row{display:flex;justify-content:space-between;margin-top:11px;font-size:12px}
.card .row b{font-variant-numeric:tabular-nums}
.pill{
  display:inline-block;padding:1px 8px;border-radius:99px;font-size:10px;font-weight:700;
  text-transform:uppercase;letter-spacing:.4px;
}
.pill.planning{background:var(--blue-l);color:var(--blue-d)}
.pill.active{background:var(--green-l);color:var(--green-d)}
.pill.on-hold{background:var(--amber-l);color:var(--amber-d)}
.pill.completed{background:var(--line);color:var(--muted)}
.sec-head{
  font-size:10.5px;text-transform:uppercase;letter-spacing:1px;color:var(--muted);
  margin:0 0 9px;font-weight:700;
}
/**
 * Charts (ui/charts.js). The SVG is drawn at the width it is shown at and keeps its own
 * proportions — `height:auto`, never a fixed height on a stretched canvas, which is what
 * pulled every digit sideways before. Colours are tokens, so dark mode and paper follow.
 */
.chart-box{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:12px 12px 10px}
.chart{display:block;width:100%;height:auto;overflow:visible;font-family:var(--font)}
.chart .ch-grid{stroke:var(--line);stroke-width:1;stroke-dasharray:3 4}
.chart .ch-zero{stroke:var(--faint);stroke-width:1}
.chart .ch-axis{fill:var(--muted);font-size:11px;font-variant-numeric:tabular-nums}
.chart .ch-in{fill:var(--green);opacity:.78}
.chart .ch-out{fill:var(--red);opacity:.78}
.chart rect:hover{opacity:1}
.chart .ch-area{fill:var(--navy-ink);opacity:.07}
.chart .ch-line{fill:none;stroke:var(--navy-ink);stroke-width:2.25;stroke-linejoin:round;stroke-linecap:round}
.chart .ch-dot{fill:var(--navy-ink);stroke:var(--card);stroke-width:1.5}
.chart .ch-dot.warn{fill:var(--amber)}
.chart .ch-dot.bad{fill:var(--red)}
.chart .ch-call{font-size:11.5px;font-weight:800;paint-order:stroke;stroke:var(--card);stroke-width:3.5px;
  stroke-linejoin:round}
.chart .ch-call.warn{fill:var(--amber-d)}
.chart .ch-call.bad{fill:var(--red)}
.chart .ch-plan{fill:none;stroke:var(--faint);stroke-width:2.25;stroke-linejoin:round}
.chart .ch-actual{fill:none;stroke:var(--teal-d);stroke-width:3;stroke-linejoin:round;stroke-linecap:round}
.chart .ch-spent{fill:none;stroke:var(--amber);stroke-width:1.75;stroke-dasharray:4 4}
.chart .ch-today{stroke:var(--red);stroke-width:1;stroke-dasharray:4 3}
.chart .ch-today-t{fill:var(--red);font-size:11px}
.chart .ch-now{fill:var(--teal-d);stroke:var(--card);stroke-width:2}
.chart .ch-now-t{fill:var(--teal-d);font-size:12.5px;font-weight:800;paint-order:stroke;stroke:var(--card);
  stroke-width:3.5px;stroke-linejoin:round}
.ch-legend{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:8px;padding-left:4px;font-size:11.5px;color:var(--muted)}
.ch-legend span{display:inline-flex;align-items:center;gap:6px}
.ch-legend i{display:inline-block;flex:none;width:11px;height:11px;border-radius:3px}
.ch-legend .lg-in{background:var(--green);opacity:.78}
.ch-legend .lg-out{background:var(--red);opacity:.78}
.ch-legend .lg-line,.ch-legend .lg-plan,.ch-legend .lg-actual{width:18px;height:3px;border-radius:2px}
.ch-legend .lg-line{background:var(--navy-ink)}
.ch-legend .lg-plan{background:var(--faint)}
.ch-legend .lg-actual{background:var(--teal-d)}
.ch-legend .lg-spent{width:18px;height:0;border-radius:0;border-top:2px dashed var(--amber)}
.ch-legend .lg-low{border-radius:50%;background:var(--amber)}
.ch-legend .lg-low.bad{background:var(--red)}
@media print{
  .chart *,.ch-legend i{print-color-adjust:exact;-webkit-print-color-adjust:exact}
}
.card .row b.neg{color:var(--red)}
.card .row .neg{color:var(--red);font-weight:700}
.empty{text-align:center;padding:60px 20px;color:var(--muted)}
.empty h2{color:var(--ink);font-size:17px;margin:0 0 6px}
.banner{
  padding:9px 18px;background:var(--amber-l);color:var(--amber-d);
  border-bottom:1px solid var(--amber-m);font-size:12.5px;flex:none;
}
.banner b{color:var(--amber-d)}

/* ---------- gantt ---------- */
.gscroll{flex:1;overflow:auto;background:var(--card);position:relative}
.gstage{position:relative;width:max-content;min-width:100%}
.ghead{position:sticky;top:0;z-index:20;display:flex;background:var(--card)}
.ghead-left{
  position:sticky;left:0;z-index:21;width:var(--left-w);flex:none;background:var(--card);
  border-right:2px solid var(--line);border-bottom:1px solid var(--line);
}
.ghead-right{flex:none;border-bottom:1px solid var(--line);position:relative}
.hrow{display:flex;height:26px;align-items:center;font-size:9.5px;text-transform:uppercase;
  letter-spacing:.6px;color:var(--muted);font-weight:700;background:var(--line-2)}
.hrow.top{height:35px;background:var(--card);border-bottom:1px solid var(--line-2)}
.hrow>div{padding:0 8px;flex:none;overflow:hidden;white-space:nowrap}
.c-name{width:212px} .c-date{width:64px} .c-dur{width:44px;text-align:right}
.c-pct{width:52px;text-align:right} .c-cost{width:100px;text-align:right}

.months{display:flex;height:22px;border-bottom:1px solid var(--line-2)}
.month{flex:none;font-size:11px;font-weight:600;padding:3px 6px;border-right:1px solid var(--line);
  overflow:hidden;white-space:nowrap}
.holband{height:13px;position:relative;background:var(--card);border-bottom:1px solid var(--line-2)}
.holmark{position:absolute;top:2px;width:7px;height:9px;margin-left:-3px;background:var(--amber);
  border-radius:2px;cursor:help}
.ticks{display:flex;height:26px;background:var(--line-2)}
.tick{flex:none;font-size:9.5px;color:var(--muted);text-align:center;padding-top:6px;
  border-right:1px solid var(--line);overflow:hidden}
.tick.we{background:var(--bg);color:var(--faint)}
.tick.hol{background:var(--amber-l);color:var(--amber-d);font-weight:700}

.gbody{display:flex;position:relative}
.gbody-left{position:sticky;left:0;z-index:12;width:var(--left-w);flex:none;background:var(--card);
  border-right:2px solid var(--line)}
.gbody-right{flex:none;position:relative}

.grow{display:flex;height:var(--row-h);align-items:center;border-bottom:1px solid var(--line-2)}
.grow:hover{background:var(--bg)}
.grow.parent{font-weight:700;background:var(--bg)}
.grow>div{padding:0 8px;flex:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}
.grow .c-name{display:flex;align-items:center;gap:6px}
.twist{width:14px;height:14px;flex:none;display:grid;place-items:center;cursor:pointer;
  color:var(--muted);font-size:9px;user-select:none}
.indent{width:16px;flex:none}
.dot{width:7px;height:7px;border-radius:99px;flex:none}
.c-cost,.c-pct,.c-dur{font-variant-numeric:tabular-nums;color:var(--muted)}
.grow.parent .c-cost{color:var(--ink)}
.c-cost.derived{background:var(--teal-l);border-left:2px solid var(--teal);font-weight:600;color:var(--ink)}
.hbadge{display:inline-flex;align-items:center;background:var(--amber-l);color:var(--amber-d);
  border:1px solid var(--amber-m);border-radius:99px;padding:0 5px;font-size:9.5px;font-weight:700;
  flex:none;cursor:help;line-height:15px}

.gl{position:absolute;top:0;bottom:0;width:1px;background:var(--line-2)}
.gl.month{background:var(--line)}
.nonwork{position:absolute;top:0;bottom:0;background:var(--bg)}
.nonwork.hol{background:var(--amber-l)}
.rl{position:absolute;left:0;right:0;height:1px;background:var(--line-2)}
.today{position:absolute;top:0;bottom:0;border-left:2px dashed var(--red);z-index:4;pointer-events:none}
.today-pill{position:absolute;z-index:22;transform:translateX(-50%);background:var(--red);color:#fff;
  font-size:10px;font-weight:700;padding:2px 7px;border-radius:4px;white-space:nowrap}
svg.arrows{position:absolute;inset:0;pointer-events:none;z-index:2;overflow:visible}
svg.arrows path{fill:none;stroke:var(--faint);stroke-width:1.5}
svg.arrows polygon{fill:var(--faint)}

.bar{position:absolute;height:17px;border-radius:4px;z-index:3;cursor:grab;user-select:none;
  box-shadow:0 1px 2px rgba(0,0,0,.13)}
.bar:active{cursor:grabbing}
.bar .fill{position:absolute;left:0;top:0;bottom:0;background:rgba(0,0,0,.28);border-radius:4px 0 0 4px}
.bar .h{position:absolute;top:0;bottom:0;width:7px;cursor:ew-resize;z-index:2}
.bar .h.l{left:-2px} .bar .h.r{right:-2px}
.bar.late{box-shadow:0 1px 2px rgba(0,0,0,.13),inset 3px 0 0 var(--red)}
.bar.moved{animation:flash .55s ease-out}
@keyframes flash{0%{box-shadow:0 0 0 3px rgba(249,115,22,.55)}100%{box-shadow:0 1px 2px rgba(0,0,0,.13)}}
.pbar{position:absolute;height:9px;background:var(--navy-2);z-index:3;border-radius:2px}
.pbar::before,.pbar::after{content:"";position:absolute;top:100%;border-top:5px solid var(--navy-2);
  border-left:4px solid transparent;border-right:4px solid transparent}
.pbar::before{left:0} .pbar::after{right:0}
.pfill{position:absolute;left:0;top:0;bottom:0;background:var(--teal);border-radius:2px 0 0 2px}

/* ---------- inline task editing ---------- */
.tname{cursor:text;border-radius:4px;padding:1px 3px;margin:0 -3px;overflow:hidden;text-overflow:ellipsis}
.tname:hover{background:var(--line)}
/* The WBS code. Quieter than the name on a sub-task, because the name is what is being
   read and the number is what is being counted. `:empty` so a task that somehow has no
   code does not leave a gap where the separator would be. */
.wbs{color:var(--faint);font-variant-numeric:tabular-nums;margin-right:6px}
.wbs:empty{display:none}
.grow.parent .wbs{color:var(--navy-ink)}
.c-pct.editable{cursor:text}
.c-pct.editable:hover{background:var(--line);border-radius:4px}
input.inline{
  width:100%;border:1px solid var(--teal);border-radius:4px;padding:1px 4px;font:inherit;
  font-size:12px;background:var(--card);color:var(--ink);
}
.c-pct input.inline{text-align:right}
.rowmenu{
  border:0;background:transparent;color:var(--faint);cursor:pointer;font-size:14px;line-height:1;
  padding:0 3px;border-radius:4px;margin-left:auto;flex:none;opacity:0;
}
.grow:hover .rowmenu{opacity:1}
.rowmenu:hover{background:var(--line);color:var(--ink)}
.rowpop{
  position:fixed;z-index:80;background:var(--card);border:1px solid var(--line);border-radius:9px;
  box-shadow:0 10px 30px rgba(15,23,42,.2);padding:4px;min-width:168px;
  /* Same rule as .modal: never taller than the window, scroll inside if it must. */
  max-height:calc(100vh - 16px);overflow-y:auto;
}
.rowpop button{
  display:block;width:100%;text-align:left;border:0;background:transparent;padding:7px 10px;
  border-radius:6px;cursor:pointer;font-size:12.5px;color:var(--ink);
}
.rowpop button:hover{background:var(--line-2)}
.rowpop button.danger{color:var(--red)}
.rowpop button.danger:hover{background:var(--red-l)}
.rowpop hr{border:0;border-top:1px solid var(--line);margin:4px 2px}

/* ---------- data grid (BOQ, cash flow table) ---------- */
table.grid{border-collapse:collapse;width:100%;font-size:12px;background:var(--card)}
table.grid th{
  position:sticky;top:0;z-index:2;background:var(--card);text-align:left;font-size:9.5px;
  text-transform:uppercase;letter-spacing:.5px;color:var(--muted);padding:7px 7px;
  border-bottom:1px solid var(--line);white-space:nowrap;font-weight:700;
}
table.grid th[title]{cursor:help;text-decoration:underline dotted var(--line-3)}
table.grid td{padding:2px 6px;border-bottom:1px solid var(--line-2);white-space:nowrap}
table.grid .num{text-align:right;font-variant-numeric:tabular-nums}
table.grid tr.sec td{
  background:var(--line-2);font-weight:700;font-size:11px;letter-spacing:.3px;
  color:var(--navy-ink);padding:6px 7px;
}
table.grid tbody tr:hover{background:var(--bg)}
table.grid tr.under td{background:var(--red-l)}
table.grid .amt{font-weight:600}
table.grid tr.total td{background:var(--navy);color:#fff;font-weight:700;font-size:12.5px;padding:7px}
table.grid tfoot{position:sticky;bottom:0}
.muted-cell{color:var(--muted);font-style:italic;padding:7px}
.win{font-size:10.5px;color:var(--muted);position:relative;padding-right:22px !important}
.pos{color:var(--green)} .neg{color:var(--red)}

input.cell,select.cell{
  width:100%;border:1px solid transparent;border-radius:5px;padding:3px 5px;font:inherit;
  font-size:12px;background:transparent;color:inherit;
}
input.cell.num{text-align:right;font-variant-numeric:tabular-nums}
input.cell.tiny{width:44px} input.cell.narrow{width:60px}
input.cell:hover,select.cell:hover{border-color:var(--line);background:var(--card)}
input.cell:focus,select.cell:focus{border-color:var(--teal);background:var(--card);outline:0}
.x{
  position:absolute;right:4px;top:50%;transform:translateY(-50%);border:0;background:transparent;
  color:var(--faint);cursor:pointer;font-size:15px;line-height:1;padding:0 3px;border-radius:4px;
}
tr:hover .x{color:var(--red)}
.x:hover{background:var(--red-l)}

/* ⚠️ Two of these in one cell used to sit on top of each other — `.x` is pinned to the
   right of the cell, so Edit and Delete overlapped and only the top one could be
   clicked. A row with more than one action puts them in this instead. */
/* The Statement of Work Accomplished. Folded away on screen — it is forty lines nobody
   reads at a desk — and always on the paper, where it is the thing the client's engineer
   checks the billing against. */
.swa{display:none}
.swa.show{display:block}

/* Activity rows: a summary that leads somewhere looks like it does, and one that does
   not stays grey. Nothing in between. */
.act-link{color:var(--teal);text-decoration:none;border-bottom:1px dotted currentColor}
.act-link:hover{color:var(--navy-ink);border-bottom-style:solid}

.rowacts{display:flex;gap:1px;justify-content:flex-end;align-items:center}
.rowacts .x{position:static;transform:none;padding:2px 5px}
.rowacts .x[data-edit-entry]{color:var(--muted)}
tr:hover .rowacts .x[data-edit-entry]{color:var(--teal)}
.rowacts .x[data-edit-entry]:hover{background:var(--teal-l)}

/* ---------- V1: the BOQ, estimated against actual ----------
   Two header rows now — ESTIMATED / ACTUAL over the figures — so the whole head sticks
   as one block rather than each cell on its own, which would slide the second row
   under the first. */
table.grid.boq thead{position:sticky;top:0;z-index:3}
table.grid.boq thead th{position:static}
table.grid.boq tr.grp th{
  text-align:center;font-size:10px;letter-spacing:1.2px;padding:5px 7px 3px;
  border-bottom:0;color:var(--navy-ink);
}
table.grid.boq th.grp-est{background:var(--teal-l);border-left:2px solid var(--card)}
table.grid.boq th.grp-act{background:var(--amber-l);color:var(--amber-d);border-left:2px solid var(--card)}
/* The Actual side is read, never typed — a faint tint says so without a word. Solid,
   not translucent: this is data. */
/* ⚠️ Line rows only. On the section and total rows this rule out-ranked their own
   background, so the Actual end of the navy DIRECT COST bar went pale — with white
   text on it, the actual total was simply invisible. */
table.grid.boq tbody tr:not(.sec) td.act{background:var(--row-act)}
table.grid.boq td.na{color:var(--faint)}
/* With seventeen columns the table lays out tight, and a width:100% box in an auto
   column collapses to nothing — the quantity simply vanished. Typed figures get a
   fixed width that holds ₱1,000,000.00. */
table.grid.boq td > input.cell.num:not(.tiny){width:92px}
table.grid.boq td > input.cell.narrow{width:60px}
table.grid.boq td.e-mat{color:var(--muted)}
.labcell{display:flex;align-items:center;justify-content:flex-end;gap:2px}
.labcell select.cell.mode{width:36px;padding:3px 2px;text-align:center}
.labcell input.cell{width:78px}
.labcell input.cell.tiny{width:48px}
.labpeso{font-size:10.5px;color:var(--muted);min-width:58px;text-align:right}
.labprint{display:none}
/* The printed twin of a typed figure: "₱40,000.00" on paper, where the box holds 40000. */
.pv{display:none}

/* The summary under the table — Total Material, Total Labour, the "+" lines and the
   Total Project Cost. Narrow on purpose: three figures across do not need 1400px. */
table.grid.boqsum{max-width:760px;margin:16px 18px 0;width:calc(100% - 36px)}
table.grid.boqsum td{padding:6px 8px}
table.grid.boqsum td.num{min-width:130px}
table.grid.boqsum tr.sub td{font-weight:700;border-top:1px solid var(--line)}
table.grid.boqsum td.acts{width:64px}
table.grid.boqsum tr.addrow td{padding:8px}
table.grid.boqsum tr.addrow .hint{margin-left:8px}
table.grid.boqsum tfoot{position:static}
table.grid.boqsum tr.total td.over{color:var(--red-m)}
.adj-how{font-size:11px;color:var(--muted);margin-left:6px}
.adj-how input.cell{display:inline-block;width:58px}
.adj-pct{display:none}
.adj-sfx{margin:0 6px 0 2px;color:var(--ink)}
.boqnote{max-width:760px;margin:8px 18px 0;font-size:11.5px;color:var(--muted-on-wash);line-height:1.55}
.boqnote a{color:var(--teal-d)}
.boqvo{padding:20px 18px 24px}
.boqvo table.grid{max-width:1100px}
.boqvo tfoot{position:static}
.boqvo tr.vo-tally td{font-size:11.5px;color:var(--muted);padding:7px}
.vo-link{font-size:11px;font-weight:600;text-transform:none;letter-spacing:0;margin-left:10px;
  color:var(--teal-d)}
.boqvo > .hint{color:var(--muted-on-wash)}

/* ---------- cash flow layout ---------- */
.cash{flex:1;display:flex;min-height:0;background:var(--card)}
.chartbox{flex:1.5;padding:10px 12px 4px;min-width:0;display:flex;flex-direction:column}
.tablebox{flex:1;border-left:2px solid var(--line);overflow:auto;min-width:280px}
#chart{flex:1;min-height:0;width:100%}
.legend{display:flex;gap:15px;font-size:10.5px;color:var(--muted);padding:3px 4px 0;flex-wrap:wrap}
.legend i{width:9px;height:9px;border-radius:2px;display:inline-block;margin-right:4px}

/* ---------- settings ---------- */
.settings{max-width:900px}
.panel{background:var(--card);border:1px solid var(--line);border-radius:11px;padding:16px 18px;margin-bottom:15px}
.panel h2{font-size:13px;margin:0 0 12px;text-transform:uppercase;letter-spacing:.7px;color:var(--muted)}
.panel h2 .count{
  background:var(--line-2);color:var(--muted);border-radius:99px;padding:1px 8px;
  font-size:11px;margin-left:6px;letter-spacing:0;
}
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:0 16px}
.days{display:flex;gap:7px;flex-wrap:wrap}
.daybox{
  display:flex;align-items:center;gap:6px;border:1px solid var(--line);border-radius:8px;
  padding:7px 12px;cursor:pointer;font-size:12.5px;background:var(--card);
}
.daybox:has(input:checked){background:var(--teal-l);border-color:var(--teal);font-weight:600}
.holyear{margin-bottom:14px}
.holyear h3{font-size:12px;margin:0 0 7px;color:var(--ink)}
.holyear .tag{
  background:var(--teal-l);color:var(--teal-d);border-radius:99px;padding:1px 7px;
  font-size:10px;font-weight:700;margin-left:4px;
}
.holgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:5px}
.holrow{
  display:flex;align-items:center;gap:8px;border:1px solid var(--line);border-radius:7px;
  padding:5px 8px;font-size:12px;position:relative;padding-right:26px;
}
.holdate{font-variant-numeric:tabular-nums;color:var(--amber-d);font-weight:700;
  background:var(--amber-l);border-radius:4px;padding:1px 6px;flex:none;white-space:pre}
.holname{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* ---------- company branding screen ---------- */
.logo-row{display:flex;gap:18px;align-items:flex-start;flex-wrap:wrap}
.logo-box{
  width:120px;height:120px;flex:none;border:1px solid var(--line);border-radius:12px;
  background:var(--card);display:grid;place-items:center;overflow:hidden;padding:9px;
}
.logo-box img{max-width:100%;max-height:100%;object-fit:contain}
.logo-box.empty{border-style:dashed;background:var(--line-2)}
.logo-box.empty span{font-size:11.5px;color:var(--faint)}
.logo-do{display:flex;flex-wrap:wrap;gap:8px;align-items:flex-start}
label.btn{display:inline-block}

.colour-row{display:flex;align-items:center;gap:10px}
.colour-row input[type=color]{
  width:56px;height:38px;padding:2px;border:1px solid var(--line);border-radius:8px;
  background:var(--card);cursor:pointer;
}
.colour-row code{font-size:12px;color:var(--muted);font-family:Consolas,monospace}
.presets{display:flex;gap:7px;flex-wrap:wrap;align-items:center;margin-top:4px}
.preset{
  width:44px;height:28px;border:1px solid var(--line);border-radius:7px;overflow:hidden;
  display:flex;cursor:pointer;padding:0;background:none;
}
.preset span{flex:1;display:block}
.preset:hover{border-color:var(--ink);transform:translateY(-1px)}

/**
 * A small sheet of paper, on screen.
 *
 * ⚠️ The proportions here have to match the real printed page — see .print-head .ph-logo.
 * A preview that shrinks the logo to a square badge tells the customer their letterhead
 * looks like something it does not, and the first time they find out otherwise is when
 * the page is already in a client's hands.
 */
/* z-index:0 makes this a stacking context, which is what keeps .pv-mark's negative
   z-index inside the sheet instead of dropping it behind the panel — the same pairing
   the print block uses for .content and .watermark. */
.preview-doc{
  position:relative;z-index:0;border:1px solid var(--line);border-radius:10px;
  overflow:hidden;background:var(--card);
}
.pv-head{
  position:relative;z-index:1;
  display:flex;gap:12px;align-items:center;padding:13px 16px;border-bottom:2px solid var(--navy);
}
.pv-head img{height:52px;width:auto;max-width:180px;object-fit:contain;flex:none}
.pv-nologo{
  width:52px;height:52px;flex:none;border:1px dashed var(--line);border-radius:6px;
  display:grid;place-items:center;font-size:8.5px;color:var(--faint);text-align:center;
}
/* The same mark the print stylesheet paints, shown on the sample sheet at the same
   strength AND the same paint order the app gives it on paper — behind the content, so
   the preview cannot promise something the printer will not do. */
.pv-mark{
  position:absolute;inset:0;z-index:-1;pointer-events:none;
  background-repeat:no-repeat;background-position:center center;
}
.pv-title{font-size:15px;font-weight:800;color:var(--navy-ink)}
.pv-sub{font-size:10.5px;color:var(--ink-2);margin-top:2px}
.pv-foot{font-size:9px;color:var(--muted);margin-top:4px;letter-spacing:.3px}
.pv-body{position:relative;z-index:1;padding:13px 16px;font-size:12px;color:var(--muted)}

/**
 * The Print button that lives on a row — a billing, a variation.
 *
 * Quiet until the row is hovered: on a list of thirty billings, thirty dark buttons
 * would be the loudest thing on the screen and none of them is what you came to read.
 * It stays reachable by keyboard whatever the mouse is doing.
 */
.rowprint{
  flex:none;width:28px;height:28px;margin-right:2px;
  border:1px solid transparent;border-radius:7px;background:none;
  color:var(--muted);font-size:14px;line-height:1;cursor:pointer;opacity:.45;
  transition:opacity .12s,background .12s,border-color .12s;
}
.reqcard:hover .rowprint{opacity:1}
.rowprint:hover{background:var(--teal-l);border-color:var(--teal);color:var(--teal-d)}
.rowprint:focus-visible{opacity:1;outline:2px solid var(--teal);outline-offset:1px}
@media print{ .rowprint{display:none !important} }

/* The "planned, not written" page — see ui/screens/soon.js. */
.soon-panel{max-width:620px}
.soon-stage{
  display:inline-block;background:var(--teal-l);color:var(--teal-d);
  font-size:10.5px;font-weight:700;letter-spacing:.6px;text-transform:uppercase;
  border-radius:99px;padding:3px 11px;margin-bottom:10px;
}
.soon-what{font-size:14px;color:var(--ink);margin:0 0 12px}

/* Tick-boxes in a dialog — laid out in a row so three or four options read as one
   question rather than a list of four separate ones. */
.checks{display:flex;flex-wrap:wrap;gap:6px 16px;padding:4px 0}
.check{display:flex;align-items:center;gap:7px;font-size:12.5px;cursor:pointer;white-space:nowrap}
.check input{width:15px;height:15px;accent-color:var(--teal);cursor:pointer}

/* What the typeahead says about what you just typed. */
.match-note:empty{display:none}
.match-note.good{color:var(--green)}
.match-note.warn{color:var(--amber-d)}
.match-note.bad{color:var(--red)}

/* The who-can-do-what grid on People. Columns are people, so they stay narrow and
   centred; the permission wording carries the row. */
table.grid.matrix td:first-child,
table.grid.matrix th:first-child{white-space:normal;min-width:220px}
table.grid.matrix th.num,
table.grid.matrix td.num{text-align:center;min-width:86px}
table.grid.matrix th.num .muted{font-weight:400;font-size:9px;letter-spacing:0}
.mx-on{color:var(--green);font-weight:700}
.mx-off{color:var(--faint)}
/* An override is the row worth arguing about, so it is the only one with a background. */
.mx-over{background:var(--amber-l);color:var(--amber-d)}

/* Watermark chooser — three plain choices, because there is nothing to tune. */
.wm-choices{display:flex;gap:9px;flex-wrap:wrap;margin-bottom:12px}
.wm-choice{
  border:1px solid var(--line);border-radius:10px;background:var(--card);cursor:pointer;
  padding:9px 14px;text-align:left;font-size:12.5px;color:var(--ink);min-width:150px;
}
.wm-choice small{display:block;color:var(--muted);font-size:11px;margin-top:2px}
.wm-choice:hover{border-color:var(--ink)}
.wm-choice.on{border-color:var(--teal);background:var(--teal-l);font-weight:600}
.wm-choice[disabled]{opacity:.5;cursor:not-allowed}

.about{display:flex;gap:14px;align-items:flex-start}
.about-mark{width:48px;height:48px;flex:none;border-radius:11px;border:1px solid var(--line)}
.about b{font-size:14px}
.danger-zone{border-color:var(--red-m)}
.dz-row{display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:11px 0;border-top:1px solid var(--line-2)}
.dz-row:first-of-type{border-top:0}

/* ---------- modal ---------- */
.modal-bg{position:fixed;inset:0;background:rgba(15,23,42,.45);display:grid;place-items:center;z-index:60;
  padding:16px}
/**
 * ⚠️ Never taller than the window (Genard, 25 Sep: "dili sya ma scroll nya ga lapas sya
 * sa screen"). A dialog had no height limit, so a long one — New asset, a delivery with
 * ten lines on the DR — ran off the bottom with its Save button out of reach and nothing
 * to scroll.
 *
 * Now the dialog is a column capped at the window: the title stays at the top, the
 * fields scroll between, and Cancel / Save stay pinned at the bottom. The buttons must
 * never be the part that scrolls away — a dialog whose Save you cannot see looks like a
 * dialog with no way to save.
 */
.modal{background:var(--card);border-radius:13px;padding:20px 20px 0;width:420px;max-width:92vw;
  box-shadow:0 18px 50px rgba(0,0,0,.3);
  display:flex;flex-direction:column;
  max-height:calc(100vh - 32px);max-height:calc(100dvh - 32px)}
.modal h2{margin:0 0 14px;font-size:16px;flex:none}
.modal form{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  margin:0 -20px;padding:0 20px}
.modal .actions{display:flex;gap:8px;justify-content:flex-end;margin-top:16px;
  /* Solid, not `inherit`: the parent is the form, which is transparent, and the fields
     scrolling underneath showed straight through the buttons. */
  position:sticky;bottom:0;z-index:1;background:var(--card);padding:12px 0 16px;
  border-top:1px solid transparent}
/* Only when there is more above it: a hairline says "the form continues up there". */
.modal form.scrolls .actions{border-top-color:var(--line)}

/* ---------- quotations ---------- */
.quotelist{display:flex;gap:8px;flex-wrap:wrap;margin:10px 0}
.qchip{
  position:relative;border:1px solid var(--line);border-radius:9px;padding:7px 30px 7px 11px;
  background:var(--card);font-size:12px;
}
.qchip.expired{opacity:.6;border-style:dashed;background:var(--line-2)}
.qchip b{display:block}
.qchip span{font-size:11px;color:var(--muted)}
.bestprice{background:var(--green-l);font-weight:700}
.bestmark{
  display:inline-block;background:var(--green);color:#fff;border-radius:99px;padding:0 6px;
  font-size:9px;font-weight:700;margin-left:5px;vertical-align:middle;text-transform:uppercase;
}
code{background:var(--line-2);border-radius:4px;padding:1px 5px;font-size:11px;
  font-family:Consolas,monospace}

/* ---------- material requests ---------- */
.reqcard{background:var(--card);border:1px solid var(--line);border-radius:10px;margin-bottom:9px;overflow:hidden}
.reqcard.overdue{border-color:var(--red-m)}
.reqcard.open{box-shadow:0 3px 14px rgba(15,23,42,.09)}
.rq-head{display:flex;align-items:center;gap:16px;padding:11px 14px;cursor:pointer}
.rq-head:hover{background:var(--bg)}
.rq-no{flex:none;width:190px;min-width:0}
.rq-no b{font-size:13px;display:block}
.rq-status{
  display:inline-block;font-size:10px;font-weight:700;border-radius:99px;padding:1px 8px;
  margin-top:2px;background:var(--line-2);color:var(--muted);
}
.rq-status.s-submitted{background:var(--amber-l);color:var(--amber-d)}
.rq-status.s-approved{background:var(--blue-l);color:var(--blue-d)}
.rq-status.s-partially_fulfilled{background:var(--blue-l);color:var(--blue-d)}
.rq-status.s-fulfilled{background:var(--green-l);color:var(--green-d)}
.rq-status.s-rejected{background:var(--red-l);color:var(--red-d)}
.rq-late{background:var(--red);color:#fff;font-size:9.5px;font-weight:700;border-radius:99px;
  padding:1px 7px;margin-left:4px;text-transform:uppercase}
.rq-where{flex:1.3;font-size:12.5px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rq-where span{display:block;font-size:11px;color:var(--muted)}
.rq-when{flex:none;width:150px;font-size:11.5px;color:var(--muted)}
.rq-when span{display:block;font-size:10.5px;color:var(--faint)}
.rq-prog{flex:none;width:150px}
.rq-bar{height:7px;background:var(--line);border-radius:99px;overflow:hidden}
.rq-fill{height:100%;background:var(--teal);border-radius:99px}
.rq-prog span{font-size:10.5px;color:var(--muted);display:block;margin-top:3px}
.rq-caret{flex:none;color:var(--faint);font-size:13px}
.rq-body{padding:0 14px 12px;border-top:1px solid var(--line-2)}
.rq-actions{display:flex;gap:8px;margin-top:11px;align-items:center;flex-wrap:wrap}
.rq-status.s-draft,.rq-status.s-cancelled{background:var(--line-2);color:var(--muted)}

/* ---------- the bell, the drawer, and "something is waiting" ----------
   Genard, 25 Sep. One rule for all of it: attention without nagging. The count and the
   amber dot are always there while anything waits; MOVEMENT happens only when something
   new arrives, three beats, then still. Anything that moves for ever becomes wallpaper. */

.topwrap{display:flex;flex:none;align-items:stretch;min-width:0}
.topwrap .topbar{flex:1;min-width:0}
.bell-slot{flex:none;display:flex;align-items:center;padding:0 14px 0 6px;
  background:var(--card);border-bottom:1px solid var(--line)}
.bell-slot:empty{display:none}
.bell{position:relative;width:38px;height:38px;border-radius:10px;border:1px solid var(--line);
  background:var(--card);cursor:pointer;display:grid;place-items:center;padding:0}
.bell:hover{border-color:var(--teal);background:var(--teal-l)}
.bell-ico{font-size:17px;line-height:1;filter:grayscale(1);opacity:.55}
.bell.has .bell-ico{filter:none;opacity:1}
.bell-count{position:absolute;top:-6px;right:-7px;min-width:19px;height:19px;padding:0 5px;
  border-radius:99px;background:#b45309;color:#fff;font-size:10.5px;font-weight:800;
  display:grid;place-items:center;border:2px solid var(--card);font-variant-numeric:tabular-nums}
.bell-count.late{background:var(--red)}
.bell.ring .bell-ico{animation:bell-swing .9s ease-in-out 3;transform-origin:50% 10%}
.bell.ring .bell-count{animation:attn-pop .9s ease-in-out 3}
@keyframes bell-swing{
  0%,100%{transform:rotate(0)} 15%{transform:rotate(16deg)} 30%{transform:rotate(-14deg)}
  45%{transform:rotate(9deg)} 60%{transform:rotate(-6deg)} 75%{transform:rotate(2deg)}
}
@keyframes attn-pop{0%,100%{transform:scale(1)} 40%{transform:scale(1.22)}}

/* The list under the bell. Solid white: it is records, not chrome. */
.bell-panel{position:fixed;top:56px;right:14px;z-index:75;width:380px;max-width:calc(100vw - 28px);
  max-height:min(70vh,560px);display:flex;flex-direction:column;background:var(--card);
  border:1px solid var(--line);border-radius:12px;box-shadow:0 16px 44px rgba(15,23,42,.22);overflow:hidden}
.bp-head{display:flex;justify-content:space-between;align-items:center;padding:11px 14px;
  border-bottom:1px solid var(--line-2);font-size:13px}
.bp-head span{font-size:11.5px;color:var(--muted)}
.bp-body{overflow:auto;flex:1}
.bp-desk{font-size:9.5px;font-weight:800;letter-spacing:.8px;text-transform:uppercase;color:var(--muted);
  padding:9px 14px 3px}
.bp-row{display:grid;grid-template-columns:1fr auto;gap:1px 10px;padding:7px 14px;text-decoration:none;
  color:var(--ink);border-left:3px solid transparent}
.bp-row:hover{background:var(--line-2)}
.bp-row.new{border-left-color:var(--amber-d);background:var(--amber-l)}
.bp-row.late .bp-age b{color:var(--red)}
.bp-step{font-size:12.5px;font-weight:700}
.bp-n{display:inline-block;min-width:17px;padding:0 5px;margin-left:4px;border-radius:99px;
  background:var(--amber-l);color:var(--amber-d);font-size:10.5px;text-align:center}
.bp-title{grid-column:1;font-size:11.5px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bp-age{grid-column:2;grid-row:1 / span 2;align-self:center;font-size:11px;color:var(--muted);white-space:nowrap}
.bp-empty{padding:22px 14px;text-align:center;color:var(--muted);font-size:12.5px}
.bp-foot{display:block;padding:10px 14px;border-top:1px solid var(--line-2);font-size:12px;font-weight:600;
  color:var(--teal-d);text-decoration:none}
.bp-foot:hover{background:var(--teal-l)}
/* Search and sound, inside the bell's list. */
.bp-head b{margin-right:auto}
.bp-head span{margin-right:8px}
.bp-snd{border:1px solid var(--line);background:var(--card);border-radius:8px;width:30px;height:26px;
  cursor:pointer;font-size:13px;line-height:1;padding:0}
.bp-snd:hover,.bell-panel.show-sound .bp-snd{border-color:var(--teal);background:var(--teal-l)}
.bp-sound{display:none;padding:10px 14px;border-bottom:1px solid var(--line-2);background:var(--line-2);font-size:12px}
.bell-panel.show-sound .bp-sound{display:block}
.bp-switch{display:flex;align-items:center;gap:8px;font-weight:600;cursor:pointer}
.bp-switch input{width:15px;height:15px;accent-color:var(--teal-d)}
.bp-tone{display:flex;align-items:center;gap:8px;margin-top:8px}
.bp-tone span{color:var(--muted);flex:none}
.bp-tone select{flex:1;min-width:0;padding:5px 8px;border:1px solid var(--line);border-radius:8px;
  background:var(--card);color:var(--ink)}
.bp-tone .btn{flex:none;padding:5px 10px}
.bp-sound-note{margin-top:7px;font-size:11px;color:var(--muted)}
.bp-search{display:flex;align-items:center;gap:7px;margin:9px 12px 4px;padding:0 10px;
  border:1px solid var(--line);border-radius:9px;background:var(--card)}
.bp-search:focus-within{border-color:var(--teal);box-shadow:0 0 0 3px color-mix(in srgb, var(--teal) 18%, transparent)}
.bp-search span{color:var(--muted);font-size:15px}
.bp-search input{flex:1;min-width:0;border:0;outline:0;background:transparent;color:var(--ink);padding:7px 0;font-size:12.5px}

/* ---------- the search box in the top bar of a list screen (ui/search.js) ---------- */
.qbox{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 10px;min-width:0;
  flex:0 1 220px;width:220px;max-width:100%;border:1px solid var(--line);border-radius:9px;background:var(--card);cursor:text}
.qbox:focus-within{border-color:var(--teal);box-shadow:0 0 0 3px color-mix(in srgb, var(--teal) 18%, transparent)}
.qbox.on{border-color:var(--teal)}
.qbox .q-ico{color:var(--muted);font-size:16px;line-height:1}
.qbox .q-in{flex:1;min-width:0;border:0;outline:0;background:transparent;color:var(--ink);font-size:12.5px;padding:0}
.qbox .q-count{flex:none;font-size:11px;font-weight:700;color:var(--teal-d);white-space:nowrap}
.q-hide{display:none !important}
.q-none{margin:14px 18px 0;padding:12px 14px;border:1px dashed var(--line-3);border-radius:10px;
  color:var(--muted);font-size:12.5px;display:flex;align-items:center;gap:12px;flex-wrap:wrap}
@media (max-width:720px){ .qbox{width:100%;order:5} }

/* The count beside a sidebar item. */
.nav-badge{margin-left:auto;min-width:18px;height:18px;padding:0 5px;border-radius:99px;
  background:#b45309;color:#fff;font-size:10px;font-weight:800;display:grid;place-items:center}

/* A KPI card that opens something. Same card, plus a dot, plus a hand. */
button.kpi.kpi-action{font:inherit;text-align:left;cursor:pointer;background:transparent;border:0;
  border-right:1px solid var(--line);color:inherit}
button.kpi.kpi-action:hover{background:var(--amber-l)}
.kpi.attn .val{color:var(--amber-d)}
.kpi.attn .sub b{color:var(--amber-d)}
.attn-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--amber-d);
  margin-right:6px;vertical-align:1px}
.kpi.ring .attn-dot{animation:attn-ping 1.1s ease-out 3}
.kpi.ring .val{animation:attn-pop 1.1s ease-in-out 3;display:inline-block}
@keyframes attn-ping{
  0%{box-shadow:0 0 0 0 rgba(180,83,9,.55)} 80%,100%{box-shadow:0 0 0 9px rgba(180,83,9,0)}
}

/* The drawer — see openDrawer() in ui/dom.js. */
/* ⚠️ Below .modal-bg (60): a drawer's own actions open dialogs, and a dialog that
   opens BEHIND the drawer that asked for it looks like a click that did nothing. */
.drawer-wrap{position:fixed;inset:0;z-index:55}
.drawer-bg{position:absolute;inset:0;background:rgba(15,23,42,0);transition:background .18s}
/* The page behind steps back — darker and slightly out of focus — so the card reads as a
   separate sheet laid over it, not as more of the same screen (Genard, 1 Oct: "murag iya
   lang jud gi sapawan ang main display"). */
.drawer-wrap.open .drawer-bg{background:rgba(15,23,42,.38);
  backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px)}
/**
 * The side card, every one of them (openDrawer): frosted glass carrying a hint of the
 * company's own colour (--teal is the accent they chose under Company), a coloured edge
 * where it meets the page, and a tinted head.
 *
 * ⚠️ Glass on the FRAME only. The rule since Stage 2 is "glass on the chrome, never on
 * the data": the body stays nearly opaque (94%) so a column of figures is read against a
 * flat surface, not through a blur.
 */
.drawer{position:absolute;top:0;right:0;bottom:0;max-width:100vw;display:flex;flex-direction:column;
  background:color-mix(in srgb, var(--teal) 5%, color-mix(in srgb, var(--card) 94%, transparent));
  backdrop-filter:blur(22px) saturate(1.5);-webkit-backdrop-filter:blur(22px) saturate(1.5);
  border-left:3px solid var(--teal);
  box-shadow:-22px 0 60px rgba(15,23,42,.34), inset 1px 0 0 var(--glass-hi);
  transform:translateX(100%);transition:transform .18s ease-out}
.drawer-wrap.open .drawer{transform:none}
.drawer-head{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;
  background:color-mix(in srgb, var(--teal) 13%, transparent);
  border-bottom:1px solid color-mix(in srgb, var(--teal) 35%, var(--line))}
.drawer-head h2{margin:0;font-size:15px}
@supports not ((backdrop-filter:blur(2px)) or (-webkit-backdrop-filter:blur(2px))){
  .drawer{background:color-mix(in srgb, var(--teal) 5%, var(--card))}
}
@media (prefers-reduced-transparency:reduce){
  .drawer{background:color-mix(in srgb, var(--teal) 5%, var(--card));backdrop-filter:none;-webkit-backdrop-filter:none}
  .drawer-wrap.open .drawer-bg{backdrop-filter:none;-webkit-backdrop-filter:none}
}
.drawer-x{border:0;background:transparent;font-size:16px;cursor:pointer;color:var(--muted);
  width:30px;height:30px;border-radius:7px}
.drawer-x:hover{background:var(--line-2);color:var(--ink)}
.drawer-body{flex:1;overflow:auto;padding:4px 0 0}

/* The approval list inside it. */
.dr-intro{font-size:11.5px;color:var(--muted);padding:8px 16px 4px;line-height:1.5}
.dr-empty{padding:40px 16px;text-align:center;font-size:14px;font-weight:700;color:var(--green)}
.dr-empty span{display:block;font-size:12px;font-weight:400;color:var(--muted);margin-top:5px}
.ap-group{padding:6px 0}
.ap-group-h{font-size:9.5px;font-weight:800;letter-spacing:.8px;text-transform:uppercase;color:var(--muted);
  padding:8px 16px 4px;display:flex;gap:6px}
.ap-group-h span{color:var(--faint)}
.ap-dr{margin:4px 12px 8px;border:1px solid var(--line);border-radius:9px;overflow:hidden}
.ap-dr-h{display:flex;align-items:center;gap:8px;padding:7px 10px;background:var(--line-2);font-size:12px}
.ap-dr-h span{color:var(--muted);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ap-all{padding:3px 10px;font-size:11.5px}
.ap-row{display:flex;align-items:center;gap:10px;padding:8px 16px;border-top:1px solid var(--line-2)}
.ap-dr .ap-row{padding:7px 10px}
.ap-dr .ap-row:first-of-type{border-top:0}
.ap-tick{width:16px;height:16px;accent-color:var(--teal);flex:none;cursor:pointer}
.ap-what{flex:1;min-width:0}
.ap-what b{display:block;font-size:12.5px}
.ap-what span{display:block;font-size:11px;color:var(--muted)}
.ap-what .ap-by{color:var(--faint)}
.ap-do{flex:none;display:flex;gap:5px}
.ap-do .btn{padding:4px 10px;font-size:13px;line-height:1}
.ap-foot{position:sticky;bottom:0;display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:10px 16px;background:var(--card);border-top:1px solid var(--line)}

/* ---------- V1 Stage 7: signatures, VAT, previously billed ---------- */
/* Only on paper: the client's summary of a variation, which on screen would repeat
   the row heading above it. */
.print-only{display:none}
.co-title b{display:block;font-size:15px;letter-spacing:.3px}
.co-title span{font-size:11.5px;color:var(--muted)}
/* Signature lines are for paper (Genard, 25 Sep: "pointless… dapat mu gawas ra sya kung
   e print"). On screen they took space and said nothing; the names are set in Settings. */
.sigs{display:none;gap:26px;margin:26px 0 6px;break-inside:avoid;page-break-inside:avoid}
.sigs-3{grid-template-columns:repeat(3,1fr)}
.sigs-2{grid-template-columns:repeat(2,minmax(0,260px));justify-content:space-between}
.sig-role{font-size:11px;font-weight:700;color:var(--muted)}
.sig-line{height:34px;border-bottom:1px solid var(--ink)}
.sig-name{font-size:12.5px;font-weight:700;margin-top:4px;text-align:center;min-height:16px}
.sig-title{font-size:10.5px;color:var(--muted);text-align:center}
.sig-date{font-size:10.5px;color:var(--muted);margin-top:8px}
.vatbox{margin-top:12px;max-width:620px;border:1px dashed var(--line);border-radius:8px;padding:8px 12px;
  font-size:12px;display:grid;grid-template-columns:1fr auto;gap:2px 16px}
.vatbox .vb-h{grid-column:1 / -1;font-size:10px;font-weight:800;letter-spacing:.7px;text-transform:uppercase;
  color:var(--muted);margin-bottom:2px}
.vatbox .num{text-align:right;font-variant-numeric:tabular-nums}
.vatbox.vb-noprint-note{border-style:dotted}
.bill-sub{font-size:10px;font-weight:800;letter-spacing:.7px;text-transform:uppercase;color:var(--muted);
  margin:16px 0 4px}
@media print{
  .sigs{display:grid !important;margin-top:34px}
  .sig-line{border-bottom-color:#000}
  .vatbox{border-color:var(--faint)}
  /* What the contractor keeps from the client: costs and margin on a variation. */
  /* ⚠️ Specific enough to beat `body.print-one .reqcard.print-me .hint`, which puts a
     record's own notes back on the page — an internal note is still internal inside
     the record being printed. It lost to that rule once, and "No priced lines…" and
     "Approved by Demo Owner" went out on a variation (Genard's test print, 25 Sep). */
  /* The extra class on each selector is deliberate: at equal specificity the LATER
     rule wins, and the one that shows record notes sits further down this file. The
     first fix was exactly equal and lost — caught by checking the printed page. */
  body.print-one .internal,
  body.print-one .reqcard.print-me .internal,
  body.print-one .reqcard.print-me .hint.internal,
  body.print-one .reqcard.print-me table.internal{display:none !important}
  .print-only{display:table !important}
  div.print-only{display:block !important}
  /* A variation prints its own titled summary, so the screen row above it goes. */
  body.print-one .reqcard.print-me.co-card .rq-head{display:none !important}
  .vat-hidden-on-print{display:none !important}
  /* Used across the app for screen-only notes and controls, and never actually defined
     until now — it only looked like it worked because the things carrying it were
     hidden on paper by other rules. */
  .no-print{display:none !important}
}

/* ---------- Billing & Collections: register + drawer (Genard, 25 Sep) ----------
   One scrolling page: the billings first, one line each; aging and the advance as two
   small cards under them; a billing's full statement in the drawer. */
.bill-banner{border-radius:8px;margin:0 0 10px}
.bill-remind{font-size:12px;color:var(--amber-d);background:var(--amber-l);border-radius:8px;
  padding:7px 12px;margin:0 0 10px}
.bill-remind .btn.link{font-size:12px;font-weight:700}
.bill-reg-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:6px}
.bill-reg-head .sec-head{margin:0}
.bill-filters{display:flex;gap:6px;flex-wrap:wrap}
.bill-filters .chip span{opacity:.6;margin-left:3px;font-variant-numeric:tabular-nums}
/* ⚠️ Capped, with its own scroll and a header that stays put (Genard, 25 Sep: "kung
   daghan na… dili mag huot sa screen"). With a hundred billings the figures above and
   the aging and advance below stay where they are; only the list scrolls, and the
   column names never scroll away from the numbers under them. With three billings the
   box is simply three rows tall — the cap is a ceiling, not a size. */
.bill-register{padding:0;overflow:auto;max-height:max(300px, calc(100vh - 500px));
  max-height:max(300px, calc(100dvh - 500px))}
table.grid.bill-table thead th{position:sticky;top:0;z-index:2;background:var(--card);
  box-shadow:inset 0 -1px 0 var(--line)}
table.grid.bill-table td{padding:8px 8px}
/* The row under the pointer — and only that row — lights up, with a bar on its left
   edge so it reads as "this one" even on a long list. */
.bill-row{cursor:pointer}
.bill-row:hover td{background:var(--teal-l)}
.bill-row:hover td:first-child{box-shadow:inset 3px 0 0 var(--teal)}
.bill-row.is-open td{background:var(--teal-l)}
.bill-row.is-open td:first-child{box-shadow:inset 3px 0 0 var(--teal-d)}
.bill-row.over:hover td{background:var(--red-l)}
.bill-row.cancelled td{color:var(--faint);text-decoration:line-through}
.bill-row.cancelled td:last-child,.bill-row.cancelled td:nth-last-child(2){text-decoration:none}
.bill-row .rowprint{opacity:1}
.bill-side{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:12px;margin-top:14px}
.bill-mini{padding:12px 14px}
.bm-head{display:flex;justify-content:space-between;align-items:baseline;gap:10px;margin-bottom:6px}
.bm-head b{font-size:13px}
.bm-head span{font-size:11.5px;color:var(--muted)}
.bm-row{display:flex;justify-content:space-between;font-size:12.5px;padding:3px 0;
  border-top:1px solid var(--line-2)}
.bm-row span{color:var(--muted)}
.bm-row b{font-variant-numeric:tabular-nums}
.bm-note{font-size:11.5px;color:var(--amber-d);margin-top:8px;display:flex;align-items:center;
  gap:8px;flex-wrap:wrap}
.bm-note .btn{padding:3px 10px;font-size:11.5px}
/* The billing, in the drawer. */
.bill-detail{padding:4px 16px 20px}
.bd-top{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:6px 0 10px}
.bd-meta{font-size:12px;color:var(--muted)}
.bd-actions{display:flex;gap:6px;flex-wrap:wrap;padding-bottom:10px;border-bottom:1px solid var(--line-2)}
.bd-actions .btn{padding:5px 11px;font-size:12px}
/* The sheet that prints: never on screen, only on paper. */
.bill-sheet{display:none}
.bs-head{display:flex;justify-content:space-between;gap:20px;margin-bottom:6px}
.bs-head b{display:block;font-size:15px}
.bs-head span{font-size:11.5px;color:var(--muted)}
.bs-dates{font-size:11.5px;text-align:right;color:var(--muted)}
/* The billing's short sections, two across (Genard, 25 Sep — one page, portrait). */
.bill-pair{display:grid;grid-template-columns:1fr 1fr;gap:0 18px;align-items:start}
.bill-pair > div, .bill-one{min-width:0}
table.grid.bill-mini-table{width:100%}
/* The one line that stands for the older billings / payments on a printed billing. */
/* Folding happens on the PRINTED billing only — the board (the drawer on screen) always
   lists every billing and payment (Genard, 26 Sep: "sa e print ra ni"). */
table.grid tr.folded td{font-style:italic;color:var(--muted);background:var(--line-2)}
@media print{
  /* ⚠️ It WRAPS. The first version did not (table cells are nowrap app-wide), so its long
     label widened its half of the page and ran the Previously billed figures on top of
     Payment received — caught on the test print, 26 Sep. */
  .bill-sheet table.grid tr.folded td{white-space:normal}
  /* And the two halves can never push into each other, whatever is in them. */
  .bill-sheet .bill-pair > div{overflow:hidden}
  .bill-sheet .bill-pair table.grid.bill-mini-table{table-layout:fixed}
}
@media print{ table.grid tr.folded td{print-color-adjust:exact;-webkit-print-color-adjust:exact} }
.bill-due{font-size:12px;margin-top:10px}
.bill-foot{margin-top:3px;font-size:10.5px}
.drawer .bill-pair{grid-template-columns:1fr}
@media print{
  /* ---- the billing as ONE portrait page ----
     Full width of the paper, tighter rows, the headings small — the shape of a printed
     billing form, not of a screen. Signatures stay on the same page as the figures they
     sign off; the attachment starts page 2. */
  .bill-sheet table.grid{max-width:none !important;width:100% !important;font-size:9.5px}
  .bill-sheet table.grid td{padding:2px 6px}
  .bill-sheet table.grid th{padding:3px 6px;font-size:8px}
  .bill-sheet table.grid tr.total td{padding:4px 6px;font-size:10px}
  .bill-sheet .bill-sub{margin:10px 0 3px;font-size:8.5px}
  .bill-sheet .bill-pair{grid-template-columns:1fr 1fr;gap:0 16px}
  .bill-sheet .bs-head{margin-bottom:6px}
  .bill-sheet .bs-head b{font-size:14px}
  .bill-sheet .sigs{margin-top:22px;gap:18px}
  .bill-sheet .sig-line{height:26px}
  .bill-sheet .bill-due{font-size:10px;margin-top:8px}
  .bill-sheet .hint{font-size:9px}
  /* The Statement of Work Accomplished is the ATTACHMENT, and starts its own page
     (Genard, 25 Sep): running it on straight under the signatures made the billing
     and its attachment look like one long document. */
  .bill-sheet .swa{break-before:page;page-break-before:always}
  /* A long history's full lists: their own page, between the billing and the SWA. */
  .bill-sheet .bill-schedule{break-before:page;page-break-before:always}
  body.print-one .bill-sheet{display:block !important}
  body.print-one .bill-remind,body.print-one .bill-filters,body.print-one .bill-side{display:none !important}
}

/* ---------- V1 Stage 6: Equipment & Tools ---------- */
/* Page tabs: a row of their own at the very top of the bar (order:-1, full width), so
   nothing that changes between the tabs — the title, the buttons — can move them. */
.topbar .page-tabs{order:-1;flex-basis:100%;display:flex;margin:0}
/* A segmented toggle on glass: the track is the chrome, the chosen side is solid. */
.tabs-pill{display:inline-flex;gap:3px;padding:3px;border-radius:11px;
  background:var(--glass-bg);border:1px solid var(--glass-line, var(--line));
  backdrop-filter:blur(14px) saturate(1.4);-webkit-backdrop-filter:blur(14px) saturate(1.4);
  box-shadow:var(--glass-shadow), inset 0 1px 0 var(--glass-hi)}
.tabs-pill a{padding:6px 14px;border-radius:8px;font-size:12.5px;font-weight:600;
  color:var(--muted);text-decoration:none;white-space:nowrap;transition:background .15s,color .15s}
.tabs-pill a:hover{color:var(--ink);background:var(--teal-l)}
.tabs-pill a.on{background:var(--teal);color:#fff;box-shadow:0 1px 3px rgba(0,0,0,.18)}
.tabs-pill a:focus-visible{outline:2px solid var(--teal);outline-offset:2px}
/* With the toggle's row on top, the name / light-dark / bell sit with the TITLE row,
   not floating halfway between the two. */
.topwrap:has(.page-tabs) .bell-slot{align-items:flex-end;padding-bottom:11px}
@media print{ .page-tabs{display:none !important} }
.chip-sel{border:1px solid var(--line);border-radius:99px;padding:5px 10px;font:inherit;font-size:12px;
  background:var(--card);color:var(--ink);margin-left:auto}
/* Condition, in words and colour both — a colour alone says nothing on a printout. */
.cond{display:inline-block;font-size:10.5px;font-weight:700;border-radius:99px;padding:2px 8px;white-space:nowrap}
.cond.c-good{background:var(--green-l);color:var(--green-d)}
.cond.c-fair{background:var(--amber-l);color:var(--amber-d)}
.cond.c-for_repair{background:var(--amber-l);color:var(--amber-d)}
.cond.c-out_of_service{background:var(--red-l);color:var(--red-d)}
.where-pill{display:inline-block;font-size:11px;border:1px solid var(--line);border-radius:99px;
  padding:1px 8px;margin:1px 2px 1px 0;white-space:nowrap;background:var(--card)}
.where-pill b{font-variant-numeric:tabular-nums}
table.grid.assets td{padding:6px 7px}
/* One table per category, so the columns are fixed — otherwise each table sizes itself
   to its own contents and "Where" jumps sideways from Equipment to Vehicles. */
table.grid.assets{table-layout:fixed}
table.grid.assets th:nth-child(1){width:84px}
table.grid.assets th:nth-child(2){width:28%}
table.grid.assets th:nth-child(4){width:120px}
table.grid.assets th:nth-child(5){width:17%}
table.grid.assets th:nth-child(6){width:104px}
table.grid.assets th:nth-child(7){width:88px}
table.grid.assets td{overflow:hidden;text-overflow:ellipsis}
table.grid.assets td.where{white-space:normal;max-width:360px}
.asset-row{cursor:pointer}
.asset-row.retired td{color:var(--faint)}
.asset-sub{display:block;font-size:10.5px;color:var(--muted)}

/* The asset drawer. */
.as-facts{display:grid;grid-template-columns:1fr 1fr;gap:8px 14px;padding:10px 16px 12px;
  border-bottom:1px solid var(--line-2)}
.as-facts div span{display:block;font-size:10px;letter-spacing:.4px;text-transform:uppercase;color:var(--muted)}
.as-facts div b{font-size:12.5px;font-weight:600}
.as-facts .btn.link{grid-column:1 / -1;justify-self:start;font-size:12px}
.as-place{margin:6px 12px;border:1px solid var(--line);border-radius:9px;padding:9px 10px}
.as-place.late{border-color:var(--red-m);background:var(--red-l)}
.as-where b{display:block;font-size:13px}
.as-where > span{display:block;font-size:11.5px;color:var(--muted);margin-top:3px}
.as-acts{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px}
.as-acts .btn{padding:4px 10px;font-size:12px}
.as-hist{display:flex;gap:10px;padding:6px 16px;border-top:1px solid var(--line-2);font-size:12px}
.ah-date{flex:none;width:78px;color:var(--muted);font-variant-numeric:tabular-nums}
.ah-what{flex:1;min-width:0}
.ah-what > span:last-child{display:block;font-size:11px;color:var(--muted)}

@media (prefers-reduced-motion: reduce){
  .bell.ring .bell-ico,.bell.ring .bell-count,.kpi.ring .attn-dot,.kpi.ring .val{animation:none}
  .drawer,.drawer-bg{transition:none}
}
@media print{ .bell-slot,.bell-panel,.drawer-wrap{display:none !important} }

/* ---------- V1 Stage 5: routing ----------
   The trail — Requested › Approved › Purchased › For Delivery › Received. Done steps
   are ticked, the current one is filled, the rest are outlined. On a one-person
   installation the hand-off steps are not drawn at all (core/requests.js requestTrail). */
.trail{display:flex;flex-wrap:wrap;align-items:center;gap:3px;padding:0 14px 10px}
.trail.small{padding:4px 0 0}
.tr-step{font-size:10.5px;border-radius:99px;padding:2px 9px;border:1px solid var(--line);
  color:var(--muted);background:var(--card);white-space:nowrap}
.tr-step.done{background:var(--green-l);border-color:var(--green-m);color:var(--green-d)}
.tr-step.current{background:var(--teal);border-color:var(--teal);color:var(--on-accent);font-weight:700}
.tr-step.partial{background:var(--blue-l);border-color:var(--blue-m);color:var(--blue-d);font-weight:700}
.tr-sep{color:var(--faint);font-size:11px}
.trail.small .tr-step{font-size:9.5px;padding:1px 7px}

/* One heading per project — "naka separate per project ang requests". */
.sec-head.proj-head span{font-weight:400;text-transform:none;letter-spacing:0;margin-left:6px;
  color:var(--muted-on-wash)}

/* Purchase order: where it is delivered, and every delivery against it. */
.po-dest{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:10px 0 9px;font-size:12.5px}
.po-dest > span:first-child{font-size:10.5px;font-weight:700;letter-spacing:.4px;text-transform:uppercase;
  color:var(--muted)}
.po-dest select{border:1px solid var(--line);border-radius:7px;padding:5px 8px;font:inherit;font-size:12.5px;
  background:var(--card)}
.po-dels{margin-top:12px;border:1px solid var(--line-2);border-radius:8px;overflow:hidden}
.po-dels-h{font-size:10.5px;font-weight:700;letter-spacing:.4px;text-transform:uppercase;color:var(--muted);
  padding:6px 10px;background:var(--line-2)}
.po-del{display:flex;gap:12px;align-items:baseline;padding:6px 10px;border-top:1px solid var(--line-2);
  font-size:12px}
.po-del:first-of-type{border-top:0}
.pd-date{flex:none;width:84px;font-variant-numeric:tabular-nums}
.pd-dr{flex:none;width:160px;color:var(--muted)}
.pd-to{flex:none;width:190px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pd-items{flex:1;min-width:0}
.pd-state{flex:none;font-size:11.5px}

/* The Routing screen: one row per thing waiting, grouped by whose desk it is on.
   Solid white — these are records, not chrome. */
.route-list{display:flex;flex-direction:column;gap:6px;margin-bottom:20px}
.route-row{display:flex;align-items:center;gap:16px;background:var(--card);border:1px solid var(--line);
  border-radius:10px;padding:10px 14px;color:var(--ink);text-decoration:none}
.route-row:hover{border-color:var(--teal);box-shadow:0 3px 12px rgba(15,23,42,.08)}
.route-row.late{border-color:var(--red-m)}
.rr-ref{flex:none;width:170px;min-width:0}
.rr-ref b{display:block;font-size:13px}
.rr-ref span{display:block;font-size:11px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rr-what{flex:1;min-width:0}
.rr-step{font-size:13px;font-weight:700}
.rr-title{font-size:11.5px;color:var(--muted)}
.rr-age{flex:none;width:120px;text-align:right;font-size:12px;font-weight:600}
.rr-age span{display:block;font-size:10.5px;color:var(--muted);font-weight:400}
/* ⚠️ The rule above is for the "since …" line under the age — but the LATE pill is a span
   in the same box, and it was being turned grey-on-red and stretched to a block: the one
   word on the row that has to be read (Genard, 1 Oct). */
.rr-age span.rq-late{display:inline-block;color:#fff;font-weight:800;font-size:10.5px;letter-spacing:.5px;
  padding:2px 8px;margin:0 4px 0 0;vertical-align:1px}
.rr-go{flex:none;font-size:11.5px;color:var(--teal-d);font-weight:600}
.route-solo{margin-bottom:14px;max-width:760px;line-height:1.55}
.muted-on{color:var(--muted-on-wash);font-weight:400}
@media (max-width:700px){
  .route-row{flex-wrap:wrap;gap:6px 12px}
  .rr-ref{width:auto}
  .rr-age{width:auto;text-align:left}
}
.tag-ok{background:var(--green-l);color:var(--green-d);border-radius:99px;padding:1px 8px;font-size:10px;font-weight:700}

/* ---------- costs: budget vs actual ---------- */
table.grid tr.over td{background:var(--red-l)}
table.grid tr.subrow td{background:var(--row-sub);color:var(--muted);font-size:11.5px}
.spendbar{position:relative;height:9px;background:var(--line);border-radius:99px;display:flex;overflow:hidden}
.sb-fill{height:100%;background:var(--teal);border-radius:99px 0 0 99px}
.sb-fill.over{background:var(--red)}
.sb-over{height:100%;background:repeating-linear-gradient(45deg,#dc2626,#dc2626 3px,var(--red-m) 3px,var(--red-m) 6px)}
.dirtag{
  display:inline-block;padding:1px 7px;border-radius:99px;font-size:10px;font-weight:700;
  text-transform:uppercase;letter-spacing:.3px;
}
.dirtag.out{background:var(--red-l);color:var(--red-d)}
.dirtag.in{background:var(--green-l);color:var(--green-d)}

.catbars{display:flex;flex-direction:column;gap:7px;max-width:720px}
.catbar{display:flex;align-items:center;gap:12px}
.cb-label{width:96px;flex:none;font-size:12px;text-transform:capitalize}
.cb-track{flex:1;height:16px;background:var(--line-2);border-radius:5px;overflow:hidden}
.cb-fill{height:100%;background:var(--teal);border-radius:5px}
/* A bar is its background colour and nothing else — and browsers drop backgrounds on
   paper unless told to keep them. Without this "Where the money went" printed as a
   list of labels with nothing beside them (Genard, 1 Oct). */
@media print{ .cb-track,.cb-fill{print-color-adjust:exact;-webkit-print-color-adjust:exact}
  .cb-track{border:1px solid var(--line-3)} }
.cb-value{width:150px;flex:none;text-align:right;font-size:12px;font-variant-numeric:tabular-nums;font-weight:600}
.cb-value span{color:var(--muted);font-weight:400;margin-left:5px}

/* ---------- materials & stock ---------- */
.locbar{display:flex;gap:7px;flex-wrap:wrap;margin-bottom:14px}
.chip{
  border:1px solid var(--line);background:var(--card);border-radius:99px;padding:5px 13px;
  cursor:pointer;font-size:12px;color:var(--muted);
}
.chip:hover{background:var(--line-2)}
.chip.on{background:var(--navy);border-color:var(--navy);color:var(--on-sidebar);font-weight:600}

table.stock tbody tr{cursor:pointer}
table.stock tr.low td{background:var(--amber-l)}
table.stock tr.low:hover td{background:var(--amber-l)}
.tag-low{background:var(--amber-l);color:var(--amber-d);border:1px solid var(--amber-m);
  border-radius:99px;padding:1px 8px;font-size:10px;font-weight:700}
.pend{color:var(--muted);font-style:italic}

.queue{background:var(--card);border:1px solid var(--amber-m);border-left:4px solid var(--amber);
  margin:0 18px 14px;border-radius:10px;overflow:hidden}
.queue-head{padding:10px 14px;background:var(--amber-l);border-bottom:1px solid var(--amber-m)}
.queue-head b{color:var(--amber-d);font-size:12.5px}
.queue-head span{display:block;font-size:11px;color:var(--amber-d);margin-top:1px}
.queue-row{display:flex;align-items:center;gap:14px;padding:9px 14px;border-bottom:1px solid var(--line-2)}
.queue-row:last-child{border-bottom:0}
.qr-what{flex:1.4;min-width:0}
.qr-what b{display:block;font-size:12.5px}
.qr-what span{font-size:11.5px;color:var(--muted)}
.qr-where{flex:1.4;font-size:11.5px;color:var(--muted);min-width:0}
.qr-where .dr{display:inline-block;background:var(--line-2);border-radius:4px;padding:0 5px;margin-left:5px}
.qr-when{flex:none;font-size:11.5px;color:var(--muted);text-align:right}
.qr-when span{display:block;font-size:10.5px;color:var(--faint)}
.qr-do{flex:none;display:flex;gap:6px}

.lowstock{margin:0 18px 16px}
.ls-head{margin-bottom:8px}
.ls-head b{font-size:12.5px;color:var(--amber-d)}
.ls-head span{font-size:11px;color:var(--muted);margin-left:8px}
.ls-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:9px}
.ls-card{background:var(--card);border:1px solid var(--amber-m);border-radius:10px;padding:11px 13px}
.ls-card.urgent{border-color:var(--red-m);background:var(--red-l)}
.ls-name{font-weight:700;font-size:12.5px}
.ls-loc{font-size:11px;color:var(--muted);margin-bottom:6px}
.ls-qty{font-size:19px;font-weight:800;font-variant-numeric:tabular-nums}
.ls-qty span{font-size:11px;font-weight:500;color:var(--muted)}
.ls-days{font-size:11.5px;color:var(--amber-d);margin-top:2px}
.ls-card.urgent .ls-days{color:var(--red)}
.ls-days b{font-size:13px}
.ls-pending{font-size:11px;color:var(--teal-d);margin-top:2px;font-weight:600}
.ls-re{font-size:10.5px;color:var(--faint);margin-top:3px}
.muted{color:var(--faint)}

.histrow td{background:var(--line-2);padding:0 !important}
.hist{padding:9px 14px}
.hist-head{font-size:10.5px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);
  font-weight:700;margin-bottom:5px}
.hist-row{display:flex;gap:12px;padding:3px 0;font-size:11.5px;align-items:baseline}
.hist-row.unapproved{opacity:.6;font-style:italic}
.h-date{width:82px;flex:none;color:var(--muted);font-variant-numeric:tabular-nums}
.h-type{width:150px;flex:none}
.h-delta{width:70px;flex:none;text-align:right;font-weight:700;font-variant-numeric:tabular-nums}
.h-bal{width:80px;flex:none;text-align:right;color:var(--muted);font-variant-numeric:tabular-nums}
.h-note{color:var(--faint);font-size:11px}

/* ---------- empty states ---------- */
.blank{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  flex:1;padding:50px 24px;text-align:center;color:var(--muted);
}
.blank .mark{
  width:52px;height:52px;border-radius:14px;background:var(--teal-l);color:var(--teal-d);
  display:grid;place-items:center;font-size:24px;margin-bottom:14px;
}
.blank h2{color:var(--ink);font-size:17px;margin:0 0 6px}
.blank p{margin:0 0 4px;max-width:440px;line-height:1.55}
.blank .steps{
  text-align:left;margin:16px 0 18px;max-width:420px;background:var(--card);
  border:1px solid var(--line);border-radius:10px;padding:14px 18px;
}
.blank .steps li{margin:5px 0;color:var(--ink);font-size:12.5px}
.blank .steps li span{color:var(--muted)}

/* ============================================================================
   V1 STAGE 2 — GLASS
   ============================================================================

   Everything in this block is the redesign's surface treatment. It deliberately
   sits in ONE place, after the components it restyles, so it can be read as a
   whole and removed as a whole.

   ## The rule, and why it is a rule

   ⚠️ Glass on the CHROME. Never on the data, never on paper.

   Glassmorphism works by being see-through, and see-through costs contrast. On a
   printed billing, or on a site-office monitor in daylight with the sun on it, low
   contrast is not "subtle" — it is unreadable, and the person holding the page is a
   client. So: the frame around the work may be glass; the work itself stays solid
   black on solid white. Table rows, figures, totals and anything that prints are
   untouched below.

   ## Glass needs something behind it

   `backdrop-filter` blurs whatever is BEHIND an element. On the old flat var(--bg)
   page there was nothing behind anything, so every "glass" panel rendered as a
   slightly grey box — the effect cost a repaint and bought nothing. Hence the
   ambient wash on .content: two very low-alpha brand-coloured pools that the panels
   have something to pick up. It is built from the theme variables, so a customer who
   sets their own colours gets their own wash for free.
*/

:root{
  /* One place to tune the whole treatment. */
  --glass-bg:rgba(255,255,255,.72);
  --glass-bg-strong:rgba(255,255,255,.82);
  --glass-line:rgba(255,255,255,.75);
  --glass-blur:14px;
  --glass-shadow:0 1px 2px rgba(15,23,42,.04), 0 8px 24px -12px rgba(15,23,42,.14);
}

/**
 * The wash. Fixed to the content column, painted once, never scrolls.
 *
 * `background-attachment: fixed` rather than a child element: no extra node, nothing
 * to keep in sync with the layout, and no new stacking context to trip the print
 * watermark over (see the z-index note in the print block).
 */
.content{
  background:
    /* ⚠️ The pools sit INSIDE the viewport. Centred just off the edge, as they were
       first drawn, only the faint outer rim of each one is ever on screen — the wash
       was there, and invisible, which is the same as not having done it. */
    radial-gradient(ellipse 70% 55% at 6% 10%,   color-mix(in srgb, var(--teal) 38%, transparent), transparent 62%),
    radial-gradient(ellipse 60% 48% at 96% 6%,   color-mix(in srgb, var(--navy) 26%, transparent), transparent 58%),
    radial-gradient(ellipse 65% 50% at 78% 96%,  color-mix(in srgb, var(--teal) 26%, transparent), transparent 62%),
    var(--bg);
  background-attachment:fixed;
}

/* ---- the chrome: bounded in number, so real blur is affordable ---- */

.topbar,.bell-slot,
.kpis,
.panel,
.card,
.preview-doc{
  background:var(--glass-bg);
  backdrop-filter:blur(var(--glass-blur)) saturate(140%);
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(140%);
  border-color:var(--glass-line);
}
/* The lit top edge is what makes a pane read as glass rather than as a pale box: real
   glass catches the light along its upper rim. One inset line does the whole job. */
.panel,.card{
  box-shadow:var(--glass-shadow), inset 0 1px 0 var(--glass-hi);
}
/* The two bars that frame the work read better slightly more solid — the figures in
   the KPI row are the most-read numbers in the app. */
.topbar,.bell-slot,.kpis{background:var(--glass-bg-strong)}

.card:is([data-open], a, button, [role="button"]):hover{
  border-color:var(--teal);
  box-shadow:0 1px 2px rgba(15,23,42,.05), 0 14px 32px -14px rgba(13,148,136,.45);
  transform:translateY(-1px);
}
.card{transition:border-color .14s, box-shadow .14s, transform .14s}

/**
 * ⚠️ Repeated list items get the LOOK without the blur.
 *
 * `.reqcard` is one row per material request, and a busy warehouse has fifty of them
 * in a scrolling column. `backdrop-filter` is composited per element per frame, so
 * fifty of them is a measurable stutter on the kind of PC this runs on — and the
 * customer blames the app, not the fashion. Translucency and the light border carry
 * the same appearance down a list; only the top layer actually refracts.
 */
.reqcard{
  background:var(--glass-bg-strong);
  border-color:var(--glass-line);
  box-shadow:0 1px 2px rgba(15,23,42,.04);
}
.reqcard.open{background:var(--card)}

/* ---- the sidebar: glass over the navy, not over the page ---- */

.sidebar{
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--navy) 92%, transparent),
                            color-mix(in srgb, var(--navy) 99%, transparent)),
    var(--navy);
  border-right:1px solid rgba(255,255,255,.07);
}
.nav a.on{
  box-shadow:0 2px 10px -2px color-mix(in srgb, var(--teal) 55%, transparent);
}
.active-project,.sync-status a,.edition a,.projpick select{
  backdrop-filter:blur(6px);
  -webkit-backdrop-filter:blur(6px);
}

/* ---- controls: dropdowns, dates, and the row Print button ---- */

/**
 * ⚠️ A native `<select>` and `<input type="date">` are TWO things: the closed control,
 * which is ours to style, and the popup list or calendar, which the operating system
 * draws and no stylesheet can touch. Everything below dresses the closed control. The
 * dropdown list that appears on click will still look like Windows — that is not a
 * setting anybody has, and pretending otherwise would mean rebuilding the select in
 * JavaScript and losing the keyboard, the touch handling and the type-to-jump that come
 * free with the real one.
 */
select,
input[type="date"],
input[type="month"],
input[type="time"],
.field input,
.field select,
.field textarea{
  background:var(--glass-bg-strong);
  backdrop-filter:blur(8px) saturate(140%);
  -webkit-backdrop-filter:blur(8px) saturate(140%);
  border:1px solid var(--glass-line);
  border-radius:8px;
  box-shadow:inset 0 1px 0 var(--glass-hi), 0 1px 2px rgba(15,23,42,.05);
  color:var(--ink);
}
select:hover,
input[type="date"]:hover,
.field input:hover,
.field select:hover{border-color:color-mix(in srgb, var(--teal) 45%, var(--glass-line))}
select:focus,
input[type="date"]:focus,
.field input:focus,
.field select:focus,
.field textarea:focus{
  outline:0;border-color:var(--teal);
  box-shadow:inset 0 1px 0 var(--glass-hi), 0 0 0 3px color-mix(in srgb, var(--teal) 22%, transparent);
}
/* The OS draws the open list in its own colours, so the options need a readable pair of
   their own or they inherit something unreadable on a translucent control. */
select option{background:var(--card);color:var(--ink)}

/* ⚠️ Not the in-cell editors. Those sit inside a table, and a table row is data —
   glass on it is the thing the whole treatment is supposed to stay off. */
input.cell,select.cell{
  backdrop-filter:none;-webkit-backdrop-filter:none;
  box-shadow:none;
}

/**
 * The row Print button was too faint to find.
 *
 * It was drawn at 45% opacity and only came up on hover, which is invisible on a laptop
 * trackpad and impossible on a touch screen. It is a real button now — a small glass
 * chip that is always there — and still quiet enough that thirty of them down a list do
 * not shout over the figures.
 */
.rowprint{
  opacity:1;
  background:var(--glass-bg);
  backdrop-filter:blur(8px) saturate(140%);
  -webkit-backdrop-filter:blur(8px) saturate(140%);
  border:1px solid var(--glass-line);
  box-shadow:inset 0 1px 0 var(--glass-hi), 0 1px 2px rgba(15,23,42,.06);
  color:var(--navy-ink);
}
.reqcard:hover .rowprint{
  border-color:color-mix(in srgb, var(--teal) 50%, var(--glass-line));
  color:var(--teal-d);
}
.rowprint:hover{
  background:var(--teal-l);border-color:var(--teal);color:var(--teal-d);
  box-shadow:inset 0 1px 0 var(--glass-hi), 0 2px 8px -2px color-mix(in srgb, var(--teal) 55%, transparent);
}

/* ---- text that sits ON the wash, not on a panel ---- */

/**
 * ⚠️ MEASURED, not guessed: `--muted` (var(--muted)) on the strongest part of the wash comes
 * out at **3.24:1**. WCAG AA wants 4.5:1 for text this size, and `.sec-head` is 10.5px
 * — bold does not make it "large text".
 *
 * And it cannot be fixed by softening the wash. Solving the contrast equation for
 * var(--muted) at 4.5:1 puts the required backdrop luminance at 0.961; plain var(--bg) is
 * 0.958. In other words **any wash visible at all** fails with that grey. So the wash
 * stays and the text darkens — which is the right way round, because these are labels
 * on a page rather than captions inside a card.
 *
 * The rule for every screen built from here: text directly on `.pad` or `.screen` uses
 * --ink-on-wash or --muted-on-wash. Text inside a panel or a card may stay --muted,
 * because a panel is 72–82% white and the wash never reaches it.
 */
:root{
  --ink-on-wash:#334155;    /* 7.06:1 on the worst case */
  --muted-on-wash:#475569;  /* 5.16:1 on the worst case */
}
.sec-head{color:var(--ink-on-wash)}
.pad > .hint,
.screen > .hint,
.blank .steps li span,
.blank p{color:var(--muted-on-wash)}

/* ---- where glass must not go ---- */

/**
 * Data stays solid. A number behind frosted glass is a number somebody has to lean in
 * to read, and these are the rows people copy into a bank instruction.
 */
table.grid,
table.grid th,
table.grid td,
tr.total td,
.modal{
  backdrop-filter:none;
  -webkit-backdrop-filter:none;
}
.modal{background:var(--modal-bg)}

/* ---- when the machine, or the person, says no ---- */

/**
 * ⚠️ Two honest escape hatches, and both matter more than the effect does.
 *
 * `prefers-reduced-transparency` is set by somebody who has told their operating system
 * that translucency makes their screen hard to read. Overriding that with a fashion is
 * not a design decision, it is ignoring an accessibility setting.
 *
 * The @supports arm catches the older browsers this app is expected to survive on —
 * without it they get the low-contrast background with none of the blur that made it
 * legible, which is the worst of both.
 */
@supports not ((backdrop-filter:blur(2px)) or (-webkit-backdrop-filter:blur(2px))){
  .topbar,.bell-slot,.kpis,.panel,.card,.reqcard,.preview-doc,.modal,
  select,input[type="date"],input[type="month"],input[type="time"],
  .field input,.field select,.field textarea,.rowprint{background:var(--card)}
}
@media (prefers-reduced-transparency:reduce){
  .topbar,.bell-slot,.kpis,.panel,.card,.reqcard,.preview-doc,.modal,
  select,input[type="date"],input[type="month"],input[type="time"],
  .field input,.field select,.field textarea,.rowprint{
    background:var(--card);
    backdrop-filter:none;-webkit-backdrop-filter:none;
  }
  .content{background:var(--bg)}
}

/* ---------- print ---------- */
.print-head{display:none}
.watermark{display:none}
/* Printed-page context inside table headers — see the print block below. */
table.grid tr.ctx{display:none}

@media print{
  /**
   * ⚠️ Orientation is a CHOICE now, not a constant.
   *
   * Landscape suits a Gantt and a wide cost table. It does not suit a billing, which is
   * a letter to a client and has always been printed on a portrait page in this
   * industry — and everything in this app used to come out landscape whatever it was.
   *
   * `body.print-portrait` is set by the ⎙ menu before printing (see printMenu in
   * ui/dom.js); the two @page rules cannot be combined because @page takes no class.
   */
  @page{size:landscape;margin:11mm}

  /* Portrait pages are narrower, so tables get a little more room by losing the side
     padding the screen layout carries. */
  body.print-portrait .pad{padding-left:0;padding-right:0}
  html,body{height:auto;overflow:visible;background:var(--card)}

  /* Chrome that belongs on a screen and not on paper. */
  .sidebar,.toolbar,.topbar,#toast,.rowpop,.rowmenu,.legend,.modal-bg,.x,
  .banner,.seg,.btn,.twist{display:none !important}

  .app{display:block;height:auto}
  .content{display:block;min-height:0}
  .screen{display:block;overflow:visible;min-height:0}
  .pad{overflow:visible;padding:0}

  /**
   * The watermark — one element, repeated on every printed page.
   *
   * `position: fixed` is what repeats it: a fixed element is painted once per page by
   * the print engine, which is the only way to get something on every sheet without
   * inserting it between the rows. (The same trick was tried for the letterhead and
   * abandoned — a header has to reserve space and a watermark must not.)
   *
   * ⚠️ The opacity and the size here are only the starting point, and the app decides
   * the real ones — paintWatermark() in ui/app.js measures the image and writes them
   * inline. Behind a printed billing the job of this mark is to be recognised, not read;
   * anything darker competes with the figures, and a contractor who could set it to 50%
   * would find out after it had reached their client. So it is not a setting.
   *
   * ⚠️ `z-index: -1`, and it has to be negative. It was 0, with the content set to 1,
   * which looks like the same thing and is not: a POSITIONED element at z-index 0 paints
   * above ordinary in-flow content, so the mark was tinting the navy total bars on a real
   * printed billing — "murag ga sapaw", and it was. Only a negative z-index puts an
   * element behind its siblings' backgrounds. It still sits above .content's own
   * background, which is why it stays visible at all.
   *
   * `print-color-adjust: exact` stops the browser helpfully dropping it to save ink.
   */
  .watermark{
    display:block;position:fixed;inset:0;z-index:-1;pointer-events:none;
    background-repeat:no-repeat;background-position:center center;background-size:55% auto;
    opacity:.06;print-color-adjust:exact;-webkit-print-color-adjust:exact;
  }
  /* z-index:0 rather than 1: .content must be the stacking context that holds the mark,
     otherwise a negative z-index escapes it and lands behind the page background. */
  .content{position:relative;z-index:0}
  .print-head{position:relative;z-index:1}

  /**
   * ⚠️ Now that the mark is genuinely underneath, every white panel hides it.
   *
   * On screen these backgrounds separate a card from the page behind it. On paper the
   * page IS white, so the only thing they do is paint over the watermark — turning it
   * into a mark that shows in the gaps between panels and nowhere else.
   *
   * Anything with a real colour is left alone on purpose: the navy total bars, a section
   * heading, an overdue row. Those mean something, and the mark belongs behind them.
   */
  .panel,.card,.reqcard,.kpis,.cash,.gscroll,.chart-box,
  table.grid,table.grid th,.preview-doc,.screen,.pad{background:transparent}

  /**
   * ⚠️ No glass on paper. Ever.
   *
   * The V1 surface treatment is for a screen, where the light comes from behind the
   * pixels. Paper has no backlight: a translucent panel prints as a grey wash, a
   * soft shadow prints as a smudge, and the ambient colour wash on .content prints
   * as a tinted page — on a document going to a client or a bank.
   *
   * `backdrop-filter` is also what creates a containing block for fixed-position
   * elements, which would trap the watermark inside a panel instead of letting it
   * span the sheet. Stripping it here keeps that fix working.
   */
  .topbar,.bell-slot,.kpis,.panel,.card,.reqcard,.preview-doc,.modal,
  .active-project,.sync-status a,.edition a,.projpick select,
  select,input[type="date"],input[type="month"],input[type="time"],
  .field input,.field select,.field textarea{
    backdrop-filter:none !important;-webkit-backdrop-filter:none !important;
    box-shadow:none !important;
  }
  .content{background:var(--card) !important}

  .print-head{
    display:flex;align-items:center;gap:11px;
    border-bottom:2px solid var(--navy);padding-bottom:7px;margin-bottom:11px;
  }
  /**
   * ⚠️ The customer's logo, at letterhead size — and never squashed.
   *
   * It was 34×34px: a postage stamp beside a 15px project title, on the page that goes
   * to their client. Worse, forcing a square shape stretched every logo that is not one,
   * and almost no construction logo is — they are wordmarks, wider than they are tall.
   *
   * So: a fixed HEIGHT (the thing that makes a letterhead look level), width free up to
   * a limit, and `contain` so the shape is the shape they gave us.
   */
  .print-head .ph-logo{
    height:80px;width:auto;max-width:280px;flex:none;object-fit:contain;object-position:left center;
    print-color-adjust:exact;-webkit-print-color-adjust:exact;
  }
  .print-head .ph-text{min-width:0}
  .print-head .ph-title{font-size:15px;font-weight:800;color:var(--navy-ink)}
  .print-head .ph-sub{font-size:10.5px;color:var(--ink-2);margin-top:2px}
  .print-head .ph-foot{font-size:9px;color:var(--muted);margin-top:4px;letter-spacing:.3px}

  /* The Gantt is drawn with absolute positions and a sticky pane; on paper it has
     to be one flat block. gantt.js re-renders at a width that fits before printing. */
  .gscroll{overflow:visible !important;height:auto !important}
  .gstage{width:auto !important}
  .ghead,.ghead-left,.gbody-left{position:static !important}
  .ghead-left,.gbody-left{border-right:1px solid var(--line-3)}
  .grow{break-inside:avoid}
  .bar,.pbar{box-shadow:none !important;print-color-adjust:exact;-webkit-print-color-adjust:exact}
  .bar .fill,.pfill,.nonwork,.tick.hol,.holmark,.c-cost.derived,.hbadge,
  .kpi .bar-inner,.pill,tr.sec td,tr.total td{print-color-adjust:exact;-webkit-print-color-adjust:exact}

  .kpis{border:0;border-bottom:1px solid var(--line-3);break-inside:avoid;overflow:visible}
  .kpi{border-right:1px solid var(--line);padding:6px 12px}
  .kpi .val{font-size:13px}

  table.grid{font-size:9.5px}
  table.grid thead{display:table-header-group}   /* repeat headers on every page */

  /* The context line — project, report, company, date. Only on paper, and only
     because page two of a long table is a loose sheet that otherwise says nothing
     about whose job it belongs to. */
  table.grid tr.ctx{display:table-row}
  table.grid tr.ctx th{
    text-align:left;font-size:9px;font-weight:600;color:var(--ink-2);letter-spacing:.2px;
    padding-top:2px;padding-bottom:5px;border-bottom:0;
  }
  table.grid tr{break-inside:avoid}
  table.grid th{border-bottom:1px solid var(--faint)}
  input.cell,select.cell{border:0 !important;background:transparent !important;
    -webkit-appearance:none;appearance:none;padding:0}

  .cash{display:block}
  .chartbox{padding:0 0 8px}
  #chart{height:210px;width:100%}
  .tablebox{border:0;overflow:visible}
  .chart-box{border:1px solid var(--line-3);break-inside:avoid}
  .cards{display:block}
  .card{break-inside:avoid;margin-bottom:8px;box-shadow:none}

  /* A billing goes to the client on its own. `print-one` keeps everything else off
     the page — the aging buckets and the other invoices are the contractor's
     position, and none of the client's business. */
  /* ⚠️ Everything that belongs to the SCREEN rather than to the record. The list was
     just the KPI strip and the other rows, which left the advance panel, the aging
     buckets and the section headings on a sheet going to a client — a variation sent
     for signature arrived with the whole change history and the contract position
     underneath it. If a new screen-level block appears, it belongs on this list. */
  body.print-one .kpis,
  body.print-one .card,
  body.print-one .panel,
  body.print-one .banner,
  body.print-one .sec-head,
  body.print-one .hint,
  body.print-one .reqcard:not(.print-me){display:none !important}
  /**
   * ⚠️ …but only the ones OUTSIDE the record being printed.
   *
   * The list above hides `.sec-head` and `.hint` as screen furniture, which is right
   * for "PROJECTS" and the aging buckets and wrong for the billing's own
   * "Statement of Work Accomplished" heading and the line explaining it — those are
   * part of the document. Hiding them printed the attachment as an unlabelled table
   * of figures, on a sheet going to a client.
   */
  body.print-one .reqcard.print-me .sec-head,
  body.print-one .reqcard.print-me .hint,
  body.print-one .reqcard.print-me .panel{display:block !important}

  body.print-one .reqcard.print-me{border:0;box-shadow:none}
  body.print-one .reqcard.print-me .rq-caret,
  body.print-one .reqcard.print-me .rq-actions{display:none}
  body.print-one .reqcard.print-me .rq-head{border-bottom:1px solid var(--faint);padding-bottom:6px}
  body.print-one table.grid{font-size:11px}

  /**
   * ⚠️ V1 — the BOQ asks "Include the Actual columns?" before it prints.
   *
   * `print-boq-estimate` is the answer No, and it is the default: the copy that goes to
   * a client. It drops the Actual side AND the KPI strip — the strip carries the budget
   * and the gross margin, which were printing on every BOQ before this question existed.
   * `print-boq-actual` is the office copy and keeps both.
   *
   * The scheduling columns never print. They put the money on the calendar, and the
   * Gantt is what prints the calendar.
   */
  table.grid.boq .tim,.boqsum .acts,.boqsum tr.addrow,.vo-link{display:none !important}
  body.print-boq-estimate .act,
  body.print-boq-estimate .kpis,
  body.print-boq-estimate table.grid.boq tr.grp{display:none !important}
  table.grid.boq thead{position:static}
  .labcell select,.labcell input,.labpeso,.adj-how input,.adj-sfx,input.scr{display:none !important}
  .labprint,.adj-pct,.pv{display:inline}
  table.grid.boq td.e-mat{color:inherit}
  table.grid.boq tbody tr:not(.sec) td.act{background:transparent}
  table.grid.boq th.grp-est,table.grid.boq th.grp-act{print-color-adjust:exact;-webkit-print-color-adjust:exact}
  table.grid.boqsum,.boqnote{margin-left:0;margin-right:0;width:100%}
  table.grid.boqsum{break-inside:avoid}
  .boqvo{padding:14px 0 0;break-inside:avoid}
}

/* ---------- critical path ----------
   Deliberately not "red = bad". A critical task is not a problem, it is a task with
   no room — so it gets a dark outline and a diamond, and everything with slack is
   faded back. The eye should land on the chain, not on an alarm. */
.bar.crit{
  outline:2px solid var(--navy);outline-offset:1px;
  box-shadow:0 0 0 4px rgba(13,33,55,.10);
}
.bar.crit::after{
  content:'◆';position:absolute;left:-13px;top:50%;transform:translateY(-50%);
  font-size:9px;color:var(--navy-ink);
}
.bar.slack{opacity:.42}
.bar.slack:hover{opacity:.8}

@media print{
  .bar.crit{outline-color:#0d2137;print-color-adjust:exact}
  .bar.slack{opacity:.5}
}

/* ---------- sign in ---------- */
.signin{
  position:fixed;inset:0;z-index:90;background:var(--navy);
  display:flex;align-items:center;justify-content:center;padding:24px;overflow:auto;
}
.si-card{
  background:var(--card);border-radius:14px;padding:26px 28px;width:100%;max-width:380px;
  box-shadow:0 18px 50px rgba(0,0,0,.35);
}
.si-brand{display:flex;align-items:center;gap:9px;margin-bottom:18px}
.si-brand img{width:30px;height:30px;border-radius:6px}
.si-brand b{font-size:13px;color:var(--navy-ink);letter-spacing:.2px}
.si-card h2{margin:0 0 5px;font-size:18px;color:var(--ink)}
.si-card p{margin:0 0 16px;font-size:12.5px;color:var(--muted);line-height:1.55}
.si-card .f{display:block;margin-bottom:13px}
.si-card .f>span{display:block;font-size:11.5px;font-weight:700;color:var(--ink);margin-bottom:4px}
.si-card .f input{
  width:100%;border:1px solid var(--line);border-radius:8px;padding:9px 11px;
  font:inherit;font-size:14px;background:var(--card);
}
.si-card .f input:focus{outline:2px solid var(--teal);outline-offset:-1px;border-color:transparent}
.si-card .f em{display:block;font-style:normal;font-size:11px;color:var(--muted);margin-top:4px}
.si-card .btn{width:100%;justify-content:center;padding:9px;font-size:13px}
.si-card .btn+.btn{margin-top:7px}

.si-people{display:flex;flex-direction:column;gap:7px}
.si-person{
  display:block;width:100%;text-align:left;cursor:pointer;font:inherit;
  border:1px solid var(--line);border-radius:9px;padding:10px 13px;background:var(--card);
}
.si-person:hover{background:var(--line-2);border-color:var(--teal)}
.si-person b{display:block;font-size:13.5px;color:var(--ink)}
.si-person span{display:block;font-size:11px;color:var(--muted);margin-top:2px}

.si-alt{margin-top:16px;padding-top:14px;border-top:1px solid var(--line);text-align:center}
.si-alt>span{display:block;font-size:11px;color:var(--muted);margin-bottom:8px;
  text-transform:uppercase;letter-spacing:1px}
.si-alt em{display:block;font-style:normal;font-size:11px;color:var(--muted);
  margin-top:7px;line-height:1.5}

.si-err{color:var(--red);font-size:12px;margin-top:10px;min-height:16px;font-weight:600}
.si-err.shake{animation:si-shake .3s}
@keyframes si-shake{
  0%,100%{transform:translateX(0)} 25%{transform:translateX(-5px)} 75%{transform:translateX(5px)}
}

/* ---------- toast ---------- */
.toast{
  position:fixed;left:50%;bottom:22px;transform:translateX(-50%);background:var(--navy);color:#fff;
  padding:9px 16px;border-radius:8px;font-size:12.5px;box-shadow:0 6px 20px rgba(0,0,0,.28);
  z-index:70;opacity:0;pointer-events:none;transition:opacity .18s;
}
.toast.show{opacity:1}
.toast b{color:var(--teal)}
.toast.bad{background:var(--red)} .toast.bad b{color:#fff;text-decoration:underline}

/* A new build is ready — stays until used; one button reloads into it. See register-sw.js. */
.update-bar{
  position:fixed;left:50%;bottom:22px;transform:translateX(-50%);z-index:80;
  display:flex;align-items:center;gap:14px;flex-wrap:wrap;justify-content:center;
  background:var(--navy);color:#fff;padding:10px 12px 10px 18px;border-radius:10px;
  font-size:13px;box-shadow:0 8px 26px rgba(0,0,0,.3);max-width:calc(100vw - 32px);
}
.update-bar b{color:#fff}
.update-bar .btn{padding:6px 14px}
@media print{ .update-bar{display:none !important} }

/* ---------- V1 Stage 8 — Accounting (Cash Flow · Receivables · Payables · P&L) ----------
   Same register-and-drawer shape as Billing, so the accountant meets one way of working
   on every money screen. */
.acct-aging{display:grid;grid-template-columns:repeat(5,1fr);gap:0;padding:0;margin-bottom:12px;overflow:hidden}
.aa-cell{position:relative;padding:9px 12px 12px;border-left:1px solid var(--line-2);min-width:0}
.aa-cell:first-child{border-left:0}
.aa-cell span{display:block;font-size:11px;color:var(--muted)}
.aa-cell b{display:block;font-size:14px;font-variant-numeric:tabular-nums;margin-top:2px}
.aa-cell i{position:absolute;left:0;bottom:0;height:3px;background:var(--teal)}
.aa-cell.late b{color:var(--red)}
.aa-cell.late i{background:var(--red)}
.acct-waiting{padding:10px 12px;margin-bottom:12px;border-left:3px solid var(--amber)}
.acct-waiting table.grid{margin-top:4px}
.acct-sum{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:10px 0}
.acct-sum > div{background:var(--line-2);border-radius:8px;padding:8px 10px}
.acct-sum span{display:block;font-size:11px;color:var(--muted)}
.acct-sum b{font-size:14px;font-variant-numeric:tabular-nums}
/* The payment voucher (ui/voucher.js) — exists only on paper. */
.voucher-sheet{display:none}
.acct-acts{white-space:nowrap}
.acct-ret{margin-bottom:12px}
@media print{
  body.print-one .voucher-sheet{display:block !important;border:0;box-shadow:none;padding:0;background:transparent}
  .pv{font-size:11.5px;color:#111;line-height:1.45}
  .pv-head{display:flex;justify-content:space-between;align-items:flex-end;border-bottom:2px solid #111;padding-bottom:6px;margin-bottom:10px}
  .pv-head b{display:block;font-size:15px}
  .pv-head > div > span{font-size:15px;font-weight:800;letter-spacing:2px}
  .pv-no{display:grid;grid-template-columns:auto auto;gap:1px 10px;text-align:right;font-size:11px}
  .pv-head .pv-no span{font-size:10px;font-weight:400;letter-spacing:0;color:#444}
  .pv-no b{font-size:12.5px}
  table.pv-t{width:100%;border-collapse:collapse;margin-bottom:10px}
  table.pv-t th,table.pv-t td{border:1px solid #333;padding:5px 8px;text-align:left;vertical-align:top}
  table.pv-who th{width:19%;font-weight:600;font-size:10.5px;background:#f1f5f9;print-color-adjust:exact;-webkit-print-color-adjust:exact}
  table.pv-t .num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
  .pv-amt{font-weight:800;font-size:13px}
  table.pv-lines thead th{font-size:10.5px;background:#f1f5f9;print-color-adjust:exact;-webkit-print-color-adjust:exact}
  table.pv-lines tfoot td{font-weight:800}
  table.pv-lines .pv-space td{height:40px}
  .pv-sigs{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;margin-top:26px;font-size:10.5px;text-align:center;break-inside:avoid}
  .pv-sigs.pv-two{grid-template-columns:2fr 1fr;margin-top:30px}
  .pv-sigs b{display:block;font-size:10.5px}
  .pv-sigs span{display:block;color:#333}
  .pv-line{border-bottom:1px solid #111;height:28px;margin-bottom:3px}
  .pv-recv{margin-top:22px;border-top:1px dashed #777;padding-top:10px;break-inside:avoid}
  .pv-recv p{margin:0}
}

/* Accounts: banks, petty cash, credit cards (ui/accounts-ui.js). */
.acc-item{display:grid;grid-template-columns:1fr auto auto;gap:4px 12px;align-items:center;padding:9px 11px;
  border:1px solid var(--line);border-radius:10px;background:var(--card);margin-bottom:6px}
.acc-item.closed{opacity:.6}
.acc-item b{font-size:13px}
.acc-item span{display:block;font-size:11px;color:var(--muted);font-weight:400}
.acc-item span.neg{color:var(--red)}
.acc-item span.warn{color:var(--amber-d)}
.acc-item .acc-amt{text-align:right;font-weight:700;font-variant-numeric:tabular-nums;font-size:13.5px}
.acc-item .acc-amt.neg{color:var(--red)}
.acc-item .btn{padding:4px 10px;font-size:11.5px}
.acc-item .acc-btns{display:flex;flex-direction:column;gap:4px}
.acct-cards{margin-bottom:12px}
.acct-cards .bm-head a{color:var(--teal-d)}
.rq-soon{background:var(--amber-l);color:var(--amber-d);font-size:9.5px;font-weight:700;border-radius:99px;
  padding:1px 7px;text-transform:uppercase;letter-spacing:.3px;border:1px solid var(--amber-m)}
.acct-h3{font-size:12px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);margin:16px 0 6px}
/* A reversed line and its reversal: both stay on the record, visibly cancelled. */
tr.acct-reversed td{color:var(--faint)}
tr.acct-reversed td.num{text-decoration:line-through}
.acct-book td:first-child,.acct-book th:first-child{width:26px;text-align:center}
.kpi.warn .val{color:var(--amber-d)}
@media (max-width:760px){ .acct-aging{grid-template-columns:repeat(2,1fr)} .acct-sum{grid-template-columns:1fr} }
@media print{
  .acct-book input[type=checkbox]{appearance:auto}
  .bill-page .bill-register{max-height:none !important;overflow:visible !important}
}

/* ---------- V1 — the dark theme (Genard, 28 Sep: "light, dark, or what the computer says") ----------
   `html.dark` is set by lib/theme.js from the person's choice — System follows Windows.
   ⚠️ SCREEN ONLY. Paper is always white: a billing printed from a dark screen must come
   out exactly like one printed from a light one, so none of this reaches @media print. */
@media screen{
  html.dark{
    color-scheme:dark;
    --bg:#0b1220; --card:#131c2e; --ink:#e5e9f0; --ink-2:#cbd5e1; --muted:#9aa7b9; --faint:#6b7a90;
    --line:#26324a; --line-2:#1a2438; --line-3:#35425c; --row-sub:#162034; --row-act:#1d1f24;
    --navy-ink:#b9cbe2;
    --teal-l:rgba(20,184,166,.14); --teal-d:#2dd4bf;
    --red:#ef4444; --red-l:rgba(239,68,68,.14); --red-m:rgba(239,68,68,.38); --red-d:#fca5a5;
    --green:#22c55e; --green-l:rgba(34,197,94,.13); --green-m:rgba(34,197,94,.35); --green-d:#86efac;
    --amber-l:rgba(245,158,11,.14); --amber-m:rgba(245,158,11,.4); --amber-d:#fcd34d;
    --blue-l:rgba(59,130,246,.16); --blue-m:rgba(59,130,246,.38); --blue-d:#93c5fd;
    --glass-bg:rgba(19,28,46,.72); --glass-bg-strong:rgba(19,28,46,.86); --glass-line:rgba(255,255,255,.07);
    --glass-hi:rgba(255,255,255,.05); --modal-bg:rgba(19,28,46,.98);
    --glass-shadow:0 1px 2px rgba(0,0,0,.3), 0 8px 24px -12px rgba(0,0,0,.6);
    --ink-on-wash:#cbd5e1; --muted-on-wash:#9aa7b9;
  }
  html.dark body{background:var(--bg);color:var(--ink)}
  html.dark .content{
    background:
      radial-gradient(ellipse 70% 55% at 6% 10%, color-mix(in srgb, var(--teal) 14%, transparent), transparent 62%),
      radial-gradient(ellipse 65% 50% at 78% 96%, color-mix(in srgb, var(--teal) 9%, transparent), transparent 62%),
      var(--bg);
    background-attachment:fixed;
  }
  html.dark .btn{background:var(--card);color:var(--ink);border-color:var(--line)}
  html.dark .btn:hover{background:var(--line-2)}
  html.dark .btn.primary{background:var(--teal-d);border-color:var(--teal-d);color:#04211d}
  html.dark .chip{background:var(--card);color:var(--muted);border-color:var(--line)}
  html.dark .chip.on{background:var(--teal-d);border-color:var(--teal-d);color:#04211d}
  html.dark input,html.dark textarea,html.dark select{color:var(--ink)}
  html.dark table.grid tr.total td{background:#0a1628;color:#e5e9f0}
  html.dark .toast{background:#1e293b}
  /* Charts draw with SVG attributes; CSS wins over an attribute, so the light-page inks
     are swapped here rather than in every chart's code. */
  html.dark svg [stroke="#12314f"]{stroke:#93c5fd}
  html.dark svg [fill="#12314f"]{fill:#93c5fd}
  html.dark svg [stroke="#f1f5f9"],html.dark svg [stroke="#e2e8f0"]{stroke:#26324a}
  html.dark svg [stroke="#fff"]{stroke:var(--card)}
  html.dark svg [fill="#64748b"]{fill:#9aa7b9}
  html.dark ::-webkit-scrollbar-thumb{background:#2a3650}
}

/* The Light / Dark / System switch, beside the bell (ui/mode-switch.js). */
.mode-slot{position:relative;padding:0 0 0 6px}
.mode-slot:has(+ .bell-slot:empty){padding-right:14px}
.mode-btn .mode-ico{filter:none;opacity:.75;font-size:16px}
.mode-menu{position:fixed;z-index:76;min-width:210px;padding:6px;
  background:var(--card);border:1px solid var(--line);border-radius:10px;
  box-shadow:0 12px 32px -10px rgba(15,23,42,.35)}
.mode-head{font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);padding:4px 8px 6px}
.mode-menu button{display:flex;align-items:center;gap:8px;width:100%;padding:7px 8px;border:0;border-radius:7px;
  background:transparent;color:var(--ink);cursor:pointer;font-size:12.5px;text-align:left}
.mode-menu button:hover{background:var(--line-2)}
.mode-menu button.on{background:var(--teal-l);font-weight:600}
.mm-ico{width:18px;text-align:center}
.mm-tick{margin-left:auto;color:var(--teal-d)}
.mode-note{font-size:10.5px;color:var(--faint);padding:6px 8px 2px;border-top:1px solid var(--line-2);margin-top:4px}
@media print{ .mode-slot,.mode-menu,.who-slot{display:none !important} }

/* Who is signed in — beside the bell, not only at the foot of the sidebar. */
.who-slot{padding:0 0 0 10px}
.who{display:flex;align-items:center;gap:8px;height:38px;padding:0 10px 0 4px;border-radius:10px;
  border:1px solid var(--line);background:var(--card);color:var(--ink);cursor:pointer;font:inherit}
.who:hover{border-color:var(--teal);background:var(--teal-l)}
.who-av{width:28px;height:28px;border-radius:8px;display:grid;place-items:center;flex:none;
  background:var(--navy);color:#fff;font-size:11px;font-weight:800;letter-spacing:.3px}
.who-txt{display:flex;flex-direction:column;align-items:flex-start;line-height:1.15;text-align:left}
.who-txt b{font-size:12.5px;max-width:110px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.who-txt small{font-size:10px;color:var(--muted);white-space:nowrap}
@media (max-width:700px){ .who-txt{display:none} .who{padding:0 4px} }

/* ---------- V1 Stage 9 — Human Resources ----------
   The time record looks like the paper timesheet it replaces: a row per worker, a box
   per day. Tokens only, so it works in the dark theme too. */
.dtr-weeknav{display:flex;gap:4px}
.dtr-weeknav .btn{padding:6px 10px}
.dtr-legend{display:flex;flex-wrap:wrap;gap:6px 14px;align-items:baseline;margin:0 0 10px;font-size:12px;color:var(--muted-on-wash)}
.dtr-legend b{color:var(--ink);font-size:13px;padding:0 3px;border:1px solid var(--line);border-radius:5px;background:var(--card)}
.dtr-legend-tip{flex-basis:100%}
.dtr-legend-tip b{border:0;background:none;padding:0;font-size:12px}
.dtr-card{padding:0;overflow:auto}
/* Fixed columns, so the days never spread across a wide screen and squeeze the totals
   into the edge (Genard's screenshot, 28 Sep). The worker column takes what is left. */
table.grid.dtr-grid{min-width:1020px;width:100%;table-layout:fixed}
table.grid.dtr-grid col.c-name{width:auto}
table.grid.dtr-grid col.c-charge{width:230px}
table.grid.dtr-grid col.c-day{width:82px}
table.grid.dtr-grid col.c-tot{width:72px}
table.grid.dtr-grid th.num,table.grid.dtr-grid td.num{padding-right:16px}
table.grid.dtr-grid td.dtr-count{text-align:center;padding-right:3px}
table.grid.dtr-grid th.dtr-day{text-align:center;width:74px;line-height:1.15}
table.grid.dtr-grid th.dtr-day span{font-size:15px;font-weight:700;color:var(--ink)}
table.grid.dtr-grid th.dtr-day i{display:block;font-style:normal;font-size:9.5px;font-weight:700;text-transform:uppercase}
table.grid.dtr-grid th.hol-regular i{color:var(--red)}
table.grid.dtr-grid th.hol-special i{color:var(--amber-d)}
table.grid.dtr-grid th.today{box-shadow:inset 0 -3px 0 var(--teal)}
.dtr-name{min-width:0;overflow:hidden;text-overflow:ellipsis}
.dtr-name .muted{font-size:10.5px}
.dtr-charge select{width:100%;font-size:11.5px;padding:4px 6px}
td.dtr-td{padding:3px !important;text-align:center;position:relative}
td.dtr-td input.dtr-cell{width:64px;text-align:center;padding:6px 4px;border:1px solid var(--line);border-radius:7px;
  background:var(--card);color:var(--ink);font:inherit;font-variant-numeric:tabular-nums}
td.dtr-td input.dtr-cell:focus{outline:0;border-color:var(--teal);box-shadow:0 0 0 3px var(--teal-l)}
td.dtr-td.dt-rest input,td.dtr-td.dt-special input,td.dtr-td.dt-special_rest input{background:var(--amber-l)}
td.dtr-td.dt-holiday input,td.dtr-td.dt-holiday_rest input{background:var(--red-l)}
td.dtr-td.absent input{color:var(--red);font-weight:700}
td.dtr-td.locked input{background:var(--line-2);color:var(--muted);cursor:not-allowed}
td.dtr-td .dtr-lock{position:absolute;top:1px;right:3px;font-size:8px;font-weight:400}
td.dtr-td.bad input{border-color:var(--red);box-shadow:0 0 0 3px var(--red-l)}
td.dtr-td.saved input{border-color:var(--green);transition:border-color .2s}
.dtr-else{display:inline-block;font-size:11px;color:var(--muted);line-height:1.1}
.dtr-else small{display:block;font-size:9px;max-width:70px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dtr-add{margin-top:12px;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.dtr-add label{font-size:12px;font-weight:600;color:var(--ink-on-wash)}
.dtr-add input{width:min(360px,100%);padding:7px 10px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit}
/* The payroll register is wide: deductions narrow, and typed in place while a draft. */
.pay-register{overflow:auto}
.pay-register table.grid{min-width:1200px}
.pay-register th.ded,.pay-register td.ded{background:color-mix(in srgb, var(--amber-l) 45%, transparent)}
input.ded-in{width:78px;text-align:right;padding:4px 6px;border:1px solid var(--line);border-radius:6px;
  background:var(--card);color:var(--ink);font:inherit;font-size:12px}
/* Payslips: never on screen, two to a page on paper. */
.pay-sheet{display:none}
/* The final pay sheet — the payslip's look, on screen too, with a quitclaim on paper. */
.card > .ps-head b{font-size:15px}
.card > .ps-cols td,.card > .ps-cols th{padding:4px 0;font-size:12.5px}
.card > .ps-cols small,.fp-sheet small{color:var(--muted);font-size:10.5px}
.card > .ps-net{border-color:var(--line-3);border-radius:8px;font-size:14px;margin-top:10px}
.fp-quit{margin:14px 0 0;font-size:11px;line-height:1.5}
.fp-sign{margin-top:26px}
.payslip{border:1px solid #333;border-radius:4px;padding:10px 12px;margin:0 0 12px;break-inside:avoid;font-size:10.5px;color:#000}
.ps-head{display:flex;justify-content:space-between;border-bottom:1px solid #999;padding-bottom:5px;margin-bottom:5px}
.ps-head b{display:block;font-size:12.5px}
.ps-head span{letter-spacing:.2em;font-size:10px}
.ps-period{text-align:right;font-size:10px}
.ps-who{margin-bottom:6px}
.ps-cols{display:grid;grid-template-columns:1fr 1fr;gap:12px}
table.ps-t{width:100%;border-collapse:collapse}
table.ps-t th{text-align:left;font-size:10px;text-transform:uppercase;border-bottom:1px solid #999;padding:2px 0}
table.ps-t td{padding:2px 0}
table.ps-t td:last-child{text-align:right;font-variant-numeric:tabular-nums}
table.ps-t tr.ps-sum td{border-top:1px solid #999;font-weight:700}
.ps-net{display:flex;justify-content:space-between;margin-top:6px;padding:5px 8px;border:1.5px solid #000;font-size:12px}
.ps-sign{display:flex;justify-content:space-between;margin-top:16px;font-size:10px}
@media print{
  body.print-one .pay-sheet{display:block !important}
  body.print-one .pay-register,body.print-one .bill-remind{display:none !important}
  .dtr-weeknav,.dtr-add,.dtr-legend{display:none !important}
  td.dtr-td input.dtr-cell{border:0;background:transparent !important;width:auto}
  /* On paper the sheet is a table, not a form: no scrollbar, no dropdown arrows. */
  .dtr-card{overflow:visible}
  table.grid.dtr-grid{min-width:0}
  table.grid.dtr-grid col.c-name{width:150px}
  table.grid.dtr-grid col.c-charge{width:190px}
  table.grid.dtr-grid col.c-day{width:auto}
  .dtr-name{white-space:normal}
  .dtr-charge select{appearance:none;-webkit-appearance:none;border:0;background:transparent;padding:0;
    white-space:normal;color:var(--ink)}
  .dtr-printwk{font-size:11px;color:var(--ink-2);margin:0 0 8px}
  .dtr-printwk b{color:var(--ink)}
  .pay-register{overflow:visible}
  input.ded-in{border:0;background:transparent}
}

/* ---------- People — what someone can do and see (Genard, 28 Sep) ----------
   Tick boxes grouped by desk, a search, and the projects as a searchable list. */
.acc{padding:4px 16px 0}
.acc-top{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:6px 0 8px}
.acc-top label{display:flex;flex-direction:column;gap:4px;font-size:11.5px;font-weight:600;color:var(--muted)}
.acc-top select{padding:7px 8px}
.acc-note{margin-bottom:10px}
.acc-note .btn.link{font-size:12px;font-weight:700;padding:0 4px}
.acc-search{width:100%;padding:8px 11px;border:1px solid var(--line);border-radius:8px;background:var(--card);
  color:var(--ink);font:inherit;margin-bottom:10px}
.acc-group{border:1px solid var(--line);border-radius:10px;margin-bottom:10px;overflow:hidden;background:var(--card)}
.acc-gh{display:flex;align-items:center;gap:8px;padding:9px 12px;background:var(--line-2);font-size:12.5px;cursor:pointer}
.acc-gh .muted{margin-left:auto;font-size:11px}
.acc-row{display:flex;align-items:flex-start;gap:9px;padding:8px 12px;border-top:1px solid var(--line-2);cursor:pointer;font-size:12.5px}
.acc-row:hover{background:var(--teal-l)}
.acc-row input{margin-top:2px;flex:none;width:15px;height:15px;accent-color:var(--teal-d)}
.acc-row span{flex:1;min-width:0}
.acc-row small{display:block;color:var(--muted);font-size:11px;margin-top:2px}
.acc-row.changed{background:color-mix(in srgb, var(--amber-l) 60%, transparent)}
.acc-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--amber);flex:none;margin-top:5px}
/* `.acc-row span{flex:1}` is for the label text — without this it stretched the dot into a bar. */
.acc-row .acc-dot{flex:0 0 8px;min-width:8px;margin-top:4px}
.acc-pbar{display:flex;gap:6px;align-items:center;padding:8px 12px 0;border-top:1px solid var(--line-2)}
.acc-pbar .acc-search{margin:0}
.acc-projects > .hint{padding:8px 12px}
.acc-save{position:sticky;bottom:0;display:flex;justify-content:flex-end;gap:8px;padding:12px 0 16px;
  background:linear-gradient(transparent, var(--card) 30%)}
@media (max-width:640px){ .acc-top{grid-template-columns:1fr} }

/* ---------- Breathing room at the right edge (Genard, 28 Sep — "huot na kaayo") ----------
   The last column of a register sat against the card's edge; figures there read as cut
   off. Every register gets the same margin on the right as on the left. */
table.grid th:last-child,table.grid td:last-child{padding-right:14px}
table.grid th:first-child,table.grid td:first-child{padding-left:12px}
/* Wide registers scroll sideways inside their card on a small screen instead of
   squeezing every column until the figures touch. */
.pay-register table.grid td.num,.pay-register table.grid th.num{white-space:nowrap}
.bill-register{overflow-x:auto}
/* Names and references wrap onto a second line in the registers when the screen is
   narrow; figures never do. A long "SSS · PhilHealth · Pag-IBIG · BIR" no longer pushes
   the Balance column off a 1280px laptop. */
table.grid.bill-table td:nth-child(-n+3):not(.num){white-space:normal;min-width:90px}
/* Genard, 29 Sep — "OT HRS 5" ran straight into "active": a right-aligned figure followed
   by a left-aligned word has no gap between them at all. Every table, everywhere: a text
   column that follows a figure starts with room. */
table.grid th.num + th:not(.num),
table.grid td.num + td:not(.num){padding-left:24px}
/* A short day (a Saturday half day paid as a whole day) — its own shade on the time record. */
td.dtr-td.dt-short input{background:var(--blue-l)}
/* Overtime waiting for approval — an amber corner on the box; approved short of what was
   asked — the same corner, hollow. Not paid until someone who may approve has looked. */
td.dtr-td.ot-wait::after,td.dtr-td.ot-cut::after{content:"";position:absolute;top:3px;left:calc(50% - 32px);
  width:0;height:0;border-style:solid;border-width:9px 9px 0 0;pointer-events:none}
td.dtr-td.ot-wait::after{border-color:var(--amber) transparent transparent transparent}
td.dtr-td.ot-cut::after{border-color:color-mix(in srgb, var(--amber) 45%, transparent) transparent transparent transparent}
.dtr-legend-ot{display:inline-block;padding:0 4px;border-left:6px solid var(--amber);font-size:11px}
@media print{ td.dtr-td.ot-wait::after,td.dtr-td.ot-cut::after{print-color-adjust:exact;-webkit-print-color-adjust:exact} }
/* The cash-advance slip — only ever on paper: two copies to a sheet, cut in half. */
.ca-sheet{display:none}
@media print{
  body.print-one .ca-sheet{display:block !important;border:0;box-shadow:none;padding:0}
  .ca-slip{border:1px solid #333;padding:14px 18px;font-size:12px;line-height:1.55;break-inside:avoid;color:#111}
  .ca-head{display:flex;justify-content:space-between;align-items:baseline;border-bottom:1.5px solid #111;padding-bottom:5px;margin-bottom:8px}
  .ca-head b{font-size:14px}
  .ca-head span{font-size:10px;letter-spacing:.6px;font-weight:700}
  .ca-meta{display:flex;justify-content:space-between;font-size:11px;margin-bottom:6px}
  .ca-slip p{margin:6px 0}
  .ca-sigs{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:30px;font-size:10.5px;text-align:center}
  .ca-line{border-bottom:1px solid #111;height:26px;margin-bottom:3px}
  .ca-cut{text-align:center;font-size:9px;color:#666;border-top:1px dashed #999;margin:22px 0;padding-top:2px}
}
/* An employee's contact card — the emergency line stands out while it is empty. */
table.grid.emp-contact td:first-child{width:170px;color:var(--muted)}
table.grid.emp-contact td{white-space:normal}
table.grid.emp-contact tr.emp-missing td:last-child{color:var(--amber-d);font-style:italic}
/* Equipment charges — the period picker at the top of the drawer. */
.eq-period{display:flex;gap:12px;flex-wrap:wrap;margin:6px 0 4px}
.eq-period label{display:flex;flex-direction:column;gap:4px;font-size:11.5px;font-weight:600;color:var(--muted)}
.eq-period input{padding:6px 8px}
/* A day that came from a clock (the form, or the fingerprint machine) — a small clock
   mark; late or undertime — a red corner. The times themselves are in the tooltip. */
td.dtr-td .dtr-times{display:block;font-size:9.5px;line-height:1.1;margin-top:2px;color:var(--muted);
  white-space:nowrap;font-variant-numeric:tabular-nums;letter-spacing:-.1px}
td.dtr-td.late .dtr-times{color:var(--red);font-weight:600}
td.dtr-td.late input.dtr-cell{border-color:color-mix(in srgb, var(--red) 55%, var(--line))}
.sch-card{margin-bottom:10px}

/* ---------- Bringing data in (Genard, 29 Sep) ---------- */
.imp-what{font-size:13px;margin:4px 0 12px}
.imp-steps{display:grid;gap:10px;margin-bottom:12px}
.imp-step{display:flex;gap:12px;border:1px solid var(--line);border-radius:10px;padding:12px 14px;background:var(--card)}
.imp-step > b{flex:none;width:26px;height:26px;border-radius:50%;display:grid;place-items:center;background:var(--teal-l);color:var(--teal-d)}
.imp-step h4{margin:0 0 4px;font-size:13px}
.imp-step p{margin:0 0 8px;font-size:12px;color:var(--muted)}
.imp-pick{cursor:pointer;display:inline-flex}
.imp-fields summary{cursor:pointer;font-size:12px;color:var(--muted);margin:6px 0}
.imp-fields td{white-space:normal}
table.grid.imp-map select{width:100%;max-width:260px;padding:4px 6px}
table.grid.imp-map tr.imp-missing td{background:var(--red-l)}
table.grid.imp-map td:last-child{max-width:200px;overflow:hidden;text-overflow:ellipsis}
.imp-sum{grid-template-columns:repeat(4,1fr)}
.imp-check-wrap{max-height:calc(100vh - 330px);overflow:auto;border:1px solid var(--line);border-radius:8px}
table.grid.imp-check td:last-child{white-space:normal}
table.grid.imp-check tr.imp-err td{background:var(--red-l)}
.imp-intro{padding:14px 18px;margin-bottom:14px}
.imp-intro ol{margin:8px 0 6px 18px;padding:0;font-size:12.5px;line-height:1.6}
.imp-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:12px}
.imp-card{display:flex;gap:12px;padding:14px 16px}
.imp-card.imp-off{opacity:.55}
.imp-num{flex:none;width:28px;height:28px;border-radius:50%;display:grid;place-items:center;font-weight:800;
  background:var(--navy);color:var(--on-sidebar);font-size:12px}
.imp-body{min-width:0;flex:1}
.imp-body h3{margin:2px 0 4px;font-size:14px}
.imp-body p{margin:0 0 8px;font-size:12px;color:var(--muted)}
.imp-cols{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px}
.imp-cols span{font-size:10.5px;padding:2px 7px;border-radius:99px;background:var(--line-2);color:var(--muted)}
.imp-acts{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
@media (max-width:640px){ .imp-sum{grid-template-columns:1fr 1fr} }
.dtr-legend-times{font-size:10.5px;color:var(--muted);font-variant-numeric:tabular-nums}
.dtr-legend-times.late{color:var(--red);font-weight:600}
/* A quiet line in the top bar where a button would be for someone else. */
.topbar-note{font-size:11.5px;color:var(--muted);max-width:260px;text-align:right;line-height:1.3}
