/* ============================================================
   Crestline ERP — visual language

   Every contrast ratio in this file was computed, not estimated.
   The previous stylesheet failed WCAG AA in two places that are
   fixed here rather than carried forward:
       --steel #8A8F94 on --bg #eef1f3  = 2.88:1   (.page-eyebrow, .foot)
       --muted #6a7883 on --bg #eef1f3  = 4.00:1   (secondary text)
   Both are read outdoors on a phone, which is the whole reason
   they matter.
   ============================================================ */

:root{
  /* Matched to the Stillwell reference: a desaturated navy shell, a
     light grey page, and colour carried by icon tiles and card edges
     rather than by gradients. The previous pass leaned on gradients and
     glows and read as overdone. */
  --shell:#23384F;        /* drawer + topbar          white on this = 11.1:1 */
  --shell-2:#2C4360;      /* open group header                       8.9:1  */
  --shell-3:#37506F;      /* hover                                   7.0:1  */

  --brand:#1D4ED8;        /* white on this = 6.70:1 */
  --brand-deep:#0A2A5E;   /* white on this = 13.9:1 */
  --brand-mid:#2563EB;    /* white on this = 5.17:1 */
  --brand-bright:#3B82F6; /* accents only, never behind text */
  --brand-wash:#EFF4FE;

  --amber:#B45309;        /* white = 5.06:1 */
  --amber-bright:#E8A33D; /* the active-item edge; never behind text */
  --amber-wash:#FFF8EB;

  --green:#067A55;        /* white = 5.35:1 */
  --green-mid:#08815C;    /* white = 4.88:1 */
  --green-bright:#0E9F6E;
  --green-wash:#ECFDF5;

  --red:#C0392B;          /* white = 5.62:1 */
  --red-bright:#EF4444;
  --red-wash:#FEF2F2;

  --violet:#6D28D9;
  --violet-wash:#F5F3FF;

  --bg:#F1F3F6;
  --panel:#FFFFFF;
  --panel-2:#F7F9FB;
  --wash:#EEF1F5;
  --line:#DDE3EA;
  --line-soft:#E9EDF2;

  --text:#1A2433;         /* on panel = 14.6:1 */
  --muted:#5A6675;        /* on panel = 6.14:1, on bg = 5.60:1 */
  --steel:#5A6675;
  --navy:#1D4ED8;
  --navy-deep:#0A2A5E;
  --navy-ink:#1F3557;     /* headings — on panel = 10.9:1 */
  --steel-light:#B6C4D6;

  --sh-1:0 1px 2px rgba(26,36,51,.07);
  --sh-2:0 1px 3px rgba(26,36,51,.10);
  --sh-3:0 6px 18px rgba(26,36,51,.14);
  --sh-brand:0 2px 6px rgba(29,78,216,.22);

  --r-sm:6px; --r:8px; --r-lg:10px; --r-xl:14px;

  --font:"Segoe UI Variable Display","Segoe UI Variable","Segoe UI",
         system-ui,-apple-system,"Inter",Roboto,"Helvetica Neue",Arial,sans-serif;
  --mono:"Cascadia Code","SF Mono",ui-monospace,Menlo,Consolas,monospace;
}

*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{
  font-family:var(--font);
  background:var(--bg);
  color:var(--text);
  -webkit-font-smoothing:antialiased;
  /* tabular figures everywhere: money columns must align down the page */
  font-variant-numeric:tabular-nums;
}
@media (prefers-reduced-motion: reduce){*{animation:none!important;transition:none!important}}

/* ---------- LOGIN ---------- */
#login{
  position:fixed;inset:0;z-index:100;
  background:var(--shell);
  display:flex;align-items:center;justify-content:center;padding:24px;
}
/* faint drafting grid — texture at 3% so it reads as material, not pattern */
#login::before{
  content:"";position:absolute;inset:0;
  background-image:
    linear-gradient(rgba(255,255,255,.05) 1px,transparent 1px),
    linear-gradient(90deg,rgba(255,255,255,.05) 1px,transparent 1px);
  background-size:46px 46px;
}
#login::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:150px;
  background:repeating-linear-gradient(120deg,rgba(255,255,255,.05) 0 3px,transparent 3px 26px);
  -webkit-mask:linear-gradient(180deg,transparent,#000);mask:linear-gradient(180deg,transparent,#000);
}
.login-card{
  width:100%;max-width:410px;background:var(--panel);border-radius:var(--r-xl);
  box-shadow:0 40px 90px rgba(3,15,35,.55),0 2px 0 rgba(255,255,255,.6) inset;
  padding:38px 34px 30px;position:relative;z-index:2;
}
.brand{display:flex;flex-direction:column;align-items:center;margin-bottom:24px}
.login-logo{width:100%;max-width:340px;height:auto;display:block;margin:0 auto 4px;object-fit:contain}
.stay-signed{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--muted);margin:-4px 0 14px;user-select:none;cursor:pointer}
.stay-signed input{width:16px;height:16px;accent-color:var(--brand);cursor:pointer}
.slogan{margin-top:14px;font-size:11px;letter-spacing:.26em;text-transform:uppercase;
  font-weight:800;text-align:center;color:var(--brand)}
.mark-full{width:100%;max-width:280px;height:auto;display:block;margin:0 auto;border-radius:var(--r);background:#BFBFBD}
.field{margin-bottom:15px}
.field label{display:block;font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);margin-bottom:7px;font-weight:800}
.field input{
  width:100%;padding:13px 14px;border:1.5px solid var(--line);border-radius:10px;
  font-size:15px;font-family:inherit;background:var(--panel-2);
  transition:border-color .15s,box-shadow .15s,background .15s;
}
.field input:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 4px rgba(29,78,216,.14);background:#fff}
.signin{
  width:100%;margin-top:8px;padding:14px;border:none;border-radius:10px;
  background:var(--brand);
  color:#fff;font-size:14px;letter-spacing:.09em;text-transform:uppercase;font-weight:800;cursor:pointer;
  font-family:inherit;transition:background .15s,transform .06s;
}
.signin:hover{background:var(--brand-deep)}
.signin:active{transform:translateY(1px)}
.signin:disabled{opacity:.6;cursor:default;box-shadow:none}
.login-hint{margin-top:16px;text-align:center;font-size:12px;color:var(--muted);line-height:1.5}
.login-hint code{background:var(--brand-wash);padding:2px 7px;border-radius:5px;font-size:11.5px;color:var(--brand);font-family:var(--mono);font-weight:600}
/* The forgotten-password panel. Collapsed by default so it does not
   compete with the two fields that are the whole point of this screen,
   and open one tap away for the person who cannot get past them. */
.login-hint a{color:var(--brand);font-weight:600;text-decoration:none}
.login-hint a:hover{text-decoration:underline}
.login-forgot{margin-top:14px;padding:14px 16px;background:var(--brand-wash);
  border-radius:8px;font-size:12.5px;line-height:1.65;color:var(--navy);text-align:left}
.login-forgot p{margin:0 0 9px}
.login-forgot p:last-child{margin-bottom:0}
.login-forgot-num{padding-top:9px;border-top:1px solid rgba(0,0,0,.08);color:var(--muted)}
.login-err{color:var(--red);font-size:12.5px;text-align:center;margin-top:12px;min-height:16px;font-weight:700}

/* Change-password modal */
.cp-modal{position:fixed;inset:0;background:rgba(15,20,32,.55);z-index:200;display:flex;align-items:center;justify-content:center;padding:20px;backdrop-filter:blur(2px)}
.cp-card{background:#fff;border-radius:14px;padding:24px;max-width:400px;width:100%;box-shadow:0 20px 60px rgba(0,0,0,.35)}
.cp-title{font-size:18px;font-weight:700;color:var(--navy-ink);margin-bottom:4px}
.cp-sub{font-size:12.5px;color:var(--muted);margin-bottom:16px}
.cp-field{margin-bottom:12px}
.cp-field label{display:block;font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:6px}
.cp-field input{width:100%;padding:10px 12px;border:1px solid var(--line);border-radius:8px;font-size:14px;background:var(--surface)}
.cp-field input:focus{outline:none;border-color:var(--brand)}
.cp-err{color:var(--red);font-size:12.5px;min-height:16px;margin:6px 0 10px;font-weight:600}
.cp-row{display:flex;gap:10px;justify-content:flex-end}
.cp-row .btn.primary{background:var(--brand);color:#fff;border-color:var(--brand)}

/* ---------- APP SHELL ---------- */
#app{display:none;min-height:100%;flex-direction:column}

/* Painted before the first frame, from the inline script in index.html.

   Whether a session token EXISTS is answerable synchronously with no
   network. Whether it is still VALID takes a round trip to Supabase —
   about 220ms on a desk, half a second on a phone — and CSS painted the
   login card for the whole of that wait. Every refresh flashed the
   sign-in screen and then replaced it with your work. Nothing was
   broken; it looked broken, which for the person refreshing is the same
   thing.

   restoreSession still has the last word: if the token turns out to be
   expired it sets the inline styles and the login screen comes back. So
   the worst case is what happened before, and the common case stops
   flickering. */
html.has-session #login{display:none}
html.has-session #app{display:flex}
.topbar{
  background:var(--shell);
  color:#fff;display:flex;align-items:center;justify-content:space-between;
  padding:13px 18px;position:sticky;top:0;z-index:40;
  box-shadow:0 1px 0 rgba(255,255,255,.10) inset, 0 6px 22px rgba(7,26,56,.30);
}

.topbar .tb-brand{display:flex;align-items:center;gap:11px;position:relative;z-index:1}
.topbar .tb-brand .tb-logo{height:34px;width:auto;display:block;background:#BFBFBD;border-radius:8px;padding:3px 5px}
.topbar .tb-brand .tb-name{font-size:15px;font-weight:800;letter-spacing:.11em;text-transform:uppercase;line-height:1}
.topbar .tb-brand .tb-tag{font-size:8.5px;letter-spacing:.28em;color:var(--steel-light);text-transform:uppercase}
.tb-right{display:flex;align-items:center;gap:14px;position:relative;z-index:1}
.tb-user{
  width:36px;height:36px;border-radius:50%;
  background:var(--brand);
  border:1.5px solid rgba(255,255,255,.45);box-shadow:0 2px 8px rgba(0,0,0,.25);
  display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:800;letter-spacing:.04em}
.tb-burger{background:none;border:none;color:#fff;cursor:pointer;padding:4px;display:flex;border-radius:8px;transition:background .12s}
.tb-burger:hover{background:rgba(255,255,255,.12)}
.tb-burger svg{width:26px;height:26px}

/* ---------- EXECUTIVE RIBBON ----------
   A slim, dark strip that sits directly under the topbar and shows the
   five numbers the owner asked to have with him on every screen. Only
   rendered when isExecutive() is true — for everyone else the [hidden]
   attribute removes it from the flow so the shell looks identical to
   before this bar existed. */
.exec-bar{
  background:linear-gradient(180deg,#0F2340 0%, #0A1B33 100%);
  color:#E6EDF7;
  border-bottom:1px solid rgba(255,255,255,.06);
  box-shadow:0 4px 14px rgba(7,26,56,.20);
  position:sticky;top:60px;z-index:30;      /* stays below topbar (which is z:40) */
}
.exec-bar[hidden]{display:none}
.exec-bar-inner{
  display:flex;align-items:stretch;gap:0;
  padding:0 14px;
  /* horizontal scroll on narrow screens so five tiles never squash */
  overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;
  scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.18) transparent;
}
.exec-bar-inner::-webkit-scrollbar{height:6px}
.exec-bar-inner::-webkit-scrollbar-thumb{background:rgba(255,255,255,.18);border-radius:3px}

.exec-bar-eyebrow{
  align-self:center;flex:0 0 auto;
  font-size:10px;font-weight:800;letter-spacing:.18em;
  color:#F4C15C;                             /* warm amber — the "owner" mark */
  padding:8px 12px 8px 4px;margin-right:6px;
  border-right:1px solid rgba(255,255,255,.10);
  text-transform:uppercase;user-select:none;
}

.exec-tile{
  flex:1 1 0;min-width:150px;
  display:flex;flex-direction:column;align-items:flex-start;justify-content:center;
  gap:2px;
  padding:9px 14px;
  background:transparent;border:none;color:inherit;
  border-left:1px solid rgba(255,255,255,.06);
  cursor:pointer;text-align:left;
  transition:background .12s ease;
  font-family:inherit;
}
.exec-tile:first-of-type{border-left:none}
.exec-tile:hover{background:rgba(255,255,255,.06)}
.exec-tile:focus-visible{outline:2px solid #F4C15C;outline-offset:-2px}
.exec-tile .et-lbl{
  font-size:10px;font-weight:700;letter-spacing:.10em;
  color:#9FB1CC;text-transform:uppercase;
}
.exec-tile .et-val{
  font-size:18px;font-weight:800;line-height:1.1;
  color:#FFFFFF;font-variant-numeric:tabular-nums;
  letter-spacing:-.01em;
}
.exec-tile .et-note{
  font-size:10.5px;color:#8A9BB6;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;
}
.exec-tile.tone-green .et-val{color:#5FE0A5}
.exec-tile.tone-red   .et-val{color:#FF8A7A}
.exec-tile.tone-amber .et-val{color:#FFC46B}
.exec-tile.tone-muted .et-val{color:#E6EDF7}

.exec-tile.skeleton{opacity:.4;pointer-events:none}
.exec-tile.skeleton .et-lbl,
.exec-tile.skeleton .et-val,
.exec-tile.skeleton .et-note{color:#5F7290}

@media (max-width:640px){
  .exec-bar{top:56px}                        /* topbar is slightly shorter here */
  .exec-tile{min-width:132px;padding:8px 12px}
  .exec-tile .et-val{font-size:16px}
  .exec-bar-eyebrow{padding:8px 10px 8px 2px;font-size:9.5px}
}

/* ---------- NAV DRAWER ---------- */
#drawer{
  /* Opens from the LEFT, matching the reference. */
  position:fixed;top:0;left:0;height:100%;width:min(340px,88%);
  background:var(--shell);
  z-index:60;transform:translateX(-100%);transition:transform .24s cubic-bezier(.4,0,.2,1);
  overflow-y:auto;box-shadow:12px 0 40px rgba(0,0,0,.35);
}
#drawer.open{transform:translateX(0)}
#scrim{position:fixed;inset:0;background:rgba(4,15,30,.55);backdrop-filter:blur(2px);z-index:55;opacity:0;pointer-events:none;transition:opacity .2s}
#scrim.open{opacity:1;pointer-events:auto}
.drawer-head{display:flex;align-items:center;justify-content:space-between;padding:16px 18px;border-bottom:1px solid rgba(255,255,255,.12)}
.drawer-head span{color:var(--steel-light);font-size:12px;letter-spacing:.22em;text-transform:uppercase;font-weight:800}
.drawer-head button{background:none;border:none;color:#fff;font-size:24px;cursor:pointer;line-height:1;border-radius:6px;padding:0 6px}
.drawer-head button:hover{background:rgba(255,255,255,.12)}

.nav-group{border-bottom:1px solid rgba(255,255,255,.07)}
.nav-group-head{
  display:flex;align-items:center;justify-content:space-between;width:100%;
  padding:15px 20px;background:none;border:none;cursor:pointer;font-family:inherit;
  color:#fff;font-size:13px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;
  transition:background .12s;text-align:left;
}
.nav-group-head:hover{background:rgba(255,255,255,.06)}
.nav-group.open > .nav-group-head{background:var(--shell-2)}
.nav-caret{transition:transform .2s;font-size:11px;opacity:.7}
.nav-group.open .nav-caret{transform:rotate(180deg)}
.nav-group-body{display:none;padding-bottom:8px}
.nav-group.open .nav-group-body{display:block}
.nav-sub{padding:9px 20px 4px;color:var(--steel-light);font-size:10px;letter-spacing:.18em;text-transform:uppercase;font-weight:800;opacity:.7}
.nav-item{
  display:flex;align-items:center;gap:12px;padding:11px 20px 11px 26px;color:#D6E2F2;cursor:pointer;
  font-size:13.5px;letter-spacing:.02em;font-weight:600;transition:background .12s,color .12s;
  border-left:3px solid transparent;
}
.nav-item:hover{background:var(--shell-3);color:#fff}
/* The reference makes the current screen unmistakable: a solid white
   bar with dark text and an amber edge, rather than a slightly lighter
   shade of the same navy. */
.nav-item.active{
  background:#fff;border-left-color:var(--amber-bright);
  color:var(--shell);font-weight:800;
}
/* Icons sit in tinted tiles, one hue per section, so the menu is
   scannable by colour before you read a word of it. */
.nav-item .ico{
  width:28px;height:28px;flex:none;display:flex;align-items:center;justify-content:center;
  font-size:14px;border-radius:var(--r-sm);background:#E8EDF4;
  box-shadow:0 1px 2px rgba(0,0,0,.18);
}
.nav-group[data-group="home"]       .ico{background:#DCEAFB}
.nav-group[data-group="sales"]      .ico{background:#E5DEFB}
.nav-group[data-group="inventory"]  .ico{background:#D8F0E4}
.nav-group[data-group="purchasing"] .ico{background:#FBE9CF}
.nav-group[data-group="production"] .ico{background:#FBDDD8}
.nav-group[data-group="reports"]    .ico{background:#D6ECF5}
.nav-group[data-group="admin"]      .ico{background:#E4E8EE}
.nav-item .soon{margin-left:auto;font-size:8.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--steel-light);border:1px solid rgba(255,255,255,.22);border-radius:999px;padding:2px 8px;font-weight:800}
.nav-item.locked{opacity:.5}
.nav-signout{padding:16px 20px;color:#7FB6EE;font-size:13px;cursor:pointer;font-weight:700}
.nav-signout:hover{color:#A9D2F7}

/* ---------- MAIN ---------- */
main{flex:1;padding:22px 16px 60px;max-width:1140px;width:100%;margin:0 auto}
.page-eyebrow{font-size:11px;letter-spacing:.22em;text-transform:uppercase;color:var(--steel);font-weight:800;margin-bottom:4px}
/* Sentence case rather than uppercase: shouting every title flattened
   the hierarchy. Solid ink — gradient-filled text printed blank. */
.page-title{
  font-size:28px;font-weight:800;letter-spacing:-.02em;margin-bottom:20px;
  line-height:1.15;text-transform:none;color:var(--navy-ink);
}

/* ---------- KPI CARDS ----------
   The single biggest change. These were flat white boxes with a 3px top
   border; they are now built objects — tinted gradient field, a coloured
   spine down the left, and lift on hover. */
.kpi-grid{display:grid;grid-template-columns:1fr 1fr;gap:13px;margin-bottom:24px}
/* min-width:0 because a grid item defaults to min-content width: one long
   unbreakable value ($256,250.00) widens its column, then the grid, then
   the page. KPIs use fmtMoneyShort for this reason, but the layout must
   not depend on every caller remembering. */
/* A plain white card with a coloured top edge, as in the reference.
   The tinted gradient field and corner bloom this replaces were too
   much — the cards competed with the numbers on them. */
.kpi{
  position:relative;min-width:0;background:var(--panel);
  border:1px solid var(--line);border-top:4px solid var(--brand);
  border-radius:0 0 var(--r) var(--r);
  padding:17px 16px 15px;box-shadow:var(--sh-1);
}
.kpi .val{font-size:30px;font-weight:800;letter-spacing:-.025em;line-height:1.05;color:var(--navy-ink);overflow-wrap:anywhere}
.kpi .lbl{font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--muted);margin-top:6px;font-weight:700}

/* Each state gets its own hue family, so the four money cards are
   distinguishable at a glance instead of four identical navy tiles. */
.kpi.green{border-top-color:var(--green)}
.kpi.red{border-top-color:var(--red)}
.kpi.amber{border-top-color:var(--amber-bright)}
/* The number stays near-black whatever the edge colour — a red figure
   for "you owe" reads as an error rather than a fact. The edge carries
   the meaning. */

/* ---------- FILTER CHIPS ---------- */
.filters{display:flex;gap:8px;margin-bottom:15px;flex-wrap:wrap}
.chip{
  padding:9px 18px;border-radius:999px;border:1.5px solid var(--line);
  background:var(--panel);font-size:13px;font-weight:600;cursor:pointer;color:var(--muted);
  font-family:inherit;transition:all .14s;
}
.chip:hover{border-color:var(--muted);color:var(--navy-ink)}
.chip.active{background:var(--shell);border-color:var(--shell);color:#fff}

/* ---------- PANELS + TABLES ----------
   NOT overflow:hidden on .panel. That was here to keep table corners
   inside the rounded panel, and it cost two things:
     - autocomplete dropdowns are absolutely positioned inside a panel,
       so anything below its edge was clipped away. On the Quote Builder
       that hid 154px of a 10-item list — unreachable, on any screen.
     - a table wider than the panel was clipped with no way to scroll to
       the rest. At 375px that put 216px of every table out of reach,
       including the count box on Cycle Counts, which is the last column
       and the entire point of that screen in the yard.
   Tables scroll inside .tablewrap instead, and the corners round there. */
.panel{
  background:var(--panel);border:1px solid var(--line-soft);border-radius:var(--r);
  box-shadow:var(--sh-2);margin-bottom:20px;
}
.tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.panel > .tablewrap:last-child{border-bottom-left-radius:var(--r);border-bottom-right-radius:var(--r)}
.tablewrap table{min-width:max-content}
@media(min-width:640px){ .tablewrap table{min-width:100%} }

.panel-head{
  padding:15px 18px 13px;border-bottom:1px solid var(--line);
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  background:var(--panel);border-radius:var(--r) var(--r) 0 0;
}
.panel-head h3{
  font-size:13px;letter-spacing:.11em;text-transform:uppercase;color:var(--navy-ink);font-weight:800;
  display:flex;align-items:center;gap:9px;
}
/* a small accent tick before every panel title — cheap, and it gives the
   page a repeating rhythm the old flat headers did not have */
.panel-head h3::before{content:"";width:3px;height:14px;border-radius:2px;flex:none;background:var(--brand)}
.panel-head .count{font-size:12px;color:var(--muted);font-weight:600}

table{width:100%;border-collapse:collapse}
thead th{
  font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);text-align:left;
  padding:12px 15px;font-weight:800;background:var(--panel-2);
  border-bottom:1.5px solid var(--line);white-space:nowrap;
}
thead th.num{text-align:right}
tbody td{padding:13px 15px;border-top:1px solid var(--line-soft);font-size:13.5px;vertical-align:top}
/* zebra banding — the single cheapest way to make a long table scannable */
tbody tr:nth-child(even){background:#FBFCFE}
tbody tr:hover{background:var(--brand-wash)}
tbody td.pn{font-family:var(--mono);font-size:12px;color:var(--brand);white-space:nowrap;font-weight:600}
tbody td.num{text-align:right;font-weight:700;font-variant-numeric:tabular-nums}

/* ---------- BADGES ---------- */
.badge{display:inline-block;padding:4px 10px;border-radius:999px;font-size:10.5px;font-weight:800;
  letter-spacing:.04em;text-transform:uppercase;border:1px solid transparent}
.badge.low{background:var(--red-wash);color:var(--red);border-color:#F6CFCF}
.badge.ok{background:var(--green-wash);color:var(--green);border-color:#BFE7D7}
.badge.loc{background:var(--wash);color:var(--muted);border-color:var(--line);
  font-family:var(--mono);text-transform:none;letter-spacing:0}

/* ---------- PROGRESS BARS (cash flow, spend) ---------- */
.goalrow{display:flex;justify-content:space-between;font-size:14px;font-weight:700;color:var(--navy-ink)}
.goaltrack{margin-top:8px;height:15px;background:var(--wash);border-radius:8px;overflow:hidden;
  box-shadow:inset 0 1px 2px rgba(13,38,76,.10)}
.goalfill{height:100%;border-radius:8px;transition:width .4s;background:var(--brand)}
.repline{margin-bottom:15px}
.repline:last-child{margin-bottom:2px}
.rephead{display:flex;justify-content:space-between;font-size:13.5px;font-weight:700;margin-bottom:6px}
.repamt{color:var(--brand);font-variant-numeric:tabular-nums;font-weight:800}
.reptrack{height:11px;background:var(--wash);border-radius:6px;overflow:hidden;
  box-shadow:inset 0 1px 2px rgba(13,38,76,.10)}
.repfill{height:100%;border-radius:6px;transition:width .4s;background:var(--amber-bright)}

/* ---------- JOB CARDS ---------- */
.jobcard{
  position:relative;overflow:hidden;
  background:var(--panel);border:1px solid var(--line-soft);border-radius:var(--r);
  box-shadow:var(--sh-1);padding:16px 17px 15px 20px;margin-bottom:12px;
  transition:transform .16s cubic-bezier(.4,0,.2,1),box-shadow .16s;
}
.jobcard::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--brand)}
.jobcard:hover{box-shadow:var(--sh-2)}
.jobtop{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}
.jobcust{font-size:16px;font-weight:800;color:var(--navy-ink);letter-spacing:-.01em}
.jobdesc{font-size:13px;color:var(--muted);margin-top:3px;line-height:1.45}
.jobamt{font-size:18px;font-weight:800;color:var(--brand);white-space:nowrap;font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.jobmeta{display:flex;align-items:center;gap:10px;margin-top:12px;flex-wrap:wrap}
.stagetag{color:#fff;font-size:10.5px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
  padding:4px 11px;border-radius:999px;box-shadow:0 2px 6px rgba(13,38,76,.18)}
.jobrep{font-size:12px;color:var(--muted);font-weight:600}
.jobactions{display:flex;gap:8px;margin-top:14px;padding-top:13px;border-top:1px solid var(--line-soft);flex-wrap:wrap}

/* ---------- BUTTONS ---------- */
.stagebtn{
  padding:9px 16px;border:none;border-radius:var(--r-sm);
  background:var(--brand);
  color:#fff;font-weight:700;font-size:12.5px;letter-spacing:.02em;cursor:pointer;font-family:inherit;
  transition:background .14s,transform .06s;
}
.stagebtn:hover{background:var(--brand-deep)}
.stagebtn:active{transform:translateY(1px)}
.stagebtn:disabled{opacity:.5;cursor:default}
.stagebtn.ghost{background:var(--wash);color:var(--muted);box-shadow:none;border:1.5px solid var(--line)}
.stagebtn.ghost:hover{background:#E3EBF6;color:var(--navy-ink);filter:none;box-shadow:none}

/* ---------- AUTOCOMPLETE / BUILDER ---------- */
.blabel{display:block;font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);font-weight:800;margin-bottom:6px}
.suggbox{display:none;position:absolute;left:0;right:0;top:100%;margin-top:5px;background:#fff;
  border:1.5px solid var(--line);border-radius:var(--r);box-shadow:var(--sh-3);z-index:30;max-height:280px;overflow-y:auto}
.sugg{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:11px 14px;cursor:pointer;
  border-bottom:1px solid var(--line-soft);font-size:14px}
.sugg:last-child{border-bottom:none}
.sugg:hover{background:var(--brand-wash)}
.sugg .sprice{color:var(--brand);font-weight:700;white-space:nowrap;font-variant-numeric:tabular-nums}
.sugg.none{color:var(--muted);cursor:default;justify-content:flex-start}
.brow{display:flex;gap:14px;align-items:flex-end;margin-top:14px;flex-wrap:wrap}
.brow input{padding:10px 12px;border:1.5px solid var(--line);border-radius:var(--r-sm);font-size:14px;font-family:inherit}
.picked{flex:1;min-width:180px;padding:11px 14px;background:var(--brand-wash);border:1px solid #D8E4FB;
  border-radius:var(--r-sm);font-size:13.5px;color:var(--navy-ink);font-weight:600}

/* ---------- ADD-ROW FORM ---------- */
.addbar{display:flex;gap:9px;padding:15px 17px;background:var(--panel-2);
  border-top:1px solid var(--line);flex-wrap:wrap;align-items:flex-end}
/* Only round an addbar that actually closes the panel. Several screens
   put one mid-panel — the location picker on Cycle Counts, the building
   bar on the Configurator — and rounding those cuts a notch out of the
   middle of the card. */
.panel > .addbar:last-child{border-radius:0 0 var(--r) var(--r)}
.addbar .fg{display:flex;flex-direction:column;gap:5px}
.addbar .fg.grow{flex:1;min-width:140px}
.addbar label{font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);font-weight:800}
.addbar input,.addbar select{padding:10px 11px;border:1.5px solid var(--line);border-radius:var(--r-sm);
  font-size:13px;font-family:inherit;width:100%;background:#fff;transition:border-color .14s,box-shadow .14s}
.addbar input:focus,.addbar select:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px rgba(29,78,216,.14)}
.addbar button{padding:11px 18px;border:none;border-radius:var(--r-sm);
  background:var(--green);
  color:#fff;font-weight:800;font-size:12px;letter-spacing:.05em;text-transform:uppercase;cursor:pointer;
  font-family:inherit;white-space:nowrap;transition:background .14s}
.addbar button:hover{background:#056847}
.addbar button:disabled{opacity:.5;cursor:default;box-shadow:none;filter:none}

/* ---------- EMPTY + STATE BOXES ---------- */
.placeholder{background:var(--panel);border:1px solid var(--line-soft);border-radius:var(--r);
  padding:46px 24px;text-align:center;box-shadow:var(--sh-2)}
.placeholder .pico{font-size:38px;margin-bottom:12px;display:block;
  filter:drop-shadow(0 4px 10px rgba(29,78,216,.22))}
.placeholder h3{font-size:18px;color:var(--navy-ink);margin-bottom:8px;letter-spacing:-.01em;font-weight:800}
.placeholder p{color:var(--muted);font-size:13.5px;line-height:1.6;max-width:400px;margin:0 auto}

.loading{padding:44px;text-align:center;color:var(--muted);font-size:13.5px;font-weight:600}
/* State boxes carry a coloured spine rather than a full tinted border,
   so they read as a message and not as a broken control. */
.errbox{background:var(--red-wash);border:1px solid #F6CFCF;border-left:5px solid var(--red);
  color:#8E1616;border-radius:var(--r);padding:14px 17px;font-size:13.5px;font-weight:600;margin-bottom:16px;line-height:1.5}
.okbox{background:var(--green-wash);border:1px solid #BFE7D7;border-left:5px solid var(--green);
  color:#065F46;border-radius:var(--r);padding:14px 17px;font-size:13.5px;font-weight:600;margin-bottom:16px;line-height:1.5}

.foot{text-align:center;color:var(--steel);font-size:11px;letter-spacing:.05em;padding:26px 0 8px;font-weight:600}

/* ---------- HOME ---------- */
.homehead{display:flex;align-items:baseline;justify-content:space-between;gap:16px;flex-wrap:wrap;margin-bottom:24px}
.homedate{color:var(--muted);font-size:13.5px;font-weight:600}
.homesec{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:28px 0 13px}
.homesec h2{font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);font-weight:800;
  display:flex;align-items:center;gap:9px}
.homesec h2::before{content:"";width:3px;height:13px;border-radius:2px;flex:none;background:var(--brand)}
.homeadd{padding:8px 13px;border:1.5px solid var(--line);border-radius:var(--r-sm);background:var(--panel);
  font-family:inherit;font-size:12.5px;font-weight:700;color:var(--brand);cursor:pointer;
  box-shadow:var(--sh-1);transition:all .14s}
.homeadd:hover{border-color:var(--brand-bright);background:var(--brand-wash);transform:translateY(-1px)}
.homeempty{border:1.5px dashed var(--line);border-radius:var(--r);padding:28px 18px;
  text-align:center;color:var(--muted);font-size:13px;background:rgba(255,255,255,.55)}
.favgrid{display:grid;gap:13px;grid-template-columns:repeat(auto-fill,minmax(180px,1fr))}
.favcard{
  position:relative;overflow:hidden;
  background:var(--panel);
  border:1px solid var(--line-soft);border-radius:var(--r);padding:17px 15px;
  box-shadow:var(--sh-1);cursor:pointer;font-weight:700;font-size:13.5px;
  display:flex;align-items:center;gap:11px;color:var(--navy-ink);
  transition:transform .16s cubic-bezier(.4,0,.2,1),box-shadow .16s;
}
.favcard:hover{border-color:var(--brand);box-shadow:var(--sh-2)}
.favico{font-size:19px;filter:drop-shadow(0 2px 4px rgba(13,38,76,.18))}
/* The remove button only appears on hover so the cards stay calm, but it
   is always in the DOM and always reachable by keyboard. */
.favx{position:absolute;top:8px;right:8px;border:none;background:transparent;color:var(--muted);
  font-size:17px;line-height:1;cursor:pointer;padding:2px 6px;border-radius:6px;opacity:0;transition:opacity .14s,background .14s}
.favcard:hover .favx,.kpi:hover .favx,.favx:focus{opacity:1}
.favx:hover{background:var(--red-wash);color:var(--red)}
@media (pointer: coarse){ .favx{opacity:1} }

/* ---------- QUOTE / INVOICE ---------- */
.docsheet{padding:24px 24px 20px}
.dochead{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;
  border-bottom:3px solid var(--brand);padding-bottom:15px;margin-bottom:15px}
.doctitle{font-size:31px;font-weight:800;letter-spacing:.04em;color:var(--brand-deep);line-height:1}
.docco{font-size:12px;color:var(--muted);line-height:1.55;margin-top:8px}
.docmeta{display:grid;grid-template-columns:auto 150px;gap:6px 8px;align-items:center;
  font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);font-weight:800}
.docparties{display:grid;grid-template-columns:1fr 1fr;gap:15px;margin-bottom:15px}
.docparties textarea{resize:vertical;font-family:inherit}
.di{width:100%;padding:7px 9px;border:1px solid var(--line);border-radius:6px;
  font-size:13px;font-family:inherit;background:#fff;color:var(--text)}
.di:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px rgba(29,78,216,.13)}
.di.num{text-align:right;font-variant-numeric:tabular-nums}
.docterms{width:100%;margin-bottom:15px}
.docterms th{font-size:9.5px;letter-spacing:.07em;background:var(--brand-deep);color:#fff;
  padding:7px 9px;text-align:left;font-weight:800}
.docterms td{padding:6px 7px;border:1px solid var(--line)}
.doclines{width:100%;border-collapse:collapse}
.doclines th{font-size:9.5px;letter-spacing:.05em;background:var(--brand-deep);color:#fff;
  padding:7px 7px;font-weight:800;text-align:left}
.doclines th.num{text-align:right}
.doclines td{border:1px solid var(--line);padding:3px 5px;vertical-align:middle}
.doclines td.dn{width:26px;text-align:center;font-size:11px;color:var(--muted);background:var(--panel-2)}
.doclines td.dext{text-align:right;font-weight:700;font-variant-numeric:tabular-nums;
  white-space:nowrap;padding-right:9px;min-width:92px}
.doclines .suggbox{left:0;right:0;top:100%}
.doctotals{margin-top:15px;margin-left:auto;width:min(340px,100%)}
.dtrow{display:flex;justify-content:space-between;align-items:center;gap:10px;
  padding:7px 0;font-size:13px;border-bottom:1px dashed var(--line)}
.dtrow.dtotal{border-bottom:none;border-top:3px solid var(--brand);margin-top:6px;padding-top:10px;
  font-size:18px;font-weight:800;color:var(--brand-deep)}
.docfoot{margin-top:20px;padding-top:13px;border-top:1px solid var(--line);
  font-size:11.5px;color:var(--muted);line-height:1.65}
.docsign{display:flex;justify-content:space-between;gap:30px;margin-top:30px;
  font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);font-weight:800}
.docsign span{border-top:1px solid var(--steel);padding-top:5px;flex:1}
.docsign span:last-child{max-width:150px}

/* ---------- RESPONSIVE ---------- */
@media(min-width:640px){
  .kpi-grid{grid-template-columns:repeat(4,1fr)}
  .page-title{font-size:34px}
  main{padding:26px 22px 60px}
}

/* Touch devices get bigger targets. Measured at 375px, every control on
   the yard screens came in under 40px — count boxes at 31, Receive at
   32. That clears the WCAG minimum of 24px but is well under the 44px
   platform guidance, and these are the screens used one-handed in the
   yard, often in gloves.

   Scoped to `pointer: coarse` so a mouse keeps the compact layout: this
   is about fingers, not screen width. A laptop narrowed to 375px is
   still being driven by a cursor. */
@media (pointer: coarse){
  #view button, #view .stagebtn, #view .chip,
  #view select, #view textarea,
  #view input:not([type=checkbox]):not([type=radio]){
    min-height:44px;
  }
  #view .chip{display:inline-flex;align-items:center}
  /* hover lift is meaningless without a cursor and causes a sticky
     :hover state on tap, so it is dropped here */
  .kpi:hover,.jobcard:hover,.favcard:hover{transform:none}
}

/* ---------- PRINT ----------
   The invoice is the one thing a customer sees. Everything decorative
   above has to come off cleanly: gradients on text would print as
   nothing at all, since the fill is transparent. */
@media print{
  /* Touch sizing must not follow the page onto paper — a tablet printing
     an invoice would otherwise get 44px rows and repaginate. */
  #view button,#view .stagebtn,#view .chip,#view select,#view textarea,
  #view input{min-height:0!important}
  body{background:#fff;font-variant-numeric:tabular-nums}
  .topbar,#drawer,#scrim,.foot,.noprint,.page-eyebrow,.page-title,.exec-bar{display:none!important}
  main{padding:0;max-width:none}
  .panel{box-shadow:none;border:none;margin:0;background:#fff}
  .docsheet{padding:0}
  .di{border:none;padding:2px 4px;background:transparent}
  .doclines td,.docterms td{border:1px solid #999}
  .doclines th,.docterms th{background:#0A2A5E!important;color:#fff!important;
    -webkit-print-color-adjust:exact;print-color-adjust:exact}
  .suggbox{display:none!important}
  /* Any element whose text is painted by a clipped gradient must be
     given a solid colour back, or it prints blank. */
  /* Titles are solid ink now, so nothing needs rescuing from a
     transparent gradient fill — but keep them dark on paper. */
  .page-title{color:#1F3557!important}
  /* Decorative spines, blooms and accent ticks are pure ink cost. */
  .kpi::before,.kpi::after,.jobcard::before,.topbar::after,
  .panel-head h3::before,.homesec h2::before{display:none!important}
  .kpi,.jobcard,.favcard,.panel-head,.addbar{background:#fff!important;box-shadow:none!important}
  /* Tables scroll on screen; on paper there is nothing to scroll, and a
     clipped overflow box would drop the right-hand columns — on an
     invoice that is UNIT/FT and EXT. PRICE. */
  .tablewrap{overflow:visible!important}
  tbody tr:nth-child(even){background:#fff!important}
}


/* The in-page replacement for confirm(). Fixed and above everything,
   because it is asked at the moment of an irreversible action and must
   not be scrolled away from. */
.askwrap{position:fixed;inset:0;z-index:9999;display:flex;align-items:center;
  justify-content:center;background:rgba(16,21,28,.55);padding:20px}
.askbox{background:#fff;border-radius:var(--r,10px);max-width:460px;width:100%;
  box-shadow:0 18px 60px rgba(0,0,0,.35);padding:22px 24px}
.askmsg{font-size:14.5px;line-height:1.6;color:var(--navy,#23384F);
  white-space:pre-wrap;margin-bottom:18px}
.askrow{display:flex;gap:10px;justify-content:flex-end}
@media (prefers-color-scheme: dark){
  .askbox{background:#161D26}
  .askmsg{color:#E4EAF1}
}


/* ---------- the rate panels on Master Prices ----------
   Percentages read as a set, so they are laid out as one: equal
   columns, boxes the same width, and a hint row that holds its height
   whether or not it has anything in it. The previous flex row let a
   field with an explanation sit lower than its neighbours, which made a
   deliberate set of five figures look like five unrelated boxes. */
.rategrid{display:grid;gap:14px 18px;padding:16px;
  grid-template-columns:repeat(auto-fit,minmax(132px,1fr));align-items:start}
.ratecell{display:flex;flex-direction:column;min-width:0}
.ratelab{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--muted);font-weight:700;margin-bottom:5px;white-space:nowrap}
.rateinput{width:100%;padding:10px 12px;border:1.5px solid var(--line);
  border-radius:7px;font-size:15px;font-family:inherit;font-weight:600;
  color:var(--navy);background:#fff;font-variant-numeric:tabular-nums}
.rateinput:focus{outline:none;border-color:var(--navy);
  box-shadow:0 0 0 3px rgba(35,56,79,.12)}
.ratehint{font-size:10.5px;color:var(--muted);margin-top:5px;line-height:1.35;
  min-height:1.35em}
/* The reset sits with the fields rather than floating under them. */
.rategrid .ratecell.ratereset{justify-content:flex-end}
.rategrid .ratecell.ratereset .stagebtn{width:100%}
@media (prefers-color-scheme: dark){
  .rateinput{background:#161D26;color:#E4EAF1}
}

/* The typed-confirmation field, for actions a click is too cheap for. */
.askinput{width:100%;padding:10px 12px;margin-bottom:16px;border:1.5px solid var(--line);
  border-radius:7px;font-size:15px;font-family:inherit}
.askinput:focus{outline:none;border-color:var(--navy);
  box-shadow:0 0 0 3px rgba(35,56,79,.12)}
.askrow .stagebtn[disabled]{opacity:.45;cursor:not-allowed}


/* ---------- DEC. FT on a quote or invoice ----------
   The calculated length: feet + inches/12, which is what the extension
   has always been priced on. It used to be invisible, so a mistyped
   fraction only surfaced as a total that felt wrong with no way to see
   which line caused it.

   One figure: the length of a single piece. It briefly also carried the
   line total underneath, which on a customer's copy just asks them to
   work out which of two numbers is the length.

   This column gets printed and handed to a customer, so the greys that
   read as "secondary" on screen are lifted to real ink on paper below.
   A length a customer cannot read is worse than one never shown. */
.decft{white-space:nowrap;font-variant-numeric:tabular-nums}
.dfeach{font-weight:600}
.dfnone{color:var(--line)}

@media print{
  /* --line is a hairline grey that vanishes on paper, and --muted is
     close behind it. On screen these are restraint; on a printed quote
     they are a column the customer squints at. */
  .dfnone{color:#555!important}
  .decft{font-size:11px}
}


/* ---------- the language switch ----------
   Two buttons rather than a dropdown. With exactly two options a
   dropdown costs an extra tap and hides the one you are not on, and
   this is the control somebody needs BEFORE they can read the rest of
   the menu — so it has to be legible without reading anything. */
.nav-lang{display:flex;align-items:center;justify-content:space-between;
  gap:10px;padding:12px 18px;border-top:1px solid rgba(255,255,255,.10)}
.nav-lang-lbl{font-size:11px;letter-spacing:.08em;text-transform:uppercase;
  color:rgba(255,255,255,.55);font-weight:700}
.nav-lang-btns{display:inline-flex;background:rgba(255,255,255,.08);
  border-radius:7px;padding:2px}
.nav-lang-btns button{border:0;background:transparent;color:rgba(255,255,255,.65);
  font-family:inherit;font-size:12.5px;font-weight:600;padding:5px 11px;
  border-radius:5px;cursor:pointer}
.nav-lang-btns button[aria-current="true"]{background:#fff;color:var(--navy,#0A2A5E)}
.nav-lang-btns button:hover:not([aria-current="true"]){color:#fff}


/* ---------- language, on the sign-in card ----------
   Above the fields rather than below them. Somebody who cannot read
   "Employee number" needs this before they need anything else on the
   page, and a control you scroll to find is a control you do not find. */
.login-lang{display:inline-flex;gap:2px;padding:3px;margin:0 auto 20px;
  background:var(--wash,#F2F5F9);border-radius:8px;align-self:center}
.login-card .login-lang{display:flex;width:fit-content}
.login-lang button{border:0;background:transparent;color:var(--muted,#5A6675);
  font-family:inherit;font-size:13px;font-weight:600;padding:7px 16px;
  border-radius:6px;cursor:pointer}
.login-lang button[aria-current="true"]{background:#fff;color:var(--navy,#0A2A5E);
  box-shadow:0 1px 3px rgba(16,21,28,.12)}
.login-lang button:hover:not([aria-current="true"]){color:var(--navy,#0A2A5E)}
