/* ─────────────────────────────────────────────────────────────────────────────
   FloorFocused skin — the Add-On Console's look, as one stylesheet.

   The Add-On Console is the design standard for the whole product line, so this
   is a faithful port of its tokens and shell rather than something similar:
   the same navy/red/gold, the same black brand bar over a white menu bar with a
   red active tab, the same 6px cards and 9px inputs, the same dark mode driven
   by data-theme on <html>.

   The floor app's existing class names are mapped onto that look rather than the
   markup being rewritten around new ones — same result, far less to break.

   Edit THIS FILE to restyle the app. Page-level <style> blocks should only hold
   things genuinely unique to one screen.
   ───────────────────────────────────────────────────────────────────────────── */

:root{
  --navy:#1f3a5f; --navy2:#274b78; --red:#c8102e; --gold:#c8a24b;
  --ink:#1c2433; --muted:#6a7686; --line:#dbe0e8; --bg:#eceff3; --card:#fff;
  --ok:#128a4c; --okbg:#e7f6ee; --err:#b42318; --errbg:#fdeceb;
  --warn:#8a5a00; --brand:#c8102e; --brand-soft:#fdeceb;
  --radius:6px; --shadow:0 1px 2px rgba(16,24,40,.08);
}
:root[data-theme=dark]{
  --ink:#e6e9ee; --muted:#9aa3af; --line:#2a2f38; --bg:#15171c; --card:#1d2027;
  --brand-soft:rgba(200,16,46,.16);
}

*{box-sizing:border-box}
html,body{margin:0;background:var(--bg);color:var(--ink);
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  font-size:15px}

/* HARD RULE: no number-input spinner "tickers", anywhere. */
input[type=number]{appearance:textfield;-moz-appearance:textfield}
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}

/* ── the two-bar header ─────────────────────────────────────────────────────
   Black brand bar over a white menu bar. This is the single strongest cue that
   the two apps are the same product, so it is copied exactly. */
header{position:sticky;top:0;z-index:20}
.topbar{display:flex;align-items:center;background:#000;color:#fff;padding:6px 18px;height:76px}
.brand,.logo{display:flex;align-items:center;gap:10px}
.logo .mark,.brand .mark{width:44px;height:44px;color:#fff;flex:none}
.logo svg,.brand svg{width:100%;height:100%;display:block}
.wordmark{font-size:19px;font-weight:600;letter-spacing:.2px;color:#fff;white-space:nowrap}
.wordmark b{font-weight:800}

/* The customer's logo leads and our name is the credit beside it, carrying our
   mark so it reads at a glance rather than as four small words.

   The company NAME is not repeated next to the logo — the logo already says who
   they are, and "REAL FLOORS INC" beside "Real Floors" is the same fact twice.

   52px in a 76px bar: clearly the primary mark, with room left above and below. */
.brand.hasLogo{display:flex;align-items:center;gap:12px}
.brand.hasLogo .mark{width:auto;height:52px;flex:none}
.brand.hasLogo .mark img{height:52px;width:auto;display:block}
.brand.hasLogo .sub{display:none}
.brand.hasLogo .wordmark{
  display:inline-flex;align-items:center;gap:6px;
  font-size:10px;letter-spacing:.13em;text-transform:uppercase;font-weight:600;
  color:#8b929c;white-space:nowrap;line-height:1}
.brand.hasLogo .wordmark b{font-weight:800;color:#aeb4bd}
.pbmark{width:15px;height:15px;flex:none;color:#8b929c;display:block}
.pbmark svg{width:100%;height:100%;display:block}
@media(max-width:640px){.brand.hasLogo .mark,.brand.hasLogo .mark img{height:36px}}
.topbar .sub{color:#aeb4bd;font-size:12.5px;font-weight:500;white-space:nowrap}
.topbar .spacer{flex:1}

/* SIGN OUT MUST SURVIVE A NARROW WINDOW. This is a non-wrapping flex row holding
   the date, install, theme, the signed-in address and the button — and the
   button is last, so when the bar ran out of room it was the first thing pushed
   off the edge. Reported as "there is no logout on the console".

   The brand yields first (it can ellipsis), the right-hand group never shrinks,
   and the two purely informational items drop away before anything you click. */
.topbar .brand{min-width:0;overflow:hidden}
.topbar .wordmark{overflow:hidden;text-overflow:ellipsis}
.topright{display:flex;align-items:center;gap:14px;margin-left:auto;flex:0 0 auto}
@media(max-width:1000px){.topright .today{display:none}}
@media(max-width:820px){.topright .who,.topright .userbox{display:none}}
.today{color:#aeb4bd;font-size:12.5px;white-space:nowrap}
.who,.userbox{color:#fff;font-size:12.5px;background:#17181c;border:1px solid #303338;
  border-radius:5px;padding:5px 11px;white-space:nowrap;max-width:240px;overflow:hidden;text-overflow:ellipsis}
.iconbtn{background:#17181c;border:1px solid #303338;color:#e6e9ee;border-radius:5px;
  padding:5px 9px;cursor:pointer;font-size:14px;line-height:1}
.iconbtn:hover{background:#26282e}
.topbar .btn{background:#17181c;border:1px solid #303338;color:#cbd0d8;font-size:12.5px;padding:5px 11px}
.topbar .btn:hover{background:#26282e;color:#fff}

nav{background:transparent}
.menubar,.tabs{display:flex;flex-wrap:wrap;background:#fff;border-bottom:1px solid #d5dbe3;
  padding:0 8px;box-shadow:0 1px 3px rgba(16,24,40,.06);max-width:none;margin:0;overflow-x:auto}
.menubar button,.tab{background:transparent;border:0;border-bottom:3px solid transparent;
  color:#28313d;font-weight:600;font-size:14px;padding:11px 16px 8px;cursor:pointer;
  font-family:inherit;white-space:nowrap}
.menubar button:hover,.tab:hover{background:#eef2f7}
.menubar button.active,.tab.active{color:var(--red);border-bottom-color:var(--red)}
:root[data-theme=dark] .menubar,:root[data-theme=dark] .tabs{background:#1d2027;border-bottom-color:#2a2f38}
:root[data-theme=dark] .menubar button,:root[data-theme=dark] .tab{color:#c3c8d0}
:root[data-theme=dark] .menubar button:hover,:root[data-theme=dark] .tab:hover{background:#262a32}

main{max-width:1180px;margin:22px auto;padding:0 16px 60px}
.view{display:none}.view.active{display:block}

/* ── surfaces ───────────────────────────────────────────────────────────── */
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:22px;margin-bottom:18px}
h1{font-size:22px;margin:0 0 4px}
h2{margin:0 0 3px;font-size:19px;color:var(--navy)}
h3{margin:0 0 12px;color:var(--navy);font-size:15px}
:root[data-theme=dark] h2,:root[data-theme=dark] h3{color:#e6e9ee}
.sub,.note{margin:0 0 14px;color:var(--muted);font-size:13.5px}
.muted{color:var(--muted)}
.mono{font-variant-numeric:tabular-nums}
.hint{font-size:12px;color:var(--muted)}
.grid{display:grid;gap:14px}

/* ── forms ──────────────────────────────────────────────────────────────── */
label{display:block}
.field,.fld{display:flex;flex-direction:column;gap:6px;margin-bottom:14px}
.field label,.fld>span{font-size:13px;font-weight:600;color:#33415a}
:root[data-theme=dark] .field label,:root[data-theme=dark] .fld>span{color:#c3c8d0}
input,select,textarea{width:100%;padding:10px 12px;border:1px solid #cfd6e0;border-radius:9px;
  font:inherit;color:var(--ink);background:#fff;outline:none;
  transition:border-color .12s,box-shadow .12s}
input:focus,select:focus,textarea:focus{border-color:var(--navy2);box-shadow:0 0 0 3px rgba(39,75,120,.14)}
textarea{resize:vertical}
:root[data-theme=dark] input,:root[data-theme=dark] select,:root[data-theme=dark] textarea{
  background:#12141a;color:#e6e9ee;border-color:#333944}

/* ── buttons ────────────────────────────────────────────────────────────── */
button{font:inherit;cursor:pointer}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;
  background:#fff;border:1px solid #cfd6e0;color:var(--navy);
  padding:9px 15px;border-radius:9px;font-weight:600}
.btn:hover{background:#f3f6fb}
.btn.primary,button.primary{background:var(--red);color:#fff;border:0;padding:11px 22px;
  border-radius:9px;font-weight:700;font-size:15px;box-shadow:0 2px 6px rgba(200,16,46,.28)}
.btn.primary:hover,button.primary:hover{background:#a90d27}
.btn.small{padding:5px 11px;font-size:12.5px;border-radius:6px}
.btn.ghost{border-color:transparent;background:transparent;color:var(--muted);box-shadow:none}
.btn:disabled,button:disabled{opacity:.55;cursor:default;box-shadow:none}
:root[data-theme=dark] .btn{background:#1d2027;color:#e6e9ee;border-color:#333944}
:root[data-theme=dark] .btn:hover{background:#262a32}
/* The dark rule above is MORE specific than .btn.primary (three components to
   two), so without these the primary button quietly turns the same grey as every
   other button in dark mode — the call to action stops looking like one. */
:root[data-theme=dark] .btn.primary,
:root[data-theme=dark] button.primary{background:var(--red);color:#fff;border-color:transparent}
:root[data-theme=dark] .btn.primary:hover,
:root[data-theme=dark] button.primary:hover{background:#a90d27}

.err{color:var(--err);font-size:13.5px;margin:10px 0 0;min-height:18px;font-weight:600}
.msg.ok{color:var(--ok)} .msg.err{color:var(--err)}

/* ── tables ─────────────────────────────────────────────────────────────── */
.tablewrap{overflow-x:auto;border:1px solid var(--line);border-radius:10px;background:var(--card)}
table{border-collapse:collapse;width:100%;font-size:13.5px;background:var(--card)}
th{background:var(--navy);color:#fff;text-align:left;padding:9px 11px;position:sticky;top:0;
  font-weight:600;white-space:nowrap;border:0;letter-spacing:0;text-transform:none;font-size:13px}
td{padding:8px 11px;border-top:1px solid var(--line);vertical-align:middle}
tbody tr:hover{background:#f7f9fc}
:root[data-theme=dark] tbody tr:hover{background:#20242b}
.rescount,.count{color:var(--muted);font-size:12.5px;margin:8px 2px}

/* ── pills ──────────────────────────────────────────────────────────────── */
.pill{display:inline-block;padding:2px 8px;border-radius:20px;font-size:11.5px;font-weight:700;
  background:#eef1f4;color:#465060}
:root[data-theme=dark] .pill{background:#262a32;color:#c3c8d0}
.pill.status-open{background:#fde9c8;color:#8a5a00}
.pill.status-closed{background:var(--okbg);color:var(--ok)}
.pill.private,.pill.new{background:#e4edff;color:#274b78}
.pill.cat-carpet{background:#e8f0fe;color:#1a56db}
.pill.cat-plank{background:#e6f4ea;color:#1a7f37}
.pill.cat-vinyl{background:#fdf2e3;color:#b54708}
.pill.cat-ceramic{background:#f3e8ff;color:#7e22ce}
.pill.cat-pad{background:#fbd5d5;color:#a01818}

/* ── dashboard tiles ────────────────────────────────────────────────────── */
.tiles{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
.tile{padding:18px;background:var(--card);border:1px solid var(--line);
  border-radius:var(--radius);box-shadow:var(--shadow)}
.tile .n{font-size:30px;font-weight:800;line-height:1.1;color:var(--navy)}
:root[data-theme=dark] .tile .n{color:#e6e9ee}
.tile .t{color:var(--muted);font-size:13px;font-weight:600;margin-top:3px}
.tile .bar{height:4px;border-radius:4px;background:var(--gold);width:44px;margin-bottom:12px}

/* ── catalog controls ───────────────────────────────────────────────────── */
.cat-controls{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:12px}
.cat-controls input[type=search]{flex:1;min-width:220px}
.cat-controls select{width:auto}
.chip,.filt{background:#fff;border:1px solid #cfd6e0;color:var(--navy);border-radius:20px;
  padding:6px 15px;font-size:13px;font-weight:600;cursor:pointer}
.chip:hover,.filt:hover{background:#f1f4f8}
.chip.on,.filt.active{background:var(--navy);color:#fff;border-color:var(--navy)}
:root[data-theme=dark] .chip,:root[data-theme=dark] .filt{background:#1d2027;color:#c3c8d0;border-color:#333944}
/* Same specificity trap as the primary button: the selected chip must keep
   looking selected in dark mode. */
:root[data-theme=dark] .chip.on,
:root[data-theme=dark] .filt.active{background:var(--navy2);color:#fff;border-color:var(--navy2)}
.swatch{width:26px;height:26px;border-radius:6px;border:1px solid rgba(0,0,0,.12);
  display:inline-block;vertical-align:middle}
.thumb{width:34px;height:34px;border-radius:6px;border:1px solid rgba(0,0,0,.12);
  object-fit:cover;display:block;cursor:zoom-in}
tbody tr{cursor:pointer}
tr.cmp-on{background:var(--brand-soft) !important}

/* ── sign-in ──────────────────────────────────────────────────────────────
   The app shell starts HIDDEN and is revealed after sign-in. Without this rule
   the whole console renders underneath the login card. */
#app{display:none;min-height:100%}
#login{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px;background:var(--bg)}
.login-card{width:400px;max-width:100%;background:var(--card);border:1px solid var(--line);
  border-radius:12px;box-shadow:0 10px 30px rgba(16,24,40,.10);padding:32px;text-align:left}
.login-card h1{font-size:21px;margin:0 0 2px;text-align:center}
.login-card .tag{color:var(--muted);font-size:13px;margin-bottom:22px;text-align:center}
.login-card .mark{width:52px;height:52px;margin:0 auto 12px;color:var(--navy);display:block}
:root[data-theme=dark] .login-card .mark{color:#e6e9ee}
.brandmark{display:inline-flex;align-items:center;justify-content:center;width:42px;height:42px;
  border-radius:10px;background:var(--navy);color:#fff;font-weight:800;font-size:16px}

/* ── overlays ───────────────────────────────────────────────────────────── */
#lightbox{position:fixed;inset:0;z-index:80;background:rgba(10,14,20,.88);display:none;
  align-items:center;justify-content:center;flex-direction:column;gap:12px;cursor:zoom-out;padding:30px}
#lightbox.open{display:flex}
#lightbox img{max-width:92vw;max-height:78vh;border-radius:12px;
  box-shadow:0 20px 60px rgba(0,0,0,.5);background:#fff}
#lightbox .cap{color:#fff;font-weight:600;text-align:center;font-size:15px}

#cmpBar{position:fixed;left:50%;transform:translateX(-50%);bottom:18px;z-index:60;
  background:var(--navy);color:#fff;border-radius:12px;padding:10px 14px;display:none;
  align-items:center;gap:10px;box-shadow:0 8px 24px rgba(0,0,0,.3);font-size:14px;font-weight:600}
#cmpBar.show{display:flex}
#cmpBar .btn{border-color:#3a5578;background:#2b4b76;color:#fff}
#cmpView{position:fixed;inset:0;z-index:70;background:rgba(28,36,51,.5);display:none;
  overflow-y:auto;padding:30px 16px}
#cmpView.open{display:block}
#cmpView .inner{max-width:1100px;margin:0 auto;background:var(--bg);border-radius:16px;
  padding:20px;border:1px solid var(--line)}
.cmp-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin-top:14px}
.cmp-card{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:12px;position:relative}
.cmp-card img,.cmp-card .noimg{width:100%;aspect-ratio:1/1;object-fit:cover;border-radius:8px;
  cursor:zoom-in;background:#eef1f5;display:block}

.modal{position:fixed;inset:0;background:rgba(28,36,51,.5);display:flex;align-items:center;
  justify-content:center;z-index:60;padding:16px}
.modalbox{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow);
  padding:22px;max-width:520px;width:100%}

#toast{position:fixed;left:50%;transform:translateX(-50%);bottom:24px;z-index:90;display:none;
  background:var(--navy);color:#fff;border-radius:9px;padding:11px 18px;font-weight:600;font-size:14px;
  box-shadow:0 8px 24px rgba(0,0,0,.3)}

@media(max-width:640px){
  .topbar{height:64px;padding:6px 12px}
  .logo .mark,.brand .mark{width:34px;height:34px}
  .wordmark{font-size:16px}
  .topbar .sub{display:none}
  main{margin:14px auto}
  .card{padding:16px}
}

/* ─────────────────────────────────────────────────────────────────────────────
   Page-specific layout.

   These are genuinely local to one screen — grid shapes, the product picker, the
   device-preview frame — so they live below the design system rather than in it.
   Colours come from the tokens above, so they follow light and dark for free.
   ───────────────────────────────────────────────────────────────────────────── */

.row2{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.row3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px}
.calcgrid{grid-template-columns:minmax(280px,420px) 1fr;align-items:start}
@media(max-width:820px){.row2,.row3,.calcgrid{grid-template-columns:1fr}}

.kv{display:grid;grid-template-columns:130px 1fr;gap:6px 12px;font-size:14px;margin:14px 0}
.cmp-kv{font-size:13px;margin-top:10px;display:grid;grid-template-columns:auto 1fr;gap:3px 10px}
.cmp-card .x{position:absolute;top:18px;right:18px}

.result-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:12px}
.result-tiles .rt{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:14px;text-align:center}
.result-tiles .rt .n{font-size:26px;font-weight:800;color:var(--navy)}
:root[data-theme=dark] .result-tiles .rt .n{color:#e6e9ee}
.result-tiles .rt .t{font-size:12px;font-weight:600;color:var(--muted);margin-top:2px}

.linecard{border:1px solid var(--line);border-radius:10px;padding:12px;margin-bottom:10px;background:var(--card)}
.warnbox{background:#fffaeb;border:1px solid #fedf89;color:#93370d;border-radius:8px;padding:10px 12px;font-size:13.5px;margin-top:10px}
.okbox{background:var(--okbg);border:1px solid #bfe6cf;color:var(--ok);border-radius:8px;padding:10px 12px;font-size:13.5px;margin-top:10px}
:root[data-theme=dark] .warnbox{background:#221d10;border-color:#4a3f1e;color:#d8c89a}
:root[data-theme=dark] .okbox{background:#12281c;border-color:#1f5138}

/* type-ahead product picker */
.picker{position:relative}
.picker .menu{position:absolute;z-index:10;left:0;right:0;top:100%;background:var(--card);
  border:1px solid var(--line);border-radius:9px;box-shadow:var(--shadow);
  max-height:260px;overflow-y:auto;display:none}
.picker .menu.open{display:block}
.picker .menu button{display:block;width:100%;text-align:left;border:0;background:none;
  padding:9px 12px;font-size:13.5px;color:var(--ink)}
.picker .menu button:hover{background:#eef3fb}
:root[data-theme=dark] .picker .menu button:hover{background:#262a32}

.pill.status-reviewed{background:#fdf2e3;color:#b54708}

/* Right-hand detail drawer.

   The container rule is load-bearing and must never be dropped: .scrim and
   .panel below are position:absolute, so without a positioned, hidden parent
   they escape to the viewport — the scrim washes the whole page grey and the
   panel pins itself to the right edge as a white band. That is exactly what
   happened when this rule went missing during the reskin. */
#drawer{position:fixed;inset:0;z-index:50;display:none}
#drawer.open{display:block}
#drawer .scrim{position:absolute;inset:0;background:rgba(28,36,51,.45)}
#drawer .panel{position:absolute;top:0;right:0;bottom:0;width:430px;max-width:94vw;
  background:var(--card);box-shadow:-8px 0 30px rgba(0,0,0,.15);padding:22px;overflow-y:auto}
.drawer-close{position:absolute;top:14px;right:14px}

/* the app running in a device frame, so it can be driven from a desk */
.wapp-sizes{display:flex;gap:6px}
.wapp-stage{display:flex;justify-content:center;background:var(--bg);border:1px solid var(--line);
  border-radius:var(--radius);padding:22px 14px;min-height:520px}
.wapp-stage .phone{width:390px;height:760px;max-width:100%;background:#fff;border-radius:34px;
  border:10px solid #11161f;box-shadow:0 18px 50px rgba(16,24,40,.28);overflow:hidden}
.wapp-stage .phone.tablet{width:768px;height:900px;border-radius:20px;border-width:12px}
.wapp-stage .phone.full{width:100%;height:860px;border-radius:12px;border-width:1px;
  border-color:var(--line);box-shadow:var(--shadow)}
/* No width/height transition here: an in-flight transition overrides the cascade,
   so a throttled animation clock (background tab, automation) can pin the frame
   at its old size. Instant resize is deterministic. */
.wapp-stage iframe{width:100%;height:100%;border:0;display:block}

/* ── Add-On screens: installers, warranty, analytics, sales ──────────────────
   Ported from the GAS Add-On Console's own class names, so the two surfaces read
   as one product. Everything below draws on the tokens at the top of this file
   and therefore follows light and dark without a second set of rules. */

/* empty + loading state */
.soon{color:var(--muted);font-size:13.5px;text-align:center;padding:26px 14px;
  border:1px dashed var(--line);border-radius:10px;background:var(--card)}

/* sub-tabs inside a screen (Sales app panes) — quieter than the top tab bar so
   the two levels are never mistaken for each other */
.subnav{display:flex;gap:6px;flex-wrap:wrap;border-bottom:1px solid var(--line);
  margin-bottom:16px;padding-bottom:0}
.subtab{background:transparent;border:0;border-bottom:2px solid transparent;color:var(--muted);
  font-weight:600;font-size:13.5px;padding:8px 14px;cursor:pointer;font-family:inherit}
.subtab:hover{color:var(--ink)}
.subtab.active{color:var(--navy);border-bottom-color:var(--gold)}
:root[data-theme=dark] .subtab.active{color:#e6e9ee}

.togline{display:flex;align-items:flex-start;gap:9px;font-size:13.5px;color:var(--ink);
  background:var(--bg);border:1px solid var(--line);border-radius:9px;padding:11px 13px;margin-bottom:16px}
.togline input{width:auto;flex:none;margin-top:2px}

/* ── charts ─────────────────────────────────────────────────────────────────
   Ported from the Add-On Console's css.html so the Analytics screen is the same
   screen. Google Charts draws into .chart; everything around it is ours. */
.chartblock{margin:14px 0}
.charthead{display:flex;align-items:center;justify-content:space-between;padding:0 2px 4px}
.charthead>span{font-weight:600;font-size:14px;color:var(--navy)}
:root[data-theme=dark] .charthead>span{color:#e6e9ee}
.viewall{background:transparent;border:0;color:var(--red);font-weight:600;font-size:12.5px;
  cursor:pointer;padding:2px 4px}
.viewall:hover{text-decoration:underline}
.chartrow{display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media(max-width:760px){.chartrow{grid-template-columns:1fr}}
/* The chart itself sits on a card, like every other surface in the console. */
.chart{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow);padding:8px;overflow-x:auto}

/* ── swatch cards (Sales app) ───────────────────────────────────────────────── */
.swgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:14px}
.swcard{background:var(--card);border:1px solid var(--line);border-radius:10px;
  overflow:hidden;box-shadow:var(--shadow);display:flex;flex-direction:column}
.swcard .pic{aspect-ratio:4/3;background:#eef1f5;object-fit:cover;width:100%;display:block;cursor:zoom-in}
:root[data-theme=dark] .swcard .pic{background:#262a32}
.swcard .nopic{aspect-ratio:4/3;display:flex;align-items:center;justify-content:center;
  color:var(--muted);font-size:11.5px;letter-spacing:.04em;text-transform:uppercase;background:#eef1f5}
:root[data-theme=dark] .swcard .nopic{background:#262a32}
.swcard .body{padding:10px 12px 12px;display:flex;flex-direction:column;gap:3px;flex:1}
.swcard .st{font-weight:700;font-size:13.5px;line-height:1.25}
.swcard .co{color:var(--muted);font-size:12.5px}
.swcard .qty{margin-top:auto;padding-top:8px;font-weight:800;font-size:15px;color:var(--navy);
  font-variant-numeric:tabular-nums}
:root[data-theme=dark] .swcard .qty{color:#e6e9ee}
.swcard .qty small{font-weight:600;font-size:11.5px;color:var(--muted);margin-left:3px}
.swcard .meta{font-size:11.5px;color:var(--muted)}

/* ── installers ─────────────────────────────────────────────────────────────
   A list you edit in place, so each row is a form rather than a table cell. */
.instadd{display:flex;gap:9px;flex-wrap:wrap;align-items:center;margin-bottom:14px}
.instadd input{flex:1;min-width:170px}
/* ONE list, not a stack of cards. Every row used to be a bordered, rounded card
   with a bordered, rounded input inside it — a box in a box, times two hundred
   installers. At that length the borders stop separating anything and just make
   noise, and a name is genuinely hard to find.

   So the border moves outward: the LIST is the object, rows are hairlines inside
   it, and alternating grey does the separating that a border was failing to do.
   The row is still the form — these fields are live, not a preview — so the
   inputs keep a visible edge, just a quieter one than the row it sits in. */
.instlist{display:grid;gap:0;border:1px solid var(--line);border-radius:9px;overflow:hidden;
  background:var(--card)}
.instrow{display:grid;grid-template-columns:1fr 140px auto;gap:10px;align-items:center;
  padding:5px 10px;border-bottom:1px solid var(--line);background:transparent}
.instrow:nth-child(even){background:#f4f6f9}
.instrow:last-child{border-bottom:0}
.instrow:hover{background:#eaf0f7}
.instrow.off{opacity:.6}
.instrow input{padding:5px 9px;font-size:13.5px;border-radius:6px;border-color:#e1e7ef;background:#fff}
.instrow input:hover:not(:disabled){border-color:#c9d3e0}
.instrow .use{font-size:11.5px;color:var(--muted);white-space:nowrap}
.instrow .acts{display:flex;gap:6px;white-space:nowrap}
:root[data-theme=dark] .instrow:nth-child(even){background:#22262e}
:root[data-theme=dark] .instrow:hover{background:#282d36}
:root[data-theme=dark] .instrow input{border-color:#333944;background:#1a1d23}
@media(max-width:700px){.instrow{grid-template-columns:1fr}}

/* Written install steps — every platform hides this behind a different menu. */
.insteps{margin:10px 0 0 18px;font-size:13.5px;line-height:1.8}
.insteps b{font-weight:700}

/* Aging bands. Thirty days is a nudge, sixty is a problem — the two thresholds
   are the reason the screen exists, so they colour the number itself. */
.agecell{font-weight:800;font-variant-numeric:tabular-nums}
.age-amber{color:#8a5a00}
.age-red{color:var(--red)}
:root[data-theme=dark] .age-amber{color:#d9a441}

/* ── permission matrix ──────────────────────────────────────────────────────
   Wide enough to read the page name, narrow enough that a whole surface fits on
   one screen — ticking twenty boxes is bad enough without scrolling. */
.permgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:6px 14px}
.permrow{display:flex;align-items:flex-start;gap:8px;margin:0;padding:6px 8px;
  border:1px solid transparent;border-radius:7px;font-size:13.5px;font-weight:600;cursor:pointer}
.permrow:hover{background:var(--bg);border-color:var(--line)}
.permrow input{width:auto;flex:none;margin-top:2px}
.permrow span{font-weight:600}
.permrow .hint{font-weight:500}

/* The empty state that is the goal, not a failure — so it reads as a result. */
.caughtup{display:flex;align-items:center;gap:16px;background:var(--okbg);border:1px solid #bfe6cf;
  border-radius:12px;padding:22px 24px;color:var(--ok)}
.caughtup .ic{font-size:34px;line-height:1}
.caughtup b{font-size:17px;display:block;margin-bottom:2px}
.caughtup .muted{color:#3f7d5f;font-size:13.5px}
:root[data-theme=dark] .caughtup{background:#12281c;border-color:#1f5138}
:root[data-theme=dark] .caughtup .muted{color:#8fbfa6}

/* ── approvals ──────────────────────────────────────────────────────────────
   A card, not a table row: deciding needs the materials, the reason and the two
   money fields visible together, and none of that survives being squeezed into
   a cell. */
.tabbadge{display:none;background:var(--red);color:#fff;border-radius:20px;padding:1px 7px;
  font-size:11px;font-weight:800;margin-left:5px;vertical-align:1px}
.aprcard{padding:14px 16px}
.aprhead{display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap}
.aprbody .kv{grid-template-columns:120px 1fr;font-size:13.5px}
.apmeta{font-size:12.5px;color:var(--muted);margin:3px 0}
/* Materials as swatch tiles, the size the Add-On Console uses. */
.apmats{display:flex;flex-wrap:wrap;gap:12px;margin:10px 0}
.apmat{display:flex;flex-direction:column;align-items:center;width:92px;font-size:11px;
  text-align:center;color:var(--ink)}
/* An empty tile reads as "loading" or "broken"; plenty of older carpet simply
   has no artwork and never will, so the tile says so. */
.apmat-none{display:flex;align-items:center;justify-content:center;padding:0 6px;text-align:center;
  font-size:10px;line-height:1.25;color:#6b7280}
.apmat-none::after{content:"No image available"}
:root[data-theme=dark] .apmat-none{color:#9aa3af}
.apmat img,.apmat-none{width:84px;height:84px;object-fit:cover;border-radius:8px;
  border:1px solid var(--line);background:#eef1f5;display:block}
.apmat span{margin-top:4px;line-height:1.2;word-break:break-word}
:root[data-theme=dark] .apmat img,:root[data-theme=dark] .apmat-none{background:#12141a;border-color:#333944}
/* The money bar. Gold ground because this is the decision, not a detail. */
.appricing{display:flex;flex-wrap:wrap;align-items:center;gap:14px;margin:10px 0 4px;
  padding:10px 12px;background:rgba(200,162,75,.10);border:1px solid var(--line);border-radius:8px}
.appricing label{font-size:12.5px;font-weight:700;color:var(--navy);display:flex;align-items:center;gap:6px}
.appricing input{width:110px;padding:6px 8px}
:root[data-theme=dark] .appricing{background:rgba(200,162,75,.08)}
:root[data-theme=dark] .appricing label{color:#dbe4f2}
.ap-margin{font-size:13px;font-weight:800;color:var(--ok);margin-left:auto}
.ap-margin.neg{color:var(--red)}
.apract{display:flex;gap:10px;flex-wrap:wrap;margin-top:10px}
@media(max-width:640px){.appricing input{width:90px}.apract .btn{flex:1}}

/* ── add-on line rows ───────────────────────────────────────────────────────
   Type · material · qty · remove, with the vinyl width question spanning the
   row underneath when it applies. */
.linerow{display:grid;grid-template-columns:120px 1fr 96px 34px;gap:8px;align-items:start;margin-bottom:8px}
.linerow>select,.linerow>input{margin:0}
.linerow .del{background:var(--card);border:1px solid #e6b6b6;color:var(--red);border-radius:8px;
  height:41px;cursor:pointer;font-size:18px;line-height:1;padding:0}
.linewidth{grid-column:1/-1;display:flex;align-items:center;gap:16px;font-size:13px;color:var(--navy);
  background:rgba(200,162,75,.12);border:1px solid var(--line);border-radius:8px;padding:8px 12px}
.linewidth .lwlbl{font-weight:700}
.linewidth label{display:flex;align-items:center;gap:5px;font-weight:600;cursor:pointer;margin:0}
.linewidth input{width:auto;margin:0}
:root[data-theme=dark] .linewidth{color:#dbe4f2;background:rgba(200,162,75,.08)}
@media(max-width:700px){
  .linerow{grid-template-columns:1fr 1fr}
  .linerow .del{grid-column:2;justify-self:end;width:44px}}
/* The auto-filled Month box: shown, not editable — it comes from the submit date. */
.statfield{padding:10px 12px;border:1px dashed #cfd6e0;border-radius:9px;background:#f6f8fb;
  color:var(--muted);font-size:14px}
:root[data-theme=dark] .statfield{background:#12141a;border-color:#333944}

/* ── warranty ───────────────────────────────────────────────────────────────
   Status colours carry meaning: amber is waiting on us, blue is waiting on the
   mill, green allowed, red refused. */
.pill.st-open{background:#fde9c8;color:#8a5a00}
.pill.st-submitted{background:#e4edff;color:#274b78}
.pill.st-approved{background:var(--okbg);color:var(--ok)}
.pill.st-denied{background:var(--errbg);color:var(--err)}
.pill.st-closed{background:#eef1f4;color:#465060}
:root[data-theme=dark] .pill.st-approved{background:#12281c;color:#7bc9a0}
:root[data-theme=dark] .pill.st-denied{background:#2a1616;color:#e59a94}

.trail{display:grid;gap:0;margin:6px 0 0;border-left:2px solid var(--line);padding-left:14px}
.trail .ev{padding:7px 0;font-size:13px;border-bottom:1px solid var(--line)}
.trail .ev:last-child{border-bottom:0}
.trail .ev .when{color:var(--muted);font-size:11.5px}
.modalbox.wide{max-width:620px;max-height:88vh;overflow-y:auto}
